pax_global_header00006660000000000000000000000064152033712700014512gustar00rootroot0000000000000052 comment=9adcc5cf03c88525ef883d6ccaf16a918346ea44 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/000077500000000000000000000000001520337127000207405ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/.gitignore000066400000000000000000000001521520337127000227260ustar00rootroot00000000000000#VSCode .vscode/ # Meson _build/ data/gschemas.compiled .flatpak-builder/ .flatpak/ # Python __pycache__/ Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/.gitlab-ci.yml000066400000000000000000000027551520337127000234050ustar00rootroot00000000000000include: - project: "GNOME/citemplates" file: "flatpak/flatpak_ci_initiative.yml" .vars: image: quay.io/gnome_infrastructure/gnome-runtime-images:gnome-50 variables: MANIFEST_PATH: build-aux/flatpak/se.sjoerd.Graphs.json FLATPAK_MODULE: graphs APP_ID: se.sjoerd.Graphs RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo" CI_IMAGE_X86_64: "quay.io/gnome_infrastructure/gnome-runtime-images:gnome-master" BUNDLE: "se.sjoerd.Graphs.flatpak" interruptible: true cache: key: "$CI_JOB_NAME" paths: - .flatpak-builder/downloads - .flatpak-builder/git - .flatpak-builder/cache # Build Flatpak for x86_64 flatpak@x86_64: stage: build extends: - .flatpak@x86_64 - .vars # Build Flatpak for aarch64 flatpak@aarch64: stage: build extends: - .flatpak@aarch64 - .vars python-lint: image: python:3.12.6 stage: .pre script: - pip install flake8 flake8-docstrings flake8-simplify flake8-unused-arguments flake8-quotes flake8-bugbear flake8-pie flake8-print flake8-warnings flake8-commas flake8-builtins flake8-import-order pep8-naming - flake8 vala-lint: image: "valalang/lint:latest" stage: .pre script: - io.elementary.vala-lint graphs potfiles: stage: .pre script: - | while read -r file; do [[ -z "$file" || "$file" == \#* ]] && continue if [ ! -f "$file" ]; then echo "Potfiles missing file $file" exit 1 fi done < po/POTFILES.in Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/Graphs.doap000066400000000000000000000042441520337127000230350ustar00rootroot00000000000000 Graphs Plot and manipulate data Python Vala GTK 4 Libadwaita Sjoerd Stendahl sstendahl sstendahl sstendahl Christoph Matthias Kohnen cmkohnen cmkohnen cmkohnen Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/LICENSE000066400000000000000000001045151520337127000217530ustar00rootroot00000000000000 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 . Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/README.md000066400000000000000000000065111520337127000222220ustar00rootroot00000000000000# Graphs Plot and manipulate data with Graphs! ![image](https://gitlab.gnome.org/World/Graphs/-/raw/main/data/screenshots/sin_cos.png?ref_type=heads) Graphs is a simple, yet powerful tool that allows you to plot and manipulate your data with ease. New data can be imported from a wide variety of filetypes, or generated by equation. All data can be manipulated using a variety of operations. Apart from regular operations, Graphs also has support for curve fitting on the data, allowing you to effortlessly analyze trends within your datasets. Graphs supports extensive customization options to change the style of the plots. You can add and edit stylesheets in detail, allowing you to quickly save and apply existing stylesheets on new data. Graphs is an excellent fit for both plotting and data manipulation. The plots created with Graphs can be saved in a variety of formats suitable for sharing and presenting to a wide audience, such as in a scientific publication or presentations. It is also possible to save the plots as vector images, which can be easily edited in programs like Inkscape for further customization and refinement. Graphs is written with the GNOME environment in mind, but should be suitable for any other desktop environment as well. The operations include: - Shifting data - Normalizing Data - Smoothening data - Centering Data - Cutting Data - Combining Data - Translating data - Derivative and indefinite integral - Fourier Transformations - Custom transformations For feedback or general issues, please [file an issue](https://gitlab.gnome.org/World/Graphs/-/issues). ## Install Graphs ### Stable We provide official support for the following Flatpak and Snap packages:

Download on Flathub   Get it from the Snap Store

### Beta > The beta branch is used for testing purposes and projects may not be compatible with the stable branch. > Here be bugs, there be dragons. The latest testing version of Graphs is available in the Flathub beta channel. To install the beta, first the Flatpak remote needs to be configured: ```sh flatpak remote-add --if-not-exists flathub-beta https://flathub.org/beta-repo/flathub-beta.flatpakrepo ``` Then, install the application: ```sh flatpak install flathub-beta se.sjoerd.Graphs ``` To run the beta version by default, the following command can be used: ```sh sudo flatpak make-current se.sjoerd.Graphs beta ``` Note that the `sudo` is neccesary here, as it sets the current branch on the system level. To install this on a per-user basis, the flag `--user` can be used in the previous commands. To switch back to the stable version simply run the above command replacing `beta` with `stable`. We are always looking for feedback, so feel free to report any issues or suggestions on the GitLab [issue tracker](https://gitlab.gnome.org/World/Graphs/-/issues). ## Contributing Checkout [the contributing guide](https://welcome.gnome.org/app/Graphs/) to start contributing translations, code or ideas. ## Code of Conduct This project follows the [GNOME Code of Conduct](https://conduct.gnome.org/committee/). Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/build-aux/000077500000000000000000000000001520337127000226325ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/build-aux/flatpak/000077500000000000000000000000001520337127000242545ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/build-aux/flatpak/python-dependencies.json000066400000000000000000000645571520337127000311350ustar00rootroot00000000000000{ "name": "python-dependencies", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "openblas", "buildsystem": "cmake-ninja", "builddir": true, "config-opts": [ "-DBUILD_TESTING:BOOL=OFF", "-DBUILD_SHARED_LIBS:BOOL=ON", "-DBUILD_STATIC_LIBS:BOOL=OFF", "-DDYNAMIC_ARCH:BOOL=ON", "-DUSE_OPENMP:BOOL=OFF", "-DUSE_THREAD:BOOL=ON", "-DNUM_THREADS=64", "-DNO_AVX512:BOOL=ON", "-DCMAKE_BUILD_TYPE:STRING=Release" ], "sources": [ { "type": "git", "url": "https://github.com/OpenMathLib/OpenBLAS", "commit": "62bcfb0dc9f1cfa685fc04135c50e2780c303137", "tag": "v0.3.33", "x-checker-data": { "type": "git", "tag-pattern": "^v([\\d.]+)$" } } ] }, { "name": "python-build-dependencies", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"packaging\" \"pyproject-metadata\" \"meson-python\" \"setuptools-scm\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", "sha256": "5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", "x-checker-data": { "type": "pypi", "name": "packaging", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/1d/0b/da4851b1e2d9c40c9bd74c0abd94510a7d797da9ccde0a90e8953751ed4a/pyproject_metadata-0.11.0-py3-none-any.whl", "sha256": "85bbecca8694e2c00f63b492c96921d6c228454057c88e7c352b2077fcaa4096", "x-checker-data": { "type": "pypi", "name": "pyproject-metadata", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/16/7f/d1b0c65b267a1463d752b324f11d3470e30889daefc4b9ec83029bfa30b5/meson_python-0.19.0-py3-none-any.whl", "sha256": "67b5906c37404396d23c195e12c8825506074460d4a2e7083266b845d14f0298", "x-checker-data": { "type": "pypi", "name": "meson-python", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/e6/60/73603fbcdbe5e803855bcce4414f94eaeed449083bd8183e67161af78188/vcs_versioning-1.1.1-py3-none-any.whl", "sha256": "b541e2ba79fc6aaa3850f8a7f88af43d97c1c80649c01142ee4146eddbc599e4", "x-checker-data": { "type": "pypi", "name": "vcs-versioning", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/5c/e1/342c4434df56aa537f6ce7647eefee521d96fbb828b08acd709865767652/setuptools_scm-10.0.5-py3-none-any.whl", "sha256": "f611037d8aae618221503b8fa89319f073438252ae3420e01c9ceec249131a0a", "x-checker-data": { "type": "pypi", "name": "setuptools-scm", "packagetype": "bdist_wheel" } } ] }, { "name": "python-numpy", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "numpy", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation -Csetup-args=-Dallow-noblas=false \"numpy\"" ], "build-options": { "ldflags": "-lgfortran" }, "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", "sha256": "2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", "x-checker-data": { "type": "pypi", "name": "numpy" } } ] } ] }, { "name": "python-scipy", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "ply", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation \"ply\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/e5/69/882ee5c9d017149285cab114ebeab373308ef0f874fcdac9beb90e0ac4da/ply-3.11.tar.gz", "sha256": "00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3", "x-checker-data": { "type": "pypi", "name": "ply" } } ] }, { "name": "pythran", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pythran\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/a3/61/8001b38461d751cd1a0c3a6ae84346796a5758123f3ed97a1b121dfbf4f3/gast-0.6.0-py3-none-any.whl", "sha256": "52b182313f7330389f72b069ba00f174cfe2a06411099547288839c6cbafbd54", "x-checker-data": { "versions": { "<": "0.7.0" }, "type": "pypi", "name": "gast", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/44/e4/6e8731d4d10dd09942a6f5015b2148ae612bf13e49629f33f9fade3c8253/beniget-0.4.2.post1-py3-none-any.whl", "sha256": "e1b336e7b5f2ae201e6cc21f533486669f1b9eccba018dcff5969cd52f1c20ba", "x-checker-data": { "versions": { "<": "0.5.0" }, "type": "pypi", "name": "beniget", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/2d/25/d608f4a0a4bc3dfad40af2cdb5b92d16b907c3e0a29ff0ab6003740c63ea/pythran-0.18.1-py3-none-any.whl", "sha256": "e1d811a5843d1881f8adcc3944fe3b84c7317ebf4530617829c19c9836f18b49", "x-checker-data": { "type": "pypi", "name": "pythran", "packagetype": "bdist_wheel" } } ] }, { "name": "pybind11", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pybind11\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/b3/06/c3a23c9a0263b136c519f033a58d4641e73065fefc7754e9667ec206d992/pybind11-3.0.4-py3-none-any.whl", "sha256": "961720ee652da51d531b7b2451a6bd2bc042b0106e6d9baa48ecb7d58034ce63", "x-checker-data": { "type": "pypi", "name": "pybind11", "packagetype": "bdist_wheel" } } ] }, { "name": "scipy", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation \"scipy\"" ], "build-options": { "ldflags": "-lgfortran" }, "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", "sha256": "95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", "x-checker-data": { "type": "pypi", "name": "scipy" } } ] } ] }, { "name": "python-matplotlib", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "qhull", "buildsystem": "cmake-ninja", "builddir": true, "config-opts": [ "-DBUILD_APPLICATIONS:BOOL=OFF", "-DBUILD_STATIC_LIBS:BOOL=OFF", "-DQHULL_ENABLE_TESTING:BOOL=OFF", "-DCMAKE_BUILD_TYPE:STRING=Release", "-DCMAKE_POLICY_VERSION_MINIMUM=3.5" ], "sources": [ { "type": "git", "url": "https://github.com/qhull/qhull", "commit": "613debeaea72ee66626dace9ba1a2eff11b5d37d", "tag": "v8.0.2", "x-checker-data": { "type": "git", "tag-pattern": "^v([\\d.]+)$" } } ] }, { "name": "Raqm", "buildsystem": "meson", "config-opts": [ "--buildtype=release" ], "sources": [ { "type": "git", "url": "https://github.com/HOST-Oman/libraqm", "commit": "3a6b891a3db0e0db1364aa38088422f68d8d81e6", "tag": "v0.10.5", "x-checker-data": { "type": "git", "tag-pattern": "^v([\\d.]+)$" } } ] }, { "name": "pillow", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation \"pillow\" -C zlib=enable -C jpeg=enable -C tiff=enable -C freetype=enable -C raqm=enable -C lcms=enable -C webp=enable -C jpeg2000=enable -C avif=enable" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", "sha256": "a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", "x-checker-data": { "type": "pypi", "name": "pillow" } } ] }, { "name": "contourpy", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation \"contourpy\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", "sha256": "083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", "x-checker-data": { "type": "pypi", "name": "contourpy" } } ] }, { "name": "fonttools", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation \"fonttools\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", "sha256": "caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", "x-checker-data": { "type": "pypi", "name": "fonttools" } } ] }, { "name": "cppy", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"cppy\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/8b/3c/823fda3f226d84f983e48005527a6dd2dc365220ac4f098b770779d9f4a1/cppy-1.3.1-py3-none-any.whl", "sha256": "7ca132b6ef6187384738804bd3a453d4eab7e3274df6dcd35e5d92aae3404717", "x-checker-data": { "type": "pypi", "name": "cppy", "packagetype": "bdist_wheel" } } ] }, { "name": "kiwisolver", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation \"kiwisolver\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", "sha256": "d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", "x-checker-data": { "type": "pypi", "name": "kiwisolver" } } ] }, { "name": "cycler", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"cycler\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", "sha256": "85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", "x-checker-data": { "type": "pypi", "name": "cycler", "packagetype": "bdist_wheel" } } ] }, { "name": "python-dateutil", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"python-dateutil\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", "sha256": "4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", "x-checker-data": { "type": "pypi", "name": "six", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", "sha256": "a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", "x-checker-data": { "type": "pypi", "name": "python-dateutil", "packagetype": "bdist_wheel" } } ] }, { "name": "pyparsing", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pyparsing\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", "sha256": "850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", "x-checker-data": { "type": "pypi", "name": "pyparsing", "packagetype": "bdist_wheel" } } ] }, { "name": "matplotlib", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation --config-settings=setup-args=\"-Dsystem-freetype=true\" --config-settings=setup-args=\"-Dsystem-qhull=true\" \"matplotlib\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", "sha256": "fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", "x-checker-data": { "type": "pypi", "name": "matplotlib" } } ] } ] }, { "name": "python-numexpr", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "numexpr", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation \"numexpr\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/cb/2f/fdba158c9dbe5caca9c3eca3eaffffb251f2fb8674bf8e2d0aed5f38d319/numexpr-2.14.1.tar.gz", "sha256": "4be00b1086c7b7a5c32e31558122b7b80243fe098579b170967da83f3152b48b", "x-checker-data": { "type": "pypi", "name": "numexpr" } } ] } ] }, { "name": "python-sympy", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "sympy", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"sympy\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", "sha256": "a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", "x-checker-data": { "versions": { "<": "1.4.0" }, "type": "pypi", "name": "mpmath", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", "sha256": "e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", "x-checker-data": { "type": "pypi", "name": "sympy", "packagetype": "bdist_wheel" } } ] } ] }, { "name": "python-gio-pyio", "buildsystem": "simple", "build-commands": [], "modules": [ { "name": "gio-pyio", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} --no-build-isolation \"gio-pyio\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/5b/51/3c95292f35445e525922c2488d466b4e885595779449bd1becac66546a8e/gio_pyio-0.0.6.tar.gz", "sha256": "bab1231c5a456eee014a27e169ba48735cf532e34b36688b86b74ca3e5ab5915", "x-checker-data": { "type": "pypi", "name": "gio-pyio" } } ] } ] } ] }Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/build-aux/flatpak/python-tests.json000066400000000000000000000031311520337127000276260ustar00rootroot00000000000000{ "name": "python-test-dependencies", "buildsystem": "simple", "build-commands": [ "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pytest\"" ], "sources": [ { "type": "file", "url": "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", "sha256": "f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", "x-checker-data": { "type": "pypi", "name": "iniconfig", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", "sha256": "e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", "x-checker-data": { "type": "pypi", "name": "pluggy", "packagetype": "bdist_wheel" } }, { "type": "file", "url": "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", "sha256": "711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", "x-checker-data": { "type": "pypi", "name": "pytest", "packagetype": "bdist_wheel" } } ] }Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/build-aux/flatpak/se.sjoerd.Graphs.json000066400000000000000000000014161520337127000302700ustar00rootroot00000000000000{ "id": "se.sjoerd.Graphs", "runtime": "org.gnome.Platform", "runtime-version": "50", "sdk": "org.gnome.Sdk", "command": "graphs", "finish-args": [ "--share=ipc", "--socket=wayland", "--socket=fallback-x11", "--device=dri", "--env=NUMEXPR_MAX_THREADS=16" ], "cleanup": [ "*.la", "*.a" ], "modules": [ "python-dependencies.json", "python-tests.json", { "name": "graphs", "buildsystem": "meson", "sources": [ { "type": "dir", "path": "../.." } ], "config-opts": [ "--buildtype=debug" ] } ] } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/build-aux/snap/000077500000000000000000000000001520337127000235735ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/build-aux/snap/snapcraft.yaml000066400000000000000000000041551520337127000264450ustar00rootroot00000000000000name: graphs base: core24 adopt-info: graphs grade: stable confinement: strict compression: lzo platforms: amd64: arm64: slots: graphs: interface: dbus bus: session name: se.sjoerd.Graphs parts: python-deps: source: . plugin: python python-packages: - matplotlib==3.10.3 - numexpr==2.11.0 - numpy==2.3.2 - scipy==1.16.1 - sympy==1.14.0 prime: - -usr/bin/activate* - -usr/bin/Activate.ps1 - -usr/bin/python* - -usr/bin/pip* - -pyvenv.cfg - -share - -include - -lib - -lib64 - -usr/lib/*/dist-packages/pip* - -usr/lib/*/dist-packages/setuptools* - -usr/lib/*/dist-packages/pkg_resources* organize: bin: usr/bin lib/python3.12/site-packages: usr/lib/python3/dist-packages graphs: after: [ python-deps ] plugin: meson source: https://gitlab.gnome.org/World/Graphs.git source-tag: 'v1.8.5' source-depth: 1 meson-parameters: - --prefix=/snap/graphs/current/usr - --buildtype=release build-environment: - PYTHONPATH: $CRAFT_STAGE/usr/lib/python3/dist-packages:$PYTHONPATH build-snaps: - blueprint-compiler/latest/edge override-build: | craftctl default sed -e '1c#!/usr/bin/env python3' -i ${CRAFT_PART_INSTALL}/snap/graphs/current/usr/bin/graphs mkdir -p $CRAFT_PART_INSTALL/meta/gui cp -r $CRAFT_PART_INSTALL/snap/graphs/current/usr/share/icons $CRAFT_PART_INSTALL/meta/gui/ for i in `find $CRAFT_PART_INSTALL/meta/gui/icons -name "*.svg" -o -name "*.png"`; do mv $i "`dirname $i`/snap.$CRAFT_PROJECT_NAME.`basename $i`" done organize: snap/graphs/current/usr: usr parse-info: [usr/share/appdata/se.sjoerd.Graphs.appdata.xml] apps: graphs: command: usr/bin/graphs desktop: usr/share/applications/se.sjoerd.Graphs.desktop common-id: se.sjoerd.Graphs environment: PYTHONPATH: $SNAP/usr/lib/python3/dist-packages:$PYTHONPATH GI_TYPELIB_PATH: $SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0:$GI_TYPELIB_PATH extensions: [gnome] Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/000077500000000000000000000000001520337127000216515ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/Logo.svg000066400000000000000000000101701520337127000232710ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/generate_gresource.py000077500000000000000000000135211520337127000261000ustar00rootroot00000000000000#!/usr/bin/python # SPDX-License-Identifier: GPL-3.0-or-later """ Generate Graphs GResource. Used at build time by meson, but is build-system-independent. """ import argparse import importlib.util import logging import shutil import sys from pathlib import Path from xml.etree import ElementTree from PIL import Image from gi.repository import Gio from matplotlib import font_manager import numpy parser = argparse.ArgumentParser(description="Generate Graphs gresource.") parser.add_argument( "out", help="the output file", ) parser.add_argument( "dir", help="Path to build directory. Files provided will be copied there.", ) parser.add_argument( "style_io", help="Path to `style_io.py`. Used to generate style previews.", ) parser.add_argument( "--ui", required=True, nargs="+", dest="ui", help="List of UI files.", ) parser.add_argument( "--styles", required=True, nargs="+", dest="styles", help="List of style files.", ) parser.add_argument( "--other", required=True, nargs="+", dest="other", help="List of other files to include.", ) parser.add_argument( "--icons", required=True, nargs="+", dest="icons", help="List of icon files.", ) args = parser.parse_args() # Check fonts font_list = font_manager.findSystemFonts(fontpaths=None, fontext="ttf") for font in font_list: try: font_manager.fontManager.addfont(font) except RuntimeError: logging.warning("Could not load %s", font) # Disable matplotlib logging logging.getLogger("matplotlib.font_manager").setLevel(logging.ERROR) # dynamically import style_io spec = importlib.util.spec_from_file_location("style_io", args.style_io) style_io = importlib.util.module_from_spec(spec) sys.modules["style_io"] = style_io spec.loader.exec_module(style_io) # GResource tree creation gresources = ElementTree.Element("gresources") main_prefix = "/se/sjoerd/Graphs/" main_gresource = ElementTree.SubElement( gresources, "gresource", attrib={"prefix": main_prefix}, ) current_dir = Path(args.dir) # Begin Other Section for file in args.other: path = Path(shutil.copy(file, current_dir)) element = ElementTree.SubElement( main_gresource, "file", attrib={ "compressed": "True", }, ) element.text = str(path.relative_to(current_dir)) # End Other Section # Begin style section styles = [] style_paths = {} style_prefix = main_prefix + "styles/" styles_gresource = ElementTree.SubElement( gresources, "gresource", attrib={"prefix": style_prefix}, ) style_list = Path(current_dir, "styles.txt") for style_path in args.styles: style_file = Path(shutil.copy(style_path, current_dir)) style_element = ElementTree.SubElement( styles_gresource, "file", attrib={ "compressed": "True", }, ) style_element.text = str(style_file.relative_to(current_dir)) g_file = Gio.File.new_for_path(str(style_file)) params = style_io.parse(g_file) stylename = params[1]["name"] out_path = Path(current_dir, style_file.name.replace(".mplstyle", ".png")) style_paths[stylename] = out_path with open(out_path, "wb") as out_file: style_io.create_preview(out_file, params, "png", 31) preview_element = ElementTree.SubElement( main_gresource, "file", attrib={ "compressed": "True", }, ) preview_element.text = str(out_path.relative_to(current_dir)) styles.append([ stylename, style_prefix + style_file.name, main_prefix + out_path.name, ]) styles.sort(key=lambda x: x[0].casefold()) with open(style_list, "wt") as style_list_file: style_list_file.writelines(";".join(x) + "\n" for x in styles) style_list_element = ElementTree.SubElement( main_gresource, "file", attrib={ "compressed": "True", }, ) style_list_element.text = str(style_list.relative_to(current_dir)) def _to_array(file_path): with open(file_path, "rb") as file: return numpy.array(Image.open(file).convert("RGB")) # Generate stitched system previews for Adwaita and Yaru for sys_style in ("Adwaita", "Yaru"): light_array = _to_array(style_paths[sys_style]) dark_array = _to_array(style_paths[sys_style + " Dark"]) height, width = light_array.shape[0:2] stitched_array = numpy.concatenate( (light_array[:, :width // 2], dark_array[:, width // 2:]), axis=1, ) stitched_image = Image.fromarray(stitched_array) out_path = Path(current_dir, "system-style-" + sys_style.lower() + ".png") with open(out_path, "wb") as file: stitched_image.save(file, "PNG") preview_element = ElementTree.SubElement( main_gresource, "file", attrib={ "compressed": "True", }, ) preview_element.text = str(out_path.relative_to(current_dir)) # End style section # Begin ui section ui_gresource = ElementTree.SubElement( gresources, "gresource", attrib={"prefix": main_prefix}, ) for ui_file in args.ui: path = Path(current_dir, ui_file) ui_file_element = ElementTree.SubElement( ui_gresource, "file", attrib={ "preprocess": "xml-stripblanks", }, ) ui_file_element.text = str(path.relative_to(current_dir)) # End ui section # Begin icon section icon_gresource = ElementTree.SubElement( gresources, "gresource", attrib={"prefix": main_prefix + "icons/scalable/actions/"}, ) for icon_file in args.icons: path = Path(shutil.copy(icon_file, current_dir)) icon_file_element = ElementTree.SubElement( icon_gresource, "file", attrib={ "preprocess": "xml-stripblanks", }, ) icon_file_element.text = str(path.relative_to(current_dir)) # End icon section # Write tree = ElementTree.ElementTree(gresources) tree.write(args.out) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/graphs.1.in000066400000000000000000000031331520337127000236240ustar00rootroot00000000000000.TH Graphs 1 "@COPYRIGHT@" .SH NAME Graphs \- Plot and manipulate data .SH SYNOPSIS .B graphs .RI [ OPTIONS ] .RI [ FILE… ] .br .SH DESCRIPTION Graphs is a simple, yet powerful tool that allows you to plot and manipulate your data with ease. New data can be imported from a wide variety of filetypes, or generated by equation. All data can be manipulated using a variety of operations such as the ability to select, cut, translate, multiply, center and smoothen data, as well as apply any custom transformations on the data. Moreover, Graphs supports curve fitting on imported data and offers extensive customization options for the style of the plots. You can fine-tune and personalize stylesheets to your liking. Graphs is an excellent fit for both plotting and data manipulation. The plots created with Graphs can be saved in a variety of formats suitable for sharing and presenting to a wide audience, such as in a scientific publication or presentations. Additionally, the option to save plots as vector images allows for easy editing in software like Inkscape for further refinement. Graphs is written with the GNOME environment in mind, but should be suitable for any other desktop environment as well. .br .SH OPTIONS .TP .B \-\-version Show the version of the program. .TP .BR \-w ", " \-\-new-window Open a new window. .TP .BR \-s ", " \-\-style-editor Open a new style editor. .TP .BR \-h ", " \-\-help Show a summary of options. .br .SH SEE ALSO The user documentation may be accessed by pressing \fIF1\fR in the application or via the application menu. Alternatively, it can be seen online at @HELP_URL@ Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/000077500000000000000000000000001520337127000227645ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/axes-one-quadrant-symbolic.svg000066400000000000000000000003421520337127000306570ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/center-symbolic.svg000066400000000000000000000024621520337127000266100ustar00rootroot00000000000000 check-round-outline-whole-symbolic.svg000066400000000000000000000010721520337127000322400ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/color-picker-symbolic.svg000066400000000000000000000026341520337127000277220ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/derivative2-symbolic.svg000066400000000000000000000052031520337127000275500ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/down-symbolic.svg000066400000000000000000000007451520337127000263010ustar00rootroot00000000000000 fast-fourier-transform-symbolic.svg000066400000000000000000000026471520337127000316750ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/function-third-order-symbolic.svg000066400000000000000000000045121520337127000313740ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/graph-symbolic.svg000066400000000000000000000025031520337127000264250ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/hicolor/000077500000000000000000000000001520337127000244235ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/hicolor/scalable/000077500000000000000000000000001520337127000261715ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/hicolor/scalable/apps/000077500000000000000000000000001520337127000271345ustar00rootroot00000000000000se.sjoerd.Graphs.Devel.svg000066400000000000000000000557441520337127000337720ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/hicolor/scalable/apps se.sjoerd.Graphs.svg000066400000000000000000000273171520337127000327270ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/hicolor/scalable/apps Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/hicolor/symbolic/000077500000000000000000000000001520337127000262445ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/hicolor/symbolic/apps/000077500000000000000000000000001520337127000272075ustar00rootroot00000000000000se.sjoerd.Graphs-symbolic.svg000066400000000000000000000065121520337127000346130ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/hicolor/symbolic/apps Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/history-undo-symbolic.svg000066400000000000000000000026771520337127000300040ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/horizontal-arrows-symbolic.svg000066400000000000000000000017401520337127000310320ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/image-print-symbolic.svg000066400000000000000000000020461520337127000275420ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/info-symbolic.svg000066400000000000000000000010321520337127000262530ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/integral-symbolic.svg000066400000000000000000000006351520337127000271350ustar00rootroot00000000000000 inverse-fast-fourier-transform-symbolic.svg000066400000000000000000000021301520337127000333310ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/left-symbolic.svg000066400000000000000000000007551520337127000262650ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/list-compact-symbolic.svg000066400000000000000000000017761520337127000277360ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/loupe-symbolic.svg000066400000000000000000000015741520337127000264570ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/move-tool-symbolic.svg000066400000000000000000000011501520337127000272420ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/normalize-symbolic.svg000066400000000000000000000033461520337127000273320ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/right-symbolic.svg000066400000000000000000000007521520337127000264450ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/se.sjoerd.Graphs.Source.svg000066400000000000000000001047741520337127000301000ustar00rootroot00000000000000 Adwaita Icon Template image/svg+xml GNOME Design Team Adwaita Icon Template Hicolor Symbolic Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/settings-symbolic.svg000066400000000000000000000035731520337127000271740ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/shift-symbolic.svg000066400000000000000000000024561520337127000264500ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/smoothen-symbolic.svg000066400000000000000000000027261520337127000271670ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/transform-symbolic.svg000066400000000000000000000024201520337127000273350ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/up-symbolic.svg000066400000000000000000000007271520337127000257560ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/icons/vertical-arrows-symbolic.svg000066400000000000000000000035761520337127000304630ustar00rootroot00000000000000 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/meson.build000066400000000000000000000153471520337127000240250ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later desktop_file_in = configure_file( input: application_id + '.desktop.in', output: application_id + '.desktop.in', configuration: conf, ) desktop_file = i18n.merge_file( input: desktop_file_in, output: application_id + '.desktop', type: 'desktop', po_dir: '../po', install: true, install_dir: join_paths(datadir, 'applications'), ) desktop_file_validate = find_program('desktop-file-validate', required: false) if desktop_file_validate.found() test('Validate graphs desktop file', desktop_file_validate, args: [desktop_file.full_path()], ) endif appstream_file_in = configure_file( input: application_id + '.metainfo.xml.in', output: application_id + '.metainfo.xml.in', configuration: conf, ) appstream_file = i18n.merge_file( input: appstream_file_in, output: application_id + '.metainfo.xml', po_dir: '../po', install: true, install_dir: join_paths(datadir, 'metainfo'), ) # Validate Appdata appstreamcli = find_program('appstreamcli', required: false) if (appstreamcli.found()) test('Validate appstream file', appstreamcli, args: ['validate', '--no-net', '--explain', appstream_file.full_path()], workdir: meson.current_build_dir(), ) endif configure_file( input: application_id + '.service.in', output: application_id + '.service', configuration: conf, install: true, install_dir: join_paths(datadir, 'dbus-1', 'services'), ) install_data(application_id + '.mime.xml', install_dir: join_paths(datadir, 'mime', 'packages'), ) install_data(application_id + '.gschema.xml', install_dir: join_paths(datadir, 'glib-2.0', 'schemas'), ) gnome.compile_schemas( depend_files: [application_id + '.gschema.xml'], ) compile_schemas = find_program('glib-compile-schemas', required: false) if compile_schemas.found() test('Validate schema file', compile_schemas, args: ['--strict', '--dry-run', meson.current_source_dir()], ) endif configure_file( input: 'graphs.1.in', output: 'graphs.1', configuration: conf, install: true, install_dir: join_paths(mandir, 'man1'), ) blueprint_files = [ 'ui/dialogs/beta-disallowed.blp', 'ui/dialogs/delete-style.blp', 'ui/dialogs/invalid-project.blp', 'ui/dialogs/legacy-migration-disallowed.blp', 'ui/dialogs/reset-import-settings.blp', 'ui/dialogs/save-project-changes.blp', 'ui/dialogs/save-style-changes.blp', 'ui/import/columns/box.blp', 'ui/import/columns/item-group.blp', 'ui/import/columns/main-group.blp', 'ui/import/spreadsheet/box.blp', 'ui/import/spreadsheet/main-group.blp', 'ui/import/spreadsheet/item-group.blp', 'ui/import/sql/main-group.blp', 'ui/import/dialog.blp', 'ui/import/file-row.blp', 'ui/sidebar/edit-item/base.blp', 'ui/sidebar/edit-item/data.blp', 'ui/sidebar/edit-item/equation.blp', 'ui/sidebar/edit-item/equation-group.blp', 'ui/sidebar/edit-item/errorbar-group.blp', 'ui/sidebar/edit-item/generated-data.blp', 'ui/sidebar/edit-item/page.blp', 'ui/sidebar/figure-settings/settings-page.blp', 'ui/sidebar/figure-settings/style-page.blp', 'ui/sidebar/main.blp', 'ui/sidebar/operations.blp', 'ui/style-editor/add-style.blp', 'ui/style-editor/color-row.blp', 'ui/style-editor/editor-box.blp', 'ui/style-editor/item-color-row.blp', 'ui/style-editor/shortcuts.blp', 'ui/style-editor/window.blp', 'ui/add-equation.blp', 'ui/curve-fitting.blp', 'ui/export-figure.blp', 'ui/fitting-parameters.blp', 'ui/generate-data.blp', 'ui/item-box.blp', 'ui/smoothen-settings.blp', 'ui/style-preview.blp', 'ui/transform.blp', 'ui/window.blp', 'ui/window-shortcuts.blp', ] blueprints_ui = [] foreach b : blueprint_files blueprints_ui += b.replace('.blp', '.ui') endforeach blueprints = custom_target('blueprints', input: files(blueprint_files), output: 'ui', command: [ find_program('blueprint-compiler'), 'batch-compile', meson.current_build_dir(), '@CURRENT_SOURCE_DIR@', '@INPUT@', ], ) styles = files( 'styles/adwaita.mplstyle', 'styles/adwaita-dark.mplstyle', 'styles/bmh.mplstyle', 'styles/classic.mplstyle', 'styles/dark-background.mplstyle', 'styles/fivethirtyeight.mplstyle', 'styles/ggplot.mplstyle', 'styles/grayscale.mplstyle', 'styles/matplotlib.mplstyle', 'styles/seaborn.mplstyle', 'styles/seaborn-white.mplstyle', 'styles/seaborn-whitegrid.mplstyle', 'styles/solarized-light.mplstyle', 'styles/tableau-colorblind10.mplstyle', 'styles/thesis.mplstyle', 'styles/yaru.mplstyle', 'styles/yaru-dark.mplstyle', ) icons = files( 'icons/axes-one-quadrant-symbolic.svg', 'icons/center-symbolic.svg', 'icons/check-round-outline-whole-symbolic.svg', 'icons/color-picker-symbolic.svg', 'icons/derivative2-symbolic.svg', 'icons/fast-fourier-transform-symbolic.svg', 'icons/graph-symbolic.svg', 'icons/function-third-order-symbolic.svg', 'icons/history-undo-symbolic.svg', 'icons/horizontal-arrows-symbolic.svg', 'icons/info-symbolic.svg', 'icons/image-print-symbolic.svg', 'icons/integral-symbolic.svg', 'icons/inverse-fast-fourier-transform-symbolic.svg', 'icons/left-symbolic.svg', 'icons/list-compact-symbolic.svg', 'icons/loupe-symbolic.svg', 'icons/move-tool-symbolic.svg', 'icons/normalize-symbolic.svg', 'icons/right-symbolic.svg', 'icons/settings-symbolic.svg', 'icons/shift-symbolic.svg', 'icons/smoothen-symbolic.svg', 'icons/transform-symbolic.svg', 'icons/vertical-arrows-symbolic.svg', 'icons/up-symbolic.svg', 'icons/down-symbolic.svg', ) other = files( 'style.css', 'whats_new', ) style_io = files('../graphs/style_io.py') gresource_generator = files('generate_gresource.py') gresource_xml = custom_target('gresource_xml', input: [blueprints, styles, icons, other], output: application_id + '.gresource.xml', depend_files: [style_io, gresource_generator], command: [ gresource_generator, '@OUTPUT@', meson.current_build_dir(), style_io, '--styles', styles, '--ui', blueprints_ui, '--icons', icons, '--other', other, ], ) gresource = gnome.compile_resources(application_id, gresource_xml, source_dir: meson.current_build_dir(), c_name: 'graphs', ) scalable_dir = join_paths('icons', 'hicolor', 'scalable', 'apps') if debug icon_name = application_id + '.Devel.svg' else icon_name = application_id + '.svg' endif symbolic_icon_name = application_id + '-symbolic.svg' install_data(join_paths(scalable_dir, icon_name), install_dir: join_paths(datadir, scalable_dir), rename: application_id + '.svg', ) symbolic_dir = join_paths('icons', 'hicolor', 'symbolic', 'apps') install_data(join_paths(symbolic_dir, symbolic_icon_name), install_dir: join_paths(datadir, symbolic_dir), ) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/screenshots/000077500000000000000000000000001520337127000242115ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/screenshots/add_equation.png000066400000000000000000000531171520337127000273630ustar00rootroot00000000000000‰PNG  IHDR<£(×Ï‘sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timetor 11 jan 2024 14:44:02üØä IDATxœìÝyxu‚?þwWWúÊÑ9 ’p…pƒÜ r"—Ž32«®¢^;îø¬þft]wGewÜÁÕõ™Ýq.ÇqÅù: #Š!Ü *$ÜG$³“îtWýþUVwúN:}äýzž~º»ªºêS•OºÞý©OUDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD=Lí$ nS""ê r´ H¸s·Å2†£¸#wÇíADD‰„A躾¾ƒïëëODD}KŸ @}m‡ß×Ö—ˆˆÈŸ>€úBè ëHDDÔ] ~9 $òºEJBŸD ‰¶>DDDÑ”0á'QB,®G,–‰ˆˆb_,†ŒX,SHa§Ü›ëÛ‹ˆˆGo‘¸=ñ¼dÙuž?Q¤Èˆl8‰Ëà;õH”YˆÀ<‰ˆˆb…yÆUð‰·ÀÓSåe õU=Ù7¡'žvúÝ-«Îã¹7—MDDIáÙã¹7—ÝëâaGÞ2†r‚>¶%Ž`ÃE¨!¤'ÂOLŸXßa‡[¾PƒN éØÇ‡ˆˆbY >:¡¥pÃK̆žX<Ý ;>ëo¼ÎÇk""¢X'ûxío:_ã*ôÄê½;ýl‚ 3žÃÃùQ,n|&u§P̈Åy¸a'ÔÀ‰‹Û“ˆˆâWO‡ _á'ÜÀn9z]¬í Ãí\ì¯åÆÛ0_Ã-'ÐtDDD½¥;‡¯B >á¶öÄL艵w(å 5ìx :>ÛSÙ‰ˆˆz‹g ö–·àÓ“¡‡Ç‹PÃNOoá&–¶Q ÞZ}‚iÉ 5øÄ]艕z¤ÂŽçé侂O8‡Æ‰•mKDDñ¥'ûËjùñ|ïyz{„žXØ)G"ìxNç/è„Òúão""¢ÞLkŒ¿VŸ÷ 3 zbaÇJ|]0ذã+è 4¼ð Ų@-3¾¯`lè 妤}:ðôtØ| &è„ÒBDDDK‚ +¡ÉÇpø˜&¨…žhïÈC¹õC CMþÂN0AÇ_¶ðQ,óL$/ýŸpCO(‡¶údàénëN8a'PÐñzz²33Q¸B=e\òòÚ×™\Ý =1ßÊ­vO†ÆÛ8Ï ã­õÇßÙ[ 9DD ü‚î-¼(ï=ƒO0¡'˜>=1zb=ðê·ã+ì^¦Ó> ^>뫟à§DDD±@B×VoaEyí/ôÞ[tüå¥-G0úDàé©Ö`ÂN(AGû9ÞçIDD‹<Šï-:ÁŸî„ž˜må‰åÀlØÑ%ì^†k_k?ÏÀCDD±Lp´‡¦$t 7ž(˜ÐÌÙ]Ú²£WØ› Chge;Î[Øñ6Nð˜N 7þv8Q¬ÒíCçåµö3:×Êxåµàe¼¼Gã™®Gôvàé_×ÕñõLØÑ{<ëйM’®zvj&"¢žJ4€Ntî¿äëÃtן•£}Væ¡ìôÉ×3ÐË¡¥;b1ðx®òçkz_ýy|…îa' €ñå—_¶|ùò¢ÌÌÌ¢(Ž–e9;ì5!""ê%:®Öét«¯¯/[·n]éÓO?}€áG ;:|„|…À=Ü(<ƒ¯°£ M1£7[#B9œåí°U(§—û:<%àÛ–½f˜åå—_þè£>b2™îv…ˆˆˆbU{{û†ßþö·o<ýôÓ§Øðía/¾m òv(Ì[ ðéìZ1w1ÂX <ÞZi”÷¾[y;ëÊ[Ÿ¥µG÷Ðc9zôè#FŒø÷ׇˆˆ(æÃNUUÕƒÙÙÙO…´&DDDq¤¶¶ö•¼¼¼?ÂèÑžÅåyö–¯‹öD+O¯žÞ:û(’Áʳώgçfm뎶³²¹¢¢bÃ%ºììì§***–0ýK‡vßè¹ÿôuÛ¦žÖ+/úÞXºw8ËÛU“ýÆò<”¥´êh_Ö¬Y3â¶Ûnû}ÈkBDD‡²²²¤¦¦nÞ²eKÜ[f<;:åÜÛû@˜£®· îá,ÀàñÖIp?¬%½³² ¹±±qµÙlþž¯Â´µµÁn·ÃétQô¾EEF˜Íæh…ˆ(dï–ÙPr´'®8!ÇÔyDáÓé€Âþ"nkÂ}3,>§kkkû«Õj] gki;/+ï=gùº¨¡¿ÛQÀcú@"þ—ˆ•ž@­;Úqžgeùkáñl¶$ýçþ爹sç¾à­ .— MMM°Ûí¤P®ÝwH’„ŽŽ8$%%Ax]F"Š}U×\øÿÞoÀæ#í¨kM¼ï÷ºV ågØuÂŽ©C °š»~7'%%NNNþ¤¤¤äü‡—@¼µèÄt+Ooì©zbE}’®ïítuo!Ȱ|ùò"_ jnnf«NœN'𛛣] "¢ ¬úk#Ž×&þ÷ûñZ'žÛØèsüõ} Þ/áâ먊V }r8"Šâí§¹g‡ª@üý1õýúõ›îmæmmm ;!r:hkk‹v1ˆˆüz·ÌÖ'ÂŽâxëÊl^Ç]ßjï0àÙ-$˜ý«çë˜Ë'”ŽÎžÃ®¶ìëvlÝ ·źWúÞ÷Ôñïë|}èën ]G¼wx¯‰tà eM믬žgmy›¯·?(õ‰r6Vò¼öޝý§¯}«v>þôdè–XÝùJ‘þ¤·SÖ½ '""ê«|íƒÙ_Ú/Çä~6VO0‚ BÚVÇ%‰ˆˆúoûF]Dü ‹ Ñ<Ò£·g_)Ô×ièÞÒ+Q_ÖûRûjËŒŠhž`1¤QÈjjjPSSíb%º¸ØGG2ð„»zú´·¨ý!¶nÝŠû·Ã}÷݇eË–á±ÇÃûï¿­â¸Y¶lî½÷ÞhƒzÐ;#Y³faÖ¬YصkWÀé·mÛ†Y³fá7Þ{š+V¨Ëô|ôæõ™ÚÛÛÑÒÒâvut›Í†»ï¾wß}7¯E=nÅ©({6eÏæbv¡)àô F›Qöl.þaNj·¦‰ žÞ¯F2„EŒÔŒcDTÂŽËåÂêÕ«±oß>˜Íf@–eœ:u gÏžF‘¨())Q_—––böìÙ½¶ìÙ³gÃ`0¸ Óë{ëÎ5ÀüÇ`Ë–-xçwPXX0™L(((Æ^+ õ Ç~{/Áù£ÌØu"!®ó-5áJ”ÀS¤?üûöíÃÌ™3ñÏÿüÏHMíLë²,ó"}UUU¨¬¬Ä÷¿ÿ}|úé§Ø¹s'\.W¯…ŽU«VÁjµöʲ‚%Þ|óÍhƒP~†ˆQ9Iøð`+³`îHôàJ¼Ûs)tè…›{FZ4O°!%æšÅüq¹\x÷Ýwa±XðÔSO©at:L&±víZ|ñŨ««ƒÕjÅܹs±bÅ õWò²eË0oÞ<˜L&ìÙ³¸õÖ[ñƒü@Ÿ$IX¿~=¶nÝŠ+W®`ذa¸ï¾û0uêT´··ãü#öíÛ‡ÖÖVŒ??úÑ0`À€^ß&yJëÎüùóÑÐЀ­[·âË/¿Ä´iÓÔil6^{í5ìÚµ ‹iii]æÌ4¡ÒÎ3%%‹/Æûï¿»ï¾<òêëëqë­·büøñꡳ×^{ ï½÷Ö¬Yƒ‰'â7ÞÀ¾}ûpåÊddd ¸¸>ú( V­Z…-[¶~ðƒ@¯×c÷îÝ€ À`0`óæÍ:ÿgÞ~ûmlÞ¼µµµ:t(yäÜtÓMjy,X€[n¹f³Û·o‡ÃáÀ²eËðÿðÝÞ”n¹Þº³õX¬fÅc̘<؈g¿ýAk1èð“…VÌ)4ÃæÐØÖ5 3MtgŸL(ŠZxŠ—NËq£ººííí(,,ô¹³0 Ø¿? „Ù³gC–eüùÏÆ{ï½ç6ÝæÍ›±wï^ 4 x÷ÝwQVV¦Žýõ×ñÖ[oÁår©}&, €Î&þ7¢  ³fÍÂðâ‹/BæÕ·RII ’““1yòdõPVii©Û4?ûÙϰqãFôë×ÇÇÑ£G»Ì'˜i¼y饗°jÕ*õñç?ÿÙë<Œßÿþ÷hjj zÝŒF#víÚ…üü|,X°²,ãÝwßÅÿøGE1oÞ<<üðÃ>çõ_ÿõ_øÍo~Q1sæLTVVâÉ'ŸÄW_}å6ÝÆ±cÇäåå¡¡¡øÃÔE´p¬­vÏ9°óú¡¬ù£ÌnÓ¼ø½L|oR2®¶¸pêŠãºÌ'˜i¨çÄã!­`®5ÕÕÕà÷—±ÙlÆÛo¿­¾¿tézè!”——cÅŠnÓ¾ñÆHJJŸþô'üßÿý:„3fàêÕ«øøã‘››‹_ÿú×ný'NŸ>òòrL™2Ï=÷€Îû]íܹÕÕÕÈÍÍíÉU¦(;wîNž<‰[n¹¢(⦛n‚ ؾ};žzê)èt:\¸p;wîDNNÞ|óMˆ¢ˆW_}ëׯWçÌ4¾x†+½^;ï¼çÏŸï2Ï_|üqÐëg6›±aÃõýÅ‹qçwbïÞ½xôÑG1þ|,\¸[¶lÁ#<¢öáñTSSƒ 6`øðáxë­· Š"6n܈ŸÿüçX»v-&Mšä6ýúõë‘””„·Þz ¿ùÍopðàAÜ|óÍA—›ÓÐ,#²“Pr´ NIÆžSíd h” ÿõigÓE~¦ˆ¹#M¸ÜäÂo^S’ñÔ"+þ~zŠ:Ÿ`¦‰1ž-3qw˜+ÖOO…—¨… ¬¬,ÀåË—ýNwüøqlذGŽAss3dYîò«×jµ")) 0fÌ@cc#àÌ™3$ Ó¦MëÒYôÂ… €ƒbÉ’%nãš››Ã\3ŠUÊᬒ’õ,%I’påÊTTT`„ 8sæ `úôéÅÎûÉ“'»…™`¦ñåÓO?õÚ‡ÇÛ<çÌ™Rà€£Gâý÷ßÇ¡C‡ÐÔÔY–Õÿ…`:u ’$aæÌ™jY.\ˆŸÿüç]N&HOOWÿ÷Æhhhiy”˜”ÃY·Œ5C§Ë: ªãs 8|Ñáý:ëWÙ;œRg&øò¼?ýÛù3Mõä¾8fBQ¬ž¸—ŸŸApêÔ)œ;wC† é2ÍåË—ñôÓOcÀ€øÉO~‚!C†|Øm³¹s§qæÌušÓ§O«ã:„öövÜtÓM˜6mÒÓÓNç·w‚VB‰¿ÌaÆvïÞ­þÏìÙ³²,û< F¤5¼†õqð¼3þã¢ú¸çwµ€ù£;ƒó¹ºÎºyó ׃ͨœ$·y3 õ,þt‰€•+W¢¢¢§N£>ŠaÆ!-- gΜÁôéÓÕN–›7o†ÓéDEE€Ð®[RPP€ &àðáÃxâ‰'0eÊœ={÷ß?ÆŽ‹¥K—bÓ¦MøñŒ¢¢"ÔÕÕÁf³á§?ý)€Î>F555xûí·q×]w©;Š/JëΜ9s܆>ƒ ÂÅ‹qâÄ â†nÀ×_xÆ sk€#FœÆ——^zÉ-LÀsÏ=‡ÂÂBLœ8‡ò9O³ÙŒQ£F¡²²>ø 222P^^®ŽÏÎÎÐÙ‘Øétâ믿àÞòRXXˆO>ù¯½öfÏžx Ë¡ÞáÇãÆoÄÞ½{±råJŒ9;wî„Á`Àƒ>ÔzRߦ\{gçq÷kÒê'rÓEH‰š|uÁIùüßÃýqúŠÓíº=p²6ð4Ô³b½…'œãˆQïÄl±XðË_þ>ø Fމªª*?~ ÀèÑ£1qâDÜsÏ=EŸþ9 ºì°‚±jÕ*,Z´---Ø´iÔ_®?úѰråJ‚€>øÇŽƒÉdR[uyäddd`Ó¦Mn¿¦)¾|þùçàõ"ƒÊ°mÛ¶è %óæÍCmm-.^¼ˆ—^z ýû÷wûL0ÓxSZZŠ-[¶¸=”˜—^z sçÎEmm-jkk½ŽúÙÏ~†±cÇ¢ºº.—K æ0eÊ<ðÀEŸ|ò Q\\ìöù;ï¼K–,Auu56nÜè³Nÿû¿ÿ;¾ÿýïÃf³aÏž=7nÞxã <8à:ÝrýÖN/T.<¸`tç4ÿúÿê°½²Ù©zäeèñ¯ÿ¯WšÝ[ñƒ™&ŠârÿëO$ hÞ¾îl®'xyïyã2ÁãµòÐ_¯¿Vž­‡c·]½z5@‘É—~ýúE»'¶mÛ†Ÿþô§xä‘GðÈ#D»8ÔGܼ¦6ÚEˆŠÝÿ’íu¸Á`¸ @#§æYºþZÒ<äëíkh†A3Ìó½vzxŒó%"ý-¢ÕÂÓ)ˆˆˆ"&* ÖiÂàDDDÔ;âzŸ©À×…ˆˆˆ¢&"‚giQ¯š?>öíÛíbQˆˆˆˆbà!"¢„§cG‹>Gƒ—·źÂþ}ï{j䀾·Îþ0ðhÆh!.q»Q¬»e¬ïû¥%ª…cúÞ:ûÃÀ£a6›ÙZ"Qy[ "Šy÷Ͱ`dvßù~9@Äò=w#àDÀÀã!55•¡'H¢(ªwf'"Šu«¿gí¡gd¶ˆ¿kv1bN¤ºq…z[ eX¨·–ÐÞV¢Û·–ÐjkkƒÝnw»#3uEF£‘-;D—Þ-³¡äh;N\qBŽÈM zŸN×ÙOé–±&ÜDËN˜·–ÐÞ^ÿÖð1,”ñ!cà!""êcúbàá!-"""Jx DDÔS” £Ý·0ü„'DÚŠ§¼–$Éç4DDD¡ð 5‚ ¨Ã•ý ƒOèx‚ät”‡Ëå‚Ëå‚Óéì|ˆˆˆÂ%DQ„^¯‡^¯‡N§S >¡cà ‚6ìH’Y–át:áp8 Ìf3RRR +u›,Ë$ hkkƒÝn‡Á`€(ŠÐétj«,ËÜï‰'%ì(-:’$Án·¬V+D‘›ˆˆz–N§S[vL&œN'š››át:a4Õi”Ö†žÀxZºÚ°#IœN'l6ŒF#222vˆˆ¨Wˆ¢ˆŒŒ FØl6µ…v?Eþ1ðøàÙgG’$´··#%%‹%Š%#"¢¾Êb± %%ííín`è „MH’—˻ݳ٠“Éí"Qf2™Ôý’rxKéÓC¾q y¡=Ý\é  ÉÉÉÑ,€o÷GN§S= °•Çž”šší¢©RSSa·Ûár¹¢]”¸ÀÀãÁ³uÇårA¯×#)))Ê%#""úVRRôz=\.[y‚ÀÀã‡r vR&"¢Xd±XÐÑÑÁ ßÇ Ï+) †h‰ˆˆ¨ ƒÁ ¶ð(òŽGÃÛí#$Ibïw""ŠI‚ ¨]0xŠºÜ“{áÙ‡W°$"¢X¤\i™ýwcà  ;ÇE?ùäìÞ½ÛmØ‘#G°aÆî‹ˆˆ@÷öS} =‘’çÌ™ƒÃ‡£©© @çõöïß¹sçv{ÞDDDZlÝñ'‚RRR0uêTµ•çàÁƒ>|8233£\2""¢¾…·–ˆ°)S¦àwÞÁ™3gPQQåË—w™æÌ™3زeK—ásæÌÁ˜1cz£˜DDD 'Âôz=æÎ‹7bÞ¼y^ïÅ5lØ0üð‡?ŒB鈈ˆúÒêÇGRRFí¢õIláé%:Îçéí<¤EDDY <1€‡´ˆˆ‡Ãá@]]rrrx·ÂCZDDD=¤´´‹/Æí·ßŽ{î¹çÏŸv‘è:ž^ò£ýÈk‡e""J Ÿ}öžyæ477N:…gžy†×lj ¶ðDØž={°bÅ Ìž=wÜqþ÷ÿW·bÅ üõ¯u{ÿæ›oâ‡?ü!æÍ›‡å˗㫯¾RÇ—””à–[nN§Ãï~÷;Ü{ï½ê}[l6n½õVlܸ°hÑ"ìÚµ ­­­½´¦DD‰íÀêcÓ¦M ;q†'‚šššðôÓOã»ßý.>þøc¼òÊ+X°`Ïéðúë¯ã‰'žÀ_þòŒ?Ï<ó :::gÏžEAAàÁ„ËåŸþô'Àï~÷;â»ßý.`РAÐëõ8zôh„×’ˆˆ(öñV]¹r˜={6ÒÒÒ––æwúôôt<øàƒ?~<àÀ‡~ˆ .`øðᨪªBnn. )) Ï>û,žxâ :}ôÖ­[§ÎK§Ó!77.\ÀôéÓ#·’DDDq€-<4lØ0L›6 wß}7ž}öÙ : ·’AƒÁl6Ãf³¡½½×®]Cvv¶:þ†nÀâÅ‹ñãÿ?ùÉOÜÆǘ[ZZzn…ˆˆˆâO ‚€×_ÿýßÿ¤¤$<ýôÓxê©§Bš‡N§s{nnnvŸ™™ 0›Í]>ÛØØˆ¤¤¤pŠNDD”PxzÁÔ©SñüóÏãÍ7ßÄöíÛÕk9„Âh4Â`0àòåËê°sçÎáƒ>ÀO<5kÖt C—/_xˆˆ¨/`à‰ ¦¦&lܸµµµhooÇ_|³ÙŒôôô°æ7bÄ\ºt @ç5yžþy¬\¹+V¬ÀèÑ£ñÚk¯©ÓÚívÔ××£°°°GÖ…ˆˆ(ž1ðDPss3¶nÝŠûï¿ÅÅÅØ°a~ñ‹_À`0„5¿©S§â믿¬]»mmm¸ï¾ûÏ<ó ¶lÙ‚òòrÀ¡C‡`µZÕ³ºˆˆˆú2]”æëm¼N3\y¼¼×N#h>§¼WúëÏâõ×ʳÕápìñV(Y–t¶ž¸\.8N477#///ÀêôŽÓ§OcÅŠøä“OššêwÚ矩©©!÷""¢øRUU…ÔÔTˆ¢½^¯žü¢ôýôÆ`0Ü € €Só,]-i²æ¡¼‡æ=4Ã<ßËš×ZÞ†…2>dláñA[Q” mÇÇ7Þˆµk×ú®ººÛ¶mÃý÷ßßK%#"¢hÐîŸüâux’$A¯×G»(€Ÿüä'8}ú´ßiŒF#~ö³ŸaÀ€½T*""ŠI’Ü.gB¾ñ–†’”eYViµµµ!55‹%À*õ.›Í†ææf˜Ífõ–çåL¼á!-r£Óé ×ëyñ>""ŠI---n!‡|càñA§ÓA§ÓAEttt¨÷³"""ŠʾIEuŸE¾1ðhh+‹þðÓ IDATN§ƒ ƒõõõQ,‘»úúz u_å¹#w <^(IYÛÊ#Iššš¢]4"""455A’$·Ö¶òøÇÀã‡Ò‡G¯×Ã`0 ©© 6›-ÚÅ""¢>Ìf³¡©© ƒAÝG1èÆÀãAÛ»]y‚Qa2™PWWÇ–""ŠŠ¦¦&ÔÕÕÁd2AEõP–¶u‡áÇ;^‡'íõ dY†ÅbAss3l6233þMQ°êëëár¹`±XÔ–í••É?/t:dYVŸ¨­<`2™ÐÑÑË—/Ã`0 -- F£±K§1""¢pȲ I’`·ÛÑÔԇÃÁ“ɽ^¯¶î(غOÊ!-íÕ–µ‡¹œN'êëë!I$I 07""¢à(g_‰¢¨¶ê‚ ¶ì(Ó0ä‡ÇmëŽpdYV;‡)—óV:4K’Y–cæ¾[DD¿´}Hµ—IÑž‚îyVƒ <~x†í³Ò꣄å5QOÐå5¯wCgØ Œ'ÏÐ#Ër—bžÃ|ˆˆ(\žAFûCÛ×4O¼µôhCŽö¦£DDD=Á[GdÏpð<ž iƒŽç{öŽ'"¢HbÐé>žù >DDD‘Æ}Nøx¤­t<”EDD‘ÂÓ3xz+#Qlãõ¨‰ˆˆ(á±…'H›7oÆñãÇ» ÏËËÃ÷¿ÿý æár¹ ˲z‹ŠDám½Þ{ï=L˜0ãÆ‹bÉÜy+ç»ï¾‹Q£FaÚ´iÝž,®s$ôä6ó”¨ÿ#ôôz»\.üêW¿ÂÊ•+aµZ#¾|Y–±cÇTVVÂl6ãÖ[oEVVVXó"Š”¾õ­ÒM&LÀÍ7ßì6,”ÃYåååhhhÀ’%KzºhQ/ë孜ÇGvvvK"¹Íâ¥.õ´h¯ww—äÈTUUá¾ûîƒN§ƒÉdêáuO”ÛHPâ¸ñÆ£]„¸ÃmFžäääh…È'žôÞ{ï¡  çÏŸÇ•+W––†¢¢" 4_|ñÊÊÊ'OžÄøñãQTT—Ë…½{÷âĉp:(((Àœ9s””¤ÎsêÔ©8zô(.]º„[o½ƒV—ér¹°gÏœ9s---HIIÁŒ30zôh¿e눿eÚív¼ÿþû˜6m.\ˆ¡C‡"==)))~Çy[Ïýû÷ãôéÓX²d &Nœˆªª*|ñŘ0aAðû¡­Ë¾þF毵{÷nœ?K—.ÅøñãqöìY\¼x“&M‚Éd ºÞù*k8ÿ¯êޝõ´,ë}þüyÔÕÕaÒ¤I0›Í!/?”ï•aÆ¡££ééé¸÷Þ{1a¿ß]ÁÖ—`ÿ÷)<«W¯þ;€äñìùÐ õ}ÌàYZ!8tè~ýë_»=N:¥Ž7™LX°`rrr`6›1mÚ4Øl6444xŸÃáÀ‘#G0wî\X,¤¤¤`Ö¬Ynó€qãÆa„ èׯŸ×N…'NDVV¬V+¦M›†´´4ÔÔÔx]¦RÆÀb±`Ê”)€éÓ§#==ééé;v,ª««Ãš¿Âl6£¨¨Èë¶f½{«œZ’$áÀX°`²³³‘’’‚‘#Gª¿¨Ã õÕëõ(..FYYΞ=‹o¾ù ,p›Gqq1 „””Ì™3f³Ù­½g ´Ì––¸\. :F£YYYj‹‘¿qž\.<ˆùóç«ÛfÑ¢Ep88sæ €Ðÿ/B¿ÂétâСC(..F¿~ý`µZQ\\ôß!PY»óÿjÝ vYÊ6ò·Þá,?ÜÏxòܡԗPþ÷‰‚ÁCZ!˜4iæÎëwm'æ´´4$%%¡££Ãë´ e|ðú9I’àp8ܦËÉÉñ»Ì¶¶6TVV¢ººv»p:A•Q9“B[ÆÌÌL·÷¡Î_¡×Û€¨ÝÁ®wo•SÑÔÔ‡Ãá³Cn¸óf}ˆ‘#GbãÆX¸p¡ÚšâN§ÃÀ݃g ´ÌÌÌLäååaíÚµ6lƇüüü€ã<566B’$·m–””„œœ\»vÍ­ÌŠ@ÿáÌ_;mÿþý½.7œzN½õöÿjÝ vYÊ´þÖ;œå‡ûOžÛ"œúÌÿ>Q0x¢Èh4î½÷Þ°ÏjèèèÀúõë1bÄÌœ9©©©øóŸÿ I’z¤Œ‘˜O¬w$Êi·Ûx¿rvwæìúZ,ªc¼N§ó{ q eêt:,[¶ UUUøæ›o°iÓ&äååá;ßùŽßqž”Ó™%Ir ¸z½Þí}¸B™¿$IeÙíþvZÝ­wá~>œºʲ­w8ËÔ÷J¤ë ‘?<¤ÕË´_©©©0 8}útØó«­­E{{;n¾ùfdeeÁ`0àêÕ«hiié‰â=ÿP¾{b½#QN«Õ Y–Q[[öü½ f}¯]»†C‡aöìÙ(--UÃØl6µS¨¢¦¦ÆïuN‚ÝÆyyyX¸p!îºë.œ>}Úm}üS(×xÑ^P¶a¸×aÑþB™¿·iµº[ïÂý|8u3”eZïp–©ï•HÔ¢`1ð„@’$ttt¸=\.WПOIIÁÅ‹ÑÜÜŒŽŽ‚€©S§ª%IBKK‹×®/‹v»‡F{{;Nœ8^Ï` G0ó÷\¯@zb½#QN“É„‚‚”––âÚµkj¿‚ŽŽŽ æo6›ÑÔÔòúʲŒ-[¶`êÔ©˜2e ú÷ï]»v©ŸE555¨ªªB{{;öï߇‚ŸÛ#Ð2ÛÛÛqôèQ´´´ÀétââÅ‹HJJ‚Ùlö;ΓÁ`À¸qã°mÛ6ÔÔÔÀf³aÇŽ0›Í2dˆß¿™7ž£Pæo00fÌlݺ555hmmuÛŽÝ­wá~>œºʲ­w8ËÔ÷JO×¢PðV:„C‡¹ åJË£GÆÙ³g±víZäååáöÛoÇôéÓ¡×ë±cÇ477Ãb±`êÔ©A_Ø-##7ß|3öíÛ‡½{÷bÈ!~w„¡ fþÞÖ+î®w¤ÊyË-·`ûöíjó}¿~ýЯ_¿ æ?yòdlݺõõõ¸í¶Û‚^߃¢££“'OÌŸ?k׮ŨQ£——ƒÁ€‘#GbÛ¶mhmmÅÀñw÷wø[¦ÝnÇÉ“'±gÏ8¤§§ãÖ[o…^¯GKK‹ÏqÞÌ›7»wïÆ¦M› IòóóqÇwü›yãíoÊü‹ŠŠ°cÇüíoƒÑhÄÈ‘#|Û'¤»õ.œÏ‡[7CY–çz;V 'á.?Rß+=Y_ˆB©»^öÔié‚—÷Úit=]yè¯?‹×_+ÏV‡Ã±'„u!Šª¾rËŠH°ÙløÃþ€Ç{Œ}Dˆ4 ÃM¸85ÏÒõ×’æ¡=E]yÍ{h†y¾÷vj;| e|ÈxH‹ˆÖ•+W`µZvˆˆ‡´ˆ(q\»v ×®]C^^Z[[±{÷nõ:.DÔ·1ðQ°Ûí(//ÇæÍ›‘’’‚‰'büøñÑ.Åöá!""êc؇‡ˆˆˆ(1ðQÂcà!""¢„ÇÀCDDD ‡ˆˆˆ%<"""Jx §!"" …g¨A®ì_|BÇÀ$Ï £<\.\.œNg—àCDD.A Š"ôz=ôz=t:ú`ð O´aG’$Ȳ §Ó ‡ÃA`6›‘’’AXùˆˆ¨ÛdY†$Ièèè@[[ìv; DQ„N§S[}dYæ~'H <(aGiÑ‘$ v»`µZ!ŠÜ„DDÔ³t:Ú²c2™àt:ÑÜÜ §Ó £Ñ¨N£´ö0ôÆÓÒýІI’àt:a³Ù`4‘‘‘Á°CDD½BEdddÀh4Âf³©Ý(´û)òÇÏ>;’$¡½½)))°X,Q,õU‹)))hoow <CO l¢@’$¸\.Øív˜Íf˜L¦h‰ˆˆú0“ɤÃ[JŸò[È íéæJeHNNŽf±ˆˆˆ|»?r:êQ€­<þ0ð ¤èÔÔÔh…ˆˆH•šš »Ý—Ëí¢Äž­;.— z½IIIQ.Ñ·’’’ ×ëár¹ØÊ?”k °“2Å"‹Å‚ŽŽ^ø6 <^x^IÙ`0D»HDDD] µ…Gyw <Þn!I{¿QLAí‚ÁSÔýãžÜ Ï~<¼‚%Å"åJËì¿O<.JDD±Œû©à0ðøÀ”LDDñ„û-ÿxˆˆˆ(á1ðQÂcà!""¢„ÇÀCDDD ‡ˆˆˆQr8¸téÏšŠ1 ûì3<óÌ3hnnœ:u Ï<ó [zbO„8q;vìÀ±cǺŒ«ªªÂ‰'¢P*ßöîÝ‹ŠŠŠ™×™3gðÍ7߸ ÛºukÍ?‡VOcc#6nÜ»ÝÞkË'¢¾á³Ï>êU«àr¹Ü†Ÿ8q—/_ŽR©H‹§¤§§cÇŽ1¿£miiÁ±cÇ0}úô™ß¥K—pöìY·a<ðfÏžÝ#óUVVòòòðÕW_EeùD”˜´agÞ¼ynãRSS‘••¥’‘O/3f ²²²°k×.¿Óµµµáرc8pà*++át:ÝÆWTT ½½.\ÀÁƒqæÌä”CgJk†VKK Ž9‚¯¿þ>—ôèQ <ÉÉÉê°öövTVVâË/¿DMMM—òØívTUUáàÁƒnᦺºeee¨¬¬Ä¾}ûÔ²žÚ¥™3gvù\GG\.DQT?£×ëa4ݦ³Z­~Ë•ššt˜gz½Þ-à…ºÍ”yxžIAD †øÅÀÓË „Ñ£GcÛ¶mÈÉÉQ‡744`÷îÝx衇ÔNà ØZáÒZSXXˆþýûûV OÍÍͰZ­°X,p¹\hmmuëÄl³ÙÔ~>²,w)ŸÍfóÚGÉ›`–áO¸Û¬¹¹™‰(d¥¥¥jØyòÉ'Õ>;¯¾ú*ôz=V¯^E‹E»˜äiEÁìÙ³qåÊTVVªÃ”ÃPJë…ÒJc6›Ã^ŽÉdBnn.ÊÊÊN«Ó霜¬*JMMEzzºÛEëëëQSS£†‘††ìÛ·OßÒÒ‚óçÏ«‡ÚDQT×Ë›`–áO°ÛÌó¢_ÍÍÍHMM 8""­5kÖÀår¡¨¨ˆa'±…' ŒF#ŠŠŠ°iÓ&õl¥œœX,¼ÿþûÏ6 Öüùóñ׿þëׯG~~>ZZZ`6›½^ ''' :Ђ ðÑG¡®®iii8yò$æÎ‹””}vjjjðÁ _¿~8uê&Ož¬ž16dÈìÛ·[¶lA¿~ý0yòd·å³ ‚Ùf¹¹¹8tèDQĘ1cÐÜÜ —Ë…„·A‰¨ÏR.ûQZZЧžz Û·og؉#ÝÛ›ú¦ c¼N3Üß³çk_Aó¬}˜V­Zõ°¿Âɲ Y–!IÒÒÒ¬Žo:™™™]æ‘••“É„"33z½cÆŒARRL&¦NŠ#FÀjµª‡kt:²³³ÝÞët:äçç«}ot::_ ó°Ñ¸qã`6›át:ѯ_?Œ;ÖkÿY–qøðaÜpà :‰=z½f³³fÍR[o€ÎkäÌœ9¹¹¹S¦LÁرcÕñ)))6l:::`µZ‘™™Ùe-ÃszeXnn.ÌfsÀm–›› £Ñˆ¤¤$dffâèÑ£p:˜4iRXO"ê»~÷»ß©¯Ï;§öÙY²dIKÕÙÒh4B·Ë€(ÏÞ¬^½úìd’dzçC+Ô÷1#P0‰Ô|ƒ <‚—÷Úit 9ÊCýY¼þZy¶:Ž=Þ ¥ú$ .— N§ÍÍÍÈËË °:‰ÁétâÍ7ßÄÒ¥KÝÎŒòåOú&L˜€ñãÇ÷BéºO–e¼ýöÛ˜5kFíâQœQδ€àé§ŸV/2MUUUHMM…(ŠÐëõêI*þÁ`¸ @#§æYºþZÒ<´áGyÍ{h†y¾÷šàcX(ãCÆCZ¤E7Ýt*++ƒ <ñ¦¦¦&“‰a‡ˆÂràÀhº‡ÜŒ7ãÆ‹v1""''wÝuW´‹ADDQÀÀCnü5zÒÞ""^x^ᚈˆú [¼ôÝ!""âÏ]"""Jx þ1ðøáz´ÏJ«r”×DDD=Ax”×À·}KvBÃÀ€gè‘e¹K1Ïa >DD.Ï £ý¡ík Œ'ÞZz´!GÇ CDD=Å[GdÏpð<ž iƒŽç{öŽ'"¢HbÐé>žù >DDD‘Æ}Nøx¤­t<”EDD‘ÂÓ3xz+#Qlãõ¨‰ˆˆ(á1ðQÂcà!""¢„ÇÀCDDD ‡ˆˆˆ%<"""Jx¼Oà…So__‰õ(1±QwñZo=ƒ'LÞ¾TøE“fðV/5jöìÙƒ¡C‡zŸ••…;ï¼åå娳gFŒéÓ§£_¿~˜6mNŸ>¹sç"''’$¡¸¸V«íííX·n 0pà@455!===ôôúÎ,«ý,Å·ž¬G‡7nIJeËЯ_?œ>}ûÛßðÀ@E´µµa„ (..Æ¥K—°aÃ<ôÐCê}{(þ„R?”Nwß}7¬V+ÊÊʰk×.,^¼8¨ºáoYZ“'OÆäÉ“›6mB~~¾z7p_Ë' iõ‚íÛ·câĉسgÏ&ãììlÜvÛmxøá‡‘žžŽõë×£µµµËt‚ ÀétbÿþýصkZ[[ݦ7nœv(±ôd=ª®®FFF†º>|8RRRPWW ³ž)‡ «ÕŠÚÚÚ­õ–PêGkk+¶mÛ† 6àìÙ³¨¯¯|ÝvYpøða‚€‰'\>Q¸ØÂa•••p8X°`¶mۆݻwcþüù>§·X,¸ñÆqöìY\½zµËY 555())Á‚ ••…úúzØív¼[n"ëéz$IR—ÇC­Cžg}‚À @գшAƒáŽ;îèòÙPëF eÕÕÕáðáø뮻‚Z>Q¸¸‡Œ öövìܹ ,Ü|óÍ8uê.^¼è6]}}=jjjÔcõUUUhiiQ}›Ífõ ‡ºº:˜L& 0.— ÕÕÕ~¿l´ŸMt‡—.]J¸3"QˆK—.áòåË€‹/B–edee©óûæ›oW¯^EKK‹[×D–¨õ(”ú‘““ƒÆÆFœ>}@g?¢ŽŽu^êF e)œN'¶lÙ‚%K–¸õó ´üX—¨u(Þ±…'‚¶oߎqãÆ©g* ÌŸ?[¶lÁý÷ßQìÜümmm(++C]]$IBZZ–,Y¢þš:u*JKKqøðaÜvÛm8wîÞzë-˜ÍfäææªóñFûÙeË–%l+Pii)^xá477£  /¿ü²Ú™;ÞE¢-[¶ K—.EII \.RRRpûí·»ÕsçΡ¬¬ F£·ß~»ßz–(¹…Z?¾÷½ï¡´´ûöíƒÁ`À¤I“0bÄëF e)¾üòKÔ××ã“O>Q‡-Z´ýû÷÷»üX–Èu(ÞEê¼Àž:KKðò^;€®gf)ýõgñúkåÙêp8öx+”öЦ.— N§ÍÍÍÈËË °:MŸ}öV­Z—Ë¥+,,ĺuë"zêkUURSS!Š"ôz}—0Ïõè—¿ü%žxâ‰h£W±§/Ö`ÅZò·LƒÁp€F.Nͳtýµ¤yhÏØRÞCóšažï½éÃB²Äü¹O}†·/ ó*¯Êá¢@X¨»X‡bÅ-íŒç-RSSÝú£ùÂzDÝÅ:x(.i¿`ž|òI¼òÊ+ê=ôz=ž{î9^¤¬úÊ! Ö£Ðõ•º,Ö¡øÁÀCq§¤¤Dý‚yüñDZ|ùr¬[·¥¥¥Ï?ÿ¼ßS¶‰Ö#ê>Ö¡øÂÀCq¥¤¤Ï>û¬ú³råJ¬[·¯¾ú*AÀ /¼€¥K—F»˜ãX¨»X‡âÅ ~ÁPO`=¢îbŠO <øC=õˆº‹u(~%þ•Ä(î•––ª_0O>ù¤zœüÕW_…^¯ÇêÕ«±hÑ¢h“bëuëP|c ż5kÖÀår¡¨¨ˆ_06Ö#ê.Ö¡øÆÀÓ *++ñØcaþüùxøá‡qðàÁh)®(wb.--ÅSO=Õg¿`JKK±lÙ2¬_¿Þm8ëWpX:…S_‚ùŒ¯ú™HX‡âO„?ÿøÿˆÙ³gãÝwßÅìÙ³ñøããøñãÑ.Z\Ú¾}»zºg_ù‚ùæ›oðÃþ/¿ü2.\¸à6Žõ+<}±áÕ—@ŸñW?Y_­CñŒ'ÂÖ­[‡¹sçbùòå4h|ðAõ‹ƒB7`À¬Y³¦Ou ܸq#Š‹‹ñ—¿ü3fÌpÇúž¾X€ðêK Ïø«Ÿ‰¬¯Ö¡xÆNËVRR‚çŸÞmØâÅ‹ñâ‹/F§@qèÀÑ.BT=óÌ3>DZ~¯¯×# ¼úè3þêg¢aŠolበ»Ýކ††.w7§¼WúëÏâõ×ʳÕápìñV(Y–tþÓ»\.8N477w9%“ªªªšš Q¡×ë!î¿X(¬GÔ]¾êNç{Wl0nЈÿ¿½»÷m[»Ã8þR×)$C$èà¥2Y ô?(:wÈ– ]Ó4E†&“Îâå.½ëE·Î·S2yº]R `°(±/lÙd÷ØÇLJï¤x(~?€ ¾‰¦”ñÑïJÒ¹¤3ë>ýÿtjÝ2ëfæeÍËZæÎgÖ´Í·¬ÎúÚ¨ðä°Š B€a·‰¢7ÚŠÐŽÐVÕ6O©8Ž•¦iù†˜”4Mo|/B;‚ímÕmCSÆ«äaRrEšÍf:99øˆš““Íf³kmÅE;BÚÚªÒ†pÀSÀ¼Á˜/ÙŒ¯_¿^{“)B;BÚÚªÓ†¦®¯À3úNæ(ŠE‘æó¹–Ë¥–ËåЇ„@˜ö0ŸÏ/ÛIÚòÐŽÐV642½dˆ±Wx:}QìÆE‘â8VÇJ’D‡‡‡]þ)ŒØáá¡’$¹ln»¡¡ ÚÚ*kC=u1c¨Àô‹fÞlìOUišj±X }hØb±Pš¦×>Qå}²¢!ímÕiC$Œ­Â³ÒÉô™Ïf3%I¢Åb¡ãããUr||¬Åb¡$I.ÛE±´#H´#´×´ õ èâ…+ôÀÓäÅlõ`t7·8Ž5ŸÏµ±±¡ƒƒ>YMÐb±ÐÁÁ6664ŸÏ/ËÇö'*_9™vímÕmC-¬üüÛ·ùÐ:ûû ²,Óææ¦¾|ù¢ããcÝ»wOI’ xtèÛéé©u~~®ÍÍÍËOS¾oÄ-B;š6ÚÚêª MÇ#Š"eYvy/éòS•$mllh¹\jooOI’èÎ;ºuëÖAcŸ,Ë”¦©NNN´X,tzzª$I´±±¡Ùlvù‰Ê(ûþÚÑ4ÑŽÐV—m<%L 9MSÍf³kËæó¹ÎÎÎtxx¨4MùÔ5a®x˜Ïç—Ÿ¤â8¾ü4e¶©óÆB;šÚÚê£ MYh'S7?hZØEÑ~–e?/ÙæòÓ”yCɲìrp˜ù:o3€0MSeYÆïÜŒœ=N¾ؾìÓwÉpÑþhGÓC;B[]·!gßû%›tÕp‚j€¡ž*ÜPdÏûÖ¹¿Øz¾\.˜Ïç…Gºù&cß›OYæMÅLcüì73-]Ÿ¨ûC;š&ÚÚêº Ëåò]ü"ºïiËr¦}óÁ 5ð˜àâ»—3-Ï´ùÉúXW?oIšIZîïï¿ðàÁoªˆû&“eÙbî2ÞhÆÉ}ó°O&yÛÔÙ7íhhGh«Ï6$Iûûûï%™¯ëN­[fÝÝä™öÝeÈÀSµûªi7—/¥’Îvvv¾ñâÅ«îÈ÷ÉÊ~S1ëxcYE—çÍWÝ/íh:hGh«¯6´³³ó½¤3]œ¥âJNUU7XÃìs¤S•}Gži÷^º¨ÔØËÝ[ì™uQÑ1·¹uÿ³ÏŸ?ÿéöíÛ¿«÷”n¾‰ð¦²Þºxsñ¡M ímuÕ†ŽŽŽ¾»{÷î_%}ÕEè9·îÍÍ®øØ½&EÕ{”|QŧJ#í¥!‡Ô¥UVÉ)Zoº¯¤«î.·ìfßN¶··¿yùòeíÀc¢²ç±Þºþw¦Mímµý7ÞÞÞþFÒ‰ªwU¹aÆUN‚Iá}ÿï(Û¿»>¯Ê{æ#g»Øs_Tåùé‡~ûèÑ£¿Ôx>^|ªZO«>yÐŽÖímuÕ†vww_=~üø’~TµêŽ{/Ý Aö9ÛÙ÷Ê™wõÖ€Çxìî*3;늺µb]„xÌíöÇÿðáÃ?ÔzVŒÈ§OŸþ¶µµõwIGºpÎt5ž§Jw–ä@U0x†þ>ê6OÌ÷"æue™yû3•ôãÖÖÖ·»»»¯ZÁÚÝÝ}µµµõ­.*;ö9Ð\š.•ŸCe-ojÐòã¬çýw9p¹¬êã[fweòw…½}ûö?išþóÉ“'·’$ùU…c hGGGß½yóæÏOŸ>}/éX7«8vèñ}/Tz‚¾ Ý5t—–»MQÀqÇñøºµ|WnÙÝZv÷–=¾'–ôI·ž?þ‹gÏžýúþýû“$ùeÙ72‚(ŠöOOOÿ½··÷áÝ»wÿzýúõu1@y©«pcÛeîË®Èr»³Ì2y–Mçíž*£Í8ž¼±=vrÇò¸÷îôܺ¹ûâ@HÜ bÂŒ=6Ç­ì¸!Ç^çî+ïŠgw™ îÝc-{.½á²ô²ËÑÝíì{9ËìmÍ¥êfºìo؃³Î”¨E^ ±C‹Û…åëÚòUpòþ†»¬Îq&„À“§n2ÓöwòØ/°I®‘.þ¡Íú™®7’HWÉ®I@XìàáëŠ*¯ã»"ËpƒÏh‚Mž¯Zcæíª[Ùq§ û‹Mè‰{{½{‰û¹èÒ„É7ŽÆ ?n•Ç­ì]™å›vÿ¦»o~p«³ÿCòUdʺ¶|Óöã%èé;ÀôVuòîòj-©üŠ-{™{•W¬ëƒ‘‹®ðr÷]õ¹Ð·¼.¨¢+­ÜÐ#]¯å]…U¥ºäÕYFˆ]ZR³ªP^7—tUµ1žL×»Æì0D…0E³Þ­à¸¡Æí s÷Ý$ˆ×%…Uáq·kRå)ºlÝ÷}>yßåcoçN»ÇÀª¹¡"õL»È÷îvEczúªîÔÙ®±UUxúÇcWv ßàe#uÖÛU³}¬«+¹òöcÿV!ï|äþ¢¹€Ê‚LÞ¸6•žªVR µKKò_e/³/?wã\–gÞ×õe¶I æË‚]¨Šûº­ÊÂOÞ߯SÝ Ê*OÎ]uk¹Ó¾KÆ}Ý]EËË(b!ó…ß`ã¼î©*ÝVy—¡ß%õÿã¡®ºWk¹óyÄ]žy–¹¢¼cñ5  dî å*¿oU'ìä…’¶Õ•U„V}"oRå±ç˪ÐFWU”º©Nˆ*3ø·2‡t’î#ôTÝoYH éuÀUV…©8šVŒêìw0¡È›O]QŒßŒUÙ8ßö¾é¢íšì{P¡Ô›OUœ¾ @_êTpÚ<¶ip!ðè3ôØÛvùÜC|ë£ËàЦT÷ï#Ôu›ãjòظ|F+-ßä†6%¨°#…x¤Õ‡÷±!¿6äiÓÍåîcÕíMè'õ¶Ç×Åó ý5@ê&h´ÝGaGÇÉ<ÔÐ2†×°~ú!„¥^é¤ÝÕ±Žé9З®JÐAÇÛÉŸ+«h§ë+¾FaŒ'}º§¨'Ôn°•ó‰¾Ïcóë@ŸadTAÇX‡û*ŸÃ:¼^€õ±Êð1Ê c¬Ë <Äçâ1Âb°ñ˜jY·“òº=†4ú c¬s@Xçç@_Ö&䨦 ¦ðhk-ƒŽ1µ00µç @‘µ9¶©€©?À´L&à¸8á_ÇëX'“ 8.NðÕð:BF°)Á‰¼{¼¦€.b€ýôÁ¯Y¿¤MÕIEND®B`‚Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/screenshots/curve_fitting.png000066400000000000000000002443241520337127000276000ustar00rootroot00000000000000‰PNG  IHDRbU¢ 0sBIT|dˆtEXtSoftwaregnome-screenshotï¿>,iTXtCreation Timetis  2 jan 2024 10:27:53Í A IDATxœìÝyxSeÂþñ;kÛÐe)…Rª€ È¢€l²—qFG¢è¼™tDEÅe@yEA@P\@eq”]G”ePöE¶¥tO“üþ¨É¤mÒ&mÚtù~®«WržsžsžœRàÜ} Pá án@ Ä=Ô$®p7 &!4 ÷ €ÒÚ”‚€¡0î¡G@ó›Ú<ÔöÏ@8ÔÚ`¦¶µíóPÔš`¦6µá3PSÔèP¦&‡5ù³PÓÕÈ@¦¦…5íó€ÊÔ”à¢*~ŽªØ&Uêئ Ô„° 2?CM¸_„Ze$Õ:Œ©ÎÁBE¶ÝPÁç ¦s©bC“jÈTǰ¡"Úl¬€s€ÂœpÎjÈT· &Tí¥Ç áÊ3Õ&Œ©NaDyÛj(òZ™× 6(K â*òZ™×®tÕ!`(O˾z|u¸„Z ¡G°áH(B™*ÈTõ ¡¬í 6€)í8æ t¥Íl€SÖP¥Ê†1U9ˆ)OSZÝ’öü¼qùy_Òqþöר0¦ª å™Ç%Ð¥hyYê€ÿ*-tñ·?°¦<óÏTU1`(klRáKU¼Ÿ”W¨C¡LYƒœ²¶£ÒUµà ¬“ê–ÔÓÅW™¿òÒ®SÚqÔ6å†l SÖÞ1U&Œ©j¡B0í 6„ñÀ”V·zÄPº’§r_LYØ`†(ÕÊ ¦¼½aÊ”Àø cB9‰/Õ]°KK;}¼÷·²Ry˜*ß+&\AB(C˜’‚_ûŠ0¾zË”´šá ÿUÒRÕ¾B÷vÑ@&0&9cªtSÕƒ˜Òæ…ñÂ}çýjôQ×ß<2ÆÚþË©â½V|…(î÷%…1’ï0%­ºäÝŽ@ÔŠ &T½a a‚ `¼ëåûœÀ¿¢Á‰S¾{ÀÈ”'Œ©²½bªrhã]LcôQîýÞ»>A ¥ó^¼‡9Uc‘ãÜ¡KIAŒw9(™wàâýeðñÞ»Ž¡È{÷~÷{£}ò±­÷•å¸¨ì ¦<|,%½Â˜Š¼TpO,¿•ü1Læ ¨I‚ )œ^_IvIù*x®výVføíÕ®x¿ºÏá~¶önü½J•¦”GU bŠ;*ºÏßñþæ‹ñ˜U8„±HŠøøãûôèÑãn³ÙÜÁårÕu¹\ô†ôôt5oÞ<ÜÍÂÊ`0œÊÏÏÿÏÙ³g·,^¼xí£>z@R® BwcÐaŒT8tq+¸ø a¼Ãœ*£2{o3,É×ð£`–¡ö7ÌȨÿöt1y•Ù>þøã¾½{÷žàt:%ÉåªRß'Õ@ZZš’’’ÂÝ  JÉÉÉY>wîÜ7}ôÑý’²ôßáKý·çŒ¯!M¾æ›‘J_öÚ›¯2*%¨jAŒ¯^-îmÃ|­‚äkÎwï“ ‡1¶#GŽLŽŠŠºE"€Pv1€{÷î}ª]»vËUÆx‡0î÷E'ô-̨„2É#å¾TJ P‡Ý­Wt‚ÝC˜“'OÎ‰ŠŠºÅårÂPAZ·n=ùèÑ£Ã%ÙTøÙÜ{ŽV+}þ/)+P‘c«”Ê b*òƒÆ×7Ç{Ò]÷¼0Q‡žb2™zÀPñâââÆíر㒢TxÊïgö¢ÏõÆ"Û¥RB›ªÔ#¦´ zKë ã+ñþ†zÏcùè£úÚl¶A„0TžK/½ô¹©S§¶Tá‹‹>¿û `íãK•éSY t~_Çy1ò>Îßä¼Ráo¢Y…'é5KªsæÌ™U.—«9A €PaŽ 0ÙÙÙÕ«WïiI™*X=É{Ò^÷¶{®Éÿä½¾æŠq×ñ褽T•1þ‚_í+iïí¢óĸ‡$™—-[Ö›€ðˆŠŠô /\¤‚Îî!J¾æ‡)i4Œ|l»ëûR%zÅTFŠZZW#_Ý‘Š~ãÜÛÖž={Þ‚6€2ºë®»úK²ªøªÇE;VH%‡0¥ K F…‡5U¥GL ü­’ä¯Ì×7ÓdµZ/§7 áÓ¨Q£«T¸7LÑiGyî/ú¾Ê«ÊAL óÊø*sOðãVh²^—ËU·üÍee±X.SñÉzÝŠ.gí­¬yA•`wüŒÆÁŒ+ÚÆ Éèr¹ªr@X8åææÊn·ËápÈé,˜÷Öh4Êd2Éb±(""B&“©Ü×r¹\qòóÜ®‚‰{%ÿÏü.¯m_C^‚-¯4Ä“@•vlIቯI|Šž××òWÔz‡CYYYÊÍÍõ¹ßétÊétÊn·+++K²Ùl¡d¼ƒ©ô0þB£|¯–ä}Ž@˜ kªB_JëURo_K[û* ÖËÉÉQFFFPurss•››«èèhEFF–çòþžÙ‹–ڻŻ,ì½_|©Î½C h¼{Á”4¾ €Z'+++èÆ[FF†²²²ÊÓ_Ïì,Q]mŸíÃÄ”6Œ¯W阿åª}¥jj¡Í›7ëÎ;ïÔ!C´eË–p7«œœœò†(’ œœœœ²VÅ3~IBI× ‹p1"|¸$éý÷ßWTT”rss•ŸŸ/›Í&ƒá¿ô|•gee«•!=a|3&&¦¼§ öy¿´9`Ê:OL…Í/SU'ë B˜*Ìápè¯ý«6nÜ(›Í¦V­ZÉåriïÞ½Ú¿¸›WH=dµZ=ÛF£Q‘‘‘ºè¢‹$I’¤iÓ¦iÍš5š;w®Zµjå9ÞW¹¯ú¨XùË_<=a~øá0·÷Õ¡–››ª•”jô³|M bjô7©¦zÿý÷µqãFõèÑCãÇ÷$§.—«BþR(qãÆ)66¶Xù¬Y³Ê|N£ÑX®ú^÷îÝõî»ï†»@X•ö¼uà 7èòË/×3Ï<£zõêI’ÒÓÓ5yòdýøãúôÓOK<·Íf i{½TÉU‚Î &Ðð¤"‡8!L‡.\(›Í¦G}´P÷5ƒÁ ÈÈH;wN·ß~»Ú¶m«™3gJ’^{í5}ðÁš4i’zõ꥛nºI}úôQ||¼V¯^­&MšÈáph÷îÝzùå—Õ±cGIÒŒ3ôÉ'Ÿè…^Pûöíõæ›ojãÆÊÈÈPÇŽ5zôhÅÇÇý9nºé&Y­V}ðÁš2eŠÖ¬Y#Iºÿþûe2™ôÙgŸù-/Zß½œœ¬ÈÈH}óÍ7²Ûí8p †ê¹fVV–æÌ™£7*::Z×\s–,Y¢Áƒ+%%¥ ß µ‰Ýn/qRR’vîÜ©ñãÇëÅ_”Á`ÐO<¡}ûö)11±\çBy²€@š°…:5¥G ª™_ýU999ºâŠ+< kY}þùç’¤ÄÄDµnÝZÍš5ÓîÝ»µuëVO³yófÕ¯__;wÖÓO?­­[·ªgÏž²ÙlZ³fN:¥×^{­Ð¼.Þ¦OŸ^høPïÞ½Õ¯_¿BÇôíÛ׸\}õÕºä’KJ,÷gÕªUŠWBB‚¶oß®… ªM›6êÞ½»$é…^І Ôºuk5jÔH ,òŽÕ^›7oÖôéÓe0ô—¿üEݺu w“€JWÚ¤ºS¦LÑc=¦ƒjüøñ2 :pà€š4i¢É“'—ëܨžAL 뉣Š;vì˜$•;„q›>}º:tè I:{ö¬æÌ™£­[·jĈÚ¿¿N:¥AƒéÀÚ¼y³ºt颉'J*è:·nÝ:ýúë¯JHHðyþ 6ÚNHH(ÄôéÓGÉÉÉZ³fRRR sÇÄĨK—.Ú¼y³¤‚aIRÁXÇo¼QŸ|ò‰ÆŒ£èÌ™3ÊÌÌ,õ/”@´lÙRRÁêN=zôÐ]wÝ%«Õê·µjÕJ“'Oöô~™:uªžzê)íÛ·¯Ôs£dU½GLYƃ1?L5a³Ù4kÖ,9R—]v™Ž9¢={ö(>>^mÚ´‘$?^mڴщ'äp8‚N’œœ,©`5%ï rÿüç?køðá2Zºt©vïÞ­¨¨(¹\å28hÐ ]{íµ:~ü¸V¯^íéÁ㯼,žyæõêÕK§OŸVjjªn¸áIò»âþkóæÍºóÎ;5dÈmÙ²%ÜÍÂÂ{EX_>ýôSÍš5«Ð¤ØØXÍš5KŸ~úi¹Î]5.¨ÈÆ•vn_«Šì3úØ69ÞXä½ûËôÛ«ù·÷î×z©©©BñÐ T+V¬Ð+¯¼¢qãÆé÷¿ÿ}¸›S¥ÝyçžU“âââB¾jRZZš’’’BzN "\¸pA¹¹¹!=gDD„bbb‚ªcµZ{I:/É!)ßëÕùÛ{§×—ë·/ï÷ò*“WYÑmïãUdŸ?„«GL•N§€ªÌápÚv/­}ñŇ£9ª¡ŠX¤.*–l¢ºÏC ƒZçÓO?ÕÊ•+Õ¾}{ÜŒ÷Ï-¡ €ŠF$ï‡6÷{—ËETCƒÁ¾ ÏÏ1 €ŠB„¢Á‹Ëå’ÃáÃáÓéô|¨ÚŒF£çËd2Éd2yBw C "ÄÀ»·‹Óéô0yyy²X,ª[·®¢¢¢d±Xd42ÿ1PÕ9NÙívegg+##CÙÙÙ²Z­ž@Æh4Ò;@… ˆ)EÑ^0N§S¹¹¹2ŠWTTT˜[ XF£QŠˆˆPýúõ•­ÔÔTÙívEDDH½cTºo”ÀW“““£˜˜µhÑ‚¨!¢¢¢”˜˜¨˜˜åääxz¾yÿ¡@w“­ØØX5lØ0ÜMP6l¨ØØXegg{Â%‚?Ü`î xsssU¯^=Õ¯_?Ì-P‘êׯ¯zõê)77·ÐÜ„2B ÆïÆårÉn·Ëh4Ò¨%6l(£Ñ(»Ýîé'Æ„Ë'¯Ò™3gÃÝ $bJáp8d·ÛÕ¨Q£p7@%jÔ¨‘ìv»G¸›Rë­ûú¥¥¥Uê5wìøQ¿üòs¥^³&9w^û¯p7£Z[¾ìýp7¡Z[¿þk¥¦¦†»ÕÖþ}{õãöÂÝŒj+;;[Ÿ}º*ÜͨÖ>þèCÏ/¼mÛ¶èÈ‘ÃánJ@SDÑÞ0‡C‹E6›-Ì-P™l6›,‹½b„ AL œN§òóó˜˜åççó!CSwzõ“Ífóôˆ€P ˆñâ~Ør¹\ž/§Ó)‹Åæ–‹Åâ¦èþ’ž ìÌán@UTôËh$¯j#£ÑX, 5 anU퓟Ÿ¯%‹ßSTT”ú'÷Uç.W„»I@™Ä”Àý›ðò˜0a‚>ûì³bå]ºtÑܹsËuî@åååÉét*22ÒSvÇwè÷¿ÿ½† V)mª+wÏ8“Éî¦ÔZf³YwÞu»Zµjî¦åFS þßÿûúßÿýßBe•ùP÷æ›oêèÑ£š2eЧ¬_¿~jÓ¦M¥µÄ”*sAX­VEGG‡ 5¡3zôèp7¨˜¦zp¹\ºpáBȾ_uëÖ—ÑhÔùóçCr¾Ú&?ß¡„æ-¸åpY›¶!½ƒA111 ¯  ˆ©‡æÌ™£O?ýT‡CÉÉÉúúë¯5gÎ5oÞ\¿ûÝïôÜsÏ©[·n’¤Ý»wkäÈ‘úöÛoe·Û5sæL­_¿^§NR||¼FŒ¡?üá’¤·ß~[o¾ù¦$éË/¿Ô­·ÞªñãÇ+%%E·Ýv› $©`Ö[o½¥+VèìÙ³êÔ©“{ì15kÖL’”’’¢þýûkÓ¦MÚ³gôØcéŠ+˜«@ø;wNõêÕ YoC«Õ*£Ñ ˆˆÈÒF1G¾"##î¦T[.—SõêÕ Ùù‡ÒÒÒ²s€²!ˆ©v»]ÙÙمʬV«çáÕW_Õ–-[ôÿ÷ŠŠŠÒ¼yótâĉ€Îm±X”˜˜¨iÓ¦)22RŸþ¹&Nœ¨Ë/¿\IIIJIIQfff±¡IEÍ›7Oß|ó^|ñEEEEiÆŒ5j”>øàY,¥¥¥iöìÙZ°`š5k¦9sæhüøñZ±b«J+÷>Ìãøg2™d6›åt:Y„€0ã_âJðÞ{ï©OŸ>…¾¾úê+Ié.]ºT&LÐ¥—^ªÄÄDM˜0!¨óß~ûíjÕª•4|øp5mÚT;wî ¸~^^žÞyç=ùä“jݺµ4qâDeffjݺu’¤úõëk„ jß¾½4h aÆéÌ™3:räHPm€PËÏÏ—Õj w3€*Ïl6+???ÜÍ Ö£GL%¸ë®»ôðÃûÜwôèQ9ŽBçû›ª´´4­^½Z?üðƒ.\¸ £G*'''àúÇŽS~~~¡6DEE©C‡:xð Ïv5kÖLQQQÊÊÊ ª­j.—‹ßð0Ì{@Àÿ\ÃÌn·ËétÊét–©~vv¶† ¦Ó§Oëþûï×´iÓt饗Êáp|÷òÖEëX­ÖËÌ„‡ &Ìe0ôïÿÛï1QQQ:pà@¡2wp³{÷n¥¥¥iìØ±jÙ²¥l6›~þùg¶½1zÕso»¿L¿½š{ï~­—ššºÁ×duî2÷œ-v»]j×®])'´òòòÔ«W/-_¾\Í›7¯Ôk£æš0a‚6lèwâhø¶k×.EGGËb±Èh4z&…õR¦¥¥)))©²›Xã=:îI=R­Zµô¹?77W’²kfggËh4(""2dç,‹(##C›6m*4!ñã?®þóŸÚ±c‡'˜•©S§jòäÉš4i’:tè E‹éŸÿü§Þ{ï=ýá(v|~~¾æÏŸ¯É“'ËåréĉúøãuõÕWË`0¨U«VºýöÛ5`ÀÙl6-Y²D‹/Ö[o½¥!C†H’þøÇ?*11Qýû÷WãÆµ}ûv=ÿüóºòÊ+µbÅ IÒáÇբE -Z´H+W®ÔâÅ‹uìØ1%$$„ôó‡úþ[Ï}ÜO<¡nݺù=nýúõºýöÛÕ¿ 4HqqqÚµk—N:¥çž{Îg*âg¥ªZ¿þkµm{¹5jî¦TKû÷íUFF†:vº"ÜM©–²³³µîë5úÝ þÿN@É>þèC ¼é&ã/£mÛ¶¨I“x%&¶wSbµZ{I:/É!)ßëÕùÛ{§×—Ëë˽-¯my•Ývy½÷VÚLö!ŸéžU“(%%E·Ýv› äÙîß¿¿6mÚ¤={ö(!!A=ö˜®¸¢à?dv»]³gÏÖ_|¡ÜÜ\õïß_ùË_d³Ùd·Û5sæL­_¿^§NR||¼FŒQè"%%EúÓŸ´bÅ mß¾]S§NU÷îÝjë¼yó4oÞ¼€Ž½ï¾ûtß}÷y7€ªcÆŒêÖ­›Þzë- >\’tðàAÍš5Ko¼ñFÈC˜ÔÔTM™2E3gÎÔÐ=øag IDAT¡C%„AçÎÓÓO?í3h˜5k–æÌ™£I“&é¶ÛnSƒ <û¢££µ}ûvÅÇÇ{Ên¸á=zTóçÏ÷1Ë–-+tÎ>}úè’K.ÑM7ݤcÇŽ©iÓ¦8p :wî¬Ûo¿]M›6Õ[o½¥±cÇjÍš5êܹsPŸsåÊ•JMMõ|Æ@•åþSÏû¸AƒnVýú±>s:zà4tèP½øâ‹žë\sÍ5A}DŒŠIKKÓìÙ³5vìX-[¶LíÛ·×øñã=s½ôÒKúõ×_õöÛokÑ¢E:vì˜fΜ)I²X,JLLÔ´iÓ´téR 8P'NÔ¡C‡ ]ãÉ'ŸT¿~ýôú믫S§N·-Ðp…5A‡4jÔ(=ýôÓJOO—Tð³ÓµkWÝqÇ!¿ÞÂ… é H¤‚Þ_<ð€~úé'mÛ¶­XQ£FiÇŽ:t¨,K±ýÞ!Œ[—.]tâĉÛÒ¢EÁoñ233e4µnÝ:]zé¥9r¤fΜ©Õ«WëóÏ?:„‘¤5kÖèý÷ߺ^YîO0õ=nùòå:zô¨üñ ??zÄ(¦~ýú>|¸Ú·o/I6l˜>üðC9rDMš4Ñòå˵bÅ Ïo¾G¥ñãÇküøñ’¤Ûo¿Ýs®áÇë£>ÒÎ; Û4hn»í¶2µÏ°øëCIÚõ÷yÚ¿äC9rrƒ®ëªŠy² f“¢šÄ©ã©I¯nA×öÙgõÞ{ïéùçŸ× Aƒ´lÙ2mܸ±Ä::tО={üîwO_ÔîÝ»uÅWÈjµ*ïÝ»·$iïÞ½êÚµk¡}eæ²gϵmÛÖç¾ôôtmÙ²EãÇ×å—_îY½Ïh4ÊjµÊf³éÌ™3jРš4i"IÚ¶m›úõë§ùóçkðàÁ’¤Ó§O«sçÎ5j”&L˜t})Ëý ¦ž÷qYY™~ûöÛoÕ³gOÅÆÆJ’Nž<©ØØØbçUALdµZýþV ¨,Þcr›5k¦¨¨(eeeéСCr:1b„ç!5??_™™ÿ}hHKKÓêÕ«õÃ?èÂ… :zô¨rrr ¿cÇŽåjß}÷ݧˆˆOOïrBœüv³vΘîfxäž9§Í>¡›6}!ƒ)¸Î¨õë××”)Sôç?ÿYŸ|ò‰î¹çÏ0AÞ~ûmŸ«ä•æèÑ£Š‹‹+Vn³Ù£#GŽ}΢~þùg}ñÅúä“OŠíkÑ¢…§§Lrr²æÎ+£Ñ¨üü|uëÖM}ûöÕôéÓõÅ_¨uëÖêÔ©“¾ýö[uíÚU“&MÒ˜1cÔ»wo5kÖL÷ß¿:tè 'žxB’ôã?zþÚ¼y³öìÙ£-[¶x®Ý­[é!YYïO õ=îСCjÖ¬™.\¨§žzJÇ—ÅbÑàÁƒ5cÆ Õ­[·Ôχ @@Ü¡KLLŒ$éwÞ)¶Â—T0AݰaÃ4`ÀÝÿýŠ×È‘#åp8BÞ&÷\ î0†n¹gÎ…» ÅäO—Ón—É|’””½þúëÚ³g&NœXêñW^yeYš¨¼¼<¿?«f³ÙçУ`8;V×_½Ï•>ýôS]¸pA¿üò‹æÌ™£©S§ê•W^‘ÕjÕªU«Ô²eK½þúë:zô¨fΜ©ë¯¿ÞÓ³æá‡ÖW_}¥#FèÖ[oÕwß}§mÛ¶yBå»ï¾»X/!wO÷g/MYïO õ=îĉÚ¾}»ÒÒÒôÅ_(!!Aëׯ׽÷Þ«qãÆéõ×_/õ³€ð!ˆ”¦M›ªN:úúë¯uóÍ7Û¿{÷n¥¥¥iìØ±ž²ŸþY'Ož¬ö :Ô³! Üšè£úm/UÚîŸÃÝËF¦ÈY¶Õj ƒºvíªÜÜÜ ]&11±Ø|NRÁj;çÎSbbb¹Îÿè£êСCÚ°aƒÏýîU »wï®[o½U]»vÕ‹/¾¨§Ÿ~Z-[¬šÕ±cGEGGKR¡áMƒAÿøÇ?Ô¢E }õÕWZ³f7nìÙÿÓO?yÞ?òÈ#Ú³gÏ^9Æ ÓâÅ‹ •mÚ´I;w.óý ´^ Ç5nÜX[¶lÑwß}çéýrà 7è™gžÑ#<âéIª&‚ ÉÉÉÑùóç •¹{¸Êl6+%%E3gÎT“&MÔµkW¥¦¦êÌ™3j×®4h ŒŒ ½ÿþûºîºë´uëVIÛ*  вD×Ñ5ËêÜ;•ŸSz…"òòòd0HKùçÜ0˜L²Å7QôEå 1‚QÖ9bZ·n­>úHYYY²Ùlžòï¾ûN’tÙe—•¹M¯¾úªÞ}÷]­Y³Æ3·IIl6›úõ맯¾úJO?ý´§¼{÷î~WYóî¥WÖ¥¦M›¦I“&*sO8\Öûh=ïã¼=.))I—^zi±!H—]v™²³³•™™ôßí òĵȇ~¨?ü°P™¯ß—æž{îQDD„¦M›¦'N¨Aƒ:t¨Úµk§‹.ºHcÇŽÕܹs5{ölõêÕKÉÉÉ¡ú@ÀŒf³v|E.oÙÙÙ2 Šˆˆ q«*GYçˆIIIÑäÉ“õöÛokÔ¨Qžòyóæ©gÏžž ¼% J2wî\ýíoÓgŸ}¦6mÚÛït:‹õàp8úî»ï<½d1vìXõíÛWíÚµÓÝwß­Í›7{zϪ¤Ge½?Öó>îÎ;ïð{ÜàÁƒ5{ölýë_ÿ*4ÄkóæÍjÙ²%! UA PKL™2ES¦Lñ¹ïí·ß.q[’Ö­[çyo0ô§?ýIúÓŸ|ž/%%E)))~Ûâëü€?ùùùZ²ø=EEE©r_uîRòDµ(û1‰‰‰3fŒÆ§ÌÌLuëÖMË–-Ó²eËôñÇ{Ž{þùç5yòd­ZµJýúõ+ñœo¼ñ†ÆŒ£7ß|SRÁ¤¹n-Z´Pdd¤Ú´i£[n¹E={öTÓ¦MuêÔ)½ùæ›Ú»w¯§^i,X åË—ëûï¿WãÆÕ£G;VÿøÇ?Š;|øp]¸p! óz+ëý ´ž÷qgΤªoß~>ëÕ«—¨;î¸C'NT§N´uëVýíoc~ª‚˜Zìïÿ{¡y< *2›Íºó®ÛÕªUËp7¥V˜:uªš6mªwß}W/¾ø¢®ºê*­^½Z½zõòÓ¸qc5jÔ( ž>ø $iĈÅö-Z´H·Ür‹^|ñE-Y²D+W®ÔÉ“'¯^½ziÆ >{Ðõã?êÁÔ¼yó<ó¨,\¸P½zõÒ5×\£»ï¾»Ðñ—_~y©çô§¬÷'zÞǽóÎ;š1ãï~[ºt©&Nœ¨yóæéÈ‘#j×®ÞyçÝxãeþl rÂt^_û ^åîW£mïcŒ^õÜÛî/Óo¯æßÞ»_륦¦np¹\Åà.s:r:²ÛíÊÈȪ[´·Õ«W«nݺºúê«=e;wîÔ/¿ü¢[n¹¥L甤ýë_ºøâ‹uñÅ—ùA ˆ]»v)::Z‹EF£Ñ3|Â½Š”·´´4%%%Uvk¼GÇ=©Q£Gú bÜ“5GD”m"\_ªûФps8ò•••Í™rHK;§úõKŸK'ñ³RU­_ÿµÚ¶½¼B'·®ÉöïÛ«ŒŒ uìDIJÈÎÎÖº¯×èw7ü!ÜM©¶>þèC ¼é&/£mÛ¶¨I“x%&¶wSbµZ{I:/É!)ßëÕùÛ{§×—Ëë˽-¯my•Ývy½÷æ«,˜ýAãOvêÓ§~úé'¥§§K*è^¿yófõíÛ·LçKMMÕÞ½{U§NÙl6}ÿý÷ÊÏϨîÁƒËtM:1(::Z]ºtÑ·ß~+IúþûïÕ²eK5hРL狊ŠÒ¯¿þªmÛ¶iݺur:¥WúÍgŸ}V¦k€ÐaŽ˜ Ö¹sg-\¸PÐŽ;t×]wI’8 /¾ø¢Øñ}úôQ‹-ôÙgŸéìÙ³r8ºüòËÕ»woIÃ!ìv»œN§"##e4µyóf¥§§ëºë®“ÃáÐ’%K”œœ\êrÁN§S«V­ÒéÓ§e6›ªÊŽ ¦‚™L&õíÛWü±úõë§ÈÈ‚ù.¾øbÝwß}>ë8N]sÍ5ªW¯žrrr´xñbµjÕJƒAMš4Q·nÝÔ¢E 9rD‡CݺuÓÒ¥KuàÀ9rD—^z©š5k¦諯¾’T0Võ7Þ$õîÝÛ3ùáUW]¥ÆëСCZ±b…† &«ÕZ w€Ú‡ ¦´lÙR‹E—]vY@ÇFÏ|2.\Pff¦233ÕºukÅÇÇËh4Êf³©gÏžž:7ÜpƒæÏŸ¯¸¸8 2DRAØ3räHIÒܹs=ïÝ ƒ7n,IJJJRll¬Nž<éYq„AL%1 …VY)ihRƒ ôå—_jÀ€jذ¡Îž=ëYé@’Z·n]¬ž»‹Édò¹š‹¿6yËÏÏ—Éd ¨.AL˜”44i×®]ŠŒŒT“&M”››«_ýU;v,ñ|Ÿ}ö™nºé&íÚµK?ýô“:tèPh¿÷ÚnN§S'NœP||¼Nž<©ÌÌLÅÅÅ•ýC€ÄTA­[·Ö¡C‡´`ÁEEE)!!Af³ÿoÕÖ­[e³ÙÔªU+5kÖLï¾û® ­ÎÔ¾}ûbõL&“6mÚ¤óçÏ+22R7ß|s‰×åÃSw) ƒœN§ŒÆò­ôýÀ|¬ÕjÕïÿû€¿êª«<¢tÏ=÷To̘1_¨œNgÀCý åKj8ƒÁ £Ñ(»ÝÝ.£ÑH db|ð~è2ÊÌÌ ck„Kfff¡Þp2Ê‹ Æ÷*G&“Iiiián€0HKKó¬DF€ª*ßáR¾Ãîf @1~¸‡%™L&åææ*+++ÜMP‰²²²”››+“ÉÄð$TYY¹ý|&ðjˆ¬¬,íÛ·OgΜQdd¤Ìf³g’^#ãmÃÎåréàÁCÚµë?:{ö\…^+=Ë®5?¥–xÌòÍÇ+´ nÑÑÑJII‘$ \ÑÑѺöÚkår¹´gÏžRÏHºt预„ :T999’¤É“'kÛ¶m6l˜¢££5dÈRÏ—–i×áÔ\™LzçVs MòÁ`0Èårz5™L…öÛívYâù@`NžÏÓùÌ<™Mïya’T5FõìÙM­Zµ¬ðkÅÕ³Êd4”Æ$4Œªðv”fýúõÚ¾}»®»î:OY^^žœN§Ž?®ºuëª_¿~š={¶²²²týõ×ëºë®“Õj Ybbb´páB]}õÕúûßÿ®W_}UW^yeÈÎ$§Ë=Œaj‚˜}s/gër¹d4=á  P}ÊûÕݳð¥ö©k³h@ÇFúâÿsý±GÓJl‘o&“I]ºtÑO›3gކ ¢|P½{÷–$½öÚkúŸÿùõéÓGW\ÑÉïù€o.—tôlŽr왃‹Ä£hõRQO¥××~ƒW¹ûÕècÛû£W=÷¶ûËôÛ«ù·÷î×z©©©ÊšøªGT_¾—²†0iiiž‡\„ΣãžÔ¨Ñ#ýNÖ››[0„("""d×ÌÎΖÑhPDDdÈÎYÇ×ñãÇÕ¦MÙl6O¹ËåÒ‘#GtâÄ %&&zz¿¸={V‡–ËåRëÖ­S깇8 Ö­[û=.--M{÷îUÏž= Ú¼y³êÕ«§K.i­¬¬lÅÄÄøm;J––vNõë‡v…°ŠøY©ªÖ¯ÿZmÛ^®F…»)ÕÒþ}{•‘‘¡Ž®wSª¥ììl­ûz~wÃÂÝ”jëã>ÔÀ›n©U+ÒÚN:•% 2ñÑïö¦éí5‡µëè$um«ß_š§W6Wbb‹ŠkpY­Ö^’ÎKrHÊ÷zuþöÞéõåòúroËk[^eE·]^uö@ò~zÄÉ»GLÑ2Õ?˨ªš6mZ,d‘ þ̶hÑB-ZøþVƒ Ô Aƒ Îm2™Š…0E³ÙljÖ¬Y±cºwï.Ir8òKm;(™“¯cgsƒ^鳟ÒKþ"§×³é¦=gµågÉeM×°ÄP·¡R{"Æ+º´-€ê‰Ÿe„ËÙ y:v6OfSpÿ=—™§Ÿì-¸9]ÒK+Nè|¦=TÍDˆÑ#&x€Êå’ŽÍVvž3èF’¾ÙyV9yNÏv½Üórɨôˆ‚aÈ™¹N}õSªníA¯Ôªˆ €JâpºtèT–.É䤼n©éy’$“Ë¡›~Y©^G7Iiu«ßiM‹~’¤ãg³CÖf„C“¨9v‡öŸÌ–Kea$)®~„êæ^Шï_×ÕG7Ê — .—®ßÿ¥L.‡$)¡aTˆZP£G ,-îSéîù`Ê7½EW×qEo{Uѹé…ÊóLV9eTÝ(“®éظ\×@Å!ˆT{.Õ(Ìår1¯„Éñs¹ÊÈÉ/Ó|0E^¶\Ǧÿ]Ñù…'ãµ›,ZÚö6M=~s¼b¢xܯªøÎª5“ɤììlEFF†»)@•æp8îf@­âtI‡OgÉžï’©œ!ŒËž§Ãÿ7]©¯(¶ï|d}-횢ī:êZeëêËbÊu-T,‚@µf6›•ŸŸîfU^^^žêÔ©îf@­‘kwêpj¶ŒC¹C˜¼Ó©ÚÿäeîÜUl_Lç+Õî¯UÊeÍd5µmÛ–r]  PíEGGëܹs²Z­2›ËÿO[^^žŒÆòß®­Ž|Ùívåææ†»)Õ–Ýž²û—ŸŸ¯¼¼ òäå;uøt¶dLå\¡.ïä)í{b‚²þóŸbûêõê©‹þúŒÌ 7­ÖbÊ`Ô¨QÚ»wo±r“ɤeË–iøðá’¤÷ß_QQQÊÍÍU~~¾l6[¡e#}•gee«_ÑŸÁh4*..NW\q…†®† VÈ5+’¿{\–/_®>ø@YYYºöÚkõÀTêõšÎétjãÆ-úyÏ^µm{™.º8)ÜMðÈÌqèèÙlYB0DèÂ÷ÿÖ§Ÿ•ýܹÂ;ÜóÁŒºO#C‘ª;‚˜rèÑ£‡¬V«gÛh4*22R]t‘$yºO›6MkÖ¬ÑܹsÕªU+Ïñ¾Ê}Õ¯H={ö”$íÞ½[Ÿ~ú©víÚ¥9sæú\Õ¿{\Ñ6nܨW_}U-Z´PïÞ½Õ¼yóJ»6P[ ]|Q’š7OPýØúán€ÇÙ yJ½_þÆåÒ‰E‹õëÜyr9œ…v™êØ”ôÔÅöë[¾k Ê ˆ)‡qãÆ)66¶Xù¬Y³Ê|N£ÑX®úÁzôÑGU·n]effj̘1:|ø°6lØ þýûWZª³~øA’ôÐC©cÇŽan P3 Å7m¢¤‹Z„»)’$—K:v.GÙ9ŽrOÊëÌÊÖÁ¿=¯sÿZSl_dR µz~Š"ûe=j‚˜ pÓM7Éjµêƒ>Д)S´fMÁÔý÷ß/“ɤÏ>ûÌoyÑúîíäädEFFê›o¾‘Ýn×À5tèPÏ5³²²4gÎmܸQÑÑѺæšk´dÉ |XçÏŸ×Ûo¿­mÛ¶)55Uõë×W¿~ý4lØ0Oo™›nºI}úôQ||¼V¯^­&MšhâĉÕKNN–ÕjÕ·ß~+‡Ã¡Aƒ©oß¾š5k–vïÞ­¸¸8;V:t$åääèÍ7ßÔÆ•‘‘¡Ž;jôèÑŠ/ñ^–TÏßgxå•W´iÓ&-\¸P‡–ÍfSRR’ž~úiÅÄÄxîÙ³Ï>«o¿ýV’ôðÃK’^zé%uêÔIï¾û®¾úê+>}Z-Z´PJJŠºwï^èψ¯ëº•vÿóòòôÐCÉl6ëå—_Ùä¤J–ïpéðé,9\’©œ!LîÑ£Ú÷ø“Êޠؾz½{éâgŸ‘©Nr]UOoå0}úôBÇz÷î­~ýú:¦oß¾žàꫯÖ%—\Rb¹?«V­R||¼´}ûv-\¸PmÚ´ñ<Ü¿ð ڰaƒZ·n­FiÁ‚A§³  \Æ eµZµiÓ&µhÑBíÚµÓöíÛµtéRY­V 6ÌSçóÏ?—$%&&ªuëÖ×óþ}”œœ¬5kÖ(%%Å3‰¿ËôªZ IDATò’ÌŸ?_‹E‹-Òüùóµ}ûvuïÞ]ÇŽÓ† §W_}Uf³Y“&MÒºuëú.—K{÷îÕÊ•+e6›Õ©S'EEEiÑ¢EžcŽ?®””mÙ²¥P "©XÀh=÷çY°`ÞyçõêÕK“&M’$ÝsÏ=:|ø°Ž=*‡Ã¡Í›7«K—.š8q¢¤‚Éy×­[§_ýÕï½Ü·o_‰õ|~†mÛ¶)??_:tЈ#üö6éß¿¿vìØ¡åË—+%%EmÛ¶ÕéÓ§µråJ]tÑEš={¶Ìf³V­Z¥—_~YK—.-tŸ|Ý;·Òîbb¢ž|òI™L&B œËÈÓét{¹‡"y惙3O.g‘ù`êÖUˉϪn÷n廪4‚˜rxï½÷|ÎSêÕ«'‹Å"Ij×®¤‚á+’tèÐ!IRçÎ=¡Arrr@AÌ­·Þêyo4õÀx&œÝ³g>üðCíܹSééér¹\JOO/T?""¢XH=ïÏÓ¶m[I*´ZSÛ¶muøða¥§§ëÌ™3’¤ï¾ûN×^{m¡ó¤§§ T¼>|8 zE?Ã%—\¢˜˜­_¿^·Þz«ºuë¦!C†–íß¿_N§S]»v-ô½xùå—=ß'7_÷Î[i÷qÀ€¥¶@ù?—« Ùv™Ë9)¯#3K‡&Oѹ¯‹?«Eµn¥V/üMÍš•ë¨úbª!“ÉThÛn·K’l6[ÐçêÔ©“7n¬fÍš©oß¾ž›Nœ8¡qãÆ)..NãÆSRR’\¬~ddd¡í@ë•ôyŠ–Õ­[WRAÐ4f̘Bǹçzñ%ÐzE?C½zõôÆoèƒ>Ð7ß|£µk×jݺuš9s¦.»ì²?KNNŽ$ÉápxÊòòòd0Š]§è¶·²ÜG¡åpºt85[ùù®r‡09‡kßã”sè`±} ®½FIO<.c”ÿgÔ1•ÀÝ3"£ÈØ?åÁr÷`Ù¼y³î½÷^Y,íܹ3 ºÏ>û¬'°ð¶cÇåää¨{÷îºòÊ+=ÁB~~~‰ç+k½’$%%Éh4ê—_~Qýúõ‹ÍÕ"ù¾—Ôó§aƺï¾ûtß}÷é7ÞÐ’%KôÃ?”Ä$%%I’6mÚ¤{ï½WV«U[¶l‘Ëå jYí@îã×_-³Ù¬«¯¾:àóLn¾S‡NeËd4”{RÞóßlЉ“äÈÌ,Tn0Õìþûÿ§»Ëu~T/1• eË–’¤×^{M=zôÐ]wÝ%«Õê·ø  ¬¬ ÙÙÙ¾6õ­Í«¢®É‹<|õ`ä´TLY³)gŸÝst> ",Á<.\ˆ /¼uuuxë­·PYYÙçq3V®\‰sÎ9 p¹\¸ôÒK Ôh°Î8ã ,Z´²,cÛ¶m˜:ujD!â¡<¯??øÁ°xñbˆ¢ˆ—^z „Ãá€ñåOœÞþ-û;¯'Š¢ ==ÿûßñâ‹/Büà?ÀìÙ+˜uÿý÷ãŠ+®€×ëÅÞ½{1cÆ <ùä“¡•KÑß¿ãøñãQRR‚éÓ§###cÀ×%""""¢¾hõ£¾9ú$ŒÖÖ†/–Üš§Ÿ‰HÂ8§•`ƯŸ’$ŒªéHqH°D¹uŠFN”é=Ó×íi\èr<ø^ìá󮻜ü<ø&}ù^þòãàûT—Ëõ^_7â‰àõ×_ÇÆ±téR\vÙe±‡hLhii mO£¡sÏÒ¸íö›Q\\4bÏyàÀ~Ølv””L±çL$ÍÍMØÿñG8o‹Š›õê+•W};ÖaŒZ;wîÀŒ§ +++Ö¡ŒJå‡ÑÑÑÓϘëPF%¯×‹ww¼ƒK.ýF¬Cµ6¿ö2.¿âJˆ#ܺY7:ëÁ(šIˆî¹½‡ËQ~ß økk#Æ2.½“—Ý Ñ6øÝÝ)ªœ4+Ò’,¡cûöíENN.&M*ˆúú#Ájµž €@íò^ÿòc½Ë›Ñå-ø9º|Ž.Ǻntù¸«þ’Cž<àÖ¤¡iZXÛ`kíl§!"""""˪ê ê$LÓÖm¨Zÿ0t¯/|@–0áÖ[†¤Œat&Ž ³°Y¸f´a"&A¼ýöÛxã7pê©§¢²²~ø!Î:ë,LŸ>=Ö¡Å­ŸŠÚæd1º #†¦£öÏ¢þ…McrzŠÖ®Aò™_‰ê9@3 Ø,&fØ š,EA±ÅÔY‚HNNF À믿ŽÚÚZ\yå•XµjU¬Ã"¢8§( JKK1sæLL˜0×\s Ž92,ç}ôÑGHJJÂc=6TáE¥±ÝÚF?ä(ïŒÕ–V^²´Ç$ŒsútÌøÕsC’„QUéN™v&aF1®ˆIsçÎÅܹsc"†aà[ßú:„5kÖ`ܸqxì±Ç0oÞ<ìܹ=ï+6sžßïÇ7ÞEQ†ûË""""ê—a5Í~xü ä(³0žÏ¿@ù}+¨¯ËZ¸Kÿ‚léáÌÁQ5`B¦ IvÞÆv|‰ˆÆ¨·Þz Û¶mÃþýû1uêTÀ¹çž‹™3gbãÆØ°a÷jÕ*̘1ªªßDDDD4ªf ªÁä( 7½½U< Ý;.X¬(Xz²\Õõ@Ó HP”ã„,qL"àÖ$"¢1ê—¿ü%.ºè¢P2ÒÒÒpà 7à·¿ý-ônmÍž·k×.lÚ´ O<ñÄð|!DDDDäñk¨8î ˆª$Œª¡æégpdí#’0ÖñY8éçO Yfœ]Æ&a 1DDcÔ§Ÿ~ŠÙ³gG?çœsÐÞÞŽãÇG}^{{;nºé&lܸãLJa y÷?"""¢iî ¦ÉuBCmnÁçw-é±Lò§cÆožCÒ©§Dõ@gkêñ)Vä¥Û °LBáÖ¤!À ¢Ñk¬þ§fjjj““1–——8zôhèc³çÝsÏ=˜5k®¾úê¡þˆˆˆˆÄ0 Ô·ÐáS!EÙÉóÙg(_q?õ‘°ÊZ¸wßAŠî6Û ëlMȘˆ1©§ä 2D£G0Óõûv,%et]‡¦iÐ4-bL–;ÿk°X"‹Ê æ¼7ß|›7oÆG}zŒÙŸ“­-­p5¸ÂŽ¥¦¥ö#Q¦¨vy¡jFÔI×k›QýøFjxóÑjCÁ=KùÍoDu}Puv«ÌÖÔ Ž‰˜AêzüØ0 &aˆF!ABÉABßÇc!!#IòòòPßCuÿ౉'š>¯±±·Ývžxâ dggG«¢(xú翌8~îy³‘‘žÕµ{ãõz!Š>;øé°\?Ñiš Ç‹¿l~5Ö¡ŒZíííü÷‹BGG;\ ¡1 Žßk¨ªªŒu(£’®ëèèà÷p4Z[ÛðÆë›£¾Ž¢.·ðåï|æ¯#h*쯿 ë¾FŒé©©è¸î|l·Û¶F- ’mÆYu|Åu<7ª*+ñÑ??Œ*žþ\±àÊa½~"ãÿNƒÐ=ñbFè/ú®‡Þˆ(¾‰¢z“$ ’$…’2Á„ÌXHÆ”””à½÷Þ‹8¾oß>dffbüøñ¦Ï»ûî»Q__E‹aÑ¢Ea+--Eii)–,Y‚‡~¸ß8eYÆu×_±MjJád8œŽ~Ï7ãÀý°Ùì()™6,×OtÍÍMØÿñG8oÞ±eÔzõ•?ñÜ(ìܹ3fœ‚¬¬¬X‡2*U”FGGN?cf¬C•¼^/ÞÝñ.¹4úÕcÕæ×^Æ7/_1ŠŽF­õÍXäè~§ 4¸PQz?Ü>‰7k&Š\ KFzTÏšä§[‡¤5õ¾}{‘““‹I“ ¢¾ &b ëj]×C ˜@ ‹Å‚””8X,–¨~XÑÈÐuŠ¢Àëõ¢££^¯V«5”EqL¬ŽY¼x1n¼ñF|òÉ'8å”΂r^¯ÿû¿ÿ‹[n¹%ô8Ã0à÷ûa·Û|Þ½÷Þ‹Ûo¿=â9§OŸŽ›nº ÷Þ{/RSS§ (,œŒâ⢨¾^"""Ž·úÑêV`‘£»7kÿx?*JWBmj dûÛ˜tÇYŠê94Ý€, ˜’í`W¤1„‰˜~t_£ë:ü~?DQDnn.Žáùk, Qa³Ù`³Ù––¯× —ËEQ`³Ù`L¬Ž¹úê«ñÔSOáòË/Ǻuë0~üxlܸªª†%Q¾ñoà£>¡C‡’’2 ó²³³{Ü’T\\Œââb1©BDDDCK7 T»|P5²]ÆõÚfTÿä§045ì¸èt pÅr¤_p~T×þÝš:7Íš°¿oRϘˆéCOIŸÏ‡””dffÆ8:"*‡“&MBcc#ÚÚÚ`·ÛC«Û9c±X°eË,[¶ kÖ¬Ïçù瞋;v 777ô¸üü|ÔÔÔÀjµê<"""¢‘P;‹ò MM^=àGõcÐøÆ›c¶‰QüðCpM‰"ÒNŠj 7ÝŠT'ŒELÄ @0 ãõz‘‘‘´´á)ID±•™™ I’ÐÔÔ‡ÃQ2ÓURRžzê©>ó«_ýÊÔy=9xðà Ï!"""êK»WEm³–(·öŽŸ@ÅŠûáîá÷•Ô¯ SV¯„”œÕsè†@`kê1މ˜^Wà ðúý~¤¦¦2 C”àÒÒÒ iÚÛÛCÛ”‚5c=)CDDD4Ú¸Úühr«Q'a:þù*î_ ¥¹9|@{ý"äßv+„(몺»EÆÄL¶¦똈éA×$ŒaP¢(r;Ñ‘™™ ·Û EQ`µZ¡ë:“1DDDDqÄ0€cM>x*äh$†ü3Ž>õ jaCR’…¥+6ï¼(£í¼tf²™É¶¨¯E£1ýÐ4 Š¢D´M%¢Ä–••…ºº:H’YæJ"""¢x¡h:ª¼0 D•„Ñ=^T>´Í'bÌV0 ůƒ£0ºz0†a@Ó ¶!iMM‰3¡›î«a4MƒÅbÓéŒqdD4’œN', 4Mƒ$I\CDDD<~ Çý%ÑüFæ?v å÷­€·âHÄXêœs0eÕJHIIQ<ÿ[Sæ: ESA˜1}Ðuªª"===Ö¡Q $''£¹¹²,C’¤X‡CDDD4¦5wÐЀ,GW«¥õ½÷qd̓ÐÚÛÆ° [SS_˜ˆéCpE WÃMN§.—+´RŽˆˆˆˆFžauÍ>¸ýZtIÃ@ý¦2Ô>ó, ]’œI(\u?ÒÎe´õ`rÒØššzÇDLÁ›-Ã0Boº®Ãbá7ÑXd±XBÛƒo‚ p{ÑÑtÕ ^¨ºÕöÍíA庇в}GĘcj1Š×¯ƒm„hBý²550y<[SSß8;z¼á ~,F¹,m$<ñı(ákÂá?ˆˆˆˆhøù Ç=Ð D•„ñWÅ¡[në1 “qá|LÿÅ3Q'aT]‡UQ”ãd†úÅ1}þ%<Ï=÷®½öZ¤¤¤ôúǃ^x×_=’º„êkl Nœ8÷ßMMMðù|HIIÁìÙ³QRRbêzDcIpekÄœV·‚†r”En[w½‡#kÖBs»ÃŽ ’ˆüïߊÜëQ®tVUY)Vd$[£ºLÄćÃùóç‡jѼûî»8õÔS‘‘‘16Xxÿý÷qþùç#//º®£±±V+HQüiõ 8Þ€ÕÅÂú¨#§¦bÊÚÕH9û¬¨â ¶¦ž˜e‡ÓÆ?ÚÑÀ1Ó‘ØŠ Š‹‹CŸ×××cÚ´i=Ž †®ëؾ};®ºêªPç'I’}ÐDc·# Ýè¬ãUEÈRõ`?xð ÞÿýÐç7ÝtSŸñz<lÙ²×^{-RSS±wï^ìÚµ 'têêê°xñb‚UUUUU='"""""êM»WEm“–hZShÚº Uë†îõ…È&Üz ro¸>ªë€ªÈI³±55E…‰˜$ŠbhuÊ´iÓ°eË–AŸ¯ª*öìÙƒööv¸Ýn¸»ê*%%---¡Ïg̘3fÀ0 üìg?ë÷ùjkkáv»ñÎ;ï4MCzz::::ðÎ;ï ¸¸8´ª§·ãDDDDDD=qµÐÔ¡D•„14µ¿xõ›Ê€nÛÊåô4­]ƒä3¿Uœºa[SÓÐ`"&FAô2¶ãÇcëÖ­¸à‚ ™™‰¦¦&øýþ^ŸžžMÓpäÈL™2¥×ÇéÝŠWÙl6äççãÊ+¯Œ[¼x1***ðÉ'Ÿ`×®]X´hRSS{<ÎåzDDDDDÔ•aG½ð«zT‘ÔÖVY¹mÿØ1æ<é$¯_knN4¡BÕu8¬2&dØ òÞ††SyqÈáp ­­-âxcc#ìv;rrr ijkkC-uƒ«eº’$ óæÍÃßþö7”——‡.õõõaÏ¥( jkkt®‚ >wnn.Z[[QQQ ³h©¢(ðûýðù|())ÁE]„––øýþ^ ¥@ €ºº:ÑC4MÃ+/oÆ3O?‡?úW¬Ã!""¢()šŽòúTR‰ Ïç_ààâ›{LÂd-\€é¿üÑ'aTY㬘”ig†† WÄÄ¡3Ï<Û·oÇ¿þõ/\uÕU¡ãS§NEUUžþy8L˜0²ÜùΜ9/¾ø",X€äääÐ9%%%p:ؽ{7þþ÷¿C–e¤¥¥áÛßþ6€Î•9^x!Þxã 8Nddd )) `±X°páBlß¾»wï†ÕjÅÌ™3‘””„÷ßÐ4 _ûÚ×`·ÛQWW×ãq¢¡²}ûv¬Y³ííí(..Æc=Æ-pc€$I¸ê[ P\\ëPˆˆˆ(JnŸŠš&?d)Êz0[þŠªG…î ÿï`±bÒ’ÿÁø…WDuý·¦v°55 9&b†Y°ÜyçacwÜqGcùùùX´hQĘÕjÅe—]ÖãóÌ™3§×J&LÀÕW_ÝkŒ'tN:é¤Dz³³qíµ×FÿÖ·¾q,//¯ÇãDCá¯ý+xàhš(//DzeËPVVÆíoDDDD£@S{®v5ªÖÔP5Ô<ûKÔ¿°)bÈ:> Eë~Œ¤SO‰"ÊÎÖÔ², 0ÛÁÖÔ4,˜ˆ!¢¸×= ôÅ_ ¾¾¾×ÎaDDDD{†Ô4yáõëQ%aÔæT¬\…ö>Œwúi(~èAșф UÓ‘šdENª5ªëõ…5bˆ(®uMœwÞyacÉÉÉÈÌŒî?["""">šnàÈq7¼RIÏ¡C8ø½›{LÂd-\€i?"ê$Œ¢êÈM·3 CÃŽ‰"Š[]“0K–,Áã?Žyóæè¬²råJX­ü’ˆˆˆ(ù åõ@T[|\¯mÆg·ü7õÇÃŽ‹V K—cò²{ Hæ7{è†]70%' )n¡áÇYFDqiëÖ­¡$ÌwÜE‹¡¬¬ Û·o‡(ŠX½z5Î?ÿüX‡IDDDD=hq+8Ñèw+’¦xëÃãØõI#Z= &d:0áËB¾†ÀÑ ÑðÚ_"γæd£è¡#iÆŒ¨â ¶¦ž˜i«ÁÐHa"†ˆâÎÖ­[QZZJÂ|÷»ßEYY6lØQ±fÍš^ WQlÕ5ûÑáë¿(¯_Ñqßï>ÁÇGZCÇÕt°Ã*íÇ™o>÷O"Î7k&Š\ KFzTqªªŽ¬+2’¹ÂšF1DW˜„!"""t¨nð@QÕƒyîo•aI˜ )­UÈ߸ î@{ÄXÖ˜¼t ›o)m+q&wÂaeµyLÄQÜ`†ˆˆˆhtò+:ª]^ˆ‚0 $Œ¢éxóƒãÇ¿V»WÚ Ñï–):(\~Òç_UœÿnMídkjŠ&bˆ(.lß¾=”„Y²dI¨&̆  I|ðA\|ñű“ˆˆˆˆºióª¨oî¿LW mxýÿN¶Èº‚oz g×}ñXÛĉ(^¿Žâ¢¨âìlMmANª-ªëE‹‰"Š >ú(4Müyó˜„!"""%ÚühêPadkêd» AèÜ&”ækÅx“ÚŽE<.õë_ÔÕ+!%'G§¢êÈ˰³+ÅnˆÛ·oÇUW]…—^z©ÏÇ:t·ß~;Î?ÿ||ï{ßÇ~8BÅÞ‰'t~¿,]º”I"""¢8¦ª}hñ > ɧONAqËüèOE$a hž·Å=UF7 Øššâ 1ÃèàÁƒ¸õÖ[ñØcáèÑ£}>¶ºº·ÝvæÌ™ƒM›6aΜ9¸ãŽ;ðùçŸP´DñcÇŽ¡ÕLÂÅ—€ª£¢Þƒ€¢AÌ×Y¹Åz·~ôÆ)aÇý² sÎ]³‚hþ–UÓ Ø,Šrœ°Ê¬Cñƒ‰˜a´yófÌŸ?¯¼ò fÏžÝçcËÊÊ0wî\,Z´ùùùX¼xq()C4ÖäääàÑGea^"""¢8ãöi8rÂQ šLÂè/*Xï3O@Ôõ°±g¶\ò}üpÕ"Ø,æoWUÕ@f²“2íˆ"WD4,¸6k-[¶lÀݺu+V¯^vì’K.ÁÚµk‡8*¢ø´oß¾X‡@DDDD}hjÀÕ®Â"™OøCùòRxË+"Æ,g~ÿ±f%,ÿÜq&·FgíIãlMMq‹‰˜8à÷ûÑÒÒ‚‰'†/((@GG<œNgŒ¢#""""¢±Ì0€šf¼>mP‘ºk}7ެ^ ­½=|@{ý"äßvkÔ[‘dY@a–ƒ­©)®1ãÆ ;žšš hiia"†ˆˆˆˆˆFœª¨nð@3ÉlÆ0P¿© µÏ< £ÛV$É™„ÂU÷#íÜ9QÇ™š$³55 LÄÄ`Â¥µµYYY¡ãE«222b]Þ€Ž£./dI€ÙŒæö ò¡‡ÐòÎŽˆ1ûäÉ(~xì“'G§¢È˰±+Ü4’’’””„êêê°ãµµµHMM…ÝnQdDDDDD45wBI³üÕGqè–ÛzLÂdÌŸ¿~.ª$ŒnÐuSrœLÂШÂDLœ˜;w.¶lÙvlÛ¶m˜?~Œ"""Іa ²² Ÿ~úšššcQ«kö£¡-]=˜ÿû?üÞ-ðV ;.H"&Ü~¦¬]ÑaþÎÁÖÔŹIlMM£11rï½÷âw¿û]èón¸;wîÄï~÷;œ8q/¿ü2¶mۆ뮻.†QÅžahin…«Á¯Çëpˆˆˆ–¦8rƒ¯ Ùlg$Ã@ý ›P¾l4·;lHNMEɆŸ ÷†ëMOiM²R¬lMM£×oÅ€®ë¨©©AvvvèØI'„'Ÿ|?ÿùÏñë_ÿÓ¦MÃÓO?)S¦Ä0R"¢ØE3gŽââ¢X‡BDD”°ªÊH¢`º(¯æq£rÍѲsWĘsZ ŠÖ¯ƒ-/ÏtŒÁÖÔ3ílMM£1#äé§Ÿ},Š"6mÚñ˜¯|å+øÕ¯~5’aÑ×êQP߀%Š->¾ª*”ßW _UUÄXÆÅaò}Ë ÚÍw4Òu@’ÀÖÔ”˜ˆé‡ Ðubýì‰htÒu×»Q;ÑêG‹[* Ó´mÊ›û IDATªzº×> K˜pë-[‘¢ÀÖÔ”h˜ˆéƒ EŠ¢Àfã7=ÑX£( DQd2†ˆˆˆŽn¨vy¡hºéz0†¦£öÏ¢~SY羡.äô4­]ƒä3¿Uœªä¥ÛÌ®H”@8›{Ðõ¦KE¸Ýn&bˆÆ ·Û¶Ž """JÕ@uƒI0—„Q[[Q±r Úÿñˆ1çIÓP¼~¬¹¹¦cÔ ºŽÂñNXeîN ÄÂDL/A€ $ ---ÈÈȈuHD4ÂZZZ IRèçÑh×áSQÛ€EÏç_ by)üuuc™—^Š‚e÷@´YM_ßлU¤L»"QBb"¦ÁmI’$ÁãñÀãñÀétÆ:,"!~¿N§“Û“ˆˆˆ(!4¶Ðئ@ަÌ–¿¢ê‘G¡ûüaÇ‹K~„¬… ¢ŠQÕ Œ³ê˜˜ac†1]‚Ã0ÂÞ‹¢‹Å‚úúz±u*ÑXQ__‹Å–„éþžˆˆˆh40 àX“Þ€ Ùì6UCͳ¿Dý ‘Ý_-Y™(~h’N=%ªuÝÀ¤,>cUJpLÄô"¸AX,ø|>444`üøñ±ˆ†YCCEÝnûY@DDD4Ú¨šª Mv‚U›[P±rÚ?ø0blÜé§¡hÝZX2³LǨ€,…ÙN¶¦¦1‰˜>kĆ«Õ —ËI’X/†(555ÁårÁn·‡¶'2 CDDD£‘ǯáX£²$Àìo3žCŸ£|y)õõcY  `éÿ@-¦cT4ilMMc 1ÝtÝ–ü<˜Œ±Ùl¨¯¯‡¦i\C”€ÐÐлÝI’ õr[&͸ÚUÈ’ùß]ßÚ‚êG…î„­6Lºû.d]þͨbTu Ÿ­©i âŒïG°u­$I»ÝŽÆÆF´µµ!//|‰€ÇãA]]]h;’,Ë$ ¢(†µ¯&"""Šw†a ®Ù·_3½ÍÇP¨Þð3¸^Û1fÍ¢‡Ö!éä¦cÔ @€Âñ¶¦¦1‰‰˜ôT´7˜ˆ Ž+Š‚ÊÊJØl6¤§§#)))TØ“ˆâ›®ëPn·ÍÍÍðûýe6›-´¦ë–$®†!""¢Ñ@Ó T»¼P5ÃtFq5¢|E)Ü>‰KžyŠÖ­…œn¾Tƒ¦pØ$LH·³+YLÄô¢û%àß«b‚ÛdY†ªª¨¯¯‡®ëÐu†aÀ0ŒX…M4\7Ô|íã_ðû7¸ÚE–å°z0]ëÂpK¾€†ê/$I4„éØÿ/T”®„ÒèŠËZ¸wßA2 ©jƧX>ÎjúD‰€‰˜è~#\õlk+Ër(ÃñøÖÛÍ´Ù›ìÞ^o΃øÖ5É\ñü^&i‚#"""Šw­õÍX¢Øæãzm3ªßCUÂŽ‹V –݃ÌË.1}í`kê‚ñvØ-Rÿ'%8&bú\Óõãà{Y–¡iAàj˜Q¨·•½ñîú:?îúúó>¾u_Óuûa4󂈈ˆh¤oõ£Õ­˜NÂè?Žþä§p½þFĘmÂ?üÅE¦ãckj¢HLÄô£k2¦§cº®CӴГ1ñ«ûÍwo]q‚íI÷LðMÓ´PBŽI¹øÖuL0ùÒ= ÓýñDDDDñF7 T»|P5²d. 8Ñ€Š¥pz0b,åk_EÑšU’“MǨêÒœ2²Ùšš( 1ƒ¼ÁVŠ¢Àb± ==N§“ÅzG]×àñxÐÞ޿߫պïúúu¿ïZ3H×õ°ëY­V¤¦¦ÂétÂjµrĹ`±Þ®óÀb±Àb±`ò…ˆˆˆâ[@5PÕà(0»È¤ý£QQºjsSø€ ÷úEÈÿþ­L&x€ÎÖÔyilMMÔ~Wô£û¶]×á÷û!IÛWB¢(Ân·Ãn·###.— @6›-ô˜ à yOI˜@ Y–1aÂ΃QFEØl¶P׳à<ðù|°ÙlaÛ“ºí&"""Š¥v¯ŠÚf?,’ùßO\¯mFõO~ CSÃŽKIN®X´óÏ3}m¶¦&ê1}è- “’’‚ÌÌÌGGCÁét¢  hmm…Ýn‡a+Zº&a ÀßïGjj*çA‚è:ÚÚÚB]”&câ¦éØþλøèŸûqÚé§bÚ´©±‰ˆˆ(&\m~4¹UÓIÝ@õ£¢ñ­-c¶I1õáõ°O)4Ÿ¦pXELÈp²55Q˜ˆ€`Æëõ"##iii±‰†Xff&DQDSSD$c‚õ_‚ó ===¡Ò0ÊÌÌ„$I¡y,äK±%I"fÍ:“””ëpˆˆˆFœaÇš|ðTÈ&·ÀûkjP~ß xË+"ÆRÏ9…«€y2¦ÿêQ%aTÝ@ªSBa¶“I¢A⊘nº¯†Ñ4 ‹…]qÆ§Ó Y–¡iZhõƒ¦ie™ó` ¶¤×4 ’$qU ÃêšýpûUÈ&»ùÃáû–Ãw¤2b,íÜ9(\u?$§ùºkªn°55QøÓ]סª*ëŒAÉÉÉhnnìUU1ŽŠFZpȲ Iâžg"""^šnàhƒŠ®C2¹Ì¤õ½÷P¹úA¨aÇIDþ÷oEîõ‹`¶¥‘¦`J¶‰›+ˆÌb"¦Á1\1ö8N¸\®Ð )΃±©û< """.>EÃQ—¢sI˜`=˜gž…¡‡oE’SSQ´v’Ï>Ût|šnÀi“Ÿngkj¢(1ÓEðf+Ø!'ضÚb±Ä82I†aÀb±„:fmQ£±%8ºþLÛ“ˆˆˆhHµ¸œh @6¹ Fó¸Q¹vZÞÝ1æœV‚¢õë`ËË3[S -&bz¼á ~,šlåF£—(Š¡"­Á„çÁج  ,CDDD4TŽ·ÐæQL'a|UU(¿¯¾ªªˆ±Œ‹/Âäû–A´ÛL]›­©‰†ï,ûüKx4ž{î98p â¸aøÍo~ƒÏ>û Ï>û,ÜnwŸ×èãhh·¦Ô<,·‘LÄ %Ý*OxÐæVL׃iÙ¹ Ÿ}ïû‘IY„ÛoÔÕ+M'a4C‡$SóÇ1 C4Ęˆfº®cÏž=7ò‡Bkk+Àáp`þüùýÖ èã(þ d çÑèäWt”×»¡é€$ > ch:jž~å÷­€æ ÿ£œœ–Ši?݀ܮ7ŸªHsZØššh˜0ÓhWBˆ¢ˆŒŒ :t(ìø|€¢¢"€ (..îwËÃ@GC£ëk?ó`°8F õÑPj÷ª¨<á$ ¦ŠÞª­­øbÉݨaSçÞ¡.œ'MÃŒ_?‡ä3¿b:>EÓ‘—fÃøs+iˆ¨¬3Î>ûllß¾Ó§O>|yÝŠe=ñĸóÎ;O=õJJJP__]×1þ|ôø¸©S§¢¾¾pÎ9çàðáÃ8~ü8$IÂÅ_ŒÜÜ\x<”••áæ›o444`ëÖ­¸îºëuŠNóÀívcË–-hjj‚¦i8å”S0gÎìÙ³mmm¸è¢‹ iþð‡?àüóÏG~~>çÑ(âj ©CE6÷÷pÏç_ by)üuuc™—^Š‚e÷@´™+¨lM]”ãdkj¢aÆDÌÈÊÊBZZÊËËQ\\Œ}ûöá²Ë.Ã|ÐããUUÅìÙ³‘žžŽC‡aÛ¶mX¼xqûêW¿Šôôt8po¾ù&/^ŒÔÔTüóŸÿÄŽ;ðï|§ßø†ê:Ô·þæAp«Qjj*|>ÊÊÊP\\ŒÙ³g㥗^‘#GpôèQL›6 ùùù×ç| """ŠO€£./üªnº(oÓ_ÿ†ª‡îó‡d &þðvd_ûmÓñiº$»Œ¼4¦:GÈìÙ³±wï^TVV"==©©©½>VE¤§§¦M›†ööö=Îf³…®;mڴתëPÿúš¢(BUUìÙ³»ví‚Ûí†Ûí† ¸ôÒKñÚk¯áرc8묳z¼6çQüQ4åunT’©½Hjž~GV¯HÂX²2qÒÏŸˆ* £h:²’-ÈOg†h¤03B²³³áp8ðꫯâì³Ïðy‚ ¨ˆ$I}~>Ю/ý]‡¢Ó×<8~ü8Þ~ûm`îܹÈÉÉßßùŸ­ÕÚ¹ÄT’$Î"""¢QÂíSq丢(@4‘åP[Zñù]K:ëÁt3îôÓ1ã7Ï!é´SMÅf€ª˜<Þôqæ¶3‘9LÄŒ sÎ9³gÏFFFƈ>¯Ãဢ(¨­­ÔÖÖ¢­­mDc @uuu£¾xjoó ±±v»999Ð4 µµµ¡ÄÇ–-[pÅWÀétâ_ÿúWTÏ?ÚçC¢Ì"""JlMíÔ4 ›èŠžCŸãàM7£ýƒ#Ʋ.À´§6Â’™eêÚš¡C’LÍKbkj¢`˜”ììì^Apá…â7Þ€ÓéDFF’’’F<Žhlß¾kÖ¬A{{;Š‹‹ñØc… 6½Íƒ©S§¢ªª Ï?ÿ<&L˜Y–ñüN§ÅÅÅÈÏÏÇïÿ{L˜0ÁtBo4χDšDDD”˜ hôíŠé$LãÛo£ú‘Ç ûaÇ‹wß…¬+.7ŸªHO²°+Q ×.Àþ®ÛÓ¸Ðåxð½ØÃç]#v9/øyðMúò½üåÇÁ÷©.—뽞þš<¦ë:t]‡¢(èèèÀÉ'ŸÜÏ—CÃé¯ý+xàhš:VRR‚²²²aiÝœ€Óéx<œvÚiCþ\4p#=‚>ýôSŒ7‹¢(B;,õôœ---˜rJŽ#î“0Dc1·ºÞ|wÿ‹Brr2233c$ÎÒ4 ¯¼¼Ï<ý>þ(ºIDDDáŭà¨ËYX£î:öïÇÁÅ7Ãý¯cY  äÉÓÍmKW5I6S²°H¼ý#ŠüN¤¸Ôõæ{É’%xüñÇ1oÞ<{V®\ê$D‰‹ó€€Î×úªo-Àm·ßŒ3fr‹ Å—ºf?N´úM׃q½¶Ÿÿð 4ºÂŽ‹V ï/Åäe÷@Ì­bQu ;Õ†ü ¶¦&Š'\—FqgëÖ­¡›ï;-BYY¶oßQ±zõjœþù±“†çÅ3ݪ½ñ¦È$Œ ÷†ëQüèzÓIE5bC~“0D£ WÄÄÈyç‡éÓ§øñ¯½ööíÛ‡_|¢("Ådõx·cÇŽPkâDºùæë=8‰:ˆˆˆhôhjÀÕ¦À"›øÛµa þ…M¨ýų04=lHr&¡pe)Òæžk*.ÃèÜ*5%Ç «Ì ÑhÄDLŒÜ~ûíƒz|uu5N>ùddee SDñ!''÷ÜsæÍ›ëP†_ïÁIÔy@DDDñÏ0€šf<>²‰$Œîõ¶é¨9ðIĘ}rŠ×¯ƒ½°ÐTlšaÀ*‹˜”é`kj¢QŒ‰˜ù¯ÿú/\}õÕX¸paèóyóæa÷îÝ8tè&L˜€{ï½3gÎÄC=„—_~ðæ›o¢¸¸eee± HíÛ·/Ö! ;¾Þý 󀈈ˆâ›ª¨nð@3`ª=µÿè1T,»ReUÄXÚœÿ@áê 9“ÌŦÈH–‘•b3u>Å&bâDKK ž~úi<ÿüóÈÏÏÇ3Ï<ƒeË–áõ×_ÇŠ+””„––¬Zµ*Ö¡ÒàëMDDD_¼G]^È’3͇Zß{•«„ÚÑv\DäÝx#ònºf‹¹°55Qba±Þ8‘––†ÒÒRœzê©ÈÈÈÀ7ÞˆÆÆF=z4Ö¡Ñ0àëMñ¨¡¡„aCzž®ë¨ªªÂ¾}ûÐØØ8¡ ©æŽ@( 3h_Öƒ)¿wyDFJIÁÔÇCÞ÷›JÂhºŠrœLÂ%&bâˆ(þûåÈÏχÃá€Çã‰aD4œøzS¼¨­­Åœ9s0qâDÌš5 yyyxã7¢>Ïívã®»îBNNJJJpî¹ç"??ÿùŸÿ‰¶¶¶áü’ˆˆˆ¬®Ù†¶€©$Œæq£|y)jž~†^”×Y23~ýK¤Ìžm*.UÓ‘d“0%'É\‚ˆˆâ1Ã(à«_ýjØÛÇ<àóàSøzS,x½^Ì;éé騨¨@mm-®½öZ\sÍ5ؽ{wTçÙív¨ªŠ?ÿùÏhnnF[[6oÞŒwß}K—.©/‘ˆˆ¨GšnàÈ :¼ª©z0¾ªj|ö½ÛÐòîΈ1uæé8éÏÀ–Ÿo*6E5ÊÖÔD‰Š5b†‘ÕjÅž={bQ¯^xá´´´à÷¿ÿ=ÆøÙÏ~†Ý»wcÆ x饗LŸ'Iž|òɰó.¹ä¬X±<òÈð~aDDD}¨*Ox ‰$«MZvý*W?Íã$8®»§–@´¾¨n°5uaŽ63m³‰hT`"†ˆh +++ÃÂ… CÉ suÖ¢E‹°|ùrX­Ö!;Nœ8¤$s#ˆˆˆ¢ÕêQP߀E|ÆÐtÔ?ÿ[Ôþú7Y“.ÜV'^8e×#«7±³ŠR|mÍ0`³H˜˜ackj¢Ç4+ÑväÈLŸ>=âøi§MÓP[[õy^¯;vìÀŸþô'Ü|óÍxä‘GðÃþpè¾""¢:ÑêÇñsIµµ‡—ÞƒÚ_ý:" S“œŸõCN/¸ÜÀ½¿=€V´ìÚªt§Œ‚L;“0DcWÄÄÈï~÷»>?€wß}7ôñ~ô£a‰†_oŠG𦡾¾ãÇËÉÉÐY·°°0ªójjjpÍ5× ££ªªâž{îa"†ˆˆF”n¨vy¡hº©z0ž/£â¾ð×ÕEŒ}; žþ-(bø­•¦xâ/åøÍ¾ÒçµU ˜iC’·fDc¿Ûû!t]ëpC‰O×õ°â¹¢(rŒAÝçA¢EV«íííc~¿@g«õhÏ›:u*Nœ8MÓ°ÿ~Ü{クîºë°iÓ¦}O麎ìù*W„?õ´Sœ<®—³¢ðûèèák¤þyÜn¨ŠÂ¿(èšÎ¿(¨ŠÛÛàktàózðûfT5M~@Ìü¯ÞöÎvÔ=þSè_þ"IØÖåøCÒ×z=·ªÁƒÃÇšŸ9uÝ€(3í0 ЉàTðg ÷6G àóz‡ý{x\rò°^?‘1ÓA Š"Eÿ‘)Š¢@’¤ÐM8çÁؤ( DQLØdŒ ˜0aBÛêëë'N²ó$I¬Y³ðòË/câĉxñÅqÝu×õ§¦iغuGÄñ–¶&ŒÏÊì÷|3ÚÚZ!Š\®†a¹~¢S”ZZZ°oßÞX‡2jù|^þûE¡±ÑEQz­UE}s»;W0v¸;bJÔ¼ Ðè$3'k:Ä·Þ†ø÷íCFJ ôÿ?ì¬4‘çvññÏИþ»„À!éÀUm&¸Äæñzðá‡ûbƨÕÜÜ„––fÔÔÖç™wþüa½~"c"¦ÝWB¸ÝnÞ€1n·;,Ïy06uŸ‰˜™9s&Þzë-¬_¿>ìøÖ­[1mÚ4¤¤¤ éyœœŒüü|ŒÉ“'ãÏþ3.¾øâÿ:‰ˆ(±yüŽ5ú!KÂà‹òªjžý%ê_Ø1dÍ¢u?FÒ)'÷xê³s1cR26ï©Ã‘Œ³‰È±6áŽïœI ª2S,ÈLfÍ""êÄDL/‚[A€ÅbÏçCCCCíZ)q444„Šòq`, ü~?çÁœv»=ìgA"»æškpÍ5×ô:þýïßÔygœqÎ8㌨ã#""êKsG ­Š©­HŠ«å¥÷Ãý¯cÉgœŽ¢‡„œžÑç5¦æ%aÉ•S>ŸÿØ»’(@ÓÙššˆ"ñ'B‚5b ÀÕj…Ëå‚$IÈÈèû1NMMMp¹\°Ûí¡mi]WÄpŒ }Í"""Š/†a ®Ù·_3•„éØ¿¥« 4º"Ʋ.@ÁÝwAˤ­²§d; Kü=‚ˆÂ1ÓM×mIÁσ7á6› õõõÐ4+c¤d IDAT"LCC`·ÛCÛº®ˆÑu=´Ý‚ó quŸ] õ&ê¶$""¢ÑJÓ T7x¡êFŸs{ãzm3ªßCUÂŽ‹V î]ŠÌo\f2.À!wååï DÔ&bú¼mµÛíhllD[[òòòXÀw”óx<¨«« mC‘e9Ô-©{sÃ08T_ó€m‰ˆˆâOÑp´ÁQ„1”ªòS¸þòzĘ5'Åë×Á9}º©¸ÕÀøéNþñ†ˆzÇDLz*Ú¼Ž+Š‚ÊÊJØl6¤§§#)))Tؓ◮ëPn·ÍÍÍðûýe6›-´¢¯vÅœ‰a0óHÜ"½DDD£Q‹;€ã- ,&¶"N4 ¢ô~¸?ù4b,ù+³0eíX2Ò}]Ý0`@a¶ºêôùD4¶0Ó‹î[”€ß„oÒeY†ªª8~ü8t]‡®ë0 †aôvYŠ¡àë\å IRX®õ@ú*ÎÊy0º™LÂÅÞñV?ZÝ ,òàÿèÕþÑǨ(] µ¹)|@{ý"äÿVÒ௫ê:ì3;[S{ÕA_‚ˆÆ&b ûXpÛŠa¡-+¼ñ=ºÞ`o¸ƒïƒ+YzºéæzôTÿe 7Þœ‰Åì< ""¢‘ájó£É­šJ´øOy`”ææð`=˜Ûn…`¢¹‚ªéHvX›fåï Dd1ƒÐ}UDPðÆœ?ŒG—¾êÀôwçAâ0;ˆˆˆhxp¬Éo@…<Ød‰a ~Sjñ, M’’œ˜|)ÒÏ›k*.E5›nCªÓbê|"¢ &b©{Í®ÇhôìkÈy˜øÅ–¢é¨nð„Ñ=^T®{Íïl³O.@ñúu°:&Ý0(ÌvÀfü*"¢î˜ˆ1©ûJ}†â¦›ó`ôcò…ˆˆ(>¸}*jšü%ƒýßÙôÊ—¯€·âHÄXêœs0eÕJHIIƒŽ©³5µ„‰™vˆüˆ†1C€7rp™ÕÜ¡ ¡ÕYüŠ“Ö÷ÞGåêµP;:ÂŽ ’ˆ¼oDîâd%[‘‘lô¹DD}a"†ˆˆˆˆˆbÂ0€º?Ü>uðI˜`=˜gž…¡w«“’‚¢5«òÕÙ&bêlM=1Ó§MôùDDýa"†ˆˆâšaøì³ChnnÁ¤I‘““눈hhº£ >(º>è6Кۃª¯CóŽw#Æœ%SQ´~lùù¦b’D 8×ÉÖÔD4l˜ˆ!"¢¸f|^?&/¿¢Ã>蘂­©óÒmƒ>—ˆh0˜ˆ!"¢¸&Š"fÎ:ÅÅE±…ˆˆ†@‹[ÁñV?,’ ²,oë®÷pdÍZhnwø€,a­· ÷†ëMŤjrÒØššˆF1DDDDD4"Ž·ÐæQ¾L œ¡é¨þ·¨ûÍóõ`ä´TLY»)g9èxtà `òx¶¦&¢‘ÃD  +ݪ5M~ȃ,È MooAÕ#B÷ÂŽ + –Þ…¬—úšÁÖÔSr’`•¹‰ˆâ1Ãàĉ€ìì옜ODDDD4’šÚpµ«ƒOÂôQÆ:> E­CÒ)':ž`kꉙv0Cÿ?{wUyöü{–Y³/$! aQj1 "‹X‹  ÖêOô¢âB]^|Uê²*¸ ¨ÕZj©øZI­ÕV,¢XEd[QÖ²/³Ÿå÷Gœi&“å $™Iòý\W®dÎs–{fNfæÜó<ÏMm˜ˆ9wÝu~øá‡å’$áÿø¦OŸxçw`³Ùàñx ( ìv;„]4›Zît:C¶oïû Š"ÒÒÒ0|øpLŸ>))á»´æãŽðÞ{ïáÝwß…ÓéÄe—]†»ï¾»Mö;iÒ$$$$àÍ7ßl“ýµ5]NT¸àòha'a”Ê*š;µÿþOH[ܰó³xää3˜†¥©‰(Ê1s.ºè"˜Íÿ}EV«}ûöX,ÀsÏ=‡M›6áørssë7µ¼©íÛÓÈ‘#û÷ïÇG}„o¿ý+V¬º_Asq{Û±c^~ùedggcôèÑèÕ«W‡›ˆˆˆ(’TMÇÑÓN¨: …™„q|ý5 gσ¯¼,¤-uÊddÿæRx—*º^SïvØÌá—Ë&"ê(LÄœ…Y³f!)))dùï~÷»3Þ§(Šgµ}¸zè!ÄÇÇÃáp`æÌ™(**ÂöíÛ1nܸ‹¡3ûòË/÷ß?Î;ï¼GCDDDÔ1\^ÇÊ>ûì3Àƒ>Xºt)† †¿üå/ظq#JKK‘iÓ¦á / :Gš:nc.— .Äž={ššŠ_þò—¸òÊ+^¯÷ß?dYÆòåË!Ëüw&""¢öWåðátµ7ì¡HºÏ‹¢eÏ£ìýµ!mæô4ä,y1ƒ‡KSQgÃ+·³ðüóÏ =z4ÆŽ´Î˜1cI‚‹/¾yyy-.oκuë‘‘¬¬,ìÝ»þóŸ1hРÀÅýÓO?íÛ·£ÿþHMMÅ믿öýÑ4 ’’³ÙŒ;w";;çœsöîÝ‹·ß~f³·Þzk`›?þлwoôïßßðv ïÏW_}…U«VaÕªU2dRRRpøða<ùä“X½z5dYÆO<Ï?ÿ#GŽ„ÝnǦM›púôiüþ÷¿oñ±li;ÿ\2ïéS§°`ÁÄÆÆâꫯ†ÇãAYYYPÆHÄ\pÁ GK]DRxù’úù`ž{ºª-í6ôý’.v<ŠªÁf‘Ñ+ÙŠ.–IDÔ&˜ˆé„¤Fï€>_ýDgv»=ì} 6 =zô@ff&ÆŒ¨ØTRR‚Y³f!-- ³fÍBŸ>}pà 7„loµZƒnÝ®¥ûÓxY||<€úDÓÌ™3ƒÖóÏõÒ£Û5¾ X¹r%Þ}÷]lÛ¶ ›7oÆÖ­[ñÒK/aàÀ-Þ·Û PU5°ÌëõB„ã4¾ÝÇœ †ˆˆˆ:LKAq…¦0{h^Šž]†òu†´YzõBîÓK`Ëév<Š¢³45uz¼¢ëþ 纺:CËÃåïÁ²k×.Üyç0™Løæ›o m;þü@¢¡}ûöÁívã /ÄO~ò“@bAQ”uÛb»–ôéÓ¢(âàÁƒHLL ™«hú±4²]sRRR0cÆ Ì˜1+W®Ä[o½…/¿ü²ÕDLŸ>};wîÄwÞ ³ÙŒÝ»wC×õ3*«]RRNjł={ö¶lÙY–qñŇ½o"""¢–”ÖxPQ§„„ñž:C³‡cÿþ¶„Q#Ñoþ\Ha|.êKSk:л‡¥©‰¨Óc"¦ää䨟ë㢋.ÂÔ©Sa6››]®ÜÜ\ 2ûöíÃ=÷܃>}ú`óæÍgs=ÔOªëóù°oß>­÷Æ8ÓíZ’ššŠ«®º ÿüç?1sæL\zé¥(//‡ÃáÀã? éÇØÈvM9rä/^ŒŸüä'°Ûí!^ýúµþ­Mß¾}‘ŸŸÝ»wãî»ïFÿþý±}ûv˜L&Ü|óÍgtÿýë_cÀ€عs'z?~O<ñ   iiig´¢h§ª*>\÷1âãã1â‚óqÎ9ƒ"Q—¦é:Jj5Øœ>˜ÂæßÿÁá¹ó᫬ ndÜ<™wÍ€ †·Ï@iêTKSQ—Àtr˜2e .»ì2ãÃ?Ä‘#GZ\~&æÍ›‡Q£F¡´´eee˜8q"*…kذa˜:u*dYÆÆÑ¿ÿ‰ˆÛr»ÖÜ{x>}:DQÄÛo¿ýû÷Ãf³A×uÍ?–­mןχ¤¤$|òÉ'øë_ÿ Apï½÷"??ßP¬?þ8&Mš—Ë…Ý»wcðàÁx饗=—Â1iÒ$deea×®]ÈÈÈÀÂ… 1dÈõI¯¼¼< 4ÉÉÉa³$ £F]ˆ+¯¼ýúöi}"":c^Eñ Uƒ$„q© ë8ýö;øþþB’0RŒ9KžDÖ=w…„QTñ12ú¥Ù™„!¢.£½^ÍZÛoSíBƒåþßb·®#6ØÎÛÿ#ýø[þñoÿ²²í-]ˆwk׮Š/¼€Y³fáŠ+®ˆt8DÝBUUUÐÐ1jÍš»î¹¹¹9vÌ}û¾‚ÅbE^Þ€;fWRYY¯ö~‰±ã8¡ø™zïïàšk¯tÖ§ŸnÁàÁç"555Ò¡t*·Š•? §Ó‰ƒÚNsºpdÉS¨üdSH›%»7rŸ^ [ßðçƒñ):z&[:]ij—Ë…­[6á篌t(ÖûkþŽ«']1ÌÄÕÛ³g7ÒÓ3лwv¤C1Äl6P @ 4ø­ýø·ÖàGoðã¿·Ñ`YãÛzƒ¿j-9ÐæÉƒÎõªFÍRU5h‚[im#Ãiˆˆˆˆ¨{«¨õ¢¬Æ9Ìù`<Ç£ðÑÙp:Ò–0zúÍŸ)&&¬}jºè@¿t;KSQ—ÄDLñÑGáƒ>À!CpäÈüûßÿƈ#0hçR """¢¦é:p¢Ò §[,‡×û zû^øÔÚÚà†³œÆj‘Xššˆº4&bºˆ¸¸8x½^¬]»ÉÉɸæškpûí·G:,""""ŠRŠª£¨Ô Uäp&åÕu”¬.ÀɯB×´ &)>9 ç#þBcsë5¤j@j¼I±¦°·%"êL˜ˆé"ÆŒƒ1cÆD: """"ê\^ ÇÊ\%º¦á?‡jPVãAx [Èɨ'Ž>¹•[¶†´Ùúç"÷é%°df†‹¿4u¯+KSQ·ÀD Q'âõzñí·ß¢¢¢"¤íÒK91*µ®²Î‹²Z²$`ïáj<õî÷8]å ´÷ˆ“1m¤p÷Cá£sà::LòeÐç±G!Ú¬aÅÂÒÔDÔ1CDÔI|óÍ7¸æškpôèÑ&Û½^oGDDD‰®ë(©ò¢Öå…,Iø¡ØGßø_ðð¢ÒZ/R‹s;Ñ·‡P½m;/\ÕáZWDdþz2n¹9ìxUGBŒŒôË™ß)"¢Nˆ‰"¢Nâ@FFÞyçôéÓg1$""ƒTMGQ™ ŠªCþ±ÒæªGC’0~EÇÿm,Âü6;Œœ€~‹ þ‚aÇãSuôL´ ÞÎË"ê~øÊ×t½ÍËŠQéLÉŒ={öàwÞÁ°aÃ" u"n¯Š¢27$Qþó覆ûö»“8øàQ³kwH›}@rŸ^sFFX±h:]C¿4;ÌaVi""ê*˜ˆ9CM%_˜!ê<ü ˜†ÿ·Ñž”éÛ·o¤C "¢N¦ÚéCI¥&9ø=NÓu(ZóŸ]{Ö•àÖ¯ÿŒWèœdÉ?¿}y¢5¼!EªªÃf•‘•dgij"êÖ˜ˆ SË6ÿߺ®3 CÔ ‚H¾‚ø?ŽÖ„̵×^‹>ø€“ò‘!§ª=¨vø`j¢ç‰(ÈˈÅw'jCÚ†Ÿú ¿üî]˜ÕFsɲfÜyFóÁÔ—¦6!)Öö¶DD] 1ahœxÑuªªBUUhšø!¢è&ŠbàG’$H’HÊø2јŒ¹ÿþû‘’’‚õë×CUÕöýû÷G *""Š6š^?ŒOÕ KÍÿ¹il/Ì/øï{‡¨ë˜X¸ã‹¶„¬+'%"gÑBÄýôü°b©/M­£WŠ63/=ˆˆ&b iØÛEÓ´@ÆëõÂd2!>>6› &“ ¢È±®DÑNÓ4ø|>¸\.ÔÕÕÁårÁl62¢(Feï˜ Àf³aìØ±œ¬—ˆˆšäUt•9!$¡åÏ¥—œ“‚;.ï‹UŽÂâqà–}A^å!ëÙDîS‹aÎH+Mdè›jgij"¢˜ˆiEã^0š¦Áãñ@EdddÀf³E8B" —(аX,°X,HLL„ËåBYY|>,–úñîÑØ;æoû–-[†;î¸#Ò¡Qªu)(®òB#é1uL/\h©Äé…ÏÁ\UÒž:e2²gÝA6…‹OÕ‘ÈÒÔDDMb"¦M%aÜn7âãã‘’’á舨­Øl6ôîÝåå娩©Õj ôn‹¦dŒ®ë8ï¼ó"E¡²*jÈrxïWë?FÍ3ÏÂìö7È2²g=ˆS&…‹¢™IÄÙx©ADÔ¾:àO¸\.$''#111Ò!Q;HII$I¨¨¨€Ífƒ(ŠQ‘€ñ9r$¾þúkäççG:""Šº¯pÃåU ‡SZQqâÕ?¢äÍÕ!MRrÌwÿ=®º*¬Xü¥©ûö`ij"¢–0Ó oÿ¼ LÂuq‰‰‰PUµµµaJþ9c"”7nî¾ûnœUGZ¼‰±áÍ#CDÔ]1Ó UUáóùгgÏH‡BD(55ÅÅÅ$ ²/•ŒtDDªê|8]í {>˜²5ï£hÙ Ð_ÐrÑlAöC"åª+ÃÚŸ®š¦#»‡V“Ö¶DDÝYt\]D‘ƽaTU…Éd‚ÝnpdDÔ‘ìv;L&TU…$IQÓ+¦;Roü 6› ãÆÁù?鈈"B×uWzàð¨a%atŸÇ–¿€Ò5ÿ i3§§!gÉ“ˆ<8¬X¥©ÓXššˆ(\LÄ´@Ó4(Š‚¤¤¤H‡BD‡ÊÊJȲ Iâ7}‘"Ë2þßÔ_"77'Ò¡EŒªé(*uAÑô°ÞÒ2šó8û¾ i‹ýÉpä<±¦äð>ë*šŽD»Œ4–¦&":#LÄ´Àß#†½aˆº'»Ý޲²²@O9""¢HpûT+uC…°’0u_}ÂÙs¡T”‡´¥N™Œ>³äð¾hP4 g"KS ¾‚6à¿ØÒu=ð£iL&NòòòÎhD݉¿g\4ÌSWW‡9sæ`íÚµ¨¬¬ i¯¨¨ˆ@TDDÔÖ4Ý? KÆÞS§qhöãpìßÒ–0ò"ô[0R\\X±(ªŽñ&$ÅšÃÚŽˆˆšÇDL°Ùl˜0aB`.š­[·bÈ!HNNi סC‡°cÇŒ?={ö„¦i(//‡ÙÌ7S¢Îæ‘GÁÛo¿{î¹}úôáð("¢.ÈãÓPTæ‚(§QݾġÇçÁ×8Q/ȸy*2ïš!Œ^Þº¨*KSµ&bZÑCA@nnnàvII  Ðd[84MÃæÍ›qíµ×*?I’„´´´³š¨›ˆ¦áHkÖ¬Á²eË0mÚ´H‡BDDí Ö¥àd…¦0JSõóÁ]¶PÔ åRŒ}çÌF⸱aíOC}('ƒ¥©‰ˆÚ1èå—_F^^JJJ i&L˜€ììlõs¼Üwß}سgNž<‰·Þz ¹¹¹˜4iR Íáp`ýúõ¨¨¨€ªª8÷Üs1zôèfWQQ«ÕÚbùm§Ó‰‚‚ÜqÇ€ÒÒRlذ7Ýt ¨¨Ÿ~ú)Ün7RRRð³Ÿý v»[·nEaa!$IBïÞ½q饗B×õ&—QÛ$ ƒ ŠtDDÔÊj¼¨pøÂJÂhNŽ,y •Ÿl i³d÷FîÓ‹aëÛ/¬8MGœE@ŠYb†ˆ¨0ÓEA~~>’’’pàÀlܸÓ§OZgĈ8tèÆŒƒŒŒŒ 6ÿ0¥„„¸Ýn 77={ölòx555°Z­Ûû÷ïÇŽ;·o»í¶ãu:X¿~=n¸á$$$`÷îÝØ¶mˆââbLŸ>‚ @Qê'‚;zôh“ˉ¨mŒ9{÷îE~~~¤C!"¢6¢ëÀñ 7\^rC‡<Ç—Ñ‡Ö IDAT£ð±9p iK¸øbô[0R˜ó *šŽž‰ÈN uuamJDDa`"¦‰¢è2`À¬_¿>ìíEÁ®]»P[[ ‡Ã‡ÃÑìúñññ¨ªª ܘ¢c(|t\G‡´%O˜€>³…h3þ™«¾4µ†ì4KSE1íÌ_î»ï¾ ¶™3g6Ù–™™‰©S§†´™Íf\qÅMgôèÑÍVPÊÊÊÂ/~ñ‹fc8p Ød[ZZn¸á†å×]w]Ȳž={6¹œ¨-|üñǘ;w.Tµ¾4gaa!yätÙáoÏ?ÿ<ÊÊʰxñâÀí–phQôR5ÇJÝðiZXÕˆª?û ‡<µÑ¼€‚$"ó×3qóT„ÓEÕ5˜DýÒcÁ¢HDD‘ÁD E½ÆI¿ƒ¢¤¤¤ÙÊaÝÚµkqüøñ@"æ•W^iq}&bˆˆ¢“Û§âX™¢ O´0Œœ€œEówÁaÅ¡h:’bLèo k;""j[LÄQTk˜„;v,¶lÙh‹‹‹CJJJ£k_}ôQÐÜOœ†ˆ¨ó©r(8Uí†IƒÓòªNŽ,|UŸn i³ÈCÎS‹a óKŸª!3ÉŠ8?þE'ë%¢¨Õ0 óàƒbÙ²e7n€úɨçÍ›³ÙÙ Û‘Éd‚Íf‹tDDt†NU{QZãù1 cŒë‡BìÿÕíM&a’~9®ø}XIUÓ¡ë:rÒíLÂE ¾QTÚ°aC 3sæLL:ؼy3DQÄ‚ 0~üøH‡IDDBÓ¢R'|Š)ŒÊH7âè’§¡¹ÜÁ ²„¬w"㖛ÊCÕtÄXeôL´°*Qa"†ˆ¢Î† 0gΜ@æW¿ú °|ùrˆ¢ˆ… 6;q5Q$y|ŠÊ\ÁpFW5œüë(Y]P_Ò¨9)9‹"î§ç‡‡OÕoFRl×í9JDÔY1CDQ…IjJuU5ÊJ˛õˆ(:Õ¸W¸a £4µR]Có¢öóÏCÚì"÷©Å0g¤ÞŸ®×÷„éÓƒ¥©‰ˆ¢çˆ!¢¨Á$Ì•””D:„¨¡ª*¶oß…uë>Æá#G#Q“Jk<(©ò„•„q~ßÝvg“I˜”‰1pÅ+a%aT]ƒ$ èß3†I"¢(Æ1D6oÞHÂ<øàƒ9a–/_I’ðÄOàòË/t˜¦_¿~>|8F^½zaÔ¨Q¸ Ì2¥]…$I¸âÊË‘››éPˆˆB莕¹áQTÈFKS¨Xÿ1Ž>ó,4·'h¹`2#ûÁÿEê”ÉaÅÁÒÔDD1Dž}öY¨ªŠqãÆuû$ P_ªº  kÖ¬Á÷ßo¼±Û&bˆˆ¢•WÑPTê@2:®¢âÄ«DÉ›«CšÌ=R‘³øIÄ 97¬8UGf²±V~´'"ê øjÝ6oÞŒ_|7Ýtn¸á†f×;pà^|ñEìß¿999¸÷Þ{qþùáMÌFÔY>}@ýÿˬY³°eË–n›„€^½záá‡ÆÃ? p»Ý­lADDÉáVp¼ÂVij¥² ‡æÍGíÿi‹=o(r—<99ÅðþTM‡(ýÒmaÅADD‘ÅWìv´ÿ~̘1K—.űcÇZ\·¨¨wÝuFÕ«Wcôèј9s&¾ÿþûŠ–(zlÙ²%P¢º;&ašbµZ#ý¨¢Ö‹Þ°’ΰÿö;šL¤N™Œ/¿VFQ5ÄXdä¤Ç0 CDÔÉðU»½ÿþû˜0aþñ ??¿Åu 0fÌL:™™™˜>}z )CÔݤ§§ãÙgŸí6óõÕW_¡¼¼Šë®»wÜqjkkqóÍ7cĈX¹r%|>žyæ™H‡HDÔe©šŽ£§Pu@’Œe?tŸÇ–¿€Ò5ÿ i3§õ@ÎS‹3x°áêKSkÈNµÁjfU$"¢ÎŠ=b¢€ÇãAUUzõê´<;;uuup:ŠŒˆ¢ÉÞ½{1øÇìûÛßЫW/¬_¿¯¾ú*Þ}÷ÝGGDÔu¹¼* KœÐH+#yKËpàÞûšLÂÄþd8¯ZV¦¾45пg,“0DD{ÄDÿPƒØØØ å €ªª*Øíö‹ˆ¢‹Ïçƒ$Õø^»v-®ºê*‚€àÔ©S­lMDDg¢ÊáÃéj/dƒ½` î«¯Q8{.”Šò¶Ô)“‘ý› HÆ?†+ŠŽäx3Rã̆·!"¢èÅDLð'\ª««‘ššX^WWHNNŽH\D]†Š>ú™™™Ø´ifÏž ())A="Q×S\éA­Ë9ŒÉpËÖ¼¢e/@W|AËE‹Ù?Œ”+~V Šª#+ÅŠ+{Áušbbbƒ¢¢¢ å'OžDBB«¥`öìÙxî¹ç——‡sÏ=#FŒlÛ¶ \pA„£#"ê:TMÇáÓNÔ¹ÃIÍëÁÑ%Oãè3KC’0–^½0håÃJ¨šè:rÒíLÂu1ì%ÆŒƒõë×cüøñe7nÄ„ "E“ &`ïÞ½øöÛo1vìØÀòÉ“'ãꫯŽ`dDD]‡Ç§áh© ’(ž”×{º‡›Çþý!m #/B¿ó ÅÅŽAQ5ÄZeôL²²*QÄDL„<üðÃ2d¦M›¸å–[pÛm·á7ÞÀĉ±mÛ6lܸ¯¿þzd%¢¨’››‹ÜÜÜ eçw^„¢!"êZj\ Š+<0ÉaÌóŸ/Qøø|(•Á ‚€Œ›§"ó®DãÐ HK° 1Æx9k""ê\˜ˆ‰MÓpâÄ ¤¥¥– 8/½ô~÷»ßáµ×^ÀðÊ+¯ _¿~Œ”ˆº‹ÒÒR|úé§8}ú4.¾øb :´Í¶ûÏþƒ½{÷¢¶¶ÇÇ%—\ÒÖáµÒ*ë”°’0ekÞGÑsÏCW• åRŒ}gÏFâø±ÍlJ×M×Ñ·‡æ0b "¢Î‡‰˜òÊ+¯þE«W¯YçüóÏÇŸþô§Ž ‹ˆŸ|ò ~ùË_"-- ±±±¸ï¾ûðÐCañâÅgµ]QQf̘;wâÜsÏE]]öïßÉ“'ãí·ß†Æ7ÄDDíEÓu¯ðÀã c>EÏ>‹òׇ´Y²{£ÿSK`í××p ª®Ã$ è—j‡È±HDD]?·Bhšé0ˆ(4MƒÐÅ?—””`Ê”)¸ï¾û°ÿ~|þùçX½z5ž{î9¼õÖ[gµËåÂ%—\‚ââb|öÙgØ»w/þüç?ãý÷ßoqßDDÅ«h8Tâ„×§BŒ},ö?ŽïÉ$LÂÅcÐÊWÃJÂ(ŠŽ$» }{0 CDÔ]0ÓA Š"|>_ë+Q—ãóù Šb—NƬX±=zôÀ¼yóË~ùË_bâĉx饗Îj»bΜ9°Ùlun¼ñF 8»víj‡{CDd\[Á‘R7DQ0œ©Þ±ûoŸWá¡àA@Æ-7#÷™%cc Çà/Mo't""ê䘈iBË.Qáp8" EŠÃá>Ó2ëÖ­Ã5×\rß®»î:|þùç;þév ª*’’’Î>x"¢3TQëÅÉrd£Ÿ„u%o®FáC@­­ j’ì1È}j1²î¹Ëð¤¼,MMDÔ½1Ó A $IBUUU¤Ã!¢¨ªª‚$I׃®èرcèÓ§OÈòœœÀñãÇÛt»#GŽ °°cÆŒ9Ó‰ˆÎ˜®Ç+<(«óB68!®êp¢ðñ¹8ñÊ è†«[ûôÁ ?ý‰cŒOB®¨b,ú¥Ç@6X›ˆˆº&bšá–$I<œNg¤C"¢ät:áñx IR—žäóùP^^Ž„„„¶ÔÔT@YYY›m<ò.¹ä\zé¥g:QØUÇáÓN¸½*dƒ=WŸGŽÅbARRbbb{QtÓ4 >Ÿ‡•••ðx<ù@ü=aIꪽaü®¿þz\xá…Øºu+\.þøÇ?bàÀAëüéOBQQÒÓÓ o'Š"fΜÙìqM&SÛß"êÖª>”Tz!I0T•HW5œüë(Y]ðßu$'& ç‰Eˆûéù†¯¨âl&d$ZX‰ˆˆšÅDL3&aüüÉÿ0Y–¡( JJJ i4Mƒ®ëн‘Sôi¯ j>÷ÑÏÿÿëïí"ËrÐ|0 ç…éÊC’ëÝ»7n¾¹ùo|óóó‘ŸŸÖv½zõÂܹsÛ,F"¢–œªö ÚáƒI6ö¥˜R]Có¢öóÏCÚì ÷©Å0gd>¾OÑ‘žhAb “ÌDDÔ2&b h|!æïõâ/k+Ër à ñèÖÜÅô™^d7÷|ó<ˆn “,þoþÿe’Æ¿E7M×QTæ‚¢ê†çƒq~‡›OqqH[ÊĉÈ~ä!ˆ³¡}é4MGß4,&öŒ&"¢Ö1Ó¯˜†ûË?–õ½a:¡æz:½ðnø<ûÿnøüó>º5îÓpøáÙœDDÔ±¼J}F`¸4tÅÇÿÂѧŸæö-Lfôº÷n¤Ýp½á㫺‹IB¯dK§)MMDD‘ÇDL+&cšZ¦iTU ü0½_|7WÇ¿nS'`ü?ªªrLÊE·ÆÕЄ$a¯ODDѧ֥ ¸Ê ƒ#‘EʼnWÿˆ’7W‡4™RS»øIÄ bøøµ45E1aò_`û|>ø|>˜L&$%%Án·s²ÞN@Ó4x½^8NÔÖÖÂãñÀl6.Ä>/ÀΤiZÐþÌf3`·Ûa6›yD9ÿd½ ϓɘ<–É"¢èVVãA…Cl°*’RUCsç¡ö‹‡´Åžwr/„)%Õðñý¥©c¬ü(MDDáã»G+;Ñ4 ’$±|u'$Š"¬V+¬V+’““át:QVV¯× ‹ÅXÇÏAÞTÆëõB–edeeñ<èdDQ„Åb T=óŸn·‹%hxRãI»‰ˆ(rt8^á†Ë«@6ø¥‡óÀ÷(|l¼%%!m©S&#{Öýdc쪚Y“ncij"":cLÄ´ ¹$L|| Íã Z.˜ÌÈ~èA¤^}•á㫚ŽX«ŒŒD3߈ˆè¬0c€? ãr¹œœŒÄÄÄH‡Dm,%%¢(¢¢¢6› B’1þù_üçARRR$B¥v”’’I’ç"_""Š,§GÅñrdI€¡WeEAùþˆê÷ÿÒdNëœ%‹sÎ`Ãǯ/Mmfij""jLÄ4£ád¼þž0 LÂtaIIIÐ4 µµµ°X,A½ ü½¢¼^/™„顪jà<ê“rìCDUu>œ®ö@68+¯¯¬ÂK¿Gõá#!mqÇ!gñ"ÈIɆö¥é:t,MMDDmŠï(Mh˜„ñOÌ+Š"‡¡tþž1>Ÿ/¨ ’rWžÝCÃóÀß#+au ]×q²ÂÒZ¯á$LÝW_aÿô;€&’0©S&#ï¥ 'aMƒÙ$!7ÃÎ$ µ)öˆi…ªªðù|èÙ³g¤C¡’ššŠââbˆ¢Y®ÿáyÐýøÏI’çu UÓQTê‚¢é VF*[ó>Š–½]ñ-Íd?ü¤\9ÑðñH‰3#%ÎVÜDDDFðꢑƽaTU…ÉdbUœnÄn·C–e¨ªŠ¢ª*dYæyÐøKÒ«ª I’ i‡(u·OűR7DQ0”„Ñ}^~f*×­ i3g¤#÷©Å°hèØº®CÕ€¬d–¦&"¢öÃ~–-Ð4 Š¢ ...Ò¡P‹‹‹ƒ¢(aIŠ¢ >>>ÒaQkxQû«røPTæ$ 0’óöž.Å73îm2 s uª[f8 £j:DA@n†I""jWLÄ´Àß#†½ º»ÝUU“ôò<èžžDDÔ¾NU{ê'å5øé´ö˽Ø?ýx|´\‡€MÙcñÚÐ[±dÝ œ®ò´º/iê¾i6ÃC¡ˆˆˆÎ1 ø/¶üßþI:M&–*ìNt]‡Éd š¨×?DºÿyÐð5ऽDDmIÓu9íD­K…,ûhZ¶æ}œy?”ÊŠ åÉŒ?Šuý'Bx|>ü÷©÷åSt¤%˜Ñ3É¡§DDÔ!Øï² /¸D‘ùªîFE¨ª „σîÇ?' ðß×~HïxªªâÃu#>>#.8çœ3(Ò!Qñø4•¹ ŒtDѼ=ûÊ×}ÒVfOÁÿ †’˜´ åGN;›Þ—®Xššˆˆ:ßuZàÿ&ül¬\¹ûöí Y®ë:V­Z…ï¾ûN§¯¾ú*G‹û2ºµ ÿ¤Ž:ÂÅó¡c4,_M‘!IÆ_:¿¸þäååF:"j#µ.GN;!‰Ææƒñœ8ïnŸÑdfÊ ¼8âB’0g ýÞQÑ4˜e9éLÂQÇã;O;Ó4 »ví ¹?pફ«6› &Lhu£ëQô1r„‹çu'V«11v$ê"Êj¼(®òÀdpB˜š»°ÿ¶;á*<Ü ØÑt ÎCDÔvt8VîF…à ÙÈX$]GÉ›«ñÃCC­­ j’ì1È}j1Î}h&š×tñàd\40ùÇ]éPT½R,HŽ3Ÿõ}!"":Sœ#¦\pÁؼy3 ªŸ×à‡~@Ïž=ƒÖùío‹ûî»ðòË/#//%%%Ð4 &L@vvv“ëõïß%%%€Q£Fá‡~À©S§ I.¿ürdddÀét¢  wÜq ´´6lÀM7ÝÖ~èì´v8¬_¿PUçž{.F]»v¡¦¦?ûÙÏ ª*Þzë-Œ?™™™<ˆˆ¨Ó𩎞v‚ÙÀ¼kšÓ…Ë£jÓ–6kŸlä>µÖ¾}1€Iñûu‡Q\é˜$WžŸŒ{®®/]­j:$ÈͰ³*E1 55‰‰‰(,,Dnn.öìÙƒ+®¸_|ñE“ë+Š‚üü|$%%áÀظq#¦OŸÞäz^x!’’’°oß>¬[·Ó§OGBBþóŸÿ`Ë–-¸ñÆ[¯­öC-kí<ð5JHH€ÛíFAArss‘ŸŸ·ß~‡ƱcÇ0`Àdff†ìŸçE+‡[Á‰ áªHžcÇñãÁ}øHH[âè‹ÑwÁ\Hö˜À²ÑƒSpñ /wÁãÓPZô  È€I¡¨âl&d$šÙ‹”ˆˆ¢‡&uüü|ìÞ½GŽARRš]WE$%% €ÚF]q›[Ïb±ö;`ÀÃs´Õ~¨u-¢(BQìÚµ Û¶mƒÃá€Ãဠ˜8q"Ö¬YƒãÇcĈMî›çE£ŠZ/N”{ KÆ’ ÕÛ·ã»Ûï IÂ’ˆ¬{îBî3O%aíÐ;Õ†þ=c`’ê—)ªŽôD KSQTa"¦ƒ¤¥¥Áf³á½÷ÞÃ\`x;A }p$©ÅÛF«¾´¶:;-§NÂG}„ììlŒ3éééðx<³¹~,»$I<ˆˆ¨SÐuàd¥åu>Ȳñù` ~ J]]P“œ€þË–"ã–›a¤Ä’ŽúòÔ}zØ`ç$ßDD]˜ˆé@£FB~~>’““[_¹ Ùl6ø|>œ IDATUÎ"¢®LÕt=í‚íš“Eu:PøØœxeôF_ØäaÐkD|~¾¡c+š“$ Oª…¥©‰ˆ(*qŽ˜”––†´´´?® ¸ì²ËðÁÀn·#9911¡]z£ÙæÍ›±páBÔÖÖ"77K—. L`ÜÙ4wôïßGÅ믿›Í†¬¬,ȲŒÏ?ÿv»¹¹¹ÈÌÌÄ_þòdeeqB¯3Ÿ]é< "êªÜ>ÇÊ<ÝPÆ}´…Îûè‘¶¤Ÿ]†¾= Ñj1tlEÑoF°45E­öz‡jm¿Mµ –û‹MÜn¸ŽØ`;ÿmÿôãoùÇ¿ý¿ÊÊʶ7õmº™¦iÐ4 >Ÿuuu8çœsZ¹;Ôž>þøcÌ;ªª–ååå¡   ]Æ{ûσ}ûöÁn·œN'†ÚæÇ"ã:ú<ðûöÛo “ÉQ!þX飩cVUU¡OŸ>íKwõЬٸëž;›{f¥ÞÏľ}_Áb±"/o@‡³+©¬¬ÀW{¿ÄØq—F:”Në½¼ƒk®½>Òa„­Ê¡àtµñù`ª¶}†# ž€êt7ȲfÜY?É]סj@¯+ì Ÿ~ºƒŸ‹ÔÔÔpï8TøêêêpÞ°á‘¥Sr¹\غe~>ñÊH‡Òi½¿æï¸zÒ5Ï]ž={v#==½{wŽ/,Ífó(ÕTJƒßÚk ~ô?þÛhp –5¾­7ø»¡ÖºÚ·yW|öˆ¡¨ÖÔÅ7¥º?Ìz%o®IÂØÀà×VNÂ(ª†ørÒc˜„!"¢Nƒ‰ŠJ /¾|ðA,[¶ ãÆP_¹gÞ¼yJBÔuñ< "ŠnŸ†ÂT ô„q~ßÝv'jvïiK™8WüæŒ CÇVTIV¤'ð}€ˆˆ:M¢¨³aÆÀÅ÷Ì™31uêT`óæÍE ,Àøñã#&µ3žDDÑ­Æ¥ ¤Òø|0•ÿÚ€#O= Íí ns>M×è›f‡ÙHYl""¢(ÃD E• 6`Μ9‹ï_ýêW(((ÀòåË!Š".\ˆ+®¸"ÒaR;ãy@DÝJk<¨t›ŠŠ¯þ±~(R#¦Ôä.~1C‡:®¢i°™eôJ±¶[Å ""¢öÆD E ^|Àó€ˆ(šéŽ•»áñ©ÌSUÃóæ£fÏ!m±ç‡œÅ aJ1VÙÈ_š:9ŽC‘ˆˆ¨sc"†¢/¾ ày@DÍ¼Š†¢R ’``>˜ߣð±9ð–”„´¥N™ŒìY÷CM­îG×UÓÑ»‡63§7$"¢Î‰Š¸Í›7.¾|ðÁÀ\ Ë—/‡$Ixâ‰'pùå—G:Ljg<ˆˆ¢—íâx… &ÉX"¤ü£PôÌRhoÐrÁdFöo@꤫ íGUuȲ€¾i,MMDD]1qÏ>û,TUŸqãxñÝñ< "ŠNµ^”Õ*Æ’0-ÌcNëœ%‹sÎ`CÇUT 1fVE""¢.‡ý;#äÆoÄ믿nx}MÓ°téRL˜0¿øÅ/pèСö ®ƒ>}@}ˆY³fuÉ‹o>ß­ëçQg¢ëÀñ 7Êk}¥Ö×÷••ã»{ÿ§É$LÜða¼j¥á$ŒOÑXššˆˆº,öˆ‰±cÇbРA†×_³f öìÙƒ¿þõ¯Eñññí]älÙ²%Pš¸+]|óùOW=ę̀ªŠüý}ÄÆÄbä¨ 1løÐH‡DÔå)ªŽ¢R'T TFªûê+š3¾ò²¶Ô)“‘ý› H­ìÔtôKaij""겘ˆ‰{î¹'¬õ‹ŠŠpÎ9ç 5ÕXeÎ*===ôÆéPÚŸïðtÕó€ÎŒ$I¸öºÉÈÍ͉t(D݂˫áX™ ²$ÀHuê²5ï£hÙ Ð_ÐrÑlAöÿAÊ• WQ5Ø,2z%[a`.`""¢N‹‰˜™6m~ñ‹_`Ê”)ÛãÆÃÎ;qàÀdeeáá‡ÆðáñdÉüýï¬[·¹¹¹(((ˆdømjÏž=‘¡Ýñùn]w8ˆˆ¢]e¥5>È20ºÏ‹¢çžGÙ?׆´™3Ò‘»äIØ öU¥©‰ˆ¨Û`"&JTUUá•W^Á믿ŽÌÌL¬X±<òÖ®]‹Ù³g#&&UUU˜?~¤C¥6À盈ˆ¢Mq¥µ.d“òzO—âÐì9p|»?¤-þÂ|ä,œÉÀ°Z]4èÝÃÆÒÔDDÔmð/J$&&bΜ92d’““që­·¢¼¼ÇŽ‹thÔø|Q´P5‡O;QçR %aj¿Ü‹ýÓïMÂ2n¹ýŸ[j( £ª:DÈIg†ˆˆºöˆ‰"¢øß!™™™°Ùlp:ŒˆÚŸo""Š4¢áèi$Q04)oÙš÷QôÜóÐU%h¹h·¡ïœÙH?ÎÐqUGBŒŒôË™„MDDÔ©1ÓŽ¼^/.¹ä’ e¯¾ú*† fh{3Õu+|¾‰ˆ¨#Õ¸Wx`2PHózPôìs(_÷QH›¥w/ä>µ¶œ~†ŽëS4ôL¶"ÞÆ¡DDÔ=ñ°™ÍfìÚµ+Òa9]íA•C1”„ñ–œBáìÇáüî»¶„Q£ÐwÁ\ȱ±­î‡¥©‰ˆˆê1CDDDÔMhºŽcånxÕÐ|05;wáЂEPkj‚7OEæ]3 ˆ­ïGUuX-KS‰"""¢nÁ«h(*u ­$Ot%« pò¯BWµ &)ÆŽ>ÏAÒØ1†Ž«j@Jœ‰¥©‰ˆˆ~ÄDL„¼ñÆ-Þ€­[·þþßÿýßv‰ÚŸo""Ф:·‚“•^È¢ù`œ.Y¼•›6‡´Yûd#÷©Å°öíÛê~ü¥©{¥XY‰ˆˆ¨&bZ!4M ªpC]Ÿ¦iA“犢Èó j|uFåµ”×( ÌËâ9v…͆ëÐá¶ÄÑ£ïü¹bbZݪêe}Sm $ˆˆˆº&bZ DQ„ÏçƒÅÂòŠÝ‰Ïçƒ$I‹pžÝ“Ïçƒ(ŠLÆQ§¤ëÀ‰Jœd¹õ/ª·oÇ‘O@©« Z.H"zÞz+zÞv+ŒLðÂÒÔDDD-c"¦ {B8^€w3‡#¨÷ σî©ñyÀ„ uŠªãh©:È­õæôϳâUèZ£ù`â㑳h>âóó ×§êè™hA¼1‰ˆˆšÃwÉf‚A Iªªªœœé¨UUUA’¤@o]×QYYÉó ›ñŸþ×"¢ÎÀåÕp¬ÌYÐÚ+—êpâè“‹Q¹ekH›=¯?ržZ Kff«ÇÔtÐ~i6˜ ô¾!""êÎøNÙ ÿ°$I’àñxþ?{÷Eµÿü=[Ó; $¤@¨Š(XéEÔ«x¥Šz‘‹Š"D\‘€€H³‚¯^+¨—" ˆâ…r$J€tÒÛfëÌüþˆ»f³- I6!ï×óì“Ý9çÌ9;,›™Oæ|ª««½=$j!ÕÕÕ0P*•¶`ŒB¡€Éd‚N§óöð¨…Ôþpzµ¥U&d RzþÎ2\ÈÄo=ì4:j$ºoz­^AQ”á£Q!©£?ƒ0DDDõÀß–µX/´jÿT(P«ÕÈÏÏ÷æÐ¨]¼xjµÚîN¥R •J…‹/z{xÔBòóó¡V«í‚0uµ²,#¯ÔˆÂ ”õ8»+ûö;üöÐ .œ·/P)3k&Óž…ÂÇót\Q"‚Ô覭Oú"""§&¹d½jµƒ………èСƒ·‡Fͨ°°Ð–”׈jNpÕj5ŒF#?í€õsàããc÷]@DÔ‰’ŒÌ"=,¢ •‡(Œ,JÈç]ä¾õvM6ßZT!Áè²$ Aý¯ñØgÍÒÔ2:‡ká«áé$QCð7§Ö;!dY†F£AQQ”J%ó„\¦JJJPTTÛ´4ëÅ7?퇻ÏQkc0‰È,ÔC©Tx\&Z¬¨@Æ¢4T;æPæ—Ü IÏ/‡¦cG}J2 R ~\ššˆˆ¨ˆ©Ãš˜µöëE¸V«E~~>DQä—™ÂÂBÂÇÇÇ6 ©ö1’$A¥ªùïÂÏÁå«îç öô4NK"¢Ö¦¼ÚŒüRÔõÈËRýûÈX cn®CYØ-£ÿôSPh5÷ce„pij""¢KÂ@ŒÖ q¥R ðññAqq1***ЩS'øùùysxt‰ª««‘——g›†¢R©œ&gU(e™ŸƒË”»ÏÂÓ²¯Ô"ÊËÊQTXøúùz{8D^w±Üˆr¹^A˜Ò¯öáüŠç!Œö*%bfü'OªWŸ ˆÕ"З§DDD—‚¿I¨}WŒõ§õÜZn6›qþüyhµZ„††Âßßß–Ø“Z/I’`6›¡ÓéPZZ £Ñ•J­Vk»ÂÝrÅü\ò9˜¤×ÛDQÂÿþ÷λ€+®ìƒää®Þ‘×H²5 <æƒEDÎæ×‘¿u›C‘*4‰K— ðê~õè€,!¡ƒWE"""j ĸPwŠð×E¸õ"]¥RÁb±àâÅ‹$ ’$A–eÈu’ßQë`ýw³Þå T*íò€ÔÎâ.9+?m[c? ÂxR©ÀÐaƒ‘””èí¡y•ÉR„ÀSjKY9Î-zÇp(ó¿â $-_ux„Ç>EI†¯V‰˜P?®ŠDDDÔDˆ©‡ºbÖi+²,Û¦¬ð»í¨}m½à¶þ´ÞÉâ좛ŸƒËKc?DDÞP©· ·ÔµÒó÷Ruúï8;!LùùewŽAÜÜ' ¨Ô÷ceDià¹.Õ1nX/²k?W(¶Ä­’$9\€ó"¼u«}ñ]ûÎN/¾­Ïù9¸¼4ös@Dä EF”è,õ ”ìÞƒ +_€d4ÙmÔÄ̓ˆ1·{܇,’$#®ƒ|ÔJõ‰ˆˆ¨aˆñÀU0¦.^|·u§Õþ÷tuñÍÏÁå§1Ÿ"¢–$Ë@v‰z“*O¹ÇÜäƒÑtˆ@âòeðïÝËcŸ¶¥©#¹45Qsa ¦jßQûyí 7^€·Îò¿Ô盟ƒËKc?DD-Á"Êȸ¨ƒ ÁcÆRZ†Œg¡òÄÿÊû^‰ÄeK  ÷ܧ$#ÄO…H.MMDDÔ¬ˆi€ºwEXY/ÌyáÖ¶¸Ëã©?—Æ~ˆˆšKµQDAµªæwЇººŸÆÙ…‹`..r(‹¸s âæÍ ô|ºg‘€N!\ššˆˆ¨%ð·mÕÍR{µ] ý7äçàòÄC"ò¶Ò* ËMP)<ß]Y´c'2×¼Ùb¶Û®Ðh÷Ô\„ßv«Ç}H2 @FB_.MMDDÔBˆi¤ºwBPÛÓÝü´} ¾Qk Ë@^©:£•‡€ˆl6!sÍ:íü¡L‰¤Ëà×£‡Ç>EI†¯F˜0.MMDDÔ’ˆi¼#€Ÿ""jQ’‘Y¨‡E’=&È5!ca*t¿žr( ¼ºº,Iƒ:,ÔcŸQF‡ 5B4751DDDD^b0‹È*2@!ƒ0•?DFê"XJŠí 'MDôÃ3 (=ÜMÃ¥©‰ˆˆ¼Ž""""/(Ó™QPa‚ªËDíØ‰ÌÕë ‹»í ?_$,\€ÐáÃ<îƒKSµ Ä4æ!j»8¥Œˆ¼áb¹ å:Tî`‘LFd¾°ÅÿÙåP¦íÜIÏ/‡obýY$¡þ*tâÒÔDDDÞÆ@L#9 ¾0 CÔvpå+"òI¶æƒÇ ŒébÎ.HEõo¿9”ßx/‚* ÀcŸ\ššˆˆ¨uáoäª}Ñf}.Ë2ƒ0Dm ¶à‹ ¶ÿÇ ÈQs0š%dé¡xš¤:w¿½¸æÒRûk>˜™3 (ÜrDI†BºDúBí!èCDDD-‡˜¨x‘e¢(BEH’d{Që¦P(l¥R ¥Ri ÊX2 ÆQSªÔ[[b€ÚÃÒÔeäoÛŽÀ-Û`–ìÿÈ£ô÷Cü¿R:d°ÇþþZšÚ—KSµ2 ÄÔCí»]$I²`L&Ôj5‚‚‚àëë µZ …‡¿N‘÷I’³Ù ½^ªª*èõzh4[@F¡Pðî"j2E•&”T™=aNÿ^€¼^@ð¯GÊ|âã´b|<öÇ¥©‰ˆˆZ7b<¨{Œ$I0P(èØ±#|}}½W(¸Q{dÍ À.CDí“Ñ,!³H… ¸ ÂÈ¢„ÜM›‘¿u›C™*4‰KÒxÍÕû³ˆ2¢Ã´ðáéÑå„¿Ùݰþ%œˆÚ/ëqÌCÔ¾Uè-È/5zœŠd)+ǹg£âÿw(óëÑIËŸƒ¦c”Û}ˆ’ @—(_.MMDDtb †ˆˆˆÈ #Jª,P{ÂT§ÿ޳ó”ŸïPqçÄÍ}‚Êýtg‹(!ÀWH?‰A""¢Ë1ðŽ¢ößDí—$ËÈ.1Âh=aJvïÁ…VA2í¶ j âæÎAĘÛ=ög‘dDkâ¯gA]¾ˆ!"""ªÃd‘Y¨@é.*b‘³ùu§ù`4"¸ì9ø÷éí¶¯š¥©%ÄEøÂGÃiDDD—;bšÉ¤I“pæÌÛë   $''cÆŒ¸újÏ ú.ÕàÁƒáëë‹={ö , üüü˜|˜ˆˆÈ ADv‰ÞãÔ Ki2=‹ÊN8”ö½‰Ë–@îv-MÀ¥©‰ˆˆÚ ^‘7³aÆaĈÐh48~ü8{ì1ddd´ø8–.]Š¡C‡â?þhñ¾‰ˆˆÚŠ’JrJŒƒ0Õ¿ý†Ó>ä4qçt{õ%A˜š¥©5HèàË Q;Â;bšÙ¿þõ/C’$<úè£8vì<ˆÄÄDoˆÈ©Ý»wc×®](((ÀM7Ý„‡z>>>MÒN–e|ðÁxçwðùçŸC­vŸ¸”¨¥È2Sj€Þ z\©hÇNd®y²Ål·]¡Ñ".åI„ÿí6ýYD1a>ð÷áT$""¢ö†wÄ´…BÌæš7½^Õ«Wc̘16læÎ‹ÜÜ\[›Ã‡cÚ´iÞ{ï=\¼x))) Ä]wݣш‚‚¡¤¤¤A}1ˆ:t(zôèÈËËsÙDFF"$$¤©µr'OžÄâÅ‹ñé§Ÿâoû`úôé8p ^{í5Ì›7¯Ñízè!ìØ±>ú(æÍ›‡©S§¶Øû"rGo’U¤‡J)ÀÝ0¦Â"d¤þ º_~u( èw—.:,Ôm_QB€ B}¸*Q;Æ@L31b„Ýë‰'bÀ€HOOÇwß}‡ë®»«W¯P“PwÿþýÈÎÎFNN, úõë‡G}*Uãÿ©†ŽÑ£GcÏž=˜1c’““çÏŸwÛÇš5kÝ'µ=¯¼ò ®¹æ[0z÷îñãÇcãÆ.1õi÷øãcÍš5¶¥‰¼­´Ê„ ³Ç©H•?DFê"XJŠí ‘ãÇ#ö±G•û»[Ì¢Œ¨?—¦&""¢öS“šÙСCmÏ}}}ñä“O¨ ‚ÀÑ£GÑ¿ôïßû÷ïTTT G Â0bÄ,X°éééM:¶–胈ڎ£GbÔ¨QÛo»í6dee¹¼¯>í®¸â 7ù˜‰+¯ÔˆÂ S½òÁüþèãA…Ÿ/—¦!vÎl·A˜š¥©e$tðe†ˆˆˆ0Óìžyæ=zqqqÐëõ8räØ.H®½öZ|üñÇvääd„††âƒ>À”)SН¾ú “'OÆ©S§lû¾Ôü õ郈ÚììltêÔÉa{tt´­¼)Ûyƒ(É8WP*½*7+#I&#Î/[Q“F´Ø•i;wFÍ›:|˜û¾d*•€¤Ž~ЪyÊEDDD5xVДJ%fΜ x饗 Iºté¥R‰ß~û ¡¡¡ˆ·=4  C‡xüñÇñÙgŸaÚ´i$ LJ¯¯/ ##&“ pöìY‡~eY¶=·N;ª¬¬´«ãª"j_, ªªª Õjʬy£ª««›¬‘7˜,2ÎæWC’à6)¯ébÒÿùŠ¿üCYð ×£ç››á›ØÅm_‹ŒP?â#|¡`B"""ª…9bZȨQ£ðÎ;ï ==;vìÀرcñ÷¿ÿü1¦OŸŽÑ£G£°°:Ë—/ÇÙ³g‘ššŠÀßßß6m©k×®ðõõE=ðÛo¿aÚ´i űcÇìú Ann.6n܈iÓ¦¡[·njVW4hxàdee¹ìžzê)ôéÓ‡I5‰Ú•J…:àâÅ‹e€ØØØ&k×f³+–­vØ>bäM»¤}»RUU …B‰sŽAnòÌl6£ªª{÷ìòöPlt& T¨îƒ"ŠŒsÐlý?:} À2xòo½ù?þÏí>D ˆð´*Ùm=wªªªZÕñkkJKKQ^Vfûã5Œ¾ºQD~~ž·‡Ò&‰¢ˆ²ÒRþ¾•••øjïn d7JEE9rsrpú”c‚ù¦tóè[›uÿ—3bZˆ ˜5kžxâ ¼öÚk=z4RRR…]»vaË–-ˆE¯^½ Ë2Ìf3°{÷nèt:tìØóæÍÃ7ÞHKKÃ’%Kpþüy!55Ë–-9á€Õ IDAT³õ7{öl¬Zµ ü1n¸áÜsÏ=HOOÇ7ß|ƒÏ>û C† .û$ 999ˆŒŒôÖ!#¢‡_~ùÅa{zz:4 :vìØ¤íêK¥RáŽ;ouø>êÞ½üýý/iß®œ>ý+´Z$&&5Ëþ/weee8õëϸñ¦AÞ   Ü„òjÑ}>]YFñ'Ÿ"÷·Q´+Rúù!fþSìþýH’ …ˆ ÷õ˜{Æ“ÿ|¹C†¿¤}´gßÝ»÷@XXók/wΟCU•½ûôñöPÚ$ƒÁ€#ßæÿáK°{×ø Nœ8á±ÍÁƒ1vìXüûßÿH’„íÛ·cÚ´i}ú`áÂ…èÝ»7âããqÇwàÊ+¯´Õ9|ø0&L˜€~ýú!!!O<ñBCCqúôi€F£ÁÝwßm»#‰ˆˆš–Á$âlž’·A˜’}ûñÛÃ3aÌɱ/P)3k&º<û >®W<ej•Iý UóT‰ˆˆˆšÏ.šÙlÆÚµk1vìXÜtÓM7nþóŸÿØÊeYÆ”)S°víZ§í÷íÛ‡Q£FÙm=z4r\jž~úiL˜0Æn»ÂÉÊááá0›Í.Ç^\\ŒN.þB¸oß>Œ9‚“{³¥:·|»jß÷Uß6žêÔç8ìܹãÆs;þ°°0œ9sÆöº²²HHH°m»ùæ›ñí·ßBW'$]šòj3. R)\N’E 9^ùgÓ é veªÐ$¯[‹Ž“'¹íÇb‘æ¯F\¸œ‹DDDDÍ€Éz›Z­Fll,V¯^ ìÝ»iii¶;-A@dd$BBBÚF”••¡sçÎvÛãââPUU…êêjøùù5zl?þø£CÐB’$èt:üüóÏxóÍ7±`Á§mÏŸ?þýkæÒ‹¢ˆªª*@YYÊÊÊP^^n{ÿuÇØ˜÷UŸ6J¥²QÇ«öq0 (..†V«EJJ Ž;†àà`L˜0“&ýuÂþðÃcöìÙ0 èÛ·/>ÿüs<ú裈‹‹³Õ‰ŽŽ†R©Ä©S§0`À§Ç‘ˆˆæb¹å:3Ô*×?²”—ãܢŨøÇÊüºwGÒŠeÐtŒrÛE—¦&""¢fÇ3fr÷ÝwÛžOŸ>;vìÀ¯¿þŠøøxÀš5kœ¶+..ØmPôhl æÐ¡CÈÌÌÄßÿþw»ío¼ñ6oÞ ˆGii©ÓöÙÙÙˆ‰‰P“—¦ît¤#F†ŠÕ«WÛ•5æ}Õ§UCö[÷8Xs¼¼øâ‹xðÁ±hÑ"?~‹-B§N0|øp@ß¾}qÿý÷cÆ øòË/qã7:µA@LL ²²²ˆ!"ºD’,#³È‹(Cå&+ouúïÈX c^žCYø-· îé(´'-kˆ’ •B@b”/—¦&""¢fÇ@L3)++î]»ðã?¢²²ÙÙÙ0 ÛYåå刈ˆ°m·Þ}R;ylCbÅŠ˜={6íÊf̘‡zyyyؾ};,X€÷Þ{ÉÉɶ:ƒ¥¥¥ˆŒŒôéÓǶbÐðÎ;ï`Ë–-Mú¾êÓFÅí×Ùq°ö3`À\ýõ€aÆᮻîÂW_}e Ĥ¥¥¡  |ðÔj56mÚ„±cÇâõ×_GRR’­¨¨([ÿDDÔ8&‹ŒÌ"=nÒÁ dÏ^\Xù$ƒÑn» Ö öÉ'ÐáÎ;Üö#J2|Tè¢q:õ–ˆˆˆ¨©1GL3Ðëõ¸ÿþûQXXˆ‡~«W¯Frr²-hàŽ¿¿?üýý‘™™i·=77ÁÁÁðññiðxL&RRRpÍ5×à®»îrZG¡P &&)))èÚµ+¾ûî;»rëÉieeeƒû÷¾êÓ¦!ûuu‚‚‚ V«Ñ¯_?»}$$$ ¤¤••…/¾øK—.ERRâââ°lÙ2ôë×o¼ñ†]»òòr¨Õ\aƒˆ¨±*õœ+¨†B€ë%£-bM>˜´¥AM‡t_ÿ²Ç ŒÙ"£CæÏ¥©„!""¢–Á@L38}ú4ÊÊÊ0{öl$&&ÂÏÏééé¸xñb½Ú<{öì±Û¶ÿ~ÛÔŸ†EóçχR©Ä3Ͻ]¶—d™KS‘×0Ó ÂÂÂPUU…>úåå娷o€šD®VO=õ”Ë©<“'OÆáDZeËà“O>Áþýûqß}÷Õ«½•$IX´h222°bŠȲ ½^½^Y–qüøq¼øâ‹8qâòòòpüøq¼ð ÈÍÍuX¢ºv튼?çß§§§£ÿþèß¿?ƇŋÛ^Ïž=»ÉÞW}Úxªãé8À¤I“°sçN¼ÿþû(((À°sçN[€©[·nˆ‹‹Ãüùóñ믿¢°°»wïÆ'Ÿ|‚‘#GÚÆb4QRR‚nݺ¹ý·!""{² dP¢3Cåf.Rõ™38ýàC¨üá„CYÄc¼þe¨ÂÂ]¶·H4j%—¦&"""¯aŽ˜f€Ù³gcÓ¦Mذan¼ñF 6ÌV.IrrrlùVêêÞ½;^yå¬_¿o½õ’““±aÃtéÒ¥^í­>l»Sä¶Ûn³+ûüóϓɄåË—#??èÛ·/6mÚd—oÅêšk®ÁO?ý„{ï½IIIØ»w¯Ó~U*ç«Æ¼/OmêSÇÓqèÔ©úöí‹Õ«WcóæÍظq#°råJtíÚ@Í]Bëׯdž 0oÞý;ÞÛÃh³>„ž={;ýÃy–qöTUUáʾWy{(m’^¯Ç7‡¾Æè[nó\™œÚ¹ãÜ~Çßmç]Ô0ÇCTTGÄÆÆy{(õ¢ÑhnP@`©õSúó¹Të!×zX_£ÖkÔÚV÷µ\ëymζ5¤¼ÁÚÆÙµ ‰‰‰¸á†°uëVüóŸÿôöpZÜÜ\|ýõ×ø÷¿ÿíí¡]V”J%ÆÞ5II‰Þ 5±Ò* ËMP©\Ÿh› ‹‘ú/è~ùÕ¡, ßUH\ºê°P—í­KS'DúBénù%"""¢Â@ 5Èœ9s‘‘áía´JZ­Ï>û,¢¢¢¼="¢VM–¼R#tF‹Û LÕÉŸqvá3°”;”EÜ9qóæ@Pº>•áÒÔDDDÔ1C m—t˜þŽáÃ=߆ODÔž‰’Œ¬BÌ’äö•¢;‘¹zdÑb·]áç‹„ó:Âý÷­Ù"£c¨Á~\‰ˆˆˆZbˆˆˆ¨EÌ"²Š P‚Ë Œd2"sÕZù‡2mçÎHZ± ¾n¦©I²  f*WE"""¢Öˆ"""jve:3 *Ln—¦6],@ÆÂAwú´CYð ×£ËâEPºIo‘$ø¨•èî§"Q+Å@ 5«‹å&äëñŸ.â×Ì peB0nëßþÚšå’ªþ÷#2þµæÒRûÆ‚€Ž“&"zæ nVϰˆ@D a\ššˆˆˆZ9bˆˆˆ¨YH²ŒÌB=~Ï«ÆüwAq¥ÉVöÝé|ü}.VÝß¾ß}å4ŒÒß "dØ—}Ȳ Q:‡ûÀOëf l"""¢V‚“§›ÉÔ©S±cÇŽ&ßï™3g0kÖ, 6 >ø Nœ8Ñ$mêS§²²Ë—/Çøñã1hÐ Lž<´«sðàAŒ;ÖíÎ{÷îÅúõë=¿ÙKx?iÓÇé¹çžCÿþý>ÒÓÓ¡ÓéðöÛocòäÉ2dn½õV,[¶ €ôôtÌŸ?¿GŒˆ¨å™Eàl~5 f Ïn;e„±*/®Ä‘GžÆ…•«‚0Ú¸XôؼÉmF”dÔÑA"""j3ˆiC2331sæL 8Û¶mÃÀñØc!==ý’ÚÔ§Nyy9&Ož HKKÃÖ­[1a„……NŸ>3f`ÕªUÈÊÊr9I’°qãFôîݻ̓¦8N)))8xð ÝãÉ'ŸDll,’““a4QTT„¹sçâÃ?DJJ Μ9ƒeË–pòäI;v¬QLj¨%TDäWÖ¬Šôýo%È-58Ô ×ãÑ6¢kÖÿÊ‚oº =ß|>]\öa%ø¨Ð%ÒÏíêKDDDD­ 1mÈöíÛ1xð`Lœ8ÑÑј>}º-(p)mêSgëÖ­èÓ§.\ˆÞ½{#>>wÜq®¼òJÀÎ;1bÄ|ú駸öÚk]Žçûᅦ(Š2Äþ/œÀý÷ßߪAS'­V‹€€»Çž={p÷ÝwÂÂÂ’’‚~ýú!22ÇÇüùóqäÈ€F£ÁÝwßíöŽ#""o*ª4áb… ª?󹜻XíP§Gñ<þÿÖ£cU¾}  ãäIHZ¹J—}XD *D‹N¡ZLÊKDDDm 1Íè›o¾Á¸qã0dÈÌš5 ™™™jæ³O™2k×®mÐþöíÛ‡Q£FÙm=z4:tImêSgçÎ7nœË~ž~úiL˜0û$‰ûöíÃÈ‘#ž8K’ä¶m}ÇÚ˜6-uœê:sæ þøãÜ~ûí.ë£S§N¶×7ß|3¾ýö[ètºz÷CDÔÜd™Ez”êÌPÖúޝ=eH€Œa™‡ðÀÉwákÑÛµWúù#éù则5ÓeR^I–!É2â;ø ØOÝ,ˆˆ¨¹1ÓL²²²pèÐ!<óÌ3ø¿ÿû?„……aÆŒ0 ‘‘‘ ©÷þŒF#ÊÊÊйsg»íqqq¨ªªBuµã_ëÓ¦>u Š‹‹¡Õj‘’’‚!C†`̘1nïBqåüùóHJJˆ¢ˆòòr”——£¬¬ eee¶×}?Íu šë8}ôÑG5j‚‚‚ì¶K’„ÊÊJ9ro¾ù&,X`+‹ŽŽ†R©Ä©S§\î—ˆ¨%™E góª`²HvAÐ-‚h-FLþe;nûc7Y¶«£ê‹onBÈ .û°H´j%£ü Uóô…ˆˆˆÚ.®šÔLDQÄĉqÕUW-Z„;ï¼ûöíÃí·ßŽ5kÖ4hÅÅÅ€€€»íÁÁÁ€²²2øùù5¸•»:¢(^|ñE<øàƒX´hŽ?ŽE‹¡S§N>|x½ßGvv6bbbÔä•©;iĈ€¡C‡bõêÕ ~?Íu êS§¡ÇI§Óa÷îÝØ°aêzã7°yóf@||.û°XdDqij"""º<ðOJÍ$!!ÁvçP“Û㪫®Â¹sçµ?ëyy¹Ýöªª*°%ƒmh›†Ô0`®¿þzbذa¸ë®»ðÕW_Õû= ”––"22ЧO?~ÇÇ /¼€^½zÙ^× Â´–cДÇéË/¿Dll,®¸â ‡²3fàØ±cرc®¿þz,X°À.)pTT”­o""o)©4!§Ä•Òuž–òï¾ÃuÛ–:a$A@á-÷aø¦•.ƒ0²,Ã"Êèáà ]6ˆiAÆc“Ʉ뮻ÎîñÓO?Áßßþþþ¶<3V¹¹¹†ãIl}ÚÔ§NPPÔj5úõëgW'!!%%%õ~ÿÖ¼0•••õnÓÐ÷Ó˜6Þ:Nü1Æïòý* ÄÄÄ %%]»vÅwß}g++//‡ZÍüDä² dëQ\i†ÊժѲŒü­Ûpöé…ëä´ƒ¸z5nY4 ù`D‘KSÑ剘fRZZгgÏÚ^˲Œ_~ù‰‰‰nÛi4=zÔîÑ·o_ÀàÁƒ±gÏ»úû÷ï·Mçq¦>mêSgРAØ¿¿]óçÏ#>>Þíû©M«ÕB£Ñ ??ß¡,)) ÷ÜsÇ}xó4åq:qâòòòpË-·¸wmjµÚ.L~~¾C^"¢– J2Î]ÔAo’ tq'ŒT] Å[ï"gÃkë$b÷Kî†Þï¼ð\¯°g%ú©‘åÏ¥©‰ˆˆè²Ã@L3ÉÏÏÇöíÛqâÄ ”””ॗ^‚$I6là©§žÂ–-[´ÏÉ“'ãðáÃØ²e ðÉ'Ÿ`ÿþý¸ï¾ûluêî·>mêSgÒ¤Iعs'Þÿ}àÀعsg½‚'µuíÚyyy€ôôtôïßýû÷Ǹqã°xñbÛëÙ³g·ºcДÇéã?Æ­·ÞêÓæøñãxñÅmë´­ÜÜ\Û’ßF£%%%èÖ­[ƒŽ=Ñ¥2˜EœÍ¯† ¸ .\@öãs!üò«CYØÍ£ÐýµÐÖZ ®.‹(#*D‹Ž!œŠDDDD—'&ëm&={öD¯^½°nÝ:äääફ®Â¦M› R© Irrrl¹Rê«{÷îxå•W°~ýz¼õÖ[HNNƆ Ð¥Kpº_Omê[§oß¾X½z56oÞŒ7"!!+W®D×®]ô®¹æüôÓO¸÷Þ{‘””„½{÷:­§R9ÿhzó4Õq*--Åðî»ï:¼¿¨¨(˜L&,_¾ùùù@ß¾}±iÓ&DDDNž<‰àà`»DDDÍ­LgFA¹û|0%û÷ãÂòç!é ö*%bfü'OrÙV’e@â;ørU$"""º¬5×ý¾žöë¬\¨µÝúSáäuí:ŠZí¬¯­åŸ?U>·þ .**:"×Y:¨™>Ô\ÌK’³ÙŒªª*ôêÕËÃÛ¡úÊÈÈÀÔ©S±k×.z{8mÒâÅ‹ˆ¹sçz{(í©S§µZ …BaËg!Ž_ceee š®Gõ“2w!fÎzIIî§v6¥_~9 ­Öݺ%·XŸ­Y^©•z³Ë•‘dQBî¦ÍÈß¶½&L-ªÐ$.ICà5W»Ü¿E’à«Q¡s¸O³˜´5Ÿ}úþ>Öu1rïðáCèÙ³·íÔ0gÿ@UU®ì{•·‡Ò&éõz|sèkŒ¾å6o¥ÍÚ¹ãÜ~Çß]æ#÷Ž?†¨¨ŽˆóöPêE£ÑÜ €ÀRë§ôçs©ÖC®õ°¾F­×¨µ­îk¹ÖóÚœmkHyƒñ“M-*117Üp¶nÝêí¡´I¹¹¹øúë¯1yòdo…¨ÅȲŒü¼‹¸p>ååÞN»"ÉÀù‚jTé-.ƒ0–òrüþä<äoÝæ„ñ람žo¾î>c‘ A,ƒ0DDDÔNpjµ¸9sæ ##ÃÛÃh“´Z-ž}öYDEEy{(D-F–eœ;•èÙ³;‚ƒ™¨º%Í2‹ôP‚ˤ¼Õé¿#cA*ŒæþªMî º¯z ­ó\/²,C”€Î¾\‰ˆˆˆÚb¨ÅEGG#::ÚÛÃh“ÂÃÃ1|øpoƒ¨E) Üpõ-:5©½«Ð[_ê!ÌÞ¯páù• F»í‚Zƒÿüòº$¸ ˆ¢ •J@B¤/WE"""¢v‡"""²)¬0¢¤Êµ« ŒEDÎæ×k¦"Õ¡ŽGÒòe°ÄÆ ï·ß\4—ì¯AT0WE"""¢ö‰"""‚$ËÈ.1Âh]a,¥eÈXô,*8áPpå•H\–uxÊËËœ¶7[$t óA/O?ˆˆˆ¨ýâ™Q;g²HÈ,Ô t²"TŸIÇÙ©0åç;”EÜ9qsŸ€ R;mk]šºK”?4*NE"""¢ö""¢vLg‘]¢‡ÚŪHP¼k2_x’Ñd·]¡Ñ"vÞDÜþ7—m-¢_­ Ã|à"ÆCDDDÔ®0CDDÔN•TšPTa†Zå<#›MÈ\ûŠvìt(ÓDv@âòeðïÕÓåþ- A„2 ‘1DDDíŒ,9¥T,P¹˜‹Šqva*t¿üêPxU_$.[Uh˜ËýK2ÛÁ¾×wÚµG ĵ#QFfa5DP¹˜ŽTuògd¤.‚¹¸È¡,âÎ1ˆ›7‚Òù)„(ÊP*t ƒ0DDDDN0CDDÔNèM²ŠôP)¸ZºhÇNd®y²Ål·]¡Ñ"îé„ß:Úåþ-¢Œ`"|µ(ËnÊ‘]>ˆ!""jJ«L(¬0Cå"#™ŒÈZ½E_|éP¦‰AÒóËá›”èrÿf‹ŒNaZùªPZªk²q]nˆ!""ºÌå•QHï³K IDAT©7»œŠd*(DÆÂTèNv( ºþ:$¦= e` Ó¶’,C€€.Q~\ššˆˆˆ¨ˆ!""ºL‰’ŒÌ"=,Ùe¦òÇŸ‘º–ÒûA@ÇIýð .ÚŠ¢ ­’KS51DDD—!“EÆù‚j(”.¦#íØ‰ÌÕë ‹»íJ?$,\ˆaC\î_”€ð@5—¦&"""j bˆˆˆ.3åÕfä—š v1UH2‘¹rŠwíq(ÓÆvF×çWÀ§K‚Ó¶Ö¥©;‡ûpU$"""¢F` †ˆˆè2RPnD™Îâ2cÌÉÁÙù ¡?›áP|ãHXü TNÛŠ¢ •J@B„/” ÎE""""j bˆˆˆ.’\“Æ,J.óÁTü÷(2žMƒXYi_`Í3s…ó¶Ö¥©£‚µM=t"""¢v…""¢6Îd‘‘YX A!@)8 ¤È2ò·mGî¦ÍEÉ®Héç„E©<Èåþk/MMDDDD—†gTDDDmX•Á‚ÜRT.¦ ‰ºjœ_¾e_r(ó‰GÒóËàï´­$Ë€ t‰ò…FÅ|0DDDDM""¢6ª¸Ò„â 3T®òÁdeãù `8wÞ¡,dàMHXü ”~þNÛrij"""¢æÁ@ µj’$áûï!ýÌèÙ³;º8¿{£=‘e »Ä½É•‹;UÊÁùÅKa©ª²Û.(ˆ~x:NšWQ"‚4 P7ù؉ˆˆˆÚ;bˆˆ¨U:E¡S§N òöp¼Î"ʸPX TÎëZóÁ¼¶²dŸFŒÄ%Ï"pÀ§û®YšZFçp-|5ÔÔT@\\ú÷ïÐÐPôíÛr W2331sæL 8Û¶mÃÀñØc!==Ýe›çŸxõÕW±nÝ:dffâ‰'žh–:DD­…Á,âlž²,8 ÂXÊËñû“ó¿u›CƯ{2z¾õ†Ë Œ(ÉðÑ(Ô1€A"""¢Æ;bšÁéÓ§‘íÛ·C©TÂÂÂУG/ì/™™™èÕ«"""\ÖÑh4¶ÀÑUW]…¹sçâᇆN§ƒ¿¿?€š ÓgŸ}†ùóç׫ßíÛ·cðàÁ˜8q"`úôéøí·ß°mÛ6¤¥¥9Ô¯¨¨À_|Ý»w#<<°fÍÜvÛmøõ×_Ñ»wï&«CDÔZ”éL¸Xf†ÚE¤:ýwd,H…1/Ï¡,ü–[÷t ZÓ¶QFd!\ššˆˆˆÈ+øg°f Š"ŒF#òœœ [=ÇŽ³½>}ú4nºé&Ûë©S§âÍ7ßÄC=„!C†`Ê”)8uêÞÿ}Ü{ï½2dæÎ‹ÒÒR§û—$ o¿ý6ƇaÆá‰'ž@nn.`ùòåxï½÷ðùçŸãºë®³E<ñññZ­†VûW2Ç¥K—bøðá¸öÚkÔä2˜2e Ö®]ëtûöíèQ£ŽÅ¡C‡œÖ¿páüýýmÁ ÅÕW_Ç7i"¢Öàb¹å&¨]äƒ)ÙûÎÌü§CFP©ûÄãHX”ê4#Ë€(ʈëàà ‘1Ó úô郮]»âÿøÞ}÷]4xeeeظq#ž|òI|ú駈‹‹ÃÔ©S‘••…^xï½÷²³³±~ýz§í7oÞŒýû÷cåʕغu+4 fΜ ³ÙŒ… bÊ”)¸ãŽ;pôèQlß¾ÝíXdYFNN^}õUÜ~ûíP©jn¤Zµj:tè€G}ÔVWDFF"$$Äa?F£eeeèܹ³Ýö¸¸8TUU¡ººÚ¡MHHªªªPRRbÛ&Š"Ž=j;®MU‡ˆÈ›$YÆùB=*õ"TJ'¿ž-"r6¼†s‹—@2íŠÔáè¾þeDÞ3Þž¥Hìèµ²9†ODDDDõÄ@L3Ðh4xë­·pß}÷aûöí¸ãŽ;ššê6J]!!!HMME¯^½†)S¦|ðAÄÅÅ!..cÆŒÁ?þèÐÖd2aëÖ­X¸p!ºv튘˜¤¥¥A§Óá›o¾©÷¶oߎþýûãÚk¯ÅÃ?Œ+®¸óæÍœ8qŸ}ö>øàÜtÓM:t¨­Ýš5kðÀ8쯸¸òä¨ >ÕÕ¹sgôìÙÏ=÷ PVV†uëÖ!>>åååMZ‡ˆÈ[Œf gó«!Š2œ¤ƒ¥¬ésž¬ÉSGÀ•W¢çÛoÀÿŠ>N÷m‘dù*‘éç4× µ,bš‰ŸŸ¦NŠ/¿ü+V¬ÀÅ‹qÿý÷7(£PüõÏc]Ѩö]#]ºtqzINN,‹]N___\qÅ8þ|½û?~<Ž9‚M›6¡°°#GŽ„FSs»ûÕW_ï¾ûÎö8xð ÇýY.uUUUjòèÔ%V®\ ‹Å‚»ï¾S§NE\\nºé&DFF6i""o¨Ô[p¾@¥B€à$NR}&§x•?œp(‹¸s ’_}êpçù¾,Ð)D‹È`­Ór""""jyLÖÛÌT*†Ž!C†àž{îÁ¾}ûœœÜ$ûœ±£æŽI’ Š¢]0G£ÑØ)õa­õÕWcèСX·n6lØÐèñúûûÃßß™™™HJJ²mÏÍÍEpp0|||œ¶‹ŽŽÆË/¿l·mΜ9¸æškš¼QK*ª0¢Dgq™¦x÷nd®\Éh²Û.¨5ˆ›7wÜî´$d$tðåªHDDDD­ ÏÎZˆR©DDD„-Ñ­¯¯/Î;gWG’¤&é+66‚ àÿûŸÝ¾O:…®]»6jŸ>ú(Nœ8Ñ ©MÎ <{öì±Û¶ÿ~Œ1¢ÞûÈÏÏÇ?ü€Ñ£G7{"¢æ Ë@V±%:3TN¦ É3²Ö½ŒóK–9a4‘Ð}ã«.ƒ0¢$ÃG- 1ÊŸA"""¢VˆghÍàçŸÆêÕ«qôèQäææ"33¯¿þ:NŸ>‘#Gúöí‹;v //999X¶lÌfs“ôïçç‡1cÆàùçŸÇ©S§PRR‚Õ«W#,, ×_}£ö‹»ï¾/½ô,‹ÛºO=õ¶lÙâ´lòäÉ8|ø0¶lÙ‚‚‚|òÉ'Ø¿?î»ï>—í?úè#üðøxñ">Œ™3gbÚ´ièСC“×!"jnfQBÆEŒf*…ã¯asQ1Î<2~èPxUßš|0½z:Ý·E”¨Fçp_§ÓœˆˆˆˆÈû85©Xs¡¬^½ùùùðññAÏž=ñÚk¯!>>ðøã#-- &L@LL F¬¬¬&CJJ ^~ùeÌ›7‹×]w^yå—Ó™ê㡇Â_|?üÐ.pR›$IÈÉÉq™w¥{÷îxå•W°~ýz¼õÖ[HNNƆ Ð¥K§íÍf3~þùglÞ¼F£Ý»wǬY³póÍ7ÛöÙTuˆˆš›Î`AN‰ *¥g߯U'O"#õY˜‹‹Ê"ys (uË2 I5KSsU$"""¢Ö­¹þ^æi¿ÎÊ…ZÛ­?N^×®£¨ÕÎúÚúPþùSõçsëÏࢢ¢#²,; ÀºM’$H’³ÙŒªª*ôêÕËÃÛ!¢ËÕ©S§µZÿßÞ½Ç7Uþ'é%-·–B¹CAq^ê D/(x/8ÇüM§ÎyÛwSQ6§ÃËæ¼¡›6ï6Ù¼_'^T¦à@T®¥\ZèýÞ&9ç÷GIM“´MO’&i^ÏÇ#ä\>Ÿ~rÈ94ï~Îçc·Û[Æ] jVTT´„­ˆœë}³®¸òRí·ß¨.û™ß|ó•ÒÓ3&2czIRyK{+•ÒÆíB%¯¾¦í÷> Óݺw¤=-]ÃoørN;%h9ÔRìÒ°~q3+Ryy™¾Z»FÇb¬›’°^yù_šyvðéÈѱåË—iܸ©_¿àY£}[6oRMM94?ÖMIHõõõúxÙ‡š~Êi±nJÂzíÕ—tÆ™3[w‰Ð­Zõ¹ ¨aÆǺ)!IKK;FR¥$$·Ï³±ïµáó0}Þeù,Ëgÿ²éóÚW°uÙÞiôˆ ŠLSÚ]ѨÚwÐÆt5iû=÷«äõ7¶¥  ýîºC™cÇ­Ûm˜ÊÊLaV$€B@”x S…{ä2Œ ½UšöìÕ–›ç«vý†€m½ž Q·Þ"GïÞAëöNMÝ+ƒÿÊ ¿½ . Ke·™AC˜ê5kµeþ-r——µÞ`³iàOgkðå—ÉæìAãšzdn†Rƒl@|#ˆ Â*j]*®lÜ”†0%¯¾¦í÷Ü/ÓÓz:{f†òæß¬ìŽZ¯Ç0•‘f×¾™ÌŠ b:`³ÙdEIÈ0Œ°fCd¸Ýnýã…%ÊÈÈÐñ'LÑáGÄ÷à‘Å•Mªªsí­b45jûÝ÷¨ô­w¶¥ªÑ¼KΑyAëu{Lõïªìžin1ºAL;l6›ìv»\.—ÒÓH6.—Kv»0&ÆRRRtÁìY]:k’†)mß['—Û”Ãd<˜¢bm¾i¾ê¾û.`[ŸcŽQÞ­¿SJÏžÛ˜š {!ˆ Â÷K—ÝnWmm-A „jkk[õ†#A[]†¶—ÔËn³ aªVþW[nýƒòˆ õº=¦÷MWO'ÿ$#~ ÿ1ït¶¦iÊn··„/0@âð Z¼Á‹÷ÙÛ³ð%yU7ªvy4:'Èx0UUÚrËmªúüó€m™c÷×~wÝ¡´Ë¦ì6iä€ ¥:è= ¬bÚá [|_Ûív†¡””†ÄÆñÏ7„ñí!#)h“ ÌÞ½{URR¢8 Sï7ÔrVë…òš&•ÕÊp¶³nã&m¹i¾wí ØÖ÷”éqã ²§Î|äöꙑªAYéLM äb:ÐVãH,¾·Iju^'S³k×.þùúâ‹/d³Ù”••¥Ç\§Ÿ~zDÊY­?–\fÀ­H’TþÞRm»ë2[oa<˜þ½Ó˜š’bBâý"æ;fŒ C$ÿ Æ».Øë¾^S¦LѸqã´eËeddèÖ[oÕ¬Y³ôÁè裫œÕúãŽÛ£‹þ¦¢çžØ”Ú/Gûݱ@=>8`›iJÃÐð~r¦155šÄt‚ï/o@“ _Ü€î&Øy›,çòsÏ=§ŠŠ -^¼X={ö”$-\¸P+W®Ô}÷ݧ_|1¬rVë%—ÛÐîòFÕ7JK“Ü•ÚzËïUµjuÀ¾=9D£î¸M©9ý¶yLC©SS AL'ùöˆñ_ ±%Û¹ü /hÆŒ-!‰Ô| fÏž­›nºIMMMJK ¼&ÔrVë…ú&þüò&ýsÅNÕ6¸e“MÇ8÷èœ/ž—±·8`ÿ~3ÎÒð__'[JjÀ6·ÇTvO¦¦@pLÛ`‘ÿÔ¶S2ŸË[·nÕ°þàƒ–ÇãÑ® Òv¦œÕú»šÛcj΃ÿÓK TÛà–$^ô¥NçÁ€Æ–š¦ónÔˆ¯o3„Ü7m¢GL$ã8‰Íãñ¨¨¨Hýû÷Ø6`ÀIÍíæååY*7lØ0KõÇÂ?WìÔÊïÊ$IÓÐôÍÿÑ Û—ì—–Û_£î¸]=~t`À6aÊa“F ÈTŠƒÿÐ6‚HBv»]iiiª®®ØÖØØ<+PVV–årVëÆ4M}óÍ:íÙ³·Õú±cǨG!ÕÑž·Ví–$¥n]ºæ íW±5`ŸôCÑ~¸Uެ>jjjjµÍí1ÕÓéÐÀ¬tyÜMò¸ÃnRÂkjrÉ0Œ–ktžiš¿0x<†\.ÇÐ"·Û-·ÛÃñ³¨©©‰k`˜¼×À`³Õ¢c'ê×@›Í7·˜'"‚HB6›MC† z{PQQ‘$ièС–ËY­?·Û­×_};`ýäãÆ«ovhaN{ v;%Ù5®äÛ !Ìòa“4hú‰ÚóõÚ€mI}ÒMõH5õuØ-é><·êêêõŸwÿÝšššŽ_jjªU^Vª”~Õµ¢±±Q†áÑÎ…±nJB2 C55ÕœÃa¨ªªÖÒ÷Þu3V]]­vjÝ7ÑûíÄf“Î8sfÔêïîøß ’T~~¾Þ~ûmÝu×]­Ö/]ºTûï¿¿z÷îV9«õûKMMÕ¯~}UÀmLN§SGø){{×ZíX],—£õ_u\ŽT-{޾r¸^9m‚2Ó˜‚Ú4%Ã45¼_†ÒSùk¿òò2}µvŽ;þÄX7%a½òò¿tæYü‚kÕòåË4nÜÔ¯_à¬fèØ–Í›TSS£CÍuSR}}½>^ö¡¦ŸrZ¬›’°^{õ%~ÆYôˆ±hÕªÏ5`À@ 6<ÖMAbâLƒ[Z³ÃІbC[JMí®2U^gªÞë–]/#UÊδiPo›FåØ4n€]ùCírr劈+¯¼RS§NÕ’%K4kÖ,IRAA/^¬Ûn»­e¿‚‚küøñ*ê~¡p:êÑ#3¬÷Û–ÙS†ê­ÕÅú®ï}:ähß½JE=èÅÎÕî^ƒ4íÐ~­Bi*ÕaÓÈ~™²3F:‰¯3qbå6ClôhÅ#ÖMâF½Kª¯4µ«ÒÔêB©ùFiÒ(»NãÐÑyü•$“'OÖ•W^©K.¹DK—.Unn®žþyMœ8Q]tQË~3gÎÔ† TXX¨þýû‡\.ÔýbmÒ9ºúŒQzè-zyì ½Údhu¡ëfImu¡¡6qˆ1Qô¯5ü%ˆœ‹âAL”¬ÜfhK)cSñ`K©©•Ûè öb¢äƒÌÖÄÎIñ€ & ÜÒŠ-üõ=^ ìíÐÀÞŽX7]lÅC Ü¡ ÆRbÝ€îhÍB¯ŸM쥫Nì-Iú¿KµbcC»ûŸx@†þxn_ýíã*ýmyµ¥}ž»4WûH Xï1¤©÷îÒ’_ $M¿·êšL9SmJ±ÛT×dÈhãn²Pö …oÛLSÚSíQA©[¯­­ÕÖÕwª®Hµ)™¬Ùaèè<ògt¬¢¼RNgc¬›‘°ª«kT^Vëf$¬¦&—*+ªÕØØ¨ôôôX7'!•—W¨ªªZýúõ‹uSRee•ª«ƒÿ†ŽÕÖÖª¼¬R¦iÊf³Åº9 Çãñ¨²¢JõuõêѳG¬›“ÊÊ*”áÌ”†Åº%h ßH¢`C1AŒ×Éf´¼>alF;{FÞŠ zC}ËãÃoëÕà2µyK›÷¸ÔàjN/~{F¶>øÍ í—Þx…²Og,]_¯÷6Ô«¼ÖÐ#Òuû̾úóy9ª#ÒmJœ›Õ‡,ײeŸÄº kõª5úÏ–ź «¸¸XË—¡Ý»ŠbÝ”„õ޻˴ê‹/cÝŒ„õñGŸêý¥Ǻ kÝ7´téry<ÜmEMM–-û\7nŽuSÖûï-Ó'Ÿ|ëf ôˆ‰ém6,;Ec¦ê¥/k5ýG™š²¿S{sÏ”®pû›å*« üa?¹·kÐŽ;ߪPMcsÛœ¦{fõÕqc:ãL½ñU]Œ[×}qn&&Ó4µm[›4pàõí›ë&–Ñ#& vWñeO’NÚ׿ƒoëµrKƒúdØuØðÖ]¬3Ólšz–Þ¹n^ºr€þßÄžõ„²Og|tý`ýçWƒ$I·ŸÝWÓöµóùKsõÙMCöoo»Mšsl/ýóòúèúÁzjN;ÚÙ©ö¬ßÕ¤¿|P%I:û°æî—Ù™v]?=Kÿ¾r€–ß8X¯^5P×Lí£´[»mê¨\²ãÜLL¦ij÷îblÛ®ªÊªÊlÛV ÒÒ²(·¬mEEÅÚ¹s—åò%%¥*((´\¾²¢R›7o±\¾ººFß}·Ñrùp¹Ýn­]óuXu|¹zMB—W¬Ûÿ¿ÿ­•aXÿËË×_­SS“+¬6„cãÆÍªª²~kÎÖ-ÛT^Vn¹|aáíÝ[b¹üîÝEÚµk·åòá*/¯ÐÖ-Û,—¯ªªÖ÷ßo²\¾¾®^Ök¹|S“K_}õåò‘ës8ÖåÃõsAÄ IDATå—áýüµk¾–Ûm}pÁuë6¨¡¡ý!ÚóÝwU]]c¹|¸ URR³ŸŸ b¢ ¼Ž/{RómIµ¦¾,hÒò}cÃøßžô‡}5#¿‡Jj<Ú¼×­ N ¨'”}‚¹é´lÝ~vß–ÇIãoú`Ãã²,û®A_ø%¯½}®Ÿž¥_ß[ÃÔÊ- ;0M÷ÿ8GùÃBkcK½ß7ÿŒ¼~ÍÔݦ&qjG™[ïo¨—Ý&]xtO]rl¯vÛÔQ¹dǹ™˜ìv»&N¯SO›¦¼‘#B*³ñûÍÚ³'v½ßvîØ¥ía)ÅEÅÚ¼Éz—ìÒÒ2}»á{Ëå«««µî›õ–ˇËåré‹/V‡UÇ'Ÿ|–ÐåÃëö¯üì󰂘իÿ§ÆÆØÓ´aý·ª¬¨´\þûï7†¤lݲM»vZR wªpûËåõwoIXaneeeXAJm]Ö®µæ655jõªÿY. ±>‡c]>\Ÿ®X)Ó´þ{ߪ/¾”+Œ0xíÿ¾R}]çÆôµî› 1§ióæ-***ŽÙÏOÜšõ±ûNÜÈËIÑèÜT-]_/·aêÓÍ 2Léø±NÝó®dJÖ7ESöwª¨Ê£‹ŸØ+·aê×ÓúèÇGýÐã%”}ÚrÜþ­{¦ì(ské†Öľ­×Ö×kÚZ´¼J‹ÿñÚÚg@o‡Î>¼‡¶ìuég7·mF~Í?=Kÿob/­) =E®m4UÛhªGº}ß¼¦fü凱†d¥è¥+è˜ýœztYU›mê¨\²ãÜLLn§Ó½KJKKewØ•–fm ¥Æ¦FÙì6˽JŠ‹‹år¹,—ß½»Heee–ËïÚ¹+¬ò%%¥*¯¨°\¾¼¼B¦iZ.ßØØ¨êšš°zõÔÖÕ%lù={öH’vìØ)amŒ‰˜¿ÿÚZmÙ²U‡µY «««µm[23­/g†**­÷ +//׎;Ôäj²T¾´´Lééir¤X{ÿ{÷–¨¾¾^=7[¨´¸xLÓ°üþëêëÔÔÔdý´k—JK­_ƒöìÙ£òòrËå+++UÆ¿}}½ª««-—÷†páœ1?‡cX¾¦¦¹'HQQ‘6o¶Ö¾¶®V›7o±µW_ïlÒqû;õçY9zmmn£ù"å?#R(ûøóÎLtÊ»ƒŽóÑõƒÕä65íþæ¿4yoóùéß÷ bÚÚçØÑNÝÿã½ðß=°´ù¯f™i6}tý`í(w뜇SdoÛN¼gwË1’”žbÓÇ7 ÖŽ ·ÎÝWîÀÁiºà¨:tXºz;íê‘nÓîJOKÐÒV»;*—ìÞº‚í³­¤¹m“Æ8[øŸS6›ô}=k‚–¢_ÔGCúûŠæ>‡M—3Õ¦O75hÕ¶FUÔ5wMOñib°6…R.™%û¹ öèƒzÛ´«2y=yßl>Ë¿o=Rø–½.íªpkHVŠÆ HÕÆb—Ö6)XšžžÛ_[öº[ÊzmÚÓñ>áÚXì’–~ur-ߨ '?©V“ÛìpŸÍ{]útsƒŽÙÏ©gçæê»¢&MÙ?CMSO¬hp­Oí#·GØÇ¡ƒ†¤)ÅnÓCT¶Üb´§º9@™qX¦RҡÚo§qût Ö¦PÊ%³A½ bÄ'‚Q9ÉýeÏ;;‘w¦$_+ö­;ñ€æ}æý»T˾kPn/‡†f;4ïßeÚ[Ýz`ÂPö Ç’Õµzû›: ÎrhF~¦FõÌ'ÛÚgþËeú÷êZe¦ÙtÌh§¾ÙÙ¤¹OíÕö²ö§»›þ£LrP¦rz:´üû]üä½ðߦ¨[]Ш'?©–Û#rp¦¾/vµŒµÓ^›B)—Ì’ýÜ{ Ö+·úûI>H ‡n™žª£ó¢—?3X/Ð9É8X/=b¢ (‡ˆGœ›bo%QàL‘&âÐñdÒ(»œŒŠ ÆH ¢äÄ1Öçyœ“âAL”gg`P NŒÊ±EulßL¢è¼|îƒâç"€xAEǶëˆab –Žf×ñ£9“ÙgŸ}¦³Î:K Є ´pሕ2dˆÒÒÒ¯¿þz¤ßFL颋.ÒÈ‘#5vìX]sÍ5ª¯¯ï°ÜªU«4}útMž<9bu&*+ŸCÓ4õ¯ýKãÆÓoûÛVÛ’å³'IO=õ”Ž;î8õïß_Ó¦MÓþóŸv÷/((Ð¥—^ªC9DÙÙÙ:òÈ#õÌ3ÏD¤îDär¹4þ|åççkÈ!š5k–¶nÝÚn™+Vèì³ÏÖ¨Q£”››«iÓ¦é³Ï>kµÏ£>ô3xÔQGEóít¹Î^«ªªªôðÃëÄOÔСC•››«©S§jéÒ¥aר:{ýÛ¾}»~÷»ßi„ ÊÉÉш#ô“ŸüD7nlµ_2\­œ¿þÖ¬Y£=zèÏþsTê‡5|;‰²¹Gó—x –8“ÛG}¤SN9EyyyZ¼x±fΜ©yóæéw¿û]DÊÕÖÖêÎ;ïÔªU«Z=Ž;î¸h¾­.µ{÷nM™2EÅÅÅúë_ÿª›o¾Y¯¼òŠN;í4y<ž e¾ÿþ{]pÁš2eŠ>üðÈԙȬ|—.]ª£>ZW\q…6oÞ°=>{’t÷Ýwëšk®ÑÙgŸ­üã:t¨Î>ûl½õÖ[A÷¯©©Ñøñãåt:uë­·jñâÅ:è ƒt饗jñâÅaÕˆLÓÔ9眣%K–èÆoÔ£>ªââbüñÚ¾}{Ð2Ë–-Óù矯Ã?\?ü°yäÕÖÖêÔSOÕ¦M›Zö«­­U^^^Àgð…^誷uV®U«V­ÒâÅ‹uî¹çêÙgŸÕ“O>©¾}ûêÌ3ÏÔ'Ÿ|V݉ÈÊõï™gžÑ·ß~««¯¾Z¯¾úªþô§?iãÆ:餓TZZÚ²_w¿Z9ý566êâ‹/–ËåŠJý°.Zƒ˜tTo°í6ŸõÞg{eß}ì>å¼ËÞ‡cßsʾ×Þç>%%%ŸšfħoÓ;ùd]uÕUºúê«uÖYgé¸ãŽÓí·ß.IIóÙ+))Ñ~ûí§|P]t‘¤¾8lß¾]«W¯Z®¨¨(à˜žtÒI²Ûí-=^¬ÖhÞzë-wÞyúꫯ4zôhIÍÿWåççëœsÎÑ}÷ÝP¦±±QõõõÊÊÊjYWQQ¡Ñ£Gëºë®kéµ`Á½ùæ›Z¹re×¼™ˆÔµÊ4MM™2Ex {챈Öï¬þ?쯼¼\yyyzä‘G4{ö줸Z9ýÍ›7Oúúë¯uÑEéúë¯hý‘’––vŒ¤JIInŸgcßkÃçaú<¼ËòY–Ï:ÿeÓ絯ŽÂˆ‡ôˆé§ŒshV>3¶]iV¾£KCÄŸ/¿üR«W¯Ö•W^Ùjýܹse³ÙôüóχU®¶¶V¦iªGÑyqÀãñè‰'žÐœ9sZ¾(HÒ‘G© &´úÅÚ+--Mëׯ×ã?Þò‹]¸u&2+ŸÃC=T[·nÕ-·Ü¢ììì€íÉðÙ“¤gŸ}VN§S?ùÉOZÖÙl6ýâ¿Ð×_­U«V-ì‹ÝG¡¢¢¢°ëN4ûÛßtòÉ'·:³²²tá…êé§Ÿ–aeÒÓÓ[…0Þ2£GVqqq˺šššnýŒäµÊf³ièСª­­xÝñÌêÿÃÁdee©wïÞ-Ç0®ƒVÎ__+V¬ÐóÏ?¯|0*õ#<1]d΄ù#¾]áÌ94g·$%» 6ÈápèðÃoµ¾OŸ>:è ƒZu±·RÎûË`jjª [–»“Ý»w«¢¢B&LØvì±ÇܯïÕÞ/ÆVëLTV?‡íÃdøìIÍÇ.??_iii­ÖOš4I’ÚûìˆÕ¬^ÿ|544hÍš5ºà‚ T]]­iÓ¦IJŽë`8çouuµ.¹ä=ðÀêß¿Ðó3R×XCÓ…~1)…ž1@”ÍÊwè“a *77Wv{àuÔŽ;Â*çý¥ï„NÐ~ûí§ììlrÈ!zå•W"ø.b«°°P’4`À€€mÔÎ;ã¢ÎxfõsØždøìIÒŽ;”››°>33S½zõjù,uäûï¿×{ï½§Ë/¿<âuÇ3Ó4µsçΠçÚ Aƒ$)ä÷éìøÇ?þq˺šš½óÎ;8p òòò”••¥+®¸B{÷î@ëc/ÜkÕßþö7eddhÿý÷×=÷Ü£{î¹Gçž{nDêNá^ÿ.¼ðBõîÝ[ãÇך5kôòË/·ÜÞݯƒáž¿×_½;ì°–Ï\¤ëGøbºØœ )ºf _h¸fJ =aÐÂårµ9àaJJŠRR‚VB-7`À}öÙg*,,Tee¥V¯^­üü|ýøÇ?ֻル7cMMM’ôx´w »ºÎxfõsØždøìIÍŸ•öŽ]jjj‡ux<]sÍ5š6mšN<ñĈÖï ÃÇãió\“Òû,..Öï~÷;ÍŸ?_999-ëçÍ›§õë׫²²R………zä‘Gôæ›oêüóÏïƒÍ†{­:çœsôÅ_è7ÞÐ/ùK=þøãZ¶lYDêNá^ÿî¼óN­\¹Rÿú׿tØa‡é®»îjbuçë`8çï[o½¥×^{M=ôPË:ÿ1‘º>À:‚˜8eœCÏJcjk BŽf×óÒ­ 6L%%%r»K/..Ö°aÃÂ*×£GqÄ0`€222tðÁëé§ŸÖGÑ2c¢>|¸¤ænôþŠ‹‹5tèи¨3žYý¶'>{Ró±ó×Å«±±Qååå!»ë¯¿^cnD¢îxçp84hР ïÓ»®£ó­¡¡Açž{®Ž=öX]wÝu­¶pÀ=z´2224`ÀÍž=[>ú¨>ùä}ýõב{#1îµ*''G‡z¨¦M›¦?þñºúê«uþù竼¼´×_¸õ#rHb$¯¯M NKÕ SS5*'Z“WÝÛ¨›n˜šª§¥*¯/çZ=z´ Øѣ¾¾^ëÖ­ÓØ±c#ZNj1??¿Ût+2dˆœN§>ýôÓ€m«V­j÷Xteñ,œÏSgt·ÏžÔ|ìÖ¬Y£ºººVë½3utìþò—¿hñâÅzùå—=·îD1f̘6ϵœœõï߿ͲG_|± ÃÐã?.›­ãÿg½ct‡Ïa¤¯U§žzªÊËËõå—_&Íu0Ò׿SO=U+V¬PcccÐíÝí:håü½ë®»TTT¤Ù³g+--­å±iÓ&ÍŸ?_iiiš7ožåú911vüh»þr^šn™žªI£øçB1i”]·LOÕ_ÎKÓñ£9oܱÇ«ý÷ß_ýë_[­ÿÇ?þ!Ç£Ù³g·¬óý2Ö™rþšššôÉ'Ÿè°Ã‹Ð»ˆ­´´4ýô§?ÕÓO?­ššš–õ7nÔ‡~¨Ë.»¬e]CCCHƒuv¦ÎîÀêç°³ºÛgO’~ö³Ÿ©¾¾¾e|¯E‹iâĉ:è ƒZÖù»Ç{LwÞy§Þ}÷]pÀaÕÈæÌ™£eË–iݺu-ëêëëõì³Ïêç?ÿyË:Ó4ÕÐÐвl†æÌ™£‚‚½õÖ[!ÏLóÑGI’òóó#óbÈêõ¯­™f>ÿüsIÒÈ‘#“æ:hõú×Þ18p ÒÓÓƒnïn×A+çï 7Ü o¿ý6à!I—\r‰¾ýöÛ–)¬C­Ñ­~üEæÁ¶Û|Ö·÷ìÿº­‡ÝçÙ÷á¼á†ævâ½t‰¡Y6MÞÏ¡sóS46×®Ü^6e¤Úd³In£ù$›ŒT)·—MûçÚ5i”]皢kOÕ cš=`¦üDìØl6 2DwÜq‡ Õ«W/½ùæ›úÍo~£ßþö·š:uª$éã?Ö¡‡*»Ý®É“'‡\îÐßÿþwÕ×׫²²R«V­Òu×]§­[·êÙgŸUŸ>}bùö#æÀÔ¢E‹ôÞ{ï©ÿþúꫯt饗jüøñš?¾$©ªªJ£GÖû￯ /¼°Uù>ø@ºä’K:UgwaõsèëÉ'ŸT^^^Ë'ÉòÙëÓ§ªªªtûí·ËétÊãñháÂ…zá…´hÑ"åååIjþ ð™gž©I“&)//OÿûßuÕUW顇ÒÀU\\ÜòHOO—Óé ¹îD7vìX½÷Þ{zì±Ç”››«¢¢"ýßÿýŸJJJôðëgÏž’¤ÓN;M7Ýt“.»ì2¥¦¦jîܹzûí·µhÑ"555µ:†999jllÔÉ'Ÿ¬ÒÒRUWWkÇŽzá…ôÛßþVW]u•Î9眿óȰrý»ýöÛõ‡?üAUUU*//WAAþùÏꦛnÒ¬Y³tñŇ\w¢³zý;ýôÓõÆo¨¦¦FeeeÚ°aƒ.\¨G}T÷Þ{¯òóó“â:håüíÛ·¯²³³/¼ð‚¦Nª3Î8C™™™ª¿+,X°àqI’LI†ß³ÿÃWg—ãF÷ ªq¦HGçÙutå€p͘1C/½ô’î½÷^wÞy;v¬.\Ør¹$õêÕKýúõkÕ7”rS¦LÑ×_­ßÿþ÷Úµk—¬)S¦èÉ'ŸìãKx5JË–-Ó7Þ¨ŸÿüçêÛ·¯fΜ© ´ì“––¦ÜÜ\ <8buv'V?‡mI–Ïž$Ý}÷Ý4h/^¬?ýéO:ꨣôöÛoë˜cŽiÙ§ÿþêׯŸzõê%IºöÚk%IsçþÝíùçŸ×¬Y³B®;Ñ¥¦¦êÝwßÕ7Þ¨Ûn»M šû¬î½÷Þ–ÏÛA¤×_½eúêd¸Z9£Q?¢#ZRŽT{eß}ì ìã}8ö=§ì{í}îSRRòi(ݧ 3***Z¦Uб´´´c$UJòHrû<û^>ßÞ1Þeù,Ëgÿr°^5jc]g¶wÝ.ºA @!ˆè"1]„  ‹Ät‚€.BÐEbºA @!ˆâИ1ctÿý÷Ǻ€#ˆ"Èår餓NÒ<ë¦âA An·[………Ú³gO¬›ˆC)±nÐdddè»ï¾‹u3qŠ1]„ Póà¸<òˆÎ?ÿ| >\#FŒÐo~óUWWkÁ‚:âˆ#”““£éÓ§kýúõÖå;Ðî˜1côØcé'?ù‰FŒ¡áÇëꫯVmmmÈí»ÿþû•››«5kÖH’ ÃÐ=÷Ü£üü|åææjÆŒºë®»4nÜ8kÐ%bIåååºöÚk5mÚ4-Y²DóçÏ×¢E‹”““£²²2Ý}÷ÝzñÅU[[«™3gª©©©Su_}õÕ:á„ôâ‹/jÁ‚Z¼x±æÏŸRùGyD·ß~»Þxã åççK’~ýë_ëÐu×]§W_}US§NÕïÿ{Zzÿ€®Á1€¤ììl]{íµºôÒK%I&LÐÚµkµlÙ²V½[úõë§£Ž:Jëׯo EB­û²Ë.k©{Ë–-zî¹ç:œ]éÉ'ŸÔÍ7߬×^{MãÇ—$íܹS>ú¨^yåMŸ>]’4qâD}÷Ýwzÿý÷;ýÞ]‡ اgÏž­–GŒ!ǰN’ÊÊÊ®»¼¼¼Ý2o½õ––-[¦E‹iòäÉ-ë׬Y#›Í¦©S§¶Ú?//O6›­Sít-nMÚ,ÔˆTÐJ='NÔ¸qã´páBUVV¶¬w»Ý2 C.—+"mt‚ NeggëÍ7ßTyy¹fÍšÕ2.ÍÁ,Ã0ôÚk¯µÚ¿´´4Ít·&qlèСzã7t 'hîܹzæ™g4jÔ(Íž=[¿üå/UZZªñãÇkݺuºï¾û”››ë&ÚA ÎtÐAZ²d‰^~ùeÝ|óÍ’¤E‹éòË/×Â… 5sæL½û;w®úôéãÖÚ­‘¼:ª7Øv›Ïzï³=Ȳï>vŸrÞeïñï9eßkïsŸ’’’OMÓìÄÛ€ŽUTT´ à@,Üxãúæ›oôæ›oƺ)’´´´c$UJòHrû<û^>Óçá]–ϲ|Öù/›>¯}uD<< G ÐM,_¾\Gyd¬›hcÄ hõêÕúðÃ5yòd9=óÌ3*((Ðu×]ë¦Ú­1Ü÷D‘išzï½÷tÆghæÌ™***ÒÊ•+•ë¦@w•l#Ñ{ĘŠÞ87@Ü:òÈ#õî»ïƺ Ýù#VcÄ$ôA /&ÙD¢ ÖK€|%TVïAŒ•ƒ™Pÿ MÝ.ˆ÷  Û ˆè"1]$Þ‚˜HÝÇÕn=6›ÍˆÐÏÑÑ%AW‹· &þÐì`›é÷Úc³Ùª¢Ô6›Íæ’äQðïî¾:úÞŸPâ5ˆ1ÛyöÝÖÃðyö>$ÉÕÔÔ´Îf³E³ý n·{—$×¾Eßïî¾ßéÛ{(Èë`Ïq%–AL¨Äê –˜’Ü~øá‹ë°fÍšç$¹õCljöz¾„*ÚYCØ¢Ù-$”ºmA^û?KÍ‘ïzÿ‡=Ȳ]’Ãç‘âóܳ´´ôߦi5͸ È$ ŠŠ 1"ÖÍâžÍf«KMM=ARšÃϳ÷áÛCÆÿî—¶zÇøŽ Û^™P€¨ñtkRGo°½í¾ÿjãµï£ñwÞ¹ÇzS€UŸþù’ú-Gþ!‹¿p2….íR:ªß{[½bìA–m~ûÙƒ<·×+&cëÖ­·ôêÕëLzňzÄkll\Û«W¯K%Õ+´Þ0þÏR`8ã;$‰Ø ¦³ƒüF-(ˆ§1íië€;0í Üë»Ü0räÈ;ššš>eà^¢ÏívoïÕ«×å’Ô¹ÛŽ|Y WâB¬ƒ˜pR[SU»%ɻ웪’êüëêêê×m6›dˆŽÆÆÆµ™™™?VsOßïæÞ)¬¥Ž¿ÛËg½U1 lbÄ„*”.Em­ó&jŸeï?´GRíÈ‘#oçw~e³ÙvÈ96›­îóÏ?¿«W¯^—IªUðÛ|¿³·÷ß]°ç¸ë1bü÷io%ÿqbl~ëÚšIÉ;NŒïsŠZc—”*)ý™gž9ú¤“N:þÑq¶IDATÏéthšfoÓ4%¬cUUU:th¬›ÄœÍfs¹\®Ý_~ùåó“&Mz]ÍóºÔºc„¡¦¯öø=wt«’ÿx1Þu ²¾½×m‰Z¨Ó]?"5`¯oÈâ¿ÜÖ ½RëA{ƒ=û¿Nñyø×EWù$ÞÅûð½;Åÿµÿ³¤®¶fFö_§vžýÛÚÑ{‰Š”hV"S¡Þý|Ÿå·Îw_CÍŠ÷uG?Ã÷V&·Úz@km%¾aŠÿ¸0þá‹oàâûº­Ÿá¿®3팙xbÚÒÙ€ÆûÚÀx—½¼‰šMÍÿÐÞíµþØôCpãÛÃF"ˆ ß@$Ø-EÁçõË5ØÀ¼þLÂ.m‰Ç &Xïï²o/ÿž0þ¯½¼ûyÿq¥Ö·-Éo»oøâ m¸5 €¶§Å?”ñïãߦ½™’‚½öÿ™þû[޹®bBíÙNýR`ã `¼áï³oYÓo?ÿ1¾·Aùþ¼KG·({í[^ ÆD;X‰zpÓU¡B$gO’:žAÉwÿ¬Kvµ„·½—üëõ½,Úº•¨½™üéuoš¶fE ¥7L\Ζä·&IÖzÑ´u»’ôC/oS­oqò iè@èÚëãÝîßãÅ?lñ¿¥É¿n+IÜÝ–$ÅWÿý¬ôŠiozkÿž1¾½_‚•÷íãûÚ¿$+ÿ°ÃòÚ?˜ñ&Ø~í­Þ0Ùϲ®êÍqb|{Âx´×ËðÛîÛ+Æ»¿]?̬ÔV=¾?€dÒÖ÷d£åŽåmkÞ`!L4tIšx½5I >#’ï:ßiªýËøØ« ËÁnaòîc´³ÜÂ@wÒ™€¢½vƒÝ~ÔQ(ÓÖÏïLo˜¸Ò•¡A¤nOòljé`·-µ·¾£y WèX°P$Ø »mÝfÊíGmMW÷·%I’£+~ˆÎΞä¿ÜV0â¿Þ ²Î¿GM[m ö¡ ˆ cþƒõ¶°ø¾îLÓVXno˜.ëAÓÕƒ•^1¾ËõŠik}(ƒý¶õÚ&‚BÑÖ-Eí0¾ë:êõÒQoÿ@%®zÃHñÙ#&Ø~…%þ½VÚëã}íCí!Zkk ]ÿ}¤ŽÃ«!LBˆEOh…1RÇ=cÚ*¬×K[?£½6 ¬Ü"Jo™pB˜¸ï #ÅwlßPòílPÓÖà½mµ£³l‰ ÜP¢½^0þÛC Z¬ ÈÛÙ™žºL¬‚H÷Š ¶ÍJPl{°}@ özÁÛ§£ %Ô°%!zÃHñÄÛ×jÓÙííí ^d](!K´C˜Îî± º"Œñ.[™»3ëHV¡/¾ë:À´µO(Û:“A~»zÖ$Ñ cB]ê ¼Vo¥ ;°z«OgÇtéh6¤„a¤Øá1þë:³½½}é€5¡ö„ ¶8!L[ëÚ’´AŒ~ã¿>Ü@Æw[<M[cÅønïèu¨ÛÛ[î¾ACgÛ`5ŒéhŸŽB™Pö Ù„”ÛÖÙ€%!Œ•ý#*^B…H…1¾Û"¬D¢·ÝA¤zt6¸éL¸Ó‘˜†0R|…ÑcB­·£ð&žŽñª£^+¡!V{Øt¦Þ˜‰·€ÁJ{¢qKãÃžŽÆ‰ ¶°×ííg¥î˜Š·°Áj{"Ñë%Zeèî:Óã%œ²V‚˜vD3ŒñÝ7’ï=#‘É@#œ3ý9q#^„pÚe¥¬=ŒŸBcX(NW!Œ¿AŒÔõaŒÙx>6Ä»pnWò¯£«ËFM¼‡ á¶/ï/Þñ$H¸uÄe#%FȯaJ";¢%aG<„8Q•HaB¤ÚšHï€î.RÁI\0^‰J0ÓÝC¤g`J‰Fp›‰)^ogê2‰@D³í‰|\ˆÑ I*€ñêCW¾‡îp¼ˆ´® E2€ñê.ÁB<¾xl¡ŠÇÀ#ÛÔ)Ý-,ènïtƒÆ«;Ýù½ÐÝu›ðÅW2„Éðè.ºeã•l!E²½_A·_|%{0‘ìï€XHšàÅADk"/iƒ¡á8Ð1—0DÇЮËÿΰ—ÑÂÕIEND®B`‚Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/screenshots/previews.png000066400000000000000000004152331520337127000265730ustar00rootroot00000000000000‰PNG  IHDRúºHGø¹sBIT|dˆtEXtSoftwaregnome-screenshotï¿>,iTXtCreation Timetis  2 jan 2024 10:26:00‘ÏÈÛ IDATxœìÝy”\Wy÷ûï>çÔ<ôB!„ba-›Ð¿\‚q9>rl“B!D9*Çp]Žm*Êr£ ù–Ãë%„B±”-d_Òa)×ùl»šçõ !„Bˆ¹£™ßP¾$ÿR ³óÑfcÖ)„B!;ë\R©ý¹j¯Tì…B!V޹¬ø/™°¿”ÂîÕ¶UMú¹[!„BÌ­R·žôs!ÿö‚[ öjÚXj¸/tù¥ðú !„B,e…†êbÃ÷\„þ²üåTKm_±¶å¤¿B!Dy™­~±;¥†ö² ûåô¯&äÏöØ™îWÓ\B!„åGOs}¦å¦»Y…ýr ²WÓ¾Ð?ùöR'„B!Çl¡~ºû Ù¸šþÿe£l©!¿Ø >á¾_O!„Bˆ¥d®Cöt¡¿Ô…RÛ±àÊ-˜–:hv¦JýT·Mwûlg¶å„B!Äü¹šn:ÅþR«ûeöË-´ÓžbCþT¶Ç^Í”œB!„bþLâ…vÕ™*ðÏeØ— ?…bCþ\ü©B}9½>B!„âJSUù ©Üø—\Ø/— ;_!ò´˜ÓþRºÍ¦\^[!„Bˆr7—ýág«ôOþ}ò4Ë&ì—C?y¹™~1Õþ™–B!„ó§êûLUû™?9Ä/‹°_µ˜6LwâªBCþt¶ /'ÌB!„(/³Uâ§ òÓúBÃþl'êš©M j±ƒþ\‡|cšÛ øÅB!„‹«Ð^làw§¹i–™Í¢…ýŰ…þýB¦Äœ)äðgêÏ/}!„Bˆò2S w§¸}ªÀ_jØ/¦ ÏŠ úW[Í/%äÏð§ ûs9HW!„B®Ø©/Ý)®O73ÏÕ„ý²¯ê/VPË?SŸê¾ÉªjÿL³ñH¸B!„X3M¥9Uhý}rà/$ìÒg¿¬Ã~¹ýÙúåOò)–ÿÓ˜â±Óõã7fh‡B!„X.WVݧ é£×g û0u¦Y{Æ·£+"èÏU5¿_LÀÿ8ƒ©×)„B!ÊÃä`î2u¿À5a¿l«úåô ùão/&äSÜ>þúøÇKÐB!„(/ãƒýø.8.W†úÉÁ¿°_Èl=ãÛRˆ úÖBþ1Š›e§Ðû¦ ùSÝgLZn4ÔÏôÇß.„B!ÊÇø@?þ¢¦¸>þ1jÒõÑûG¯SÜÇ¿Sà}¥,7':è_éæÅŸîg!!ßœôS‘M<—n3(¾¾ ÖB!„(M1!Øwq€`“ÏmúÒmêÒÏÑð>þçè:F³Ûøƒé~‡õ«QŽAr·œÉ÷M·ütýõ§ ùC¾ð}å+_Yÿ|àÞêêêÛ,ËÚ¢µ®/ù™!„Bˆy£”ê±mûøÀÀÀþ'žxâŸþô§Ïò¡4ä+.ïLöab¨59ÐOòÇï,”…¬>Ómgªî9ÅL“9]7ƒË•zsÜmÁ¯|å+>ò‘ü¡ßïO¡OH!„B”t:ý½ÇüŸþô§ÏI.wïq¸\ùŸªËÏTýýaöi9Ç+»“h•[Пª*?úûtÝs¦šEgª>÷£Õ}“‰a?xôèÑ÷lܸñ E>!„BQ†NŸ>ýÙmÛ¶}|ØòG¯O°;9ø3Ãm0}ÐgŠÛ§²bƒ~±!ò2ãÙŽþ>mÈoooÿ`}}ý'‹z&B!„¢¬õôôüÍš5k¾ÉÌaü¬<“gã™î¤ZsQÕ_ ¿P³ÉÌçÅä>ù“펯æ„xýõ×–/„B±üÔ××òõ×_0±ËöøL897“~Ÿ/ Rl7âpuÝv¦:ËíLÝu&wÙ­â¿îݽ{÷Æw¼ãÿ\ô3B!„KBMMÍ}‘Hä™={ö 1±?yðìlSgNõûlsÝB5¤Ôn;0sПjð-Lì¾c1q®„†‡‡ÿŸ@ ðî➆B!„XJR©Ô÷+**>ŒŸ}gü ÜÑß'wÛ™îd\“»ïLu¢¬²é¾S.'‚šnG`¦³ãŽÿ}ªî:㿌¯î[_þò—¯‘/„B±üwùË_¾†|±wü¹“àÊYGM7nt²é²tYTõ"èÏÅnjÍñ÷O5íæTÝy¼øÀîƒ6 !„Bˆ%àRöó2õìÓõo¶,ZŠyß(—Š~¡&ïiÍvÛTÿL³¶¶vç|6R!„B”KÙo|5r·ïBråäëe¯œƒ~1x'ß6þŒ¸0±Ï¾éñx®½úæ !„Bˆ¥àRö¯9yvñ³ðLVj- Öb7€é_œBnŸ­ÿÔ”gÇÕZ×—ÐN!„B1GÇ!“ÉËåp×Ík5 Ó4ñx<ø|>Lóê'‰¼”ý¦Ì…äæÂô™r¶™yн}ÁÌwÐ/fg¶eg:ú0Õ ŠÉëÜK!„B,0ÇqH&“d2™)ïw]×uÉår$“I|>Á`p.ÿä¹óg«àOÒ ¦žmgü: øóº3Pý©ÌÖj¦jÿTSoNu»B!„X@étšD"QÔc2™ ™L†p8Œßᅳ??]&œ|[¡Õùñ·-zõ~*K¹º]ÈÀø*þLý¯„B!IJØMB!„`×®]ìÚµkÁÿ®ã8WUÉŸ,‘Hà8Îì ί%‘Mç³~©/À\Oc´ ÿˆÁÁA>þñsæÌ¶nݺZ±B$“Ižxâ ~þóŸÓÑÑA0¤¥¥…?øƒ?`çΤÓilÛ& b…Õsî»ï>?úÑæ¹õBˆ•f.*ùS­3‰\íjŠÍ“³õÁ/µŸþ¼õï_*ýR-hÈ ùëÖ­ã«_ýêBþy!Ä àº.ŸùÌgøÆ7¾ÁÐÐ7Þx#‘H„ƒbÛ6_üâyë[ßÊ™3g¹µBˆ•nt ͹–Éd檪¿$*ó¥*×Ywеèÿ¤¡¡!>ö±…ü¯ýëÔÔÔ,v³„ËÌñãÇyùå—¹å–[øÚ×¾†RùÍ_*•Âçó-rë„b¢ÙBþƒ>ÈöíÛùüç?OEE±XŒ/|á ¼öÚk<óÌ33®; Îi{Ç)ËYtе˜ýBÃù|všò… ¥··ÈûÑ >@ À0 >÷¹Ï±gÏ~ï÷~»îº €}èCìÚµ‹Ã‡=æ«_ý*»víâàÁƒWüT*ÅßþíßòðÃóÀðéOšÎÎÎù|jBˆe(—ËÍxÿºuëxã7xôÑG&‹ñçþç¼öÚk477_Õº‹0ßYsÑ Ò˽ëμ“/„XHÛ¶mÃï÷sôèQ~ë·~‹Ç{ŒsçÎÝß}÷]¿çž{øð‡? Àý÷ßÀÆîñÅ©ªªâ¦›nºâïüÅ_üÿùŸÿÉæÍ›¹ûî»Ù·o>úèØ™+…¢³u¯ùâ¿ÈªU«8þ<>ú(>ú(gΜ¡¡¡/|á Wµn±4»î2ßé‚ùÓ?ýSΜ9CKK _ûÚרªªZÌæ!–¹ºº:¾úÕ¯òÿðœóΟ?@}}=_þò—ihh¸ªuÏÉÝw–\wžr úsÚ,üöBˆ…rë­·ò/ÿò/¼ôÒK<ýôÓ<÷ÜsìÙ³¥õW5åcÙ¶mo¼ñ###ìÛ·˜x`Ôè—íþýû¯±XlnŸŒbų, ¯×;ö»Çã™ðû™Ë Z6;åô—œ¿û»¿ëºóÑ~”Ç{ŒÚÚÚÅn–b™SJ͉ý®w½‹üã:thÆÇÜÿý=z”ƒ²oß>***¸ù曯Xnt@ÜÎ;ùÔ§>5á¾U«VÍÝ“BÌ‹é*ó£;îóQ¹ŸŽa3VÞyôÑG¹páÂØÑ¶¶6þìÏþŒÝ»wÏØS¢ÐéƒW2y…®Ree%=ö---´¶¶ò±}Œ¾¾¾Ån–b™Êår;vlÂm£ƒrGÇYV¾†Ç',7ÚOÿùçŸçàÁƒÜsÏ=˜¦9vÿè—ñúõë1 ƒ'NP]]ͺuëÆ.g~ž˜bY¿™Êg?ûÙ±¿{÷nvïÞMss3mmm|ö³Ÿ½ªu úsB¾b¡¼ôÒK|ðƒä]ïzò'Â#<Â'>ñ Þ÷¾÷ŒõËÿû¿ÿ{þéŸþ‰l6 \î¾óÔSO‘N§Ç‚?䫸ƒƒƒ<þøã„B!Þóž÷‹Åøð‡?Ì7¾ñ ¾ô¥/Íú¥+„“ÍVç8Z½¯ªªb÷îÝ´´´Ìz.)<̮܃~)ý¥¥Ó¼„}!ÄBhnnæýï?Ñh”'NpñâE¶oßοøEÞùÎwùÀÿàƒÒÑÑÁSO=ÅÙ³gÇ?î#‘·ÜrËØíÿøÇ©©©á»ßý.§NâŸøýèG1 ƒoûÛ¼ñƃA´.›®§Bˆ%`¶ó{<óÌ3<öØcºèTUUñØcÍ8‡~!ë.Á’É…šÏÆÍ¶î©fÏQ“î3¦ø]MZÞ˜t}ôb^úi]º>ú³"›Íî-ò¹lpppìì¸[·nå›ßüæ|ý)!„(ÚÞ½{ùÄ'>Á;Þñ>÷¹Ï-vs„ h1úèC¾á\Ÿ×çó‰DŠzŒ×ë½À÷Ó½tÝwÑ—.ã¯3î6ÆÝ6ù÷ñË3é¾éÌKe±*úe½÷s5ªªªøÚ×¾ÆÖ­[cĸBÌè¿øo~ó›·!Bˆc>Î^;gÄ/‹’}«¢?Õ}¥TôÇWóË¢¢/„å*—ËñÐC‘ÉdøéOŠßï_ì& !Vˆt:M"‘˜“u…Ãá’¶_%VôÇWõ¡ôŠ>ÓÜVÈ}%›¯Šþ²­Ø !ÄRµoß>âñ8·Ýv›„|!Ä‚òûýsR…ƒËuû5/Ùy¾y±ýóGo“оB!Ä2u5•ýR+ù£Ê¼¢_ÈýE“f !„Bˆá÷ûñx<$“É‚èú|>‚Á Ì›_ úB!„bÁ˜¦I$! ’ÉdÈår8Ž3vÒ>Ã00MǃÏç“€$è !„BˆgšæRœ=gI)÷f !„B!J A_!„BˆeH‚¾B!„Ë}!„B!–! úB!„B,Cô…B!„X†$è !„B± IÐB!„b’ /„B!Ä2$A_!„BˆeH‚¾B!„Ë}!„B!–! úB!„B,Cô…B!„X†$è !„B± IÐB!„b²»B!„BC)5vÐZ]Äeô…B!Ä’aÙl–ööv:;;hjjbÍš5x½^\×]ä– úB!„bIPJ‘Íf9pàÀ„Û;;;éììdçÎx<©ì_"}ô…B!Ä’ ”¢½½}ÚûÛÛÛǺó úB!„b‰PJu×™Jgg§ýq$è !„B± Iý%ê—'3¼Üšåx—Mû M,-}ÑÄì¢~Åš*‹-·®órÏfßb7I!„óD‚þ’ÈhžØŸä»‡’ìEIbiÍÑÎG;s|çPЍ_ñðŽ ¸-HØ'‡:…BˆåD‚þñÃ#i{.._Ì©XZó/ûFøî¡${K„w^ï_ì&•,“ÉJ¥Èd2ضã8‹Ý$±˜¦‰eYø|>>ßò9Ê%Ÿ QŠåü™X‰$è/³'Îw¥&ÜvÇ/¿}k-aŸ!ÅØ Ž=Êç?ÿyŽ=ºØM)+ÕÕ54­ÛHź[¬¼‹.VùÀÿ¥§cœèÊñÉ"‹ÜÊâ¤R)b±†a‰DˆF£† ?…s]—l6K,Ãu]¢Ñ(@`±›U²ÑÏDkk+ûöíãðáÜ>}šþþþÅnšXjjjظq#7ÝtwÜqëÖ­[òŸ‰•L‚~™ûËÄØs,=öû¼|êæ"¶J,Uý ôá—€¯sËÝo'ÙòßÇÿw¥ˆ§5ù®èâ6´@8ŽCMM –%›3QÃ0ðûýøý~lÛfppT*Euuõb7­hœ>}š'Ÿ|’gžyf±›#– þþ~úûûy饗xüñÇyðÁyÿûßÏÆ—ägb¥“²Wû›=ñ !ÿsïˆòÕ÷UJÈsæ•çŸæØÿ÷»lIþdì¶=ÇÒüÍžø"¶jv®ëÒÝÝÏ磮®NB¾˜3–eQWW‡Ï磻»{Éœasô3ñÔSOñÈ#HÈsæ™gžá‘Gá©§žZRŸ ‘'A¿LýðHzBw¿ûíJܾtûO‹ò¶ïß¿ÄÖ¡ûý;‡RüðHz†G,®ÞÞ^***…B‹Ý±L…B!***èíí]즤··—'Ÿ|’Ý»w/vSÄ2µ{÷nž|òÉ%ó™yôËP"£yì¹ËÕϽ#Êm×x±Eb%Øû½¯O¨ì?ö\œD¦ü ‡ñûeÇWÌ/¿ßO8f```±›2£ž~úiüñÅnŠXæüqž~úé²ÿLˆË$è—¡'ö_ž>óŽ ^©ä‹³ïß¿D#üÝ'ö'¹E¥R)Ç‘J¾X0¡PÇqH¥R³/¼R©§OŸ–J¾X0»wïæôéÓeû™IÐ/Cß=t9\}j‰Í€"–¾à™o]ÿ^,±XŒªªªÅn†XaªªªˆÅb‹ÝŒ)Åb1ž|òÉÅn†Xaž|òɲýLˆ‰$è—™_žÌL¨æËÀ[±Ð^yþé Uý_žÌ,r‹ò2™ †aÈÀ[±à,ËÂ0 2™òø,ŒÊd2´¶¶ÊÀ[±àžyæZ[[Ëî3!®$A¿Ì¼Üš»þÛ·±%b%«úõØõñïÉÅ”J¥ˆDä—X‘H¤ìº*¤R)öíÛ·ØÍ+Ô¾}ûÊî3!®$A¿Ìï²Ç®oi”Ê¥Xí¯Œ]ÿž\L™L¯W¥‹ÅáõzË®z™Éd8|øðb7C¬P‡.»Ï„¸’ý2Ó>x9T…}òï‹£³õôØõñïÉÅdÛöœŸñVëò›UH”'Ã0°íòø,Œ²m›Ó§OϾ`”’Ó¬‹Âœ>}ºì>âJ’$ËÌhÿ|c··Édþ”蓃M.—#—›û®¶m“NÏÏ<ì™Lz^6.–eaYž9_ïèº=žùY·ßÀ4çv,ÇÀ@ÿØõñïÉÅä8NÁ˺®‹ëºcï÷L&C:;ы֚d2É@ÿÀ„õº®K:ÍõN@*•"“™ûτ֚áááyùL¸®ËÀ@Q¯}!´ÖŒŒŒÌˉwÇ!™™óõŽ®»œ8ŽCÿì ’ßQ1 c,È{½^|>ߨïJ)‚Á ÕÕÕ¶'J)|^ßœoc ?}©×ë›óõ*¥‡#óÒfÃ0¨¬¨œó¢ƒRŠ@ 8çë…|›Àœ¯·¿î· bîIÐ_â\×eppx<Žëºd2†‡‡ž´“É$ÃÃWŽÏå²d³óôçëË6™LÍSÐ÷àõÎ_П¯n'Á`ÃAÛ£F?]]]är9lÛæâÅ‹¼úê«Äb1ÇÁu]²Ù,##É aSkM.—›—`›É¤ç峿º.‰Db^>ŽãŒm[æRþõÈLØ›+£ÛAq™aD£Ñ±³H[–ECC[·n%íx=BÁ‰aS©üxÓ0ç´Ú¯”ÂëñÎKdt§Å4ç¾û«a„Âá9߉PJáõz0Ôü}éö¸rIÐ_ÂF¿,Ÿ}öY~þóŸ“Éd8yò$¿úÕ¯øáH[[Û¤åûbÕZãjíºä\÷ÒmÅ^7±/]·´õÌõå2Uð%ÿ%¦@)0UþŠqéwUøzÆ.J2@™—.Fñë(°Ýùïßñ·¯\ŽãpøðaŽ9B2™¤»»›#GŽ`Û6‡š—°½ü•ÇQQÃ0ضm×^{-~¿ŸÚÚZ¶lÙ‚išlß¾}ÞŽ6.®•½b”Œö\”Røý~¶oßNOOÙl–Ó§Osï½÷rìØ1†††&,‹ÅP ‚Á‡žLŒ·$äõsïêë©6˜îû¹âhí˒ʺ¤²9Û¥.êeÛ*/¸Y’É$ÏÜWFFFp‡\.7í2™LÇSÔ‰•|>Ú2ÈÖùq¶ÖæŸ`g3–Å“ÖEdY#Œí­Án@¹#„Óg ÍCŸp¿?€mÛx<—+ºù×'»"«*¥hii¡½½×u¢©©‰h4ÊùóçÇ–s]ÍÙ³çH¦’ÔÕÕbCÙßi™€å㮚MTû„­ÂNX—s\:³tÇlb)—LN“±5Í5^®[í#“J`Y&¶=·ÿ×uH$☦‰Ï7·Ý rvŽ¡ø0gÎ÷óÂÐiª|a6‡hôUPá ñf­@jÀq\†’6q›sý9޶'ñ«,ÝRKc¥Ÿg¶»4Èå §†I(š—îåNkMkk+MMMcÕýžž‰«W¯¾Ü}Ç0X¿~=@îžžü‘œ ‡ô uè¬Mø|5’…Laïa­L\o9+Š£8ÊÂÅÂkÌtúqgÎÿ'†a q]gÎwìMË"¨4p® C2‹¯/ƒË¡Ò6¤í|Um6Êĵ‚¸Vˆ´UCÖ¿Š”Ç%8ð*d‡Áþû­X–eáóù'5KãºîØIÅò%A‰=D©µæüùó¬^½šW_}•ááan¼ñÆ+–‡Ü²,¢©V²§í0/õœæúÊfÞÜ´æp kú€žs4­ÝIþõé;X¦ÂT ÛÕŒ¤lº¹š»6Gy,<ž¹‹Y–‰e™­Ûq ïÎóûas-zu²9y¡¹ÂM:èƒa0Î Ý”‰]µ\ÅrÊ—ß°Ú#dƒk‰Ù«ðò Fü<ʵ™«*éhW”ñÏÕuõ¼ô^ à  âóùÈårx<z{{q]—ÚÚÚqÝ4¡Pp8ŒßïÏÞV6~Ó˾ž“¼1p75láºêµ4‡kñÆ4]Ò9—xš'^èáLw ¯ÇÄP ­Á44¿yk-ׯ¶ð{¼øýs{¦k×uñzóëË Ÿqlv’ƒñ ìíjÓàâÈ/÷œ¦Â °µb5÷­¹†@>sꊰÖÉ9¼znˆŽ pº;í*|–A<•¥'ÞÃûÙ²:B$`1=ClÛÂqœ+^gÃP+v ©Öšt:=V±m›šššüÎíÐÐØ¶B)E2™$‘ˆu­ÂrQ9w}™UQŒ3ƒpq=º-œn3fxÐÞ™š]ؾz´kƒvÑ(4 Âcwâæ2sÞÕÊ0 r¹™Lfnƒ¾e`L’«dVGA;Pé'»ÎÂI;] ô‰^ˆ¥Ážnû«À°p£ë°+6“óÕãb€k3bÈÖ†ñô¾Œ‘ì{n¦®t.íLM~µžû®s¢üHÐ_¢Ñ(ëÖ­#›ÍÒÒÒ©S§hjj¢¦¦fÂr‘H˜††zL3ß×Ò¯Üݰ…F_”úOñz¬Îì0ïm¹ƒµë§¬Ô9®æbw’¤µ7Ë»£‰µuAB~“œ£yú•nž><ˆRŠÛ[‚¬ Ìý¹Òé4~`ÆÁE£!¯ Á–ÕAìk«ÐkB¸½ ôëù uMwuÙÆ\_‡þõyHeò‡4&3¼¸¡F²Õ;Qv #~3Ñ†Ê bD×âÖÞD¼æ,ׇ9te'ó_W)—ËÎ[ÿï¥H)E4¥¥¥¥555c¯±±ǃÖÃ0hhh ¡¡~¬ëB£×Ëo­Ûś𶲧ãÿ»õE~Üq˜Oïx[«Öà1®Üdj '‘䛿èâXGŠß»·™­Í¼–AÎvùÑËNE IDATÝ|õøÐ=5¼ë¶Us>(Îq¼^~¿Nw"ú}üWûþëâ^Þ·ñNÞ½þ6B–Ÿ‹#ê;˳íGèsFøÃmPˆN¹Ûќûûh® ððkØÔ¦&âáÈ™¾õ«þþ‡müö›VóÞ;Wá1«ûùq¹y|¸Ti­‰Çã´µµa ÷½½½Ø¶R ×qèî馧·w숩‘Ë8Ô…>ݽ¥v4À¶ÜŸž„®ø´…í“«» ×ׄÕùf²\”…S{‰¦ñîEõœóAê†aÍŽý9܉0n¨¥ç–*ÜWÚq_퀌ª à6Wµõ4п>#Ó<'eâ†êÈ®z•îÃì>€•ì°ø«¯!V}'é¦ßÀêy³çÀ¥¢ÐÕq Ë2çe2Qþ$è/•••TVVŽý¾cÇŽi—Í÷çΓJQé qKm w®ÝÎá¾óüëÉ_ðí¿¤9\K­?2!ì»úbYžøeG.ÄøýûšyûÍ x¬ü2Ž«ÙÔæëOŸå»/u1œ¨dUC-‘€gN*uóÂPô Þ¼UE½rçõ¹š»âèÓýÐ\‰ñÐH¢_ï‚dvb%K™¸Þ(¹U÷‚›ÃÓöSŒ‘‹Œ.ä× ”;Œ¾ŽÜšÀÆì=€ÊÍÏ€å•L)…ÏçÃëõŽU«¢Ñ|ÝÉÍå€l.‹ã¸Œï¢ì3-6DøPEoYsß8ú3þשøãm°>Ú0áo¹Zs¡7Å¿>ׯ­1>þŽ Ü¾¹š ÏD©ügæ÷ßâÅ0ß¹/È{ïŒö›s9­Ör´Ko*Æ×^š ±>ÞòoÛ´“ STûÃl¬hd}¤¯ù1MÁ*~{ã]D¼Ô¸î2®ÖœíáŸzžµu>ùž¬© ൠšëšƒüåÿ±™ÿØÛÅw_ê¤/žåCo]GÈ·òºÖÌ·ÑAæ±Øå âñ8py†*Ó4áÒÙ+f~ɹÐ7‚ÞGŸèÁ¸k=jg3ú…sÐ7y¦ÐþrMw㆚ñ´ÿcø ÊÍä7‡J¡:Ÿí¯»3A'÷£œta]^ƒ¡ 쟧£&DøùâGÚ ™/úèdzGPý#¨{[`¸ ýJ[¾Ï 7PGnÕ½¨tž O£Òý(mc(ð¦.â?÷2u;±ënE{Âx:~Ž .¥“Á¸+H2™œ²Â­”Âcz¸¥¾…w­ÛÉPf„ïž}‰Ì¸® ZC*ëðõ§Ïr¤5ÆûîXÅC·\ù¦¡¨ yø?ß±»·×óìÑ8ÿñ뜩ªßåÂï- ¨¦ ¬ŸÅs¬/âÇËØpqwìX ë«aÒ¡öF±nÇ ­ÆÛöŒT÷4F² OûÏ0{ö“«ß‰\… ›£ÝÔLÓÄ4M<gÂô‚À¥þòߟ†2ðU¾0×V®æƒ[îãB¢—½]'ˆçRèKËç—ÁDŽÿøu§:üþ}kyÓ¶*B>×2ð{ j¢>>tÿZžŸêå»/vιe›iÒv–ÿ:»¾TŒßÝøfvV\C…'€Ïô`&~ÓK¥7Äí ›xpíöuŸàùΣخ;öÚ¸ZÓ5˜á;û:èÎð‘߸†µuA"ükc™Š Ïd]]Þ¿Ž{¶×òÜ‘>Ît&HØÿ[Gk=ê]×ŶmlÛ¾¢‹ŸeM1»ŽÖù#œÉt'ÐûÎCuµ¡|ãê…ÊD{BØ ·£ƒ XÏc̽tmÐ6¸9T.Õù+Œþ£äª¯Ç©»mx(Ûí¡ÇDíX /h'Ø>‚JÙù×ÄÕs •EŸ@¿ÑÚPÚX æøï …öUàÔíD{+ð\|#Ý—ßÁ¹Ô­I¹ŒtVç¯0áTmà ԃ!3æˆÒIÐ_A‚Áà´‡ö`*ƒÛ6ò@óü¸õeŽ ¶‘´ó•„xÊæ?}‘7ZãüÎÝ«ù›°Ì+ß>JA8`ñ;w5q׿0ÿµ¯ƒó=I²ÓöW\DJ¡¨m èCíП[OÝç4cÃkÐ>„º¡ ÖTŒÝ¥­vÍ ¸›ñ´=ƒJvƒ;UXÑ(;‰§÷eT.S}=ÚW=oOOÌL)f>AØãg{ÍZv5lfOû«hÇq]4ʸ<ýJ7¿x½—‡nmà=·7ò]Ùßc*ªÂÞg›½üësmœïIb—á°í:œ÷ð“ ‡¸­~oY}=¾)Æ&(¥{ü÷kïaSÅ*¾uâ—ô¦†óa_CÎÖ|÷Åöà·6°}mtÊJ½a(«|¼í¦:šª|üÏŸµ2˜.h‹Fk’ÉYgfltG ÎõÃÖzTStì¤/ÚôâÔ܈Sµ³ïU¬¾—/U£'½×µƒ²G î'íÁnz3Ú_wif²2c*¨ ¢¶7¢Ï‰”­¯Ü%Ñ@ÆA¿tÝ“@íZaߥ°¯À0±ëvâTlÂì;„1Ò>M¥^£2د£2CäV݃ö>©„“•á§JÌ—Ñ*çL¢Þ »¯esåjž8õ<]ÉA²¶Ã@"ËSû»Ø¹©’;·ÔPš~:6C)ªÃ7_¤:âå;/vO•áÙó">h©ÛA¿ÑóÓ,s5$sèmÊ¡nZUP 7º·b3ÆÐqÌÁc(7;ýz´“¯fuïà 6âTm)ú}‹òá7=<¼a þõÄsô¥c8®C{Šÿu÷^WËý7ÔÍÚ¿<àU¼õÆZ*Cž;ÒËðÈÜͪ1WzÓ1¾n?k#u<Ð|#Ö çg0”"dùxoË´T4òx’öDÛáHkŒçŽôq÷¶ZÞ³« ¿wæíÎêšï¾½‰ƒg‡yþØ@y`»èCË îX›´†Bûª±nÇ<†9ð¸.Óm `êžÁ7 7‚SµmÍý˜®«ö¡nhB$ÑÇzÀ™á½©5dô¡‹èÞê][¡2|nÎï Çê}eÖYuŒÌVï+¸‘kp*¯-Ï ±$È;gqwÖi´LeЬäý›ÞÄ™á.öu¤=cßñzcÞ³«‰Ú¨wÖ¬†‚uuÞvSϾÖKç@º¼ªú¦‘ï‚ÓA¾C³Ì¦3ªg$¿±úQëkÐÞvýmK`õì¿4Àv–õhsè$Ff§b3®¯fæåżI&gÈPMÁ*Þ½þvFri~pþ‡ã¼rfˆdÆæí77Pš}Jþ3äýw¯æ¹#}´õ¥Ê*ÐڮˑþV^é=ÃÛ°‹º@Å¥ÏùôOÌPkB5<´öfÎws¨ïݱ$ÿû…‹lZæ½w¬"ðL;[Ñ(¿Çà––Jvm®æ×Çú9ÞÇ-×¾MË™R„BœÕÕK£_í@{­üQÎp7r >¬¾WóÛÂYfSÚÅH÷buïéچöW—W 5juj]úÐÅü”˳Ñ:?;Ûë]¨Úª¹íc×ïÂHvaõ@9©YÆ#hpsñó˜Ãgp*6å»z–í`7QÎÊè%æ[¶À³à-ÛªšyûÚ›yîâëüàØ1ž9ÔÍÛon ¡Ò×*ìmSòðÖëñYOíïb ^&‡ä•‚¨µ­†Ópf ð™.µ†‹ÃùËMkp«7 ½˜±séÂNE?Ú…Çì9?œ[[þ„ZbÁüþY§\íÖ¶­j ­»…ïŸÛÏ‘ÎöïçëY}i€i!*BÞ¼½i𣗻ˆ§ì²è«¯µ¦39À÷Ïíg]¤Žµë { ›Á'`yÙRµ†k¯ápï9öëà—oôñÀu¬®)l†¡ˆ,þø7Ö14’ã™C=dr®„ýEJ¥ ›rÑÕÐGéBݸ ]SSµ càuTf0ß¿v*? ™vpjw M?eÑW_~¸1_ͧmèÒQßätWÝ> k*që›qª¶\êŽ3PØ:´FÙ)¬‹Ï‚'„Ss¨2Ç Ê–ýÄçó<ýž×´xhÝ-€æ?޼Fo<Åûî\UÔŒJ)*‚¿{O3N rðìpY„L•¯@)ÐotM13Â,F²èóàóáÞx+†Ó‡?[t3Œ‘vÌ¡¸U[qÂÍ`,dzS–·Éƒsgõ¹µ~#Qoÿwÿ^’)Þ{Ç*Bþb> X¼mG=¯µÆØ{| ,Âlεù_§ž'‘KñÁ-÷ñ75eÄà·=À™á^¾yà««¬oM¬?Ë4X[ä®­5üòõ>Nv$ÈÚ‹ÿÚ¬(Zã3·zÚ† ƒÊ¡wÜ>?VÏTQ³Äh”“Âì?‚jÆ­Ø\•kÓ@ílFù,ôÞÖâ¿'26úùsPA_w#*3ˆJ÷N3~kÚÅH÷a ĩ܂l”®ž¢hôWÑ™ a(ƒ†`%[¢k DÓܵÃǺúà”pgâ÷š¼åúZ*B^:9Hçà"Ïãk*ˆøP×ÖÃé>èŒ?¥›«a îˆc®Ib ïÇÈÝåd1bgQé¾ü¬æÜžÕTÌLkÈd38…tÙ"ß'½ÊæÆÊMĽÝܰM±¦.€eJàõƒÛ6U‘HÛœìH`Ï4ˉ˜[Z“HŒ`Ï2ić˜d­ÛpãQTS8¿-©¯1âç0â°koA›‹X¹yQw®ƒ³ýÐ_âI •k…É¥oÀMFP7×C°´n7ÊÉbÆÎ€éG¥ $Š"A_L)ç¸rÅôG¾D)EMÔË{ïXÅÁ³Ã´÷¥Jj“(RøýþÏ-1ž¶¸áf”“Fí? –B5WB;Ïþ|nsø4nÅF´·bqfàQ@}¢~tW²¥UáµÀn¾D9Šª @u ß}´øµ]šÙínäšüìDBH‚þ ‹ÅI&“³.§µ&uØs¸—×WðÀæ¶T­âéÖCc'Ð*–RpÓ† *ƒ¿|£oq¦Ú ûPªóïdaÓiNÁ 6âF×cv¾ˆ:Ó 9µ¦¢ôª¾›Åì?‚öUá†V—×ôrKã8 ‘H$ÆÆ¤Äãq†††H&“‚½ã~†ÚD–_¼‘ŸþÚÚz®¯YË÷Ïï'i§Kªêû½&ë‚„&¿>:@fºï ¦ì=Ks¤–õцçÍŸŽãjÚúSüìµ^n^_Å[7nbkÕ^ê>ÉP¦´j¨ßkò¶›êéJóêùXIë—†A4% bYùªr("â÷û'ôÉ7‹‡¥­P~nøÁãÐ?Cpã*ðš¥UõÝ*Ý‹rÒ8•×^:[î zQk+óSdö'óc²Š¥ ´¯§ú:Œá ¨Ö èÎj}5JýžÈå¿'¼ùÉ„($Š%Ìqz{{Ù·o/¿ü2ƒƒƒ¸®ËÞ½{yá…hkk›°|8Âë}#“ʺi1’¶Ù±¾‚u••üFóÎÅ»9ë&e—6Mæªj?»¶Tó‹#}$RöÂW0ëBùyóOôæ«4%uÛ1q+6sð¤Òp¢*PUâÉ^\#y• ­B{"¥­G µ&›Íò½ï}={öNç§ Ü³gßúÖ·8vìØXÐW BÁ`A]w4ðÚùaÚzSܵµšu•ÕÜPs ÇÛ91Ô]Bå 6âåÆk*8Ò[”êÇ/r6ÖÍo^³“ oiï߬íòê¹ ÍÍ-•¬ŠTð;ßľî´%úJZ§×T´4…¨úøÑË]ØŽ.»– ¥^¯—·½ímÜ}÷Ýø|>”RÜ}÷Ý<üðÃlÚ´ér_kFF’år#kÑþÌᓨá´£š"¨†ðØÙr‹no.‘¸€^ƒöV–´Ž«ÒÚúµNH•8\™¸‘µñóA¿ÜjòUýRh•ê†\ §ö¦K!é«/f'A s‡S§N‰Dd``­5/^$N_1g¾ã8är9²Ù,¹\Û¶Ç.㌧yöH×Ôû©¯°˜&«Õ¬ Õò³¶WéOÅ&<¶ÐKÐ ;®‰04’åÕsC$RÙ’ÖSÈÅu]”RX–…eY˜~ÆšJ ËÄja)cì¾±eLÓ´®¸}üEù+ ÔˆiÇñä± ³=ŽáhŒMµ˜Ó<.¿nsšõšx”ƒwèu6 CM3¶¡u†YҀʥ.NsìØ1¶lÙ‚Ï磭­ ­5lÞ¼™¦¦¦¢_­!›syéä!¿É¦¦0>Ë`C´ž–h#{»Ž3”-­rö[|àÍkè‰exáh¡ça˜8Øw–¬kóàÚ%wÛiïKqä|Œ·ÞXOc•¯iqM´ŸéáÅî%­SŠßäÖ• ij¼tj€t®´©•Îçó±qãFΜ9C&“¡±±€úúzÎ;GwwwQÒóÜh ÊÉ ’Ýà:èþ$º'‘?ãx°´j¼rÒX]{Ñž(nåæ’Öq5Ts%˜F~êåßs®¿7ÜŒÙÿ:*3”?z<„œ›¯ê—Bk”“ÁŒC{"8Ñ2Õ¦(ˆ¼K–0­5©TŠõëדJ¥Èd2¸®Ë 7ÜÀ¹sç8|ø0---cË÷öö1<£ªº’@À(2é4®vÉdò]r4pº#Å¡3<°=Ùi²v†Û+Öó\ßqÞè8‹§rÝŒmËf3cëÏr3\Ûäå';iÙ4UÿeHÄI§Ó3vCŠÅb„Ba¢Ñ|EÈ­ô’lªÀsðÙ^ˆx¯¨èç+]àñLx¤‚-ØÞ ÑÄy|‘ð¥;L2)M¦¥–ðñaŒ¬žbÝù)ë,kúçë2Àá¢ëw5€ÂfzC(¥Èå.èt›D"^pen9I$ÔÔÔN§‰Åbär9ÞúÖ·ÒßßÏñãÇ©®®Æ0 ´†Ó§Ï‹ÅX½fJã¸d2i<–Ë“Ÿ}&g»œèHÒÑŸä†5~t6A<¦°².÷Ôná=Ç8|ñ·ÕŽ~ܑ֮ÐZÇ0MsÂÌW®Ö4†5ÕAÅá³O†£RvŽW{ϱ)X‡›Ì'{EÛm;G29ÂÐÐП «áÈÙANuÆùÔ;Va§ãÄ\ÓqXå­äH_+§º.Pí O˜²ÓuFFFЮ‹aN¿SºµÁ`OÀäGû/Òv¨϶3¢ÉålÒéjR8Ã0…B÷?_N‚Á CCCø|>"‘‡^xªª*6nÜÈË/¿œßV(EËÆ"‘mmíhÀ4 ¼>vÎÆv.ÍR¥LrFrþj™‹è0( çlŒÌÆJüëê1Z§ŸvXápÇq'Mç©ÀH0¬“Pq ‘‘7.M×YøÎˆaƒA\Ç&“-p‚C¡<&#ÍUxûÓXV`Ê„dY@€H8BnÊéªÙŠuÄTõü3èWaå°WWhªE%sº†A0ÄÀÀqiŸ­ëö0ä¦1v6â({æ"ƒLËÂïó_1¯ëº¤R³Ÿ\,mô—0Ó4Y»v-¯½öJ)8~ü8‰D¥ÕÕ+µµµ44ÔãóyǾì’É$Z»„BùКÌ:ôé¡?îðÎ;6°ºÆi(ªµËC•ažúåaúUšŠš*¼3TFƒøä6"oßiñ=­¤ RWWü¡ÙÑ íL¡¦¯¯D"Îàà¥*éúÕ(4¹ƒ­$§|L @)ƒdrš §Rd«îG'It¾ArôL¸JÁyõÍ G€óCWT‚üþ¦i222ÃL$jˆœµ·¢…þ´‘ê‡f92 E<»âNñUº¥Ï²,6nÜÈ+¯¼‚ã8¬_¿žîînB¡ŽãÐÙÙ9áuY·n-M«šðùòÒu]’#&^Ÿ¯×‹RŠ‘ŒÍ‘‹C8Zó›w¬¥ª2„a(B:Â;£·óÔŃ´g‡yK8Œ¡¦>—Ö­]LÓ$‰^qÿ½74òÃ]¤\¡ÂÏ> ù ŸJ%Çú["igØßq ¥·7o¥":õ`ò\.G<'‰^ÑíOkMÎÑœèê!ì·¸uë*<¦B)…ãºÜ³özþãÌ^N¤º¹¯¦¿yy'×u\×%`šÖ´AÿZ_ˆ{¯Ëñ_û:Éâ'οöÓÑZcÛvþL»Ñ+_ç•x”˶mZ[[¹þúë1M“¶¶6jkkI¥R˜¦I}}=†aŒ.\¸@GG'Ùl­5†ap²¹¶Ë¿—M/vt…Ýy€‘T,è+©àÕl¯%5!52mw¥Ê0Ævú&Ó}G±ëv°MT&^ÔÜü†aHŒ$ :<ŸR³¹&}¦5Ͷڲ,B¡‰‘ì+â+P&ÙšzpÒ¤zO¡FÏl(ô‰.Ô-kHÖzáÄP~ÚÎqm6”b$9‚íL? —Nå0¬cdêw¢r #9Âl;A–e]ê–uåsZ‰ß+ý%l4èWWWcš&>Ÿªª*Ç!›Í …&,ïñXþ gÍÿ4Æ**}±4/b×µUÔD}X¦‰R PÔ*¸¾z§‡»èKÇY®™¶m£cò‰W‚>Å[ªù矶rüb‚­Í*Š<ÄkjÊu7úü4Lµ¥Ý7‚îML{â“üoš³B*mEpBk±z^De‡//§5ôÄQñ l¨F· AV_±îÑË´´;‹¹'¼•*ìÄ3­{…°,‹††n¾ùf,Ë¢²²’T*E*•" ±k×.|>Zçç¿·<£].& û(¥ÐZ±ÿÔ[×DYSÀ4ó·+­yül¯iæl¼‹´kôø0¦LLJS¾ooZ_Á‹'ùÁ~ÿ-Íø½E ˆÔzìóP艎â¹4ß<ñsv6lbG݆i7þsp§ß™Q*ÿZ¸SµW¬²%\”Rø|>jjj¨¬¬ÌNŒD¨¬¬¤¾¾þŠ ?ºÑ›îKUGÛâtô§¸ïúZ¼–16q‚Bao^µ®Ô§‡»Jj³e*ªBîÜZÍ¡3Có?Ñ0 >>+òK\¥ NÅFp³¨T8“6¬‰lþÄ*×TƒÏ*y š‘êA%;qª¶¡¥ÿeÑFCicc#uuux½^***¨¯¯§¹¹™P(4µÎW;µžô™w=séÎp±?Ím›«z­ ;ɦap{Ãfº’C´%úf=ÏÄtåæÚ [Ö„ù΋ÄÓv }÷~ëN Ñ>ÒÏæŠ&¢žÙN}¢¼¬íò“ýJ±ëÚª •v¥Qoµ89ÔAÊÎæwºÇÝŸ¯~ÎÜnÃÈOµyç–j~}|€ÁÄÌŸß±õŠ1Z뱉ÆŽÒ ÐÑÑA*•š-ËBÛIÒš‰ÅÃëâúª0bgóÛÂñ÷k çPQ?Tfþk=m-ZN· IDATeú1F:±ënÅ5ý÷Õ—Û^è#"—ÚÛ“€t‰çµP&NÍõ 5Æði&TÚµ†” mCùÁÊž©º¶{¦‚›°<|êÒ‰CÓ/;¶.)­dôWDbdÆÃ˜é¬ÃásÃ(¥¸iC%Öóý*¶T­ÆozØßsªä™F,Óà-×Õ28’ãðÙØüV¢-µ® 2v~^êL?¦§j Fª#5ÅL"i;?ã„Ç„¦Ñõb{#v7´í‰Ê‰QJ ”Â4ͱJñèïæ}ÁÓ©ÌŒU®DÊæû»hi ±º&pÅgB¡Øm¤.åÇ’+qLD4h±½9J,iózk{Ï3‘vrœu²ülªX5åˆÙh ÉŒÃOvS_é㺵Ñ+Æx “íÕÍh4gb]%Ÿo ä3¹cK5G/Ĺðÿ³÷f1r¥gšÞóÿg‹}Ë}#3“ûZ¬}aI%µ¤öt«G*aFm¸§á†ö…Çx øÎw¾00¾ðUc cÆèzt{ƨ­–Ô-•öÒR —âVÜrß3–Œ=Nœå÷Å!³Èb&™y˜I+㈳"þ8Œ8ç;ßÿ~ï»úh{àãßÓ‘¿[ü¯wèïáÓv›ŸFi^÷ ASÂ.>¸ë¨@­ÖPUqr¶a×y/Âm"ës ÇðÃÂúuËè¢'¶‡Z©nïa¼7]§í2²>ûà:¾Z¨"x½ ‹ý-àÙÈòMüø¾µùÎz‡Ð)ô÷©T’Xls ½…b‹ÙÕdž“ æmþ½`8ÞE_4Ãí;ò0þášœMah’‹“k»ë®K8Ø ‹• 7"ÉJF+]wí¦RÐrP³kˆ]á©ï í"¢]ÆKê$åî"B@2™X÷߈ùB“w>Zå•C²þ[H!Kõ3ï⹨:ÍPß €ÑÞC¹ÏUiØ»7DoV¸Všã‹Ç鉆 zó•b±ÔbfµÉ‰‘$Ù¤ù@ãV èey¹÷ ß›ú€’.)×24Ž'ð”âý[k¡Öè°E”¢Z«®çOlø+‡—;V™e6Xƒ|Öšˆ£=ÑCo²ˆfÑ*¢âƒ(%’f`½|sªáì£eeð­®@Òäl W@¥‰š.©þðÎD¾‹l,黩ñpÇÛaÏÐ)ô;¬siª‚í*¾|º{ÓÇH)9Ó3 (®g)UØ![ÁS£)Ju‡éÕÆîl,j&¢7ÈjÂÊvôhp2u›ÈÚ,b3=¤í¯Ó—„ôÖ†"7B8Ud}?}¥‡ôæïðhŸ¸ˆlÂÇó5Öê.gÆ3DÍ»oš”Ë!€›åE?ܶ6iðÇose¶Âí¥pv[aººÂÕâ,o¿JÊ çéݰ=®ÎVIFužOoZÇ¥Ì(§»F¹Rœa®Î>T“‚l„}ÝQ®Ï×ÈWÚO%ExO úC†£ ëC#«SˆÍt󾂥j KïMÒ.#Züø@½Ò Zì° OÆ¢ÑhÒj=hy©¸žâGWîŠ0Ú»yq)€#é!z£i~µt oN÷¢IÁ«‡²¸žâ£©ÊîH- 1Þ…*6 b‡NÂUf /s­||{óm]ǃéRpQëæBáµÐÖ®ãÇúQfªsßEÇÙ´Ð/×&–ê æ"ìïblR¬à@j€áD— ÓTf¨c‰Y:_y®›•r›‰¥zèGñQaúÎND–®£¸VwøÍÇE¾|ª‡Þôæ»N–fp$3ˆ@ðQ~*ÔM`ê’/ï¢Öt¹-H›:׉›Ðùdì![ÍÿÉ]ßg¡Ðdr¹Áxü‘^ÕÝÑ$'»ös>?Éš]Ç ÑÕØßc¤;ÊÏ.çq<ç“/ãŒd`f-Ðè‡Z_ ¢½(+ƒ¶vmó]¬ZʈÔãÉwj¾Ó  dG¾³+ˆÍõȾ‚éÕ&ó…&øbQC{h‘‹$øý‘3\ÌO²Ú¬„:Ct'M²—¦+8îΦÁ*Àñ=.¦Ø—ìy¨=îC×QAHÖ{7JüÁ‹½ä’›Î5!鉦9˜`²ºB¾UeóñËÍÞ<Þ…® Þ»YÂÙņ½NëSùëŠt¡¬,záÂwxèIµÑF][ÎÁ‰ç0å!œ*¢]Æß™YÚáb_ ÄP:h…þ\ |+‹ŸG+\D8‘©ù j6¬Vƒ†P ÷+)…¶v|?9ŽêÌsuØ„N¡¿‡›¼¸ÛŽÏ{7K$"úãXÆÃ? #ÊTš\ÈOÒrÃi»S&\Ÿ¯±¼fïìv¼ \ÔdÚáv”4ð£} ôÀaB=b[W)¸UNÞ=wCØ| <­| ?9†2“áÖéðHÄ&WX¥×f«4lŸ/Þ)0F\·xµï0+Í2ÓÕÕЃêBNíO1½Ú`µ¼³ß‰¶çòËÅ«x¾Ïk}‡ÑBÚOºžÏû·Jôe,21㡾ö¦ÔùÖø+[5.¦CíTé˜ÁéÑ4&Êt\w‰‡¸à(~|4¹ö1<ê3n»¨©""i!ºb¡Èdmé¾cP°ƒ…¾.áP7J0Y oÖpG+/Ú„Ûxô0¯çã_X€˜ìx„úxÁÀ²Ÿítô;lJ瓱‡°m›VëÁT»íó«kEö÷ÆØ×³5Í`_,Ãáô ¿YºN-¤TÁÐ%ã}1r ƒ_\¤²ßKCô&‚íØù ¸! }3éAV&nëÑ'p¥PËÕ`[v_&ôEI(­|e&ñメÖèðhjµÚƒÝK¾¿¹^d gÑ›±Lÿ4ºÔH™1F’ÝÁͯ×Õ¹–^8ÁÒ5~üÑêŽv®ßå's—ˆ/ö@†h#*ùj›óeŽ'IDõG®¢IɉÜ>,Mçji.”Ë–`’“û“«mK­Ýâß«ˆ ­öÁ]®À ÕKDØkˆvxÄûïv’ªØ€áLx‡²:ÊÅ˱ƒ¶ÃšDí…¶‡š)…wÛ1’ø‰Qd}Ü-˜>ø *χTøaeß üú8ÊÌ€ 'Åëðù¦Sèï!LÃ| ÝÒWŠºíòÞÍoïÚBÄ|@ÚŒóJß!.g)Ûá†i0Üe¬/ί¯v´Ðw£nWu»h.C6jT|Œxà¶³•EPµ‡Ÿt’VÈmY/ï~|¤sß%â‰ø†AP¥z›ëóUÆúbÄ#Ú#»ÖØIžÊíg²²ÌRc-TÍ ¤àäþÝi“|¸LÓövl|¥l×¹RœápfÁx.TJ¬¯Þ^£Õöxýhc 6²RÁbÒý\)Îâ*/T±¯IÁ`6ÂX_Œ¿?¿L-¬×y‡‡ ¨otó+$èqüØ ¢¹Šp2«t/ž •@¢’Ž„k|(­6‡hWp»žC…œ+Ù¨È,—«Á9;Ô…Là¥ÆPšV¾‰ØÊÜšRÁÍÅj-(ô¥ yðƒy‰æ*^×éŽK[‡ éú{©I4íþ®JÃöøhª‚.'FRĬ­u]bºÉ™®1®Ítm•¦ûàïVÈÄ Þ<žãÂd™JÃÝ1©ÂíÆ*»š,†ìÒ„Ÿ¤× B²¶ŠëÃ\9è`õÄC^ÜTà¾ÓX ,ÛÌÔö×èðH6’îÔm—Ÿ|´JWÒâØðƒþð›aHWz!„àç WCJT aéJ²Zn³´fãïÀwB)EÑ®QsZ<×5z×SüârM|ñD¦þè÷F 0¤ÆT?5§Éte•vHg¢¾L„çÆÒüìRž•µpçœaéŽÒLÜìq¤SE«/°åŠØS0tÊÅÁîðòzÏF6ÁL¡ÌôÎÈTÁ•¥ÃüC†g¹ŽÄÏA(ÿޤi Ÿmx~0°ÑiSXg¢vYÆË Þ›>E§ÐßCøD¯Õ~u­À™±4©˜þH‰Â]t©‘‹$8’âÕ۬Ùá‚lâ–Æs£iOqe¦²#þá¶çp~u‚µÕ|à窵*PFâŽÃIJ½½KµTÛAŒfÃkJ• [éQT¬?Ü6E)°Ûm¼O…\U›.?¿\`¤;Âþ­Û›jBr(3@ÊŒq±ÈwBûÎŒ¥0tÁ­Å­¨”Úu~»|ƒçºFÙŸì µ†¯Õ¦Ël¾ÅÉ})RQcË7AÁt?Én¾?sŽš.Ó"fi<7–fµÒæÆB8_þA,Óz !¤´^ö¢UD4—·¾ž¯P«ÕÀRr$4?B²:ÊÃö£vb‡3j"Ær¨¹2ª6ˆíNÆJ¤ Y›C¸M¶|¤€Õ:”šp¢?´K›ðmduæŽ3Qç:ÑáA:…þ3ÎÝ´Ã{ ø{ïŶ[Øöý]°ù‚ÍÔJ“7Žå6õ ß Cê¼Þ„©ê sµ Òb·€”‚xDçÕÃY~u­@±2¬ä¾R,ÔKL—i-”M¨íX-°,ƒ Qm³Yµa¹†ïM„îdÉÆ2¢]ÁË ·ÀÃó¯H)±,‹l6K4]—ªÅb1Òé4–e­ÿL±³ùfæÎ¬Òm„·™¬;æËˆ¸ )+ôP®p*Èò-üä(h!ýçï%nÂ.¸¹ a¿cRCYY&²rkûÏ/7a¥öX!‹ø^Rì5ƒ¬Ý ëðLÒ)ôŸa\×ebb‚ïÿû\»v Çqð}ŸsçÎñÃþ™™™û‰D°¬O4|m×g±ìÑp‚ˆùíúgºÇ¨»6×׿Cû~G ɛǺ˜Zi0½n°÷. ÅõµyVWWs³«ƒgN Y_ÜþómµZGIƒ©ÀÝ! NÑ\ÁKìG‰Ž³Â#°m›>ø€¿ø‹¿àÇ?þ1¶mãû>õWÅw¾ó®^½Šãu!©TÃø¤˜÷•b¹âQiÁó Éz§»ö#€™ê*nH‰JwÊä^îçW ,ï€DåúÚ<Ë2G2ÃÄp:ÞºíòË«ÆûbŒöm?È-¢™Ë³Ú*3_ ž%… ÑùÚ™^æ MfóÍPzÿ½„išœ>}š?û³?ãÍ7ßÄ4M¤”|ë[ßâí·ßæàÁƒënlJ)ª•êúw!põŽˆ"+Sð0‹á͘+ —\,У‡@´«hùsøÙ£A¾Èc"úˆT$0O°Ã}O•fáe ›+Èæêöp¿Z¼FFFI9!Ý„RS‡Õi„SÝþJÝšr 1š í8!|7èÖøm¼äj''>‡´Ûm®\¹ÂŸÿùŸ£”¢\.sûöm:Ä›o¾I¡PXïà+m»M»ýIhV¡êrs©Å—Nu“Šé¡TWý±,/tàg W¨†”¨èRÒŸ‰5%—¦/ ÊS>— 3d# ²V|SKч¡¬Õ¾ÿá2/ÌГÚ~×P’ñTY+ÎTu…úVÜI6ÀÐ_;ÓK±ÖæÖbmçó7>g˜¦É¡C‡øë¿þk’É$û÷ïgrr’÷ߟl6{_ß´L ã“Ð,_‹c›½!· iÊ=¨J 5»†8Ü:< åJßÁOŒ<^ÓC JC£¾›(=Ž—;¤‡¹Nø µÚ€z;Ðé›aß­x Œ8*Ö·{ÁbžI:UÃ3ŒRŠf³¹~’nµZ(¥p])%®{—¢Z­±¼¼B"Ç0 M¡<¾|<…Óná…<7œNp¡8Ídq‘hvèÎ±ØØv‹fóÑÚG¥ SŒt™Ü˜¯°¯ÐŸÙ¼øÄ"ôþ ŽëûíW 3÷P‹¦iEJ[þ=,+‚'¶t‹ˆ›G7@è‘-¯³þ{¹¥¿?‡9YGÃÁó¶ß9òü*Ê­ rG±Ú H÷þ*Ã0±¬ûƒŸ|_á8í=×íTJáyš¦!„ÀqJ©õŸÝËj>¦it÷t!„ Vká¸>oMàÙuªl¿›.=—#ñ>þù1_XÆJDP¯Õ‘šd«Ý6á:ìë2ùÝõ_:'Ó7tÊñ}f³N­jÞ߉½ó~L×V™«8žÄo¶©º[/H\×Án5©T*\š¨³Xj1˜–øN“jˆúHµÛœí9ÂÒ_t ýg)%===¼÷Þ{ ÝWÔ\¾|™W^yå¾Ç+ 㺮‹‚dDã_ëÆÔÁs]ÂŽÁžéå|~’Vnr(р繸®‹ãl½°ýÊ©n¾÷Á‹Uºâ›»¸®‡ëz¬ÝpmέÜF—’ÑT/†…¦mý#.¥ þ˜&*w­µŠîÖÑ¥$Ìæ—rL¯¡^B&,ô–ÚÖñ¬ãÕÑ«S8}¯! ¿FS÷Ÿš¦!¥üÔÚRÊM?ï†Áøø8ßùÎw8pà•JÏó¸páÙl–^xá=2  10Ø¿.߉Fcü˯[Ä"–e†² LT u¦œ'âãRÃóƒdrkhºåñÚ±þáü seêMnhóéyµZD2I$rÿ ©ë{\Xjª„gJÚi#|é·ÑÊ·PñáN(Êb†”ç<ŠˆfðÖàqš®ÍÅŠƒˆ…”‚×g)Õò•6î6ºŽï1U]E‡3ƒ!^=ÀWpqªL<¢qf,e„¿lºÔ8žÛ‡¡|˜ŸÀ éLÔ•4y~<Í•ÙêŽ8u°í]šíq=ÔÍ<ÂÔÃwÎa!ÃeåJ¡Œäö†r5 ]wv×–'‡Aà%ö!<Y›Ç*ô_á/Vñ]_:|x–SC«Náw®î¡Sèï!,ËÂ4wÇcw(‘ã`ºŸß.ßÀöœP !àäþ ÷ƒ[¥m5•vƒ÷Vnr ÕOw4…!Ãmã++ƒŸØ‡¶vá»^ ÕfXÒ`4ÙC_4Ã{Ë7©9á^'7xn,Å\¡Éôjƒö<õŠ[•EÖÚu^ì=ˆÆÙp•†éC(Y_€©¦!'Jh3Ï ‹òÐJ×P‘Þ;Ýš‡Âi·Q;øïüig†H™1~»|ƒvH‰J:fpl$ɕ٠3«-Óù*Žkyc©>,-\áÐl+þö\™ ô‡°UÜCèŽöPk·Xj¬…’ïSã+§{¹:S%_y¼TíÁÜ“i˜ˆ]´ U+Õ`w,^¢â6‚b6>¼õ€(!}IÐ%ªÐôù!PÒ ’z+ÈæJ¨56<<_)´Á2©Hè÷ÏA+^ÁO !‹ö^ n6B Œ8~|­>‡´‹¡Öx(®‹°ôའƒònÑX@™YüXl#$¯ÃçN¡¿‡H&“Äb»7œ#…$nDx­ï×׿Xn†ÛJš§FS˜†àüD™ê&ˆ EÓkóëåëôDÓ 'ºÂ¸Î3Ö‹Ñ:!»B¡Åâ@Wè.€¬NrðRc÷ÇdcÏð%IòJï!n——XÙ¹ŽZ_>Õï+>¸µöP¾Bq)?ÍH¢›´’µTçâT™·_î"Ûyy“&5ã9âz„óù ÜÃïBÀÇrDMÉÏ.åi¶;žú¡QŠF}ƒl‰¦Ñ†©ª'ñm´ÒU”ø©ñ‡7=Aƒ¥Ô€†:$Ëö¢’ûH–Ï!½]˜wó¬5ƒÎþH&´Ÿ>€V¾ðÛøÙc(¹;n{ž :UB‡E Á›ýG)µ|¼.(Hˆ_{®—o¯±PÜø„êø— 3x¾ÇÑìѰÞùÒÀOÂÄ&â•vt÷>jºœÀ#FøP”VQ_ÄÏ„óžDï7iDx{üU–½*3v1¤£~à2óÒÁ,·—êØŽ¿A±Òö\n¬-Rj×9Ý5>¶A)n-Ö©Ô÷<–”zS‚ˆfòjß!ÖìWг8!¥Mûz¢Iòþ­õV§Ð,žÄ&aËE]XÀŽKÚ™ÇÈA¡U&QÑ^ÆÆÅ¾.½ÉÀÉf.Üv€@EûF” y´í&òn N½BÌäFaw[D}/5Þ ÏÚãt ý=„çy»;dHÒý¤"qnµVhyᤠ†&8{¬‹zËãüDyâÆñ\Þ[¹IÊŒq43ºs‰4ð2GÑZËH{熫à®6µå"öeBWOÂm ÕfQF ?Ö’!­Ø>ÇøþýZmß÷×ÿÜE)pÚí]ï^ššÎxª®XšÉÚ*Žç….ö_: Öþæã"­ ©š^›¿|žHй‘P¯¡”¢íøœŸ(3Ò!j<ÖüøC‘BpvàŽïq~u2ô C<¢óÖ‰n&–ê”jmœ]°L}Ö¹›ž~ïß?ý3î¸îìö.®Ê×pjM¼Ü‡™Å¾¬N€/}6:œ€šZ|´ìmcH/9Š´‹è8ˆÝj(· %b8|W_xvàÒíEéqT§)´géúÏ0J)šÍ&ù|žr¹ŒãAU+++¬¬¬Ðh4î{|³ÙÄqv×kZAO4Íhº¢Û`©þp™Áfhšäèp‚xDãÚ\•Jóþ_)®Ío–®ó\÷}!E:ÊHâ'†‘¥ëà† QÙŠ`Ûx¡ã] ¹ê»»ˆ°×ðÒG@vº5wQJáyù|žB¡°~c[,™››£^¯ßs °í6þ.…w=õOuïg¢²LÅÙšEæFJp°?Î_¾3CmGªB«Êf/p0=ÀÁô@¨×ð|¸½Tg±Ôâä¾ä®ŽH#ñ.¦ûùpõV¶bK— uEéI[œŸ(Ó´;]ý{‘R’ÍfÉd2ë.Sétšþþ~b±Øz±/‚w½Ð‡@«?·†êŽ3!?h²¾ˆh,ã|qã|‘¸‰8Ö «µàO„ òK¬ ²>·óC¸÷¢@•Á±îÏBØ$jßE¶Kˆv%pßéÈwö,BÿÄ÷}\×¥Õjqûöm.\¸Àûï¿OµZÅ÷}~øÃråÊòùû‡J‰‘Èî-iBòRÏ\ßãJi6T÷RŠÀ?üÕÃY–×l¦Wï¿iiû.•e–kœé%c…óøVz/{ á4EDȈ-ÓrP·òЗ ÜwB^ÜD»Š¬Ná¥ÆQzô‰HPž<Ï£X,òî»ïòÎ;ï°²²‚ïûüüç?gmm ¥Ôz¡/„ ‘ˆ£í¢½æ]„œÎâ)Ÿ÷–o†–¨t§,Ž %¹<]a¾ÐºOj¬P,Ö‹ÔœDzÃè!w¸šm¿úé,ɨÎïîAÛåïˆnòRÏ&++”ì:^È÷&ÓyëD?½”gµÒ Ϻ‹¦id³Y^zé%Ξ=KWWB^}õUR©Ô}E½jõÚ®ïü®3_AhFsá;×N ÙXÄOŽ<˜+€t$¸‘Xª†Öæ+iàö½‰p›hÅ«ìºèÏñ`º„芒£°Z}·‰\û/{e>F†K‡gšÝ¿ÂuØq–——™››£Ùl²¼¼ÌÙ³g™™™¡P(N§±,‹B¡@ooï}Ï»+ÝÑu}×;6ã©>ú£Y~2w‰¯ ?‡rïÿõ#]|x»Ì/.çynô‚J»Á¯¯q,7LO$Z¶£¬,~ú Zñ2Âk±û'pfJ߇Áj¹tù·‰ðȵk¸ý¯ãÖ(µwÝwÇammb±ˆïûÌÎÎ2>>N>ŸgnnŽþþ~t]guu˲E×u|ß§X*aE,âñR |ϧÑlàº.ŽãÜ/kx ”òéU¢žäûÓò|zI=jýÑn Cƒ · Œd%–¦°[M–ËE>Zb_¬‹=I£^ßö¤RŠù¢ÍÅ©2_8š¦+¦(æ[Ôë cçŠgß÷i6蚆Ô4zµû£]üÝÔû|käe2æöoÜ•ëqlÐäûØ\š.sl$s§æ Þ)eúª}þ% º®“J¥Èd2H)`ff†\.G?«««ø¾OWWívÛ¶ñ!»ï+åÓ~òÅO—N¡ÿ ’Éd0 Û¶i4 ===äóyŽ?N¹\æÖ­[œ8qbýyËË+”Šktug‰D"­V ß÷i4;ºEo· ú1.”'øÝäeƽ¡k-å2”üøâ2x*J<¢Ñ¨×˜hæ9¿|›³=‡iW¬¶îO(,•J$“Ir¹Íx”Ðh¦R‰dÉ–Þ%‘Œ!”I$Îwüa˜¦…”˲PšÄž®áìï"^ô‘ËÛ— )JWäÛìØ>’]yDûý©çyT«•=q÷}ŸJ¥Âüüüºæ¸ÑhàyñxœV«Å«¯¾ÊÂÂ×®]cdd]×QJ±VZ#±Ð4‰&%¾\øPà{ÞÎú(b®d4ÒÅß®\äVažÃéAŒºÙlTðÅã9>š,qfŸÅHΤí8*5Î-ßâë#/`)ÊJ·åø\*Óv<^>DymÇ¡mÛøÞÎÉaü;†mÛHM#­Ex!7ÊßÍžçLb„ãé¡k*ƺMâ–ÆÕ¹&åZËÐîÔúMJ co̳H)I&“ôõõ­ïbE£mf³ÙÄ4MΟ?O__`qqïÎç=›ÍÐl¶pß÷B`&Bˆ; ¢j†âžN³ä`Ocôe+õ  ²M\ÕÄX»ŽHíC·g1œºn`Ä´÷çWV0|‰4·/_QÒ FH«>‰iHt]¿sÓ¸s 3!‚ϧišÁ<‘­pæ*È}˜K-´¥íËŽß)ÐôlÚ‘â‘8B¹€B©OÔ{á:±—éúÏ Ñh”h4Šç'âééiº»»Éd2¬­­­wgžþùûž—ËeéééÁ0 4-(ˆî<±X|ÇŠ Ûƒõzš³|Pžâ`Ï©Èöã¸IÅ©1Åïn׸W¼r8IÓi‘¯7(;M¾8rоD7¦¼ÿ£œJ¥¨×ëÔjÕM×VV[ï†fžVqaH!h6›>',–å iF¤ÀûØC¼5N½Û@LÖBm)+Ùã#ZÉaüFÙúäwÝK'nÓ4cÿþýÁ i»Í_þå_ÒÝÝÍÉ“'y÷Ýw™šš¢Õjñå/y]£¬icc£ öcB<ÏÃl˜˜¦…iš;ØÑWH)yMãg•[L¹kœN"enßî6‘òù゙à¿ý?/²TÓ8u K˶ù°¼DÉkòµñè¹ËµPlòÁô gwsr¼—LBÒh4Hg2˜!ФÍn¢$©dM×I*Ÿ×t¿™ù-Ón‰7²'·ýÞ+éŒÏÙUn-Ö©ûQzÒqô{¬lwò÷YÆqfgg™ŸŸÀ0 ¾ýíoS,¹qã/½ôÃÃÃX–Åo~ó›u©ŽçyLNN±¸¸ÜðRjD#ŽÓÆqíè+ßÇ»íáE©§%jº­;G¢õ yì¿Âõ•iLÓ¢ÑʼnÔå9Zµv(m½²²8¹}Pú˜fqϯF©V+;:ó&¥D)Ÿz­Žçy( ¸å žï£–’p£îKTPñë4b}¸¶†hïs–ëÌ}þéúÏ0š¦122ÂÈÈ'î]]›w°-Ë"™LÜ·uíº.J©×î+¥Nuóš:Ì;s—x[¼aÈÅDZ‘4ýÙ(¿¹Yå¥#=Tis®4ÅÑÜ0ãÙ~¢úƒÃ¨š¦}ÒÝ/žÃ5rh+ïãÚM\©B<ô9a‘òSdzè"j-芢tIJoá"óóK´ÛuÜ]8îg!Ä=ÝÆà‚ù'ò'†a¼ñƼøâ‹!ˆF£ë7·wŸ+…\n°–\_s' C!}±4ÿdüU~6…Wú‘²âÛ61t¾l„Þ´Å…© _>ÕEÕkñ«¥kH÷“6ãè!r”‚¹‚͹‰2ÿó?=B&a „¤Üá÷âÎÎËÝÿBc8ÙÍÉ®ýÜ,/±Ø,1Ëmë5…]HÞ~¥ë³%ú24mgûYánÿî ¿RŠï~÷»¸®‹ëºœ;wŽK—.¡”Zo Ý}Ÿî>ïîw$XË__s' C¥TZ¨óóˆÃ=¨©4CœÇ”‡h—¡]Á‹ïC_»ŠgIÔ.T¾Žj:ªùÈv¼Ä(ÆÔwN%ƒnøn¼ëÿnÊÀ÷¾ ½ T*åfˆbßÃ(|ˆî Ñn—ï¼â~/ÑÆÝC4MZ­Ö{½´çKƒ'™¯¹Vš£å…ë~ôf,Þ:ÑÍ;å©5]>®/“o×øÃý/ Ë°÷ª/{ü6²:Í?ñ9Ü.@Ô@ô'ÃYË)i‰·çÑýß…xVÑ4\.G2™$‰ÇÉård³díÞù”z£÷w?’F”7ú±Úªp¥8‹ëo_w+˜ºäÌXš+ÓUf u>(MQu[¼Þ3„DNm×çç—óD q¢»až¿ B"šÁÛc¯²P/rcm?Ô¿`¸+«¤bÁ]‡ S_.—×ÓÑår™J¥‚mÛ÷íÆcñ'ãºse»¨ÛH˜ˆ°¾ñ ”‡¬Nã'†ñ£9ìá$~D γaµ¤ŽŸ=¾ƒl®€ÿ›) p<Ô…HG½‰pæ J¡ÙEb „Û¤Säï=:…þ"‹>×»hB’‹$ykð8ïÌ]d©.)7Ñyãh]ƒÿ÷ƒ)~6{‹t$ΙîñpÎ"BâGûP‘¢±Œl‡;®ÇEÍ•¡Þ†£}<™”šŸ&ï¨ÎöQhR’±bLõóÛ¥TVhWª7uaè‚û“ ¾·p…¡T7¿?ò\¸Át Å—g*œØ—$}ò›½ºÔÖ´Þ]¼Ú‚´Ãc µZíÉJÿ|MµZl‡#zÈÓ¡\»ÊÃÙw–ú‘.¼b um9¤ÛŽ@™üø0²6î.$á> O!_Mvu.BÑ)ô÷÷ÊžÝä+çYj¬qµ8‹"uVÓ™„Áö|/?ºy“¥z™×û6cá¶å…ÄK@Zù¨§ä¹]³Q èOB6º{©D>SD4“¯Œ^ ºú»Cw®e}٘Çtu#8…AHÜîçPÒ@_ù- –­JAÛ…ÅJ°Û7AëTû¶G§²ØCÜÕg>IL©q¦{Œ˜nqµ4KÙ'1‰Y_{¡‹jbš¨28‘ ·-/$JâåN"ë Èær¨ãÙÚ¬Ô‚ÿé ;<1”×óP!½µÃ¢KWz7"¼»ø1M·½íb_‰ˆÎ—ΤðÓ tË,cñÁP30ž¯¨6>¼]f´/Ɖ‘$ún@,fHcÙaF”¿Ÿ½@ÝyrRÃîDºöäç<…š*‚íÁ®à\æôîÙhõÐ{ he+v¸p+!Qz?9†l­"ëó÷ °>Q|…Z¬¢Z.âx˜ÑÊÛ£Sèï!<Ïâ…¾’”ã«#§™®®r»²Nª Ñt+[Á]Ëâ5Ã¥Á*i⥃•A«ÜF8!“wŠR¦Šˆ“ý{Œ`”!P4M¼´Ü šd­_8Æ\½À\­€bWIn¤Blhµ:v¸ïDÛõ¹8U¦XmóÕÓ=ºÜÕ4ÜGq$3È‹=ã|wòwLUW;ž'ˆbÑØ“ÏP*ȹ•Gd£ÁgÈ›M™h¢wÏá.  B~':~b?ÊH ¯ÜÙõ}ŠŸÃ•*Ì®!ž„®Xè Å{“N¡¿‡°,Ë yâ{L^ë;BD3øÿ¦ÞÇñ¼mûu·Å¦Ïñä—“¼sq-”ã2Ó¸}¯#K#‹OO¶s—zuy t Ž÷A¬Sþ¤BBɸñrïAz#i¾?ý!•ööwº<ßã·Ë×qX˜òëke¼mîN(`.ßä_ý?7ù½Ó=¼t(³íãØiF”¯?GÛsyå&Uç)h£÷( ¨×kxO¸!´þúÓ%TÕaæD¤@Œe»9Œ›< !v¹üHgÿ¡¯ +Û?ަ峚DìÏs :l‘N¡¿ÇxZVs}±4/÷bººÊÏ®`{[¿8¾GÑ®ñÓùK|ëè^äÒT…[‹õm6ÊHàe£Œ8úÊ{O¿›ÁX£úpq¨1|ìn–'öê¿ õö¿#ó§?$ó§?$õö¿#öÊ–Û¡öQ*p#yZ>ÒÝ‘_9Íϯp­4‡½ W*_ù\ÈOr³¼ÀלæõÑ^~òÑ*7jÛê€W?¾¸J³ísöXŽtìéJéRÒMó_ú¬ÞæVyñiÒžBjOAºs—š ×V‡ºƒÙ%}%Š0œ¾$\›Å,΢²'ñcýlG¤ôhàȦ™hå›ï3p£é+¨Ú¨÷g£9DÏö“£;ì]:…þ¶í]ñˆß Íäõþ#JðoÿšÕfg‹ƒvKÿiⷤ̿·ï8_:œ£í8üä£<Ž»U>ÄË@Ï_@Ø%am¸+´=¸¾ ]f!¹Å®¾Ññ¢:¾.A3ˆ½ö?’úÆ¿Å:öOÐ2£=‚Ð#h™Q¬ãÿ”Ô7þ/b¯ý Ÿ~A÷Y Ý¶QOI{›4£¼Ôs‘D7ß›ú€¹ZaKŸeOùÔ]›ïM þóC¯ñ§2ÔmþþÜ mWmY–|}®Æû·ÖøÚ™^ÆzchŸéXT7ùêÈsÄu‹ÿûֻԜ֖ù•R4<›ºkãª0,ËD<… è\Ï” ØDœ$<[A 05Äé~Ä…R•«H#‚—; Rg«Å¾ÄO£.!Z«OO›ÿiÚêã”í‹#`é[k 25”©u¤¡{”N¡¿‡xâºËO1Ïò±WÈ·ªüýÌù-ÉjN“ß._çÃÕ þøàYz")õFxa,Éß}°ÄÄr»ýè¥Çð2GAhhùsOÇAa3|åVà—Ü—DìË>ú„,Xî¡v2‹üêÿ†uô›ߪëè·H~í_íùb_ˆÅž‚ùº¢IþÅ©?dªºÊ÷¦?Àó-k«;6¿\¸Ê¥Â_}‰ÑT7'†¢œMòË«–J-Ü-ø†ûJñ½–hÚÿòã¤ãŸÏƒ&5º#)Þè?ÊL-ÏOç/ÑrÞ¤P(ßå³çù×·ßa¡^ ‚‡:l‹FýÉÏ­ÜG­ÿ³[ˆ\qj 8>ª>5µ``(º´¥:‘æ"zc/sef¶(áxÝgPÒĘý!Âý 哸w‚o¹(âHl%ëB¨½ÔÞ„t¤SìïA:…þB×u ãé]ÌM©³/ÑÍ7Ç^æ3ç¹±¶ðÐ.RŠ‹ù)~<û§sûùúþ‰º’&_<ÑE*fð¿÷ó…þÃ$°ëÑtÛÌÖòüõ_r85À»“0"O·`ý !„@Ó4¤”ëièºþ@¶J2™xây+÷¡ÏGÝÌÃZëιÐÜX¯/dcÁðnÛE}´Uû“ÿÝÊ£/ýíÁ8‹oeÙh{@i¼øÎðW;Íò­Ýûý—Zun‘Œò¦„\>ýkäbˆ—F+5¬‰2Øn'wÒ)ôŸq|ßgyy™µµ ÝU)Åòò2«««Ôëõûf=]ùŽvÇnóŸ~‹¥F‰¿¼öçVoÓò>ño¹mæjþý_à)Ÿ?}‘žhzý<&DLCƒ þùŽqs±ÆúÍ‹¥û=·•‘ÀÍÄùGÁ ÿ³2€»¾‚¹5øpºbˆ/€¾ÄýþúBüÿì½y˜\Uÿÿº[íU½ïK’Nwg'!, ¨à¨ ƒ€£<:êèügF‡þF¾³øw˜qTœyüႎ£‚2(B$B’°„NHBÒIï{wíË]~Ü®JUÒÙoÓÎy=O=U÷Ö­Ï=÷Ö=÷¾Ïç|Îç@méŠ:¬±$ÖÎ([wvÝÒ–‰¥ç#IÆÕòçcб,‹ÑÑQs3|öôôpôèQ‰Äq¡/AQ(„r:oáÛÄÜ¢6Ô/eÿH?}óO¼5ÖK~„¹e™D2I~qèE‡ûø—•¢Ò[T d]ªÌâY!þá¶yìnãGÏÃ0 ãõ Ób˾!¾ñøA;¾msª§ïÀ>MVh Vð±…7ð|×¾µû):£ƒ' 8~k¬—ïí}MQ¹»u=õþò)*ñôD’$B¡%%%9_YYI]]縰·,ÆÆÂSº“e fO¢UDZÕþB1;>FIZQTîÇ|²Íùù—†©#G;ÑÚŸÀ 4¢×\sò½R’0‹ZÉ̲ï…jßväDÿ¤Þyc˜0Ç|ñÒ¼J¤ë›í± '6j+H×4ib½t id *L "GÓEˆa¤R)’É$†a°sçN‚Á k×®%‹±cÇR©Ë–-£¹¹9÷;MÓд©ÿËUYfyECÉ0ìÞËÿ·o#×Ö.æ²²Ù$ôG#¼6x„Cc½ÜѲ–Å¥³pÉ…å–¯KáÚÅåô¤øÃë¨/t±¨1Hȧ10dñ4£W#§†Q»ÿˆœš>pOE<ƒuxÉ´`y=ÒêYXm}öÌ£"y5{r-YÆÚv¨µ¸ IDAT†ãXe—Ѭ•Ž}îïAVÞôíÜz­ö fÂíß²,R©–eaš&¯¿þ:²,³|ùr‰mmmƒAFFF¸ì²ËP§(¥æ©€åMüã•·óTûËüûëOqyùÞ=k9q=ͶÞ7yuð0ÃÉ(·ÌYI¿ E:¹âReV¶–p×úz~½­‡ÿ÷—o²tNˆÙ•~B>•§wõ±¥mˆE !>tM=ÞiëÍÏâQ\\S³ˆ"ÍÏ£‡·òÀk¿á#ó¯£Ô` ¦=ÒÏ‹½ûI:ÿ×’÷Pé-"“m¸ÝîÜŒèóçÏÇ4MÞxã <---D£QŠŠŠØ¿ÿô÷'`uŒÂSûà²j¤ë[ cko/h RS4#ù]X»»a$a‡ìœdDG ¿…Õ»½ò Ò³oA‰CJ éIô²¥%óc¨½ÛìçÄt'cÀÁAÌxÆnèÜÐb?âiº‘JýÐ\†¤ÈX›Þ‚HÜž©.µ`Š˜^O;ÁYaàÈ‘#ƒAªªªH$d2Ž=Juu5²,sàÀ¡oétE‘sq˜ÙPÃ0íæ6M3÷šŸââÝ+XP\Ï“í;ùAÛ˜STI4“$œŠÓ\TÃ=ó®ãòŠ&Bš·ÀNÖ®e™¸U‰÷]YI"áþÔÉ/I”ø]d2i†½ Pû_FëÞ„¤Çó´“°H’Œ,K“ÒmmÛ=KÛ) C,ƒ´nÖ5s!™AòºìüÉá$ÖÖ£H]a@oYÁÏÍp'éöMxÝŠ6.ò?>tˆÀuÿRX®@•ƒG9µ´µµ‘L& ƒ444ÐÝÝM&“¡¿¿Ÿ’’B¡ííí¹kÉ4-Âá0€Ÿß‡,K†I:Î9Çœª–™Lf¼¦&ÜÆeɬ,›K©êç©£»ØÜµ—£Ý„Óq Ó TósgÓÕ,+Ÿ†>.Ìì‰ð2d2idYB•àêy!Gã<ÿÆ ov…QÇëü`8ÅÊæ">´¶ŠYe2:éô©¿™ŒŽ®gH§ÓŽŽe0M“L&M:BQÔ3žg—%³¤¸ÏÜkøñ››xhÏ3¸d˲ÐMM’ùȼëiöWbFÎöq¤‚ð•KI’hiiÁår‹Åèî²MÓ(++cllŒh4J}}=²,ÛÏY& F‰Å㘦…,˨šf;Ê%»$IBÕ4dÃ<õØ1S‚caHHKj0[+1*H>²$#'2°««sdÅ~²¬äƤÙYµ,ÔèAtO½df ËãsqEãÜŽ¤ƒbrê±lªª¢* ªêìx7Y–QU MÓeùÌsÍôÄ`G¬nĸv.&’"#›Øâ0‰*+9ÛùdŸýS9NI0ù¡âr¹¸ì²ËX²d ‡"‹‰DP…®®.<>Ÿ¯àw=ݽ  Q^^Š×çE’$’É$–e’L:ëK§Sã¶O)Aãöš+Y¨gWø(媟%ÁzüåÈ’D&’`0RèsŽDÂ¸Ý b1{ò/ ¸eY€ ó›éNÐ3’áÍcƒl=¸ wd’_ŠNÞù ¸\¶÷Ëår~R1—Ë…,+hÚ9LˆóÅ^’5^$EÆ“°F“KCÆ„â{;I*x$È©A´C¿">°ÏU÷{þÆEþ?¡5¬qô¸¦躎ªª¤Ói4MË]ƒ]]](Š‚×ëÍ5hMÓ ãX'º®SS[…¢¨˜¦A2™$¶ŠN5~-Ë"¢(g™õjˆÌ^ËþŠ^¶ `~q-—5Ðä©@‘d$"‘Hn{Ã0‰Åbhš–ƒãSàƒ+K¸vQ}aƒÞÑ ƒ‘ ÕEWÎñPä3ˆÅ"§*B]׉ÇãD"Gò›¦™ -TÎ!o{£VħZo`Óà~<ŠF¥;D•;D¥+H@q‹ÆÐuD"†¢>ÞE!^2B »»EQÐu—Ë•{¨ªªÂ4Í‚û´"Ë44ØÂ¿»»Ý0e·ÛžÉ ëºc!ÞÙYxMÓ¯Éb<ûÖÙa[:ˆ7!é&r$É Åt”” ^ª¢âñz {m, Ã4‰Çãç0¯àâCý‹”ü‡Uee%.—‹T*EUUº®“N§imm-øMUuÕÕU¨ªíÕÊÆ2[”––8Z¾h4Ša˜ŸñÁjaQ^VÎrs> 2nYE;ÍX‚T2…×㣨¸P¼—[P_c¢ÐRf²ûéÃôŽ p¶£ŠŠŠPd™pxÌqGII1’$366zN¿³"ôJX’Dz|–•;$E‘ %‡1üµÇT± cÉ'Hoû&éÇ>„e™ã"ÿê“ì›Ñ¾ 8ªéƒ$I”––bYvd2I}}=’$QTTÄœ9sfÙ²e¹¿¢(´´6S[W“›1:Nc&@  Qp¡X–E*™FQŠ‹Ï\×BX”•”±¼¦MVìס:`‹ñ®®.¼^¡Pèø>²R˜kZ–݃¡ÈšÂYgØI&“ôt÷ †ðxœëú7 ƒd2…ÏëÏ9ΖbJh(¯ÉeæQ%E’ÆÕb2‘ •Jtž%Éîµ»TÈÞß³çÖãñÐ×g×÷X,FGG%%%ìÝ»—L&ƒ$Iè†ÁÁƒ‡èîé&•²{q\.š¦’H&H&“y½«ß[Oµþ„­$)'>ÃápÁo$I:ù,K0&a¶€i‘4LR†•;¾üí5U£¾®–ÁÁ‘paÙ¤Q,d@F‘$,Ë$†‰„yÒ>írPP6ǃ˥Ç&pݱODÖ‘J§H$§ì Ÿh_VDÂE®çºiÙÏ Ë>?·×C8@¦{ׄë/Fò”>ŸÇ“;WeeeöÏãÉ Y³½á™Œžû ÓéƒC`w€Od¡ëv—K#{-gë„Ûã.änfE¬ÿ¸wв,‘(ÁP°ÀF,Ççó”ß4 âñþ€I²0Ð1°ð–iâÎÝ™L†žî>ªªª z£LÓ$‰ dÀ€D2CF×ñz=w¥Z$â 4—+ï¾a‰D¤¡±‘|·«®ë躎Çí΋o²H§ì:+çê¬}î,ËBSOðc:CHŒ‡Ž»eYdÒ\/Ë"“ÑQÔãa7Êø¶‰d¯×‹ž·m"‘¤»«—òòм«Ã²Ëëñäu—ù÷ DÂêÙûîÈÈííí¤R)LÓk’ÆŸǯs—ËEEEyîo6MÓ»Q$I&“Éäê™,Ëx<R©T÷Øö‚»‰ÅŽgG“$‰¢P ‹X,V`ÃçóÇ Ê¯( >Ÿ—h4†%[v*-Û[*ˆnMÓ¨­­e`p€tæx¦9Y– D£Ñ<Û šæ±3y÷WI¯×G:.ð܃Aªª+éêî*8×v¨J2™Ê³!åzR²çC’W“ì’ñmUE¡²²I²_ÙòɲŒ¦i¤RyÙ„$ MÓ0 #ïY%I¿‡D"Q¸Î㡾¾–áá¡‚õªª’L& l fBèO3B‰pÒ®ø¦uvs[œØ¥>Ñ@C—¦‹ÆˆEã¹çµeZD¢$$¢yzLÓ$‹øsfË´ˆÇãøü¾“„~4µyÙKñÑXŒ£íÇó à Jãñz „~<Ççõ!eزH&ShšvRV”±±1‰DA™ Ý ‹(èè褡¾, Ÿ¿ð¡!!áö¸1tƒL^Îò` €¢(hšVð€q»ÝXã ,ЬàóûˆF¢±”``¼;ôøƒ®¸Èî}PNøo\.’$‘N¥rV²±¥ù]ê²$ÛÇ‹ç&’™`zCÖꓲIH×QÔx§Ä2I|z¯JKËrå y¦ÇpÍs™ØJ–åá|b‘$ E–‰Å¢tuê9aªg2$“Iú³¯Çq¡  jêñÐÃÌ5PeYÉÕ+=“!•Jã÷ûŽ‹`Ë"<F–e:ŽuæÖ›†‘úù×¹žÑI$þ‚YJSI{Î¯ïøŒ¡†®£j½=½„Ñ‚õ‘H”P(˜'¼!J‘Éè'•/‹£iÚq‘mA:“FU5º»º Ö™L=“)lø×9ßÉ`YöX˲CtÆÅ4 Ý`ppˆH$b¯·,LÓŽÖ\Çÿ/»‘](ôÁ¾O¥ÓiµkYCCCôôô06æüÀÖ±±1FFFµ öX‡òòrŠ‹‹µ+Ë2åååTTTà÷;39‘Ûí¦´´”@ @EEå¥EXÛþ…Ô¾Ç9í´í–Ij߯ˆnü¿O;§ÀHññ˜þükr*ñz½Ùf&ƒd2Iww7ÃÃÃŽfÔÈŒž”T•±XÌñº–͸“hÌIâñ8íííô÷÷;&ÈÒé4ÃÃÃ$“Ib±]]]D£Ñ‚‡ !‰àõzϼáÛˆ×ëeÍšÉͤåv»©ªª²“8Øp’$‰`0Hqq±£®À¾çz½^‚Á £v³áCõõõŽ \ÇC]]¥¥¥ŽyÉ5M£¨¨·Û×륺ºŸÏç˜ý5kÖL»:!8™éáªäXßêÎÅéo;œ¦wÌ ºhr¼uo¾ù&hšÆ»ßýnÇ\.óçÏψa)èîîfßKß"õæ¸ZÞƒV{r 3ÚK¦{'郿=e¸N–ënâ0u€Ÿ¿¾uzxlÜn7¦iæRhNÏ?ÿÌÚµk©««sìR©›7ofpp;ï¼Ó116::ÊŽ;ðù|¸\.Ç©/¾ø"½½½d2Þ÷¾÷QYYyAö,Ëb``€ŸýìgÜrË-´··FéïïçöÛo§´´ô‚ìëº =ݼ—n·›Y³fqã7òÌ3ÏLÊ>®ºê*¡PˆÇÜ‘ûW–9sæÐØØÈ®]»èííu¬Ñ§i«V­¢¸¸˜ßüæ7Ž5€C¡K—.%‘HN§m_qÅTTT i7n¼àp,I’(++ãæ›oæ¹çž£¾¾ŸÏGyy9O?ýô?ãn¼ñFfÍš5íê„àd„GòþËgëøæs“çÁìèè ¶¶–±±1G½Œ²,ÓÔÔDCCƒcÞ4°æ=== §ït¶kvÅŠTWW;ê¡ÈfGÈfBr*y*•¢³³“úúzâñ8]]],\¸c´ÄÎï~âFÿû&Fÿû&ÂOÜCbçCgùñ¹wç>ç_‹ÓP(4)½9YúûûY¾|yÁà;§hjj"  …kT§R)º»»ñûýäÏì9r„ÑÑQǾY‚Á ÄãqGêDÖ;¼téR$I"•J±nÝ:b±˜#÷‰‘‘‘‚AÓ‰P(ÄwÜ1iöËÊÊØ»wï¤4®;::ˆF£D£QÇ®[—ËEUUñx<7€SަÒÒR…BŽ:ÀvbÕÖÖâñxéMÌÎݱoß¾\šÔ;wâõz¹ÿÜqÇÓ¶N BrçJ_.ÓɶÃižÙ;9Ó¹[–Åðð0©TÊñ®Ó={öpðàAš››µ{àÀéïïŸÀ¹P…x<αcǨ©©q̦¢(TUUÑÕÕE8¦¶¶öÌ?: ì<äI‰UUU”••碾0ÖÜþzó¼ùw®œ^B?Û`rÒ«x¢ýx<Žßïw<&ýÀÇcô;;; ‡ÃŒ9r dq»ÝTWWÓÔÔd§‘up8ÌÚµk©¯¯w,Ëår …p»Ý¸\®ñY,Pc±X.ÇùtÄëõÒÜÜ̽÷Þ;)öíÌRvÊF§cÇçÌ™C,sKköž«(JÁ$XN½V³çÙ‰^ŽlÊÝljØl¹³uû\¹÷Þ{¹é¦›¦¼N(ŠÂ–-[N»ÍÚµk'ü\.×UÀ`zÞ»9þÙÌ{å‹þì2yËä­;qy¢Æ§Xw.ߟ3b0î4æsïIZ<·ÏÝùÒÓa6îKòùw ëT¼ø‰H’ähwé‰LÖ@L§Å}>Ng-ñ‰„Æg(=_V¬»‰øÜ»Ù?®ðŽži-òÁöèTUU1<’$Mz7÷¹Šüü”{ùd ÙIÇ&£¾MÆyÎ6¢àøl¢çƒ®ëŒŒŒäÂî.²uâæ›ofáÂ…üüç?wd€îdÞ§ÛŒ¬gšÀ‰{î©Èd2ŽŸëüt©bÿÆoäŽ;î ¹¹ù‚¶ Þ~„ПæüÓûB=Rγ¿ípšþ×kš\Ü~…ùÕ*·|V3è ¥¥eÔÌj¦hÖ FНÎe×É2Ý=ù'RZZJ"‘`hhY– ƒŽyˆg2Ù—ËU ä³ÞDUU/©s˜e7‰`š&¡Pè¢?.--eÉ’%Ìš5‹;mÛ¶ñÚk¯qèÐ!G&Öš©d3¤e{›ò׫ªŠa—̼,eee477³lÙ2Ö¬YìY³.ê:q©#Bw.žÚ“ä»›"„“Ó»kSpqòH|æº ï]â\hØÛM*•"‘HJ¥ïVÌ\²áoÙ\ã3)] ¨‚óaº× ºsnþEÂ{—x¸¶ÕÍÏvÄyüÕ¸üGy$Þ¹;Wú¸/în!·Û=íHÁT"ê„@ Bÿ""à–øÄ:?ŸXççORì:šf¯Nçˆ.„¿à¬y$êKTæW«\1Ë5m&Ã@à@à‚lÿð‡?ä_ÿõ_*©@ðöðì³Ï²hÑ"¶nÝJ:ž²r\sÍ5Ì›7/·,ê“à|˜É×ó>ð6nÜÈoû[î¿ÿ~JJJ¸çž{xî¹ç.´¸£¨S]Á¥Ë¾}ûèèèà‘GAQJKK nÈÁ¥B&“áü#ßúÖ·ø›¿ù¶oßÎ5×\3%eùÔ§>5%ûÌfúõìr¹r©ââb–.]JUU>ø «W¯& :¾Oà|}Á”aétšÞÞÞ ¿ÿâ¿x’×å'?ù ÷Þ{/Û·oçž{îáÚk¯å¶Ûn㡇à§?ý)?üáyî¹ç¸úê«ùÆ7¾ØžoûÛÜzë­ÜtÓM|å+_!‘HälßsÏ=üð‡?䓟ü$×_=ýèGÙ·o¿üå/¹ë®»¸þúë¹÷Þ{ŒÓ!¸ÄÙ¾};EEE,\¸µkײiÓ¦‚ï Ãà{ßû·Þz+7ß|3<ð@î»üÇ,H§Ó¬^½šÿ÷Ï­K$¬]»–£Gò­o}‹Ûn»õë×sûí·ó»ßý®`_ù¡Õ§L&sF‚K›Kñz¾óÎ;±,‹^xá¬lÞsÏ=lܸ‘¿ýÛ¿eÆ ìØ±ã$›Ñh”}èC<üðÃç\„ÐL!‹-bîܹ|êSŸâ'?ù ýýýßoذ_|˲rë6oÞ̆ ˆD"Ü{ï½¼ï}ïãÉ'Ÿäë_ÿ:×^{-wß}7÷ÜsïxÇ;xñÅùû¿ÿ{|ðAº»»ùÁ~Àücº»»ùÎw¾“³=::Êý×ñÙÏ~–Ç{ŒÆÆFî¹ç:;;ùêW¿Ê~ô#ºººr ÀIž}öY®¿þzÖ¯_Ÿ Yzè!¶oßÎ7¾ñ zè¡‚Fêºuëxùå—suå•W^àOúSn›W^y…ºº:fÍšE}}=_ÿú×ùÙÏ~Æ{Þó¾ô¥/qôèÑ Ë5Q}Ò4íœl.=.ÅëÙår1wî\:::ÎÚæ¿øEÖ­[ÇþçrÙe—|gÿðÿ@kk+ûØÇΩ,A!ôS†Ëåâûßÿ>þçA§÷Ù IDATÎÏþsn½õVî¿ÿ~<ÀUW]E"‘ ­­ €ááa8ÀÚµk@×u®¾új‚Á MMM,\¸ð”ûŠÅb<ñÄüÝßý¥¥¥TVVò‰O|‚Í›7ç¶)..æ _ø .¤´´”»îº €~ô£444ÐØØÈ{ßû^vïÞ=‰gEp)’H$زe 6l`ÕªUd2víÚØÍG}”ûî»––êëëù¾ûýêÕ«‰D"¼õÖ[lݺ•¿ú«¿bllŒÃ‡°cÇ®¾új>øÁÒÔÔD]]ùÈG¨­­ÍÕ³³Å ‚™É¥|=———çz}ÏÆæÍ7ßÌ>ðZZZðx<ß=ðÀÄãñ³Ì,œ £/˜R|>wß}7wÜq[¶láþçøØÇ>ÆÃ?LKK k×®eË–-,Z´ˆ-[¶°råJü~?³gÏfÅŠ|èCâê«¯ææ›oæÊ+¯<å~Ž;†išüå_þ%’$ ë:±X¬`»ìwsæÌ(ð4Í™3§`Y p‚^xÇCcccîúºì²ËxþùçY³f ˜¦Y0~%;® pùå—³sçNš››Ùºu+ÿöoÿÆxñÅijjbÇŽ|îsŸìÞ«ßÿþ÷ìÞ½›H$Bggç9g!q†`fr)_󃃬]»ö¬m.^¼xB;O>ù${öìáé§ŸFÓ´s.‡@ExôÓUU¹öÚky衇¨®®æùçŸà†n`Ë–-Àñ°Y–ùö·¿Í7¿ùM\.÷Ýw_.v"²£~üãóøãóøãóä“Oæö3ù¢_ ˜Lž{î9FFF¸îºër¯;wòä“Obº®cš&¦ižÒÆ5×\î]»èèè@Q¸æškxá…¤¯¯eË–‘H$øøÇ?Îàà ÿøÇùÚ×¾FKKËimŸˆ63—KõzN§Ó¼õÖ[455]°Í+®¸‚P(Ä£>zNeND}Á´BQÊËËq¹\¬Y³†®®.ÚÛÛyíµ×rž’,Ë—/çþûïçûßÿ>›7of`` ÷®ë¹ÏÕÕÕø|>^xá…·ç@‚³$‰°}ûv~ô£±}ûöÜë™gžA–e^yåêëëxíµ×r¿Ë»v\ó«¯¾Ê /¼«'W_}5û÷ïçÙgŸeåÊ•¨ªÊþýûå3Ÿù MMMø|>ø ;vì »»›ŽŽ~øaöïߟÄår¹X·n<ðË–-Ë¥3 ‡Ã<õÔS L&yå•Wðz½PUUÅk¯½Foo/‰DUUùð‡?Ìw¿û]vìØaôõõ±oß¾);~`Ó¦MTTT0þü‚õÙ”}›6mÂçóñž÷¼‡¯}ík´µµ188X0ìÆlmm-?üpNeC þã?þ#Ï\ZZJ4å׿þ5cccüálaq*N¬OçcCpip©\Ï™L†D"A4¥­­|_þò—Üwß}H’äHYµjŸøÄ'øçþg:;;ÏúwA>Bè ¦ŒP(ØÙpîºë.>ñ‰OðÆoðï|‡Y³få¶Û°a;wîÌ…í€í5Ú´iñÁ;ßùNžxâ ¾ò•¯äznºé&–,YÂwÞÉý÷ß؃j?üáóàƒrà 7ðéOšýû÷¿G,œÌsÏ=Wpmç³~ýzþô§?aš&ŸûÜçX±bŸûÜçøÌg>CEEµµµÛ¯[·ŽX,ÆÒ¥K l€Ý;0kÖ,þú¯ÿšïÿûüÙŸý›7oÎe¬:'Ö§ó±!¸4¸T®ç_ýêW\wÝuÜtÓM|õ«_Å4Mþû¿ÿ›ÖÖÖó.×D|ä#aÙ²eÜwß}b Œà¼˜¬ ä3Ùè{)o}ö]ž`99ïwÙåìKWÇ?gß‹ÒéôÖs8ÁsìØ1î¼óNžyæ™ ž1W ÁÅ‹¢(¹±{§bíÚµ†qÒz—Ëu0€ž÷nŽ6ó^VÞ+»LÞ2yëN\¶ò>ç3Ѻsùþœ}Á´góæÍ\yå•Bä @ œBè ¦=Ï=÷œ @ 8G„ÐLk:;;9xð ëÖ­›ê¢@ \Tˆ ³Óšúúz¶nC*@ ÎáÑ@ f Bè @ 3!ô@ ‚ˆú@ Á D}@ `"„¾@ @0B_ @ ˜¡/@ Ì@„Ð@ f Bè @ 3!ô@ ‚ˆú@ Á D}@ `"„¾@ @0B_ @ ˜¡/@ Ì@Ô©.€àüH¥R$ R©º®cÆTIp ( ªªâv»ñz½¸Ýî©.’cˆ:!8D ™ÉuâRDý‹ŒD"A8FQB¡¥¥¥È²Œ$IS]4ÁE€eY˜¦I2™$3::J(ÂëõNuÑΛlH¥R¤R)’É$‰D‚L&3ÕE\hš†×ëÅãñàv»q»Ý3¦N­;—ïÏ£`š&}}}x½^jjj„È8†Ë墦¦¯×K__¦ižùGÓ€l¥££Cˆ|cŒŒŒÐÑÑÁèèèEY'~úÓŸrýõ× ‘/pŒÇ{Œë¯¿žŸþô§UØ¡000@II ¡Phª‹"˜¡„B!JJJ˜ê¢œ„Ãazzz¦º(‚JOOápø¢ªßûÞ÷øüç??ÕEÌP>ÿùÏó½ï}!ô§9ÃÃÄB!ü~ÿTE0Ãñûý„B!†‡‡§º(§exx˜X,&â“N?±X좨¿øÅ/øò—¿<ÕEÌp¾üå/ó‹_übÚ× Áq„ПÆ$ LÓž|ÁÛF(Â4M‰ÄTeB‰ÑhTxòo===D£Ñi]'ÚÚÚ„'_ð¶ñùÏž¶¶¶i['…¡? ‡Ã”••Mu1—eee„Ãá©.Æ„„Ãa¢Ñè·³,+÷:Ý:àlˆF£ÓºN<ôÐCS] Á%ÆC=4më„ !ô§)©T EQÄÀ[ÁÛŽËåBQR©ÔT¥€lúÌ3 ¼5 ƒ—^z‰gžy†X,†eY$“IÚÚÚxì±Çعs§ðD Ή‘‘‘Üõ7H¥R$IB’¤Ié S%÷ß8‰$I¨ªŠišŽO&IŠ¢`†£ç#¿;}žeYž”ÿoãÆ,^¼xZÕ ÁÉ¡?MI¥RÓ"_­àÒÄãñL»”•Ùɰ΄$I¸ÝndYÎ=è3™ –e QU]×éîîæéOò‡(.*F‘dIF:ËéELÓ©’d¿, ²sti¨*d2i$IBÓ´ 9ôSbÉdŸÏ7©b?™N"+2±tŒ„ž ÄS‚¦h˜–‰"+(ÒÙ5”,Ë~™æñÏ##Jëø|.Er´¡dYcccD£Q®¿þzæÌ™s^v’Éä´ó^¦R)¶mÛæ¨Í¯#UU $ Òé´cbQ’$ŠŠŠrÿ“"TQêêêèïïw¼÷ÎívSUUEOO£“òɲLqq1‰D‚d2éèyÖ4P(ÄàààIß_È~¶mÛÆ_ýÕ_]HñoBèOSt]G–‹¬š ¯‰`zs!3&˲Œn»Z§ º®ŸÕCÛ4M¦»»›H$B0¤¨¨ˆ={öäf@'⬻qjƒÊìŠÙ´–¶Rî+GSÎN”ŒÀÿ±¸Ý¶°÷ù ³ZZ`õjèî>Šß¢â~b"‘û÷ïgéÒ¥“æ—½oì<°“mÓ2™[2—CLjgâ„Ü!ZJ[h*i:«kM×íóvàdÇS·´@"çå—#¼ãå46*x<ÎG"‘`çÎŒŽŽ^éX'öîÝ눭¬§Ú3~ò³Ðï÷³páBŽ;Æàà crEQX¶l†aðòË/;*ô½^/·Þz+¿ýíoéêêrÌ®$ITVVróÍ7óè£^Ðõt"n·›U«Vqøðazzz»Ö$I¢¸¸˜+¯¼’gŸ}ö¤ï’ÉäyïkïÞ½Ó®NNFýiŠag|p꺞k¨ªškÄãq,ËÂëõæl$“I†††P%·.“É‹Åðx<¸\.Ç–eåf[-))qÔÓ¨ë:G¥ººÚÑ”£–e‘J¥èî®ÎÑ®HÃ0Ããñàñx=Ï©TŠH$R $³â¬¤¤ŸÏw^¶%Ir¼ËûBÉzæÏ„,Ë„B!–,Y‚¦iƒA<­­­ô÷÷³xñb4MCUTæUÍcÁ¢ éC‰!FŒ–²|ÚéÏÛè(> õõ°d‰íÁ·÷m ÿÝ»aï^hnn RÎû8ªª²`ÁB¡ŠâLøQ>I=IûH;ýJ?‹ª1§xª¬2¿f>q=Î`lÃ#‡Ñ<óÊç6œÇ0 ‡­[¡µÕ>o~?¸\k”–ºéí ’HHÌ›¥¥Î…@ɲŒßï'Ÿ·L&3-ëÄ©ÒÌJ’„ÏçÃ4Íœ‡8ëÝ Äb±‚ EQhhhàÊ+¯dtt4'à\.¡Pˆ@ @2™tÌa$IÕÕÕ†ÁªU«úš¦a‹-¢¾¾Þ1»>ŸL&ÃÒ¥KϪ‡ñlQU•P(Dkk+õõõŽžgǃ×ëeÕªU¹õŠ¢PRRÂÎ;9räÈyÙîïïŸvuBp2Bè_Ä$“IöíÛ‡Ï磥¥MÓÈd2ìÝ»—±±1–/_NQQQN´™¦‰ËåÊ o]× ªª ¯×ë¨A’$ÊËËú†apðàAÊËË6‘H„7ß|“ÚÚZGm[–EWWuuuøý~GϳeY¹†Oþz]×/Ù°,ËTTTœäE÷x<¹q/™LY–ñh*üÔºk‰¦£<ÖöAwÙųíØäÂxLR)[äûÞe{óóÿR¿ßöæ?ú(AB!;De2"k²a“AROr`è¿=ô[>|Ù‡©ôW¢ÉÇ{;ü.?å¾rYáµÞר ÖâwùQå‰+‰lÙ³gÂöyÊâñ¸(*r1glÛ/¿ ëÖÙ§ªb¾3äR@’$–-[†eYìÚµ‹L&ƒÛífÖ¬Y,_¾œÍ›7Óßߟkú(ëׯç™gž)˜øÈ0 ¢Ñ(ccc"3Õ Çãñ‰DDèÍ%€ú1.—‹òòòܲeYD"ÊËËñù|ŒŒŒäºC ÃàÍ7ßÄëõ2{öl¼^/V2EbË+Ä5¢¥óñ•— ºÝ¹ °»@EÁ4ÍÜ@,UU‘•XÚ`8š –ÒÑ-@Q)ñjTûUdEA ™Í¬J¥°,« mh&“A×õÜÊlïCÖˤªj.{BvÛââb4Mò,ÒétNØf=†aN§sç(ëO¥R¹m³Ÿ¬ÍløSYi)ñÃôî܃R$Ô:wE)jÐOÆ4°ÆË”\™N§saVÙòë†A$ž$š2ˆêÇÆRøe‰V·Ži%qiê„ÇŸ Ÿ:Ýñ›¦™Ûö\y½^’É$]×9pàÉd’Ë/¿|¯¾™‡,ÉTù«¨ Öðzß묨]Wõæ¾O&í¸òxÜ£~ÿ©…»,Ûžþn€]» »jj&¸Ó Ã4ˆ °¸b1nÅ}ÚUV™W6p*Ì›ƒo²´z)~í¸:Ïdìóvøðq‘ºóæñÀòåvȼyBè_½½½”––æiÙûIww76lÈ9\.‹/fáÂ…´··cšf.tD–eêêJq¹4zz†I&Ó˜æÙ…ÙH’„âÒðø|h^O®éD‚èÈØñ4U!åå!jkK‰DÄbI¢Ñ$ñø¹õ‚ÈŠ‚ævã- âözID¢ÄFF1Îè3Ùgóå—_Nyy9Û·oŸÔý ¦!ô/bLÓdxx˜d2I2™$‹ …hoo'“ÉPTTTà=ƒøýþœð••Ág_$ÝÞEÉŠÅøfÕ¢–å<ÄÙßgc;-Ë´ –6ØÞ1Æ)ÝÄ0ímBn•õMETyݸÕB¯ò‰6³ŸOÌH’Ý'î?ë ÏÞ ÀîÕÈw_ÖìçüýŸ8Rî·¦…™H‘|ó±Í¯`Dc˜iÈ®½xk,h"°°ÕWâ”ï¡·Ã´è §84§'’¦?¦ãRe’ƒÑ4,­ PªJd‡Mf?›ÂîLÇoYV.UZþ’ïÑ/..¾ XäKŸæ£µ´•'Þ|‚9%s ÂUâq;ö~Õ*[|ž©ÓG’ ¨š›í¸ô÷½ÏþÍt÷ê¦Á¡áCŒ¥Æ¸²îÊ3ö I’„[u³¢fÛ:¶ÑígN‰ÙÆ0ìÞ矷{@**Î|üŠb‹ý+¯´íz½BìŸ/@€`0H(B–edYfdd„¦¦&:;;s…l¸åÐÐÐI6$ 4MeÕªy:ÔMw÷0cc1b±ÔiãÈ%IBÑT*(k¬Çåñتd™D$ʱ=mÄGÇ0."²$Ù÷ü²² Ë–5*ò¡*2‘h‚®Î!úûÇèëE×O/Ô%YÆ ,/à PVW‹iȪB÷þƒŒõ I&ÑÌê3Ùÿ}```R÷#˜Z„пˆÉÆa/\¸07³¡¡!_WW—¼ÙtcùƒAÕ€êw­£låe o}•®Ÿ? †IËÿóIÜ•eHy‚6›‘ š2Ø~lŒƒq®›[JMЪHX¼Úá;{øÈŠjZ+¼' Õ™(~¢m³ûφeCS&²™ýþl÷%Ë2z,ÁÐ_¢ãû¿`öG>@Å W¡x=$ºúˆ<ÊÀï· Q~ÝjÏñ˜Æü}™Œ&2ühW/Me^VÔQtt+ DÓüáпjâ­e,¨Ð¤s?þQUµ KUUjjjH&“b²µó$èò®¹ïâ…c/pCÓ ”zí4·ÚB½¦¦0&ÿtHÛ½0wî™SM<ç©Oq˼[ð¨g—þF‘®M¥MìêÞÅì’ÙHH¤Ó°?\}µ}Þζ‘ãrÙÞü§ž‚ª*û¼ Îl/ê¡C‡P{@x4åñǧ®®ŽmÛ¶‰D»g±«« UU z‰ ÃäÈ‘>::im­cåÊV¿üå’Éô)÷/« ÅUU”76päµ×‰ Û=̲¢P1»‘q—ŸüÑá‘I÷^;…$É45Uó®w-çØÍ?t¡ë¡ºº2–.Ã{ÒÕ9„®ŸzŒ”êÖXvÓ;h?Æà±N:ÞØ‡e¸ý>ê- ¦¥‰C;_!242©½†apäÈÞzë­IÛ‡`ê™æÁép»Ý466æÂQ²¯¦¦¦œ—7;ÑÉ©TWi1ÖP|åº~ù;zÿw#5|îŠÂ<þ¶ÈßÕfWg˜».¯¦2àÂ¥ÚC- ®láwÉ<Ù6Ä»æY,© ¢Èg›™üìp4þܲ0SizŸØÈØîý\öÍ/à©­DñzoC îÊ2MpèP7}}#|àƒWñäovÐÛ;ñ<$nŸº…óèÜ»Ÿ¾ÃGÐSiLÃË"Hrt÷„*JY¸~-Gw¿Á@û±‹ª×C0ý¸tRÌ@²an·;KŸ çÈÆ{ŸNæfÊSdÔ wE)õþn½Dß<‚™JÛêÛ[1L^ï‰rd8ÁWPráÑ䜘Ud ¯&sYMÕA¶¶²·/Šn8—¿?›QÆ©Ôcf:Ãগï9@ý]ïCk¨Fñ{m!/IÈšŠê÷áŸÛHím7ÒûÛ?2¶{?VÞþ- ž6Ø×c,©³¡¹„GÅ¥Èv#G“[aE]õsKØÓ%–6ÐÏ2ÖõTX–uÉf×™,$IB•Uf—Ì&šŽ2–Œ²o¿É¼yö Ûs›šÁ TVÚ±úÓõï²°Hè ÚGÛi*m*Ÿp¶¸7K*—ðÖð[ÄSzzlü‰™‰ÎI²3ô°gÏñÉÈgO:&•J‘Édrãt]ÏåN?qm‰Ò‰E“ìÞ}˜’’eå!Ôœ’$Q\SEyc={7m& UËBO§‰ ÑþÚê´ª¬@ž„ô°N¡ª Í͵,XÐÀÖ­û‘JeòÆÀ™¤Ó:cá8›6íaÍšùÔןœqNQUe%hn7½‡“N$ís“m™d’ÑÞ¾´‹òÆzäq‡@p¾¡‰“Í–e!»4´Ò"ŠW,¦ÿ÷/ŲlA«›&c)^82• !Z+ü¸ù$O½,I¸™+j}´–¹yôõ~bÓAoS¹œ-Ó$=8±þšŠë×\ÜJ":¹¬(:ÐâV:~úF<5®ØLÓâÀ`œ­GÇX;»˜b†*Ngžìw)´–û¨ðk¼Ò!™¹°ãÈ·-pI’¨ ÔPê)eÿÀ:º **lÁz¾ÔÕÙá;©”…fºa˜»ºwpð¨žó’$áÓ|,¨XHçÐ ûÞ4X³æü!û|öÀÜW_µcý§¹Ó÷’À4MtÝàH{Ë–ÍÁë=ž²Y’eT·›¦+.§çàa"Cö·z";†IßávzbɆõ(Ó4¦Íî]Ò¸ù–U¼üò!çl 郷õÐÑ1Èš5óq»5äñg$IxƒA殸œ®¶ýdR©‡Q>F&Cth˜d4F ¤y‚dàlB_P€ìÒ¨¸a ®Ò"ŽýèW‰$–i1’Ðyìõ>ÖÌ*bn™ù4@’@‘`a¥ŸÆboÄIÎ=¡êâÕ#1Fv¼Nù†U­XtzÛ’dÇ–nXƒ¿¹‘·¾õé Ób8‘á…#£¬]Ls¹·@äç—9k;èVYÙâùCô\X »éÞÝ}±S¬ãOí¢¨4CiÙùŸkY¶ÃO4ÍöNO·žx˲èëd(>ÄÚÆµ¸äóßáR\Ì*šÍS[ߢvÎn÷ù‡ÜH’-ö[[íIʦkoÈ¥†®›:ØM*™áê«äĬÇïgÙ;¯çèk{ˆOºR€e¢ÿÈQBe(ÓPЪªB}CüãžS†ãäcYmmÇcýúÅ^$YÆåó2gùeÜñ2ñpä”"?K&•¦kÿ]·Ž@iéi·N‡ú—8ÙpŸLÀOõÍ0S†·¾J2£;œ¤ÿŸ½7kŽëLó;ïÙsOì ¸‹ÔF-UR©ö¥­êž(wÏxªá Ïøb¾òwðgð•#ÚŽ˜p´«ËÝ.»º»ººº«¤ZX)Q\Å ±‰DîËÙÞ¹8L ±$Î)RÈ_Ìfˆü IDATC¡Dž÷,™yÎó>ïóüÿœLbµQW®ë:Ù¸É×'»¸4W"_s,w î²RÒ\ΑûÕô~ýKhÉxqÙä&üB wex÷k”¯Þ¦>»HÍv¹ø Ä±îg®rl³ùf£2U ¦L¾:ÑÅG V+vèk³jQ‡ƒCuSTo¿NbäB‹V;bìÇ?{Y}_ú\Y¾Â‹/†Îæ·¨Äe%{¡±zäºzÚq¯]ƒR)ÚX†VχÞA(‚‰‰A C'–NâÚ6…¥•¶ëÊ]ÛfáÓ; ŸÀL$Ÿð‘ïÀ#ƹsǸww‘f³½{@£asùò=Æ'ˆÅ 4]§gt„Âòʆ|æ^HßǮչ÷Áe†NL`&â&•¡èú‡˜–’ËcA³ÄFúÁ·Yùé/)äJÜ]©òÕ‰,q]Eiãf£i Kg8mâú’;¹ÎD6›õæC#%N±ÂÂÿÖ`/ÖÈŠ¡oháï6¶¢k˜½Ý |ÿë®~Êz.hL>7˜ km¿ôÜRÑÙ˜Lº*xëh_Jn­ÖB—6í¤<Ô!:ž³÷|娗Y¶§°ýè’¥Éd yïÞ³“Õ—Hl߯ñ-ú÷aqÁœÆÇÎq­ð¶g# ?Ë×´@–suÖÛHwxz 5>þè>gÏŽ’Ì$H÷öòàúM<×i»ÎÊ÷<•*ºi‘èÊlQ{û< Jv ^½0I­Ú¤Vk¶íàû’zÝæïö1Ç“HÅ:1A~n{Fd¾ç‘{0‹Ó°É¨¨E‡Ãóñ‹êð¹±Sé‡bè˜C}HÏãÃ÷®²\¨q¶?©µw«i•ªXšÂ7'»¸¾\e©>sÝÎ1·½½ç³ò7¿Ä-”9úÿ¨±ö$[¨1‹w¿Féî,¿ûùeºc:]–¾k²åÑcV… iªœê‹óñB™†¾¡S¾sðH Å"”Š ¯¼R¸¬Ö¢kMÇã®þê*<+Æ£RJjvÝ'N G¯Z…?¼2>AÜЙ.LãùÑjnÞz îÞ|xß÷©V›d³IŽž'3ØGqyiÉíð\—{^fpâÆvvÓŸBΞ%“Nðÿð1¶½¿™¹ëzÌϯÑÝ“æÜkgqê œÆþ µ¤”¸¶Cqe…ÞÑ#t"ýaèú‡)%Žãl¯Ú"J*Iê;ïàþêw¼—$Mµí%ý–ƒ*Ç{âd-_Mp}?BnïaPR«…Wšy(§Y¼r‹?ü:z÷g¤–³ð^¾BUÐ3Iô‘Aª×nóÏNu×wþ)I)i4䊜ìÓÓø§{ëÔìý¯xø¾O³¹¿‡G‡½‘2PÈÑ4ȦUÆ»ŽRhh¸HÙi!‚R”|>(Cyæh¥f‰¿»÷wtźÐÔh«Cž‹éº` Çà¥Á—¸¾rOF ô…€‘‘ äinîÙY é†Ãû¿¾Éüó¯Rœ›Ãuö§æA™JµP¤²^àØ+/¶µjü¤Q…±±>>øð¶½ÿsò}‰m;Ô.ã/œäÎï/…2À’RRZÍáÚCÇ'Ñ­Š%@¿°}VØÓt¦ŽÄ0¶0ƒ"ÛO(´,Ô…KWx}4ÍjÕf¹âàE””l©…ÚÖv¨=XD˦ˆ nY&nIUî5¶©ª¬ŽÓ_È1X\CÛ#c¹¹w3)SãÂHš‹³%JÍpÑK'£¿ß÷©×ëÔjµIçy4 J¥¶m·¥Ú´´”ÚÄ,•3}§yP|@±Y$ÒL• híê‚ååg£¹´jW™.L“±2Du¼¨×áƒ\ÓP‰éi^ÓmFúž 8äŽÆeÏRÃaÇ“’²§Ñ(Wˆ ;ôìÕ÷<Öæˆ¥’‰8b7Ň'Œª*¤3qJå:ÕJø¥7)a­&Iø á!BÞ<œ¦ÍÜOõ%´Žb‡}Ò ô9uãÛdPJ¶Ï?-6ˆ¿zŽê¥OðšÍ¶oâºÓŽf-^Isc¹JÓö”Žb˜å–«,ÿ¯¤ûÍ—‰ =öw­ Íb)%M×çZ²wüsößq+»×o·šžEWC)“¸®°\ '“¹1ù †çy\¿~Ÿþô§Ü¹sß÷±m›Ë—/ó—ù—ܾ}·”ðêj ”£…¤‘äHê—.EÊèCÑ瘙;|\t H)™+ÍñƒÓ?¥›ÿ(óó`Y”¨®CÆÌ0š¥Ô,EÎêk¤ÓAIUgnûì`X¯½Âï_á…3#‘¹Ëkyæo~Jª» Eùüx Ccrb™éòùJ¨1„(šŠ§Ç™šÉño¼ˆe… Ò¥ïã4”r9âét¨1:^:Â!¦Õȹ] èú’RÓe(mrò[¯a¤TïÏâÛí-=꺾¥IÔPIƒ‹³EÊM7t¨ÔRÆ ÜJIs5Ïê/~ƒ5ÜÿXÓ—‚D"±çƒªáú\š/Ó›‰sáû õ¹%œõâ®ÇlšæŽãššÂ×&²LçêûËê·Æî°•¥¥%Î;ÇåË—ÏVkŽ9B6›ÝuÛZ-Ðm2ú-&º&X©®Psjø2üdµåúÃõëŸoк\]f©ºÄd÷$š­lGÊ Éx`à³×4Ec$=ÂßÞý[ÖÑ;i»»ƒ€¿Ñè”ï<+h†ÁúÂ2·oΰºR¤¯/ó˜‰V»H)iVk}ñF<úÄ3,©TŒï|çòùrè1M%Ý×K½Råòo>!Û•D×ÃO^<×cñö=’ÝÙNùN‡}Ñ ôŸclÛ¦T*Q,i6›ÁL±X¤P(à8ΞË囥57SizÜX©r¶?Aj ‡Äñ£ä~ñ;¼}6µP„ ;®#ùRûê;s|Û¡tåé—Ncôu=ÖðÕθRBÍöù»O×89¤w¸‡®7_¢|ín¹ê¸tU0Ù'WµY­v̯×uQUõ¡¹‹‚ááaLÓäã?ÞÈ语­‘Ëå¶üN'ôÏÛjô×ãœ8σâ\?Z”©(pæ ܾ”ï|^Áþtaš¬•ÅTMþq epÝT6Ï£¡6Ó4ÜU;Üïc3¦hê¿÷^ûÍÌRJ–——Y]]=0Gíç!Ùl–®®.âñ8Š¢`š&Ùl–Ý¥„ÛĈY¤û{).¯PÈ—ÈçËL è#%ÍZÍ00c±ÏE'¸WtsëÖì¾p7£j:§¾ü¹óTKnÞœex¸Ó '‡ì{åµ<±T +]«Ãá¡è?Ç”Ëe~üãó£ýˆååe¤”‹EþËù/üÅ_ü+++»6­J)7œq%Ws¸ºXáxoŒx&AbbŒÕ¿ÿ5n©²§ÑÖ£ûŽé _Íp}©J#dùNË 6L½oc)GujŽñÿç_¢¥×kÞ©iv3ž”<(Ôiº>C)#¤ï;oQ¸|æj>Ô1«Š 7¡cé —çËûúœ ^_t,Ë¢X,¢ë:kkkø¾O?/¾ø"Õju#ÐO§Ód2™-Û‹A&ß²‚ÀµEÒH2’aµº9Ї`ÝÝÁþ>øS"Y«¯×â‘Çò¼À¹6“±±­ÓoM|‹™âLä~ÀÑQ¸|ÊûH¶ööö>ö9ÑQ…ïÿûü»÷˜@UU’É$ÿæßüþý¿ÿ÷œ8q"rÙŸ•J1úÂÖfçqš6ËËë¼õå3ÆÞ%;áÚ6w.~ÀЉÉÏÅ-×04ºøŸÿó÷Ôjá[Bbéf2ÝhÐl:ܽ³Èèh‰ÄþTÞZHß§Y­!T…Ì@_¨1:N:þsÌââ"œ:uŠõõõìe<gtt´-#¥Vcë£à;¹=qÞ„Ž*±‘²o¼Èúï®àÕ{ŽëyÞc¾©)|i,M¡ár;^“¼ÝfÊGÉÿú~Ó&vd`[Kq)åÆÊÈNÔl™õ&ÿü\?iKE¨*Ö@/öz‘êé·sÝUÁŠÇËC)äkí7,·&k>CUU.\¸€iš¼û¦‰ªª‹Eæææøƒ?øâñ ¸Õ4mK_†çj8'On ò[ªÁLq†¦]é(“‰‰Ï§)WJ‰íÚÄ´gúÎD¯Ù„ßüR©Ç¯›"FR#4œ…f!rƒ¦Á÷¾¨"µCË/D×õÈìçEQH$ ð‹_ü‚ . ( ªªbYwïÞ¥~ú®‰lšr.÷põ¸\iðÉ'SŒõaá‚tßó(,­ Ç,’]»—Ù= ^}uMSð¼ð¢ЦÒ54ÀG?ý{š•*¾ïS*UÌÒÕÍláÖO>3~ž}:ß”çÇqÐu}#Øóúˆ«W¯Ú €¢(ôôôpöìY2™ ÙlÃ0âÔ©S¤R©þ‘GK׊Šð>r$(ÅTMbzŒŠ]‰œÕ×õ@}çÊ•§¯©_wëüræ—ôÄzHÑʤ &*—.AÿãèB,Ý"i&¹—¿9«¯(A©´?‰ÒÊ¿¨hšF­VÛHþ†mÛüä'?ayy™_|q£¿GÓ4^~ùeÞ~ûí¶®‘U×é;:ÆÜ[Ÿ©c;\¼x›Ó§GÂ7žJ‰çº¬Ï/Ò{tô©jêêN‹‹ë‘¾§É®,±tŠJ>çº#>7nÌ299ékŅ厜>fDsE×47Þxƒ¯~õ«‘ÆéðlÓ ôŸc²Ù,¹\Žf³‰a,--áy½½½d³ÙÇd('''9uêÔ–L¿išX–…a!p}ÉÝ|ƒ„©rv8ƒª_-fÑ}ö8ª®ÑœžC>Ì8뺎iš[B[Ù¤D"±±4,¥Ä4 ,ËäD’µšMÝñQUÓ47öl¼¶Ù¥¶åˆkYÉdrãõÖþM’c­ZÔÖöÒsi.åPô¾rvËùkš¶±½¢($“É-ûW[éI!Ðtƒåº¢,]A}xLf,Æà·ÞÂY/Q›šCH¶ì¿Õ0Ûú·Óþ“¦Æ…‘W–ªxBÛöüMÓÜÚäl$“Éó—RrþüyN:u¨ÕxZÙË–úSëÿu]ßõºäóûj_ßö¾®è\ºÀ¥ÅK4½èY}Ë &åòÓ­Óo¸ ~~ÿçô%ú"Kjú~ EzòdPZó(®èŠÁjm5rF_Q ‘þ»¸ØQàÙŽ–'ˆ®ëôõõ133C&“AUUÊå2¹\Žjµºqó}ŸëׯséÒ¥¶ÆŠBv ŸZ±D½\ÙøD]×§R©S.×êŠtÍzòvT,;hE! î¹wï.†HR½½€Ø"Å+%ܸ1KWW’DŠTÚ´øé]Žœ9…¦G“Úô<+W®pñâÅHãtx¶9¼‘À€‘‘^yåNž<ÉäääFZ.—éîîæìÙ³ bC gsðØ ‚ZÙ.×—\]ª0–‘4µÏŒK„E?z„êýY¤Xœ·¶Û|Ój-•o–ÁÜü¾‰î8I“éõ®¿}¦m§q[co7îvÛ !pËUfþÓˆ8~t×÷n>î-Ç$Áó%Ëe‡ã=ñ-¡‘¢(Ćˆ ±òwïáÛöcǵyÌö¯© I“¸®R.̶ç¹yûV»y?í´¶çÎ8q""·CS5ŽfR¶Ë”š¥Èû‹Åàûß_Ÿf«EÍ©q¦ï qý`êó—–‚óHîR•p¬ëX°jñ±ÓR-Ò4X[ëúÛÑZåýÑ~ÄÝ»wyï½÷6<$4M£X,òÞ{ïQ­ Ò¾ïã8Ξ¥‹-Ue`ò•ü:Î#²ËBªµ}ý™Hz~~‘j±ˆqMÃí`š:o~éùõ2•°ÚùŸ©FÌ¢´²ºeJ¬ ÛLO¯ðÖ[§C—6n¹6¥•UÔˆýVÿØæUæ_<:‘ÀsŒ¦iŒŒŒ066†eYtwwoÔç9r˲¶ *[H)·dý}ü«Ú#õ±à[!ýÒ)ÜJ §TAz;×ÉoW£ß"iªô'uþæÓܾ›r[n¾û©Ñw+5Vÿá·$OCÙåÆ¸ÛØž”Ì—šT³‰­ÎB ˜:Ù×_|8 ÚZÒѺÎ{!KS8ÝçÞZjsïÂííÆ>l% A«™tnîñfÒͪP9ÕsŠ›«7#ïWÓ¨ÅÅ`ÿOOz,W—ùîäw$Ð_XJh‰íûZ¤Œºª3[šÜãÐrÊ]\|ª•ÏRJr¹wïÞ¥Z­R©T¨V«LMMqûömêõúc÷ŽvËU¤”E¡V,=&Îàû’é©e4U%3PB_¹ŽC£\áÄ›ÐÌ'oe*ßúÖKÌÍæB«Â !ÐM“D&MîÁìc×Óó$ kd³ÉHß[Ïu©®±’‰ÈZ;™9vøâÐ ôŸc6gä7gŒUUm{¹³¥ºÓ2º·V§'®ÓÓ¯µU‰É£¨1‹Ò•[È]:ÇÙ±F\SÃi“ûù:ùšƒ¿Ï›L«N¿¤ïSŸ]$66Œ9гû{¥¤R©l{Ós=É{S†S&ƒ)óñk£ª˜}ÝhÉN±‚|äÜÛÍ”™šÂñÞ87Vª{×€·z:DÃuáÚ5xùå œf/úý”š%l/œT !‚Zý¡¡@ƒþiPl)7ËôÅû0Ô¨Aär;¯€lFWtÎôžág÷~FÃÛ»¡/zz‚ý‹Mýh%\ZNå¾ïãyÞŽjkí j±T§Ñ ±ÍìTJÔ¸#éíM‡_Y”’ÊzÁ“h»øét‚™éÜ†ŽŠ¢päôI +«4kõÇ–›¤”T«M*•:†¾9Ü÷<Ö—œœÀˆ…Sñépxèú6(5\þæVŽ3ý ’æ6©9!0ºÒÄFYøñßá;៮]1×FRÌ›ì²0°-û ¬ü¦Mc)ÇÑÿëÇè §à Šíòá\‰‘ŒÉN *£¯›Ì«g)\º†[ݺôÛnÖDS#“|Ífz}ïåãN&æ`°í@Ó~t´½@¿7ÞË@b€µÚZdÇWö9;ûtÊPf 3L­OEÒ͇àX]7X‰m£gRUTRfŠ\-GÅŽ¾|aYpö,¼ÿþÓof>̘‰8g¾ú+S3¸;(zžÏÊr‘wÞ9»Ñç§ÞàîÅÉôõ>Q•! “‰ññ>…Bøï¦ªkóµÂΊÕjƒåå©”úÚøžGµP$3ÐGl©è6Ó ô1›ëÝ…¬VmÖj=1tu‡§¶$O£¹ºFs9÷XæºEK¶p'â†Ê·÷0¯“¯ï¯8Ù²¬¶³DÕû³?¾IúÅS({,ÿîäºëù’ÕªÃéþG2;;*¦AâøËÿß/h®|¦©ßêhOÍ Uá…þ$³ÅÆž2›Š¢ìz;´‡çA:í$Ù,Í"nÄY­­âùÑý£GMýFãÉkê{ÒãHúHä ©”A€]©Àäd{×ÍTM¾5ñ-ÖëÑ]rU5(ß™}ºý ‡Í0ˆgÒT׋»zª¬®îÁ0´å;6³7n‘ê펬0³ƒƒ]ŒŽöQ¯ÛáËv…X:ÅÌ•kTw ôÇcv6Ç»ï¾IjSJŸÙë7ÉESñéðŧèrZͧ®Ô ŸL×Õ­5è`ôuÓýöÊ×îà5¶oâÑ4í3ÅšíÆPŽdL*¶Çb©Ù¶GK}¦Ý@¿>=ßh¢%ãˆÝ ˆŽýh_ÚùwVk¼9šÞ~¥ã!ЦÂ÷9M}‰Ä“s¥9Î÷ŸÜëy4h?Äãíúº¢s,{Œr³9«¯(AÑ#A@‡§C¦¿™+×ñ}o×ÅFÃæ7¿¹ÉØÑ¾™k×vPT•dwwØCÞ“L6A2ÃÛïòò&4C'ÓßÇâ{Ø»xÍø¾O¹\GÓTR©Xèý!!÷`Žx:…™ˆwú²:ìH'ÐAÙN¾æòÖÑÌcM¸¢weþãïRºq§¸½=e»%%š"˜)ìîFvléKÊ7ïB´ù ÙnìbÃåv®ÎÑîq}—É‚¨1‹þï|…ÚýÙW;öB HtÅtn¬TqCf˜:´G£ÓÓAü~G,Íb¶8KÓkF–ŒÔõ £ÿñÇO®Þ\JI¾žÇÒ,†RC‘Çú'hE(¤Í4ùFž•êJ¤ýCÕ‡jõóq>l(ªŠn™A£é÷¥r¹Î¥K÷èïˆB &é¾Ý{¬¢Ðß—¥P¨F*…4b12ý}4k5ü=fë®ëñ·{‰±±¾Ð¿C)%N£I)·Fߨ(ʉ¬‡—N ˆi©Ì¸žÇL¡ãùô'=ëMEÏ$i.åh.ç¶-,¶m{‹±Óvg”.Ž'ÛªO–RR¯×wTôÙxŸçÑ\ZÅ­Ôèûö[ ì} 2-å-Mj¾”,”l\_bìTδ EWéýú›8ë%Ê·¦ö'3B@LWÍXÜËÕwmVniuO¹ Ÿ|”Ïì'ÐO)Þ=ñ.·s·Ì)÷½÷—Ù'AÓmò?nýޤŽDË÷ƒàzrrwIÍGB`(q ò¤šƒƒ¼g>¿÷û;„G(‚ž‘aU¥Q­îZ¶³±€®î$==©Ðû•¾Ïòý)UEÝäb}Pdôñvè²3#–NïäCpß^]-b]]ÉÐçä¹õb‰ôîaxÖRÒÛÛ»ãß{{{;ýk›8<ߌÛÒjÉ×ÉXZP¶³—Ž]Çê£65‡o;<šÐl)<솂àdoœ¦+yPhàµùÃt]wϱo;¬üÝ{è™$‰‰QD›5¢ž÷Ùr´Orw­Æ™þ8F;«ŠŠÑ›E[TnÞ ôJá1ó²½PAR§îxx’ƒýv¥;;ìÌÚZP:cYí©Ç´ÐÕ@Ef®4w æY±œ9v=‰òOz¸žKOJ×ïnÜlÚ¹Ò×éIè<(4v¼6-‰Õáð}˜™ ö¿­"tU'i$Y©D/CI&áþèÉ4—J$»Â‹ƒ/’6Ó‘Ç³í Ÿ ¿¿=•¢GËŽQµ«Ô:¾ ?Q"Èê <=yÒÃL¦¿Rn­í Êó|nÝšçØ±~ C £;M›ÒêçNèýN×5¾úµsÌή†DtË$ÓßÇìõ›xm¨Ñ«é®ëÓ×›‰4wiT«Øõºi¢DP8zžh}ÿΟ?¿%³ßÛÛËùóç·¼§C'Ð?Ô!@QY,»( ŒfÛb ]§ëÍ—ðj *·î=V¯iFÛM¢ÃiƒO–*ÔoÏò!ñx|Ï›½[®¢%ã$Omë Æ[îÂdÑ?œ/‘25Sû0~‚ÄäÒõ÷`À ¡0TNôÆùù<¥æöEQ6Ü;ìß2Áª”Í„yØJ$¦f²T]Š|<ªûµZD$®ïRj–ËŒˆIV>·nínµ†bp,sŒ‹ód5äÄ ˜šŠ3O×[0û÷W¦ÐWŽ/¹¿Vçd_UûzDÅÆ†Ñ»Òäón­jiVW“=ñ@‚´¶s–¨£¶Ï ²À}}í«Æ<Š@p$u$èÃp÷×T¾¾8¾$ùzž> e¤"ëçû~°âH쯧a3ª¢r¼ç8·r·pýèÝÇ©Tð9Þ½¬6t8X Ëdüåó¬NÏàì#ˆ ¼<æç×xõÕ‰H÷ªz¹Ìòýi¬dâ@êÑ…¤Óq®~2M¹ÞˆAAÿ±£äfæö½m©¬†÷ô¤Ðõp?&éûACîÑQÔC&µì8Õj•b±H±X¤Z­îÙxéúÏ1¶m“ËåXZZÂ~øtó}ŸR©ÄÊÊÊž²RJ 5››ËÎôÅ1µ}~„ uö8µ©YÜòÖæ¬–#c;¤LxTèŸ IDAT7GÓ<(4hîáJØj Þ- r eÖ/^¡ëõóh™ö›ÀZ.³RJ|))7]”‡.¾ûEO'IŸ;ÉâO~Ž[®íyÌÛ¡*‚¤¡2Ùg¾¸}Cëztø )%+++ܸqƒ\.‡”×uÉçóÜ¿Ÿååå‡Î Af:‘¤-à…±Ì®ïRsj‘ÊPZÄbAƒðA¶^Tš–+Ë‘p!˜ ݸ¯¾>ÐW„h)nôì›eÁ¹sASuçç²iŽ9B2™DQt]'•J1::º­gÈNh†Áàñ ÖæpC%..æëGÓÚslߎfµÆìµ¤{ºQµè 3ñ¸ÉÐP7ËËëÔëáf‡B4Ó Y«ã†øâ¹®Çí; |ó›/bYᔉ¤”øžÏ§wž¨2Q‡ç—N ÿ³¸¸ÈŸÿùŸóÓŸþ”;wîàû>µZýèGüüç?çÖ­[{ëµ&1]¡;®¡…05‰Æ¢1¿”ª<Äu]Ü6uãKTn­Ö(6öÞ¦µd·ãßç—YûÕ‡héýe~ZŠ>¾ï&Y‡S½qúûŽC'yjœâå4WBúª_ϰVw¨Ùþc"޾ï·} ®ëréÒ%lÛæg?ûRJ*• 7oÞIJ,Þ{ï=ªÕ*ªdwoh K³H à-:W” €n6ƒÌôA•™®TWøÒȗЕhž RÇU­Âñãá}€¸çlßYl/z ^Uƒ [£ñä|ž7EáßþÛËøCÞ|óMt]'“Éð¯þÕ¿â_ÿëÍÛo¿Ùæ ׈Å(®¬nè!¾”¥RééezzR¡Í³|Ï£Y­‘ìéF;3ßD†¯ãSyÄ6›Í,ÝñÉÕ<^J·§(³ Fo7ÙWÎR¼ro“IHËm·`j ņÃZ}ïò½[kSsÄ'GÑÓûwl]iz¼7]`(m`é!®h™$Ý_~{­€ \‰*#‹ºí3W|¼4äÑëìû>FccÂrXq‡d2¹1Ñu]—z½N:F×õ‡ÊMéô<õúräU‘ÁÄ ÿ8õ‘]r…ÊP|VV&hu<‡¥Ê/ ¼„Ú†ÌìnH ¿ý- ïO¡h;TE%ke™+ΈԦiB6ûxFß¶m–——™››;4R´Š¢N§i6›üîw¿crrz…ù³?û3Ž?N<ßx,#™|\êQ( V2A~a1ô=¥Zm2=½B_-B6Þs=2ý}˜ñè}&†¡3?·†m‡ÿí1‹Á㸶ӖÜèv4›6ïýêétøs’¾O½\AÑ4º†öaÎ(H$$÷£‘Ûá¹£è?ç´~ÐŽãÐl6q]wKð·90\\\dnnnKX…ã]ÒÿL²Ò÷}lÛÆ¶í»”Û¶7öÑBêúÈë^ë5@~&­éyÞ–CkûÍA•ëºÁÃ×sN›ÜY­á¸Íæöû·m{‹êNë¼í‡éO·\¥r{Š®o¼‰ƒl{ÿ­Ò§x<Žïû¬•k|ºR%k+;ÿ–ý?¤¥mï½ß~‹úì"JÝÞxïNûßîúKé“4TbºÂ½Õ2ͦ½eÿ-©ÑÍûŸžžf~~þÐú-·àz½Ž®ë Aó a¬¬¬àº.¦i è£YUTFC3¨Ø•Èå;ŠccðþûÑ}_úÜÉß!ceH‰©ÏŸŸÜh£¢…þd?wòw¨Úá›![è:ôô Ö‡$žß!Ƭ¯ªª$‰Æ}ß÷·ƒŠ¢pìØ1Nž<¹mجÕ)çòmIGn‡ã¸”Ë5ÆF{1ŒðË@Ò÷)¯åIövGªÓWÁ‰C¼ÿþuÜ=ÊEwCÓu†O§QÞÞ8²Çãúõtu%1Íðå;NÓFú>ñlûÊŠ¢099ÉéÓ§Cí·ÃóA'ÐŽÉf³Ü¸qƒÙÙY|ßç“O>a``€›7orûöm2™ÌF ¦‚‰‰ &''7nöqCå['º95˜&a}¦ ÓRr1 cËö†a`š&Ú¦õzÝб²i³‹Ø¹ša®Ô¤áaî¼ÿÍã꺎iš†”’òõ;HßgøÝ¯K¥ÚÞk_º®#•…ª$ej¤Mm÷óß´ÿŠ¢Ç™J’9’æâ Íùå=÷¿Ýõ×TSSèO<(¹è†±eÿ†a‹Å6ö¯( §OŸæøñã[ÞwØgff†/}éK¬®®¢ë:Gåý÷ßçõ×_'‹¡ª*ccGh[!j'RfŠïM~éÂ4޽H< K£Ö›ûÒçâüE’FôŒ”"P_ßþL²vB –fáú.ùFt·+] ¼.]‚Ò¦Ã0`dd¤íR•çß÷)‹Äãq^{í5fff8yò$}}}är9~øÃrïÞ=êõ  Õu]nÞ¼ÉåË—KHßg}a‘Òj.t `Û.'N‰T¢â:w‰ž‘#¨!›W…€d2†çùLO¯àºáÎIA,ÆÝ” ƒïKŠÅ©TŒîîð?,éûÔJe’ÝÝmoãyŸ|ò ~øaèývxö9¼‘À€ááaþäOþ×uÉf³xž‡eYüÉŸü Fƒl6»kÓ2[ŠªÅ®§“t½ñ"Å+Ÿ’8~5fmÔЫmêï©B0ÞC‚æË¼3‘EÝ&+Ñj¬TUõ±c–žOî— gÓ(šºo%·VckÃ,”üÁébFøef¡*èÙ4Òó)Þ¼GêüöÙ²vËZ|4_&_sèŽëý­Ï°Ýë|PU•ññqÆÇLJ sšF<çÿø±,ëÀW;tEg(5ÄTa Û³1µheO|ã™W,^ÆR"éŽuÓï‹t<dó+•`µ!›<¨½=ú6wòwx¡ï…Hc)J “Z*’ÃŽïûüÇÿøÉd2¬¯¯#D°2yëÖ-º»»YYYyª¥Lͦõk3 dÉç+8!šz‘×¶ñ‡®¡Ar3³ûî}R…¯}íkùðYxJšº†¸úó_b×Ã7”KéS«5I$,º»S,.®‡«´²Êàñ‰ÐÛwøbÒÉè?džA?ÃÃÃÄãqR©º®“ÍfIJ¬=øÍN°aQc}ß~›Ò•›ØkA™„ëºm«î@e15…‰ž7Vªx¾|¬ñ´EKçQ¤çÑ\Z%uöx(­ÄVÃt¾N¡áòÒPC ])Š¡“˜£píS¤ç‡î®ì‰ë §M.Í—ilZjî¨î<ŽÓ47þm^­I&“hšvà’¤ŠPP…JÍ©QlFÁÅmøÕÕðY}‰Äñº­nz;Ž ‚ç«W!†ƒ²nB0”¢æÔX¯¯G6ÏRUxáxðà`ŽïyFJI±XäÁƒ”ËeJ¥ÒƧ§§©ÕjûºGGÅq\>øýmÎ?­|GJ–ïMqäÔ‰P¿c!ÀЬç+¡ ÙÝ…‹E^éË]çç×n?¿v½Ai5ÇÀä1´Ž¿J‡‡tý@49Å4ȼr¡ë”¯ÝFJ¹ño¿Œe-ÊMªíï¸ývcKßÇ«Ö1z»ˆ †:n¸·Wk$ •¸®¢D … óòiD½Is9û!°t•3 .Í•¨Ú[*Àg×s)7ËÑ'ÏUdVV RâÛñË‹ô%úHíËÌîD­¿ÿ}p\…@`ª&G³G¹¶z-²¦¾Á©P8XÕ¢Ñq]ŸB¡J¥\§¯/i,ÏuQu}ßå;“²ÊZ®ÄÊJûÆ_ÛÑwlŒF%zoI‹Û·çééIcšzèD„kÛ,ݽÏÄ«/¡[‡£L­ÃÞtýCަi{ªØ´ƒPñcG(~r|]×CÕ=$ Ž÷Ä(ÔÝmuÄ…X–õX©ŠW­“ÿÍeRgy+g½á1¶—཈ ?6Âò_ÿ^-\Ô¦+‚#iOB¡¾¹™ZtœqŸ4Eã…þX©®Ððì¼&Õªd¦K!iÖëü×kÿ•Œ-¨‚ l§Pjà­ƒûiÁuËZY+‹âCH«ÓÓ©Íg‘……<çεïX¾¥Õ5–îÞÇLìOBYQR©8kùr47\E ›&J´UÍ4›óók¼òêd´¦ÜF»Þ@ï<:<¤èbZµùUÆyå,^½S¬ @¨ºÿ¤©2–µøýl‘š³ýSz»Ò §PfþGƒ5Üj…»Áùj¾ÀÐŽuÅB±jÌ"{á…>Ù"Aº„CS8Ñ#_s°® !:õùϪP9–=ÆRe‰ºS'bœ¦ÁÉ“AùN˜€Õ󃲼„=ïypÿ~Ð7pÐñƒ‚Œ™!®E—L"8¾žžÀ]ø O=Ó¬®q\Ë2Bkê{ŽC³^';4°¯•T:ÎþѬåJ¡Õv„(ªŠç8––C±®ëqóæ,çÏ$A*}ŸÜ̱tªãšÞèú‡ž°%6Û;2€Ù×EmzÏge¨ ½ ÊTloÛXi»cn,,S»?‹Ùߪ>Àö|.>(2˜4J\4#4kd„À^/"ýp×[Wgû,”šå;ùùuˆ†K³IðiîÓÈ}Mƒ×^ Ôwö[†"‘,”øÞä÷Ä wm-øY Œ飤Í43CÕ®F.ßÑ4ˆÇƒ•ÎOãÙcuµH©X#›M„RR/•}á ºÙþ÷;79uòÕjø&dESé¤^®P-DïÇiáûÏó©VÄbá³¾çQÎç1â±N~ èjZœ-­å¨˜ƒ½ÄÇGYþÛ_Q/–¶h»ï‡”©a{’ÙÂãQRJªÕêÖ&2)©Ï-Ó÷ݷѳéÐÇ_³=þêê2Ýq-´ØvHÀÕ²¯ÇÎ!l5E0’1Y,7Y­šRJðŠž¡Ô-}ù7¥(yV<d§÷ƒç{ÔÝ:¯¿Š©F¯Õ½råà3ù›Ñ#é#üzö×TìèåÝÝÁä(ª©W‡ƒ§^·)•j=Ú¦…ÿ€|×%žNaĬ¶“;==)þú¯? ^ïÆlXþð4ÈoQ«5¹ys6R¾ïy—Vè$ÑÝuÀGØáy¤sìp`EÁêcýâ'¸¥Jh§À¸®ðÍÉ.æŠMšÛ,¯>@Õf¨ÞÀÈŸþ!j"\É/a­æ34†Ó\„Lаœ~é4ùß~Ds5œf¸"YK§+¦ss¥Š”FÜg‘¬•e¢k‚µúÚ8åNLÀ‡î¯ åÆê ªvM‰¦0(‚ÇÑÓz˜=Q…Ê@r€›¹›4ÜèWË‚øôÓŽÔæ³†”’µµ2ï¼ózH-|»Ñäú?¾G÷ðP[+‰„E–Ë—ï…“öäa©¤®ã4mšÕƒkÄmáy««%&'Éd•ÜI)ñ\—fµF<½ ¿ÃóO'Ð?ä´‚€ƒªå3ûº±z©Ý›E„T˜15…/eX­Ú,”ϼue““|‡ÃI'B8Ä!Ðuý@›9µlŠ#ÿâ]ìûs(!³&ª"èIèèªÂõå­Y!ñx|Ë1.]CE˯×–J6ß;ÕKÒ/èªNÆÌ°TYÂñ£{ôõM¹årûY}Û³ï¼o)µl68Ž'‰&4Þ{‡|=Y}§%OjÁñwx¶(—ëüå_þ–ÉɡȚúv½ÁÀı=ß;>>@,nDZUu Í4Y¼sç ”Lå´kk¥Èšúr…fµJ²+»/e¢_<:Ÿ~‡EµL²¯Ÿ£±°Lõþl¤±&ºcäªv`žµÍ½YJ‰ÿ°é·ëÍ—B7áÌ›¬ÕlLMDfw„Bß·¾L}n ;_]Ú”0TÎ&¹¼°Õ<«Ã³ƒ©™ÜËß;2òúuç»áIb£ˆ@0œŠž‚¯ÕàÏÿ<¨yÒ!ˆëq<é1_š?‡×_¼:nϾ/©TêÄã&]]{gãw£²¾ŽnYˆ=|lÛåÊ•©Hûê"ÕÓõD3äRJ.]ºËØÑþЪDv£Áü­;Œ½x-äJw‡/@ÿ9FJ‰ïû5Ózž×–ã­”×uñPƒN¨*Z"†–LPŸY@z^è§ì±® K_¨»¸•j¤”4›Íà¼ëMÖÞû5#yf2ô1ûR2_jÒ×h6l¸× HD5 Šß@†\ñÐU…‰îë5‡ºíawœqŸ9 Õ`$=Âru9rV_Uƒúø‹a¯$bÓmòó©Ÿ3šÅÔ¢­ô´Êv––‚‰Æ“F¡XšÅbe1²j‘¢Àà`pÍŠÅÃì+вEB¹%©ÜòOù¼ž]’r¥ÎÐPw¤À¹¸’@Õôm3׺®10EQ–—Â/ï!Ð ×q"KçîŽd=_¡Zm0v´?´Ô¦ïy4*4CCéH0j:þsŒçy,..2;;‹mÛåÜÜsss¯íFk’p°M‚øÄ(Õû³øÍ½a'F³cY‹_N­oèÆ¾[©2÷ÿþORg&0ºÂE"¾”TmŸÕªÍÉÞ8ÍFã@'>-ÇAj2Aâä1ò¿ýß*,M¡'®³^·i†§Ã“ÃÒ,¾vìkÜX¹AÓ^$®ªA6mm÷€µæÔø`þÒfú@êóà»ß=x“¬íuúq-N¾ž?@¿«+˜¬,/¾@_Aww7“““Äãñ PÕ4FGG9~ü8‰Dâs­Ýu›T*†ª†_I­®¨ä×é>2„²M½¿iê|ÿû¯35µ¾6_M%Õ×ÃÒÝûOTAÊÀ}š¯|å+èºNww7?øÁ>ïÂ$ÓÕ«3躊e‘&ÕB ôÏ0¶™‘š–ÆàP…b5t€.…ìàHIqeõ‰«ù¾$Ÿ¯à{Ñöã¹.¥•ÝG†1¬ƒ3ìð|Ñ ôŸ#–——¹uë7nÜ`ff†¥¥%úúú0 cCK]Ó4|ßgjjŠ¥¥%܇Qçy,//“Ëåhn’¡Bàºî–ÏópgCc>+?±m×u7nt›ßÛZR¢õ¡¦“,ý¯Ä·ƒqZÛoÖÀw]Û¶7¶‡à`Û6®ã0˜ÔèOê,–Øv°Ã0ŽK}n‰®o¾ ©ÄÆynÞÞ¶í-ÙùG÷%¥¤î¸üv¦ÀD—ILWH&“[Îu§óoáyÞÆ˜­÷¶Îuók†a¯¹ZoÖp?¥ëwhËÛžkûÖµò}ãø=ÏCW“=1î®Õ(Úrc{ÇqÈår,//¾“½Ï‘ÖJ×½{÷XYY öl›¥¥%nݺE>ŸßêÃð„P„ÂD×wów#š”¡T*AÍùv4Ü+ÕÎõŸÃÒ¢§à‚FVÓ|ºzôI=Io¼—«ËWi8Ñz„€±±Àt,Bá3¢(¤R)^~ùe^yåNŸ>Íàà RJVVVGA½^§T*ñÒK/188¸Ñȯë:ƒƒƒ;v M;X1‚jµͦ˙3£‘Ü`Õ…¥eŒXlË„AAOwšúÇO¨E4É:þúVîÏà»OþÞP*Õ¨Õ¤Ó‰Ð2¤¾ç‘_XdèÄ$ú6“ UUell,êávx†éúÏ…B……æççY]]‚àU±pÆãq¾ùÍo200ÀÂÂÂF@#¥$—Ë‘Ëå¶•À–:ÿÖ¿Íuþ¾¶9xöå©y*×ï0ú/ÿ-•ÜÒ„µÝñC C¹ùXmßg¡ìòÍãÝ gƒVß÷·½&Š¢<&cÙ’'mçúI)7Î )QÎLrçÎ4öô©c#ëa»ëkÀ›c>Y¬ 4†Á©S§¨×ëŸíï ŽmÛ …Ï.ã8§Nâ׿þ5ÀFâÌÌ }}}ô=Ԋܹ\ŽŸþô§!6îs…Bï~÷»üõ_ÿ5¯¼ò Žãðõ¯¡¡!þóþÏ4 wí«W¯R©Tèêzºnª…B•«W§êfffe#i±<×¥º^àÈé“Ä3J«A­Ö‘#=œ89ÌLJ¯«ŠB<“æÎÅ©®¼îN¸®ÇÊJ‘Ó§Gùàƒ;”J!ߤdæ“kŒù›·7½¬ðÁÜ»wºÃ³H'ÐŽxTï>›Íò§ú§H)QU•'N ( ##Aà˜H$¶‡­`qsðé8ªª>6övAÏNÐv¯;ŽƒHÆü£o²ú÷¿!yâ(Ö‘})UM,”lNöƨU«¬_¾FòÔj"¶­ÒB;Çš¯¹\š/ó¾4€©*H)©T*¤R©m³Zû9ÿͯµ”‚,Ë ^5n1ôƒïP½7CöóhñØŽÛïôš@p²'FJ“hªò0è ²4ê!2I‘RR«Õ‚ÕUÝðYh•³‹Et]çÌ™3ŒŒŒpñâEΟ?@©T¢X,’J=IC5HI®,]á£ï )Ñn¹ÇŽA>ÔÏÆÖ@±¼È…¡ ("Zdîºpï^ÍïZMÑ8?pžÕê*CÉ! 5¼yªB½ž#kò„åR>WZ+³-„üøÇ?FQÇÙ¸§Ý¸qƒX,F±Xܲ²Õ*|ÚnÛ†ÍÕ«Ó¼øâ1VV ”ËõpI‰ª©$º²”rA×z&›`~~ 7‚ q䨱~Öðýý6RJ•*÷>¼¼íß7¯HwøbÒ)ÝyŽ1M“L&C6›%•JDZ,‹®®.ººº0 ãs“P“R¢Æ,£4—s4WòAói0Þm1µ^§Vw¨Üž¦rkŠÞo¼‰)æKÉôzÇóÉXêFî“,åØ<®Ð4ú¾óöZ‘Út8Íp! iªŒe ´C¬¨`Yããã?~œññqLÓdrr’ðÆoP*•62žóóó¼öÚkÛžžz{{ŸØ¤H ƒÉA>^þ×w#Ae³Að}õjà” àKŸb£Èru™Ó½§#úžï¿8Ë>¥ríÇÐÁä …Fr³i,!##¼õV,´ ë󈔒B¡@>Ÿ§\.S,)‹¬¯¯³°°@µ¾9õ qR©N2'™Œ…þ-J ”[#ÕÛ®kd2 ΞãÊÇSáÏSô˜…•Lâ>'ܽð<Ÿ»w1LžžTèkãÚ6ÍjÈÏ=‡ç®×a[žTæ·¥Ó,tëÈù‹ã5úZ IDAT;N¨n8E¼1’ApýAž¥ÿŒÌ¹“¤Îžíøçx’;¹¯¦1ÕÏV=LÓ|b×cK“˜¦bö÷¢˜ë?‰T ý´šçž4MãìÙ³¼û9s†£G’N§9sæ ï¼ó'Nœ {z –fñúðëÜ_¿'£gÎzzà¿ý7¨>4v<‡_Îü’ã]Ç1ÕèÚùÕjðßÏÓpY*]VÅf‘ùò|äñ4-hÊMFófêð„Rb7þöÞ<<Ž«Ì÷ÿTUïÝj©µZ›%[–÷ØØñ‡ÄdnBO¶Éä?.~3Ìd†Ùg¸Ã7@æà ?2 .Bˆc“ÅÙ½Äû*Y‹µ/­Þ»kûý!WG²%YKµÕ’Ïçyúé­êô©êsª¾ç=ïûžšš’i/eíGŽ#K2Á’ï»a Ç·Ï ÛŽ$Q¾¨Ž¦·÷£ÏB€‡a$) Ý`ÅŠÚ- %¸rBÿ f¤;ÝXî@ŠÇEŇn q¦•ø©³Ó³\n…†b/¿Ù×F¢ˆ’k×O;/°ašèˆKël¨ âPÞCÈº×ØˆåËa6Ùå `Eɳç0 sZƒ «lAþâqxØT½‰Ö¡Vb™ØŒË aÕªaAn *±LŒE¡E3n»º>œŠòÚk‡sÐÏ6k*Öp¢ï„-–çó^s‚‡55ó¯3%™Ì°wïi>øÁ x½³èS'˜“¡…32O¼\˜"°l1Á«–1´ïè´-×Ñ£§QãIöe<´F2ÓZü&œÔxêP뫃Ô]l²ÌUÖ‰‘9ùG"»®_‰Ãï#~ªCš*—³û%™5kÈèêÌ“’4œþdk˜ã}' ºƒ3vÛ1 hkvÛÉ¡¯È ¥¾RTCý+€îî0ž¥¶¶§sz‰B¡¡B?¥KñNo…h·ÏË¢õkémi#6žVv¢ëôõG(¯(¾ú‚)!„þŽ$IÙ‡\èûï (Þòº~ó"éžþažIb&ɶNß:DÃ=ïçê†RÞnIkSûšaÒNNj,/óáqŒnþcùÒÛÅxAÏ’,ãø¨ºëß:Hò\÷”ʵ=ä7W€bo1ož{͘a`ŸK—«¼Ýz„5…×!3³8 Ó^ ·µ–/Ÿ½l;"!áTœT*éOô“Ñ…U>“JehoïcÝºÅøýS‹—’$‰@À˺u ¼ðü>Î<‚% £Кl9nŸ‚²úÚΡ«³?À4M“ŒªqèÐYêëÊ …DT¹`ò…pc­ˆ˜«,3#³ÁÈnÞ…Ux*Ëèü¿/ M.ežiš˜ªJßî7p•QyãVnXQj˜ëŽcLAé÷Å3èˆòþe%Ü_ü%Iµö€]HÒðBVãgÙí"¸f’¬Ð÷ÂkÃVýÉ—ibfTHÃÁ¼‚¼§:XÍ®¤õôŒ¬ú&𷓆z'‘3«Í™)s]‡ýûá=ïŽȧ U—⢱¤‘#½GHªÓ̱.˜˜¦I4š$I°qc#n÷ä°²,ÑØXIGG?Mg:h>pI–(¬(ŸÒ=ÎåóRµ¼‘{^ÇÈ£¥”uM§«s§ÓÁ¢E ¦dÕw8”+*µ¬`4⟿ÂÉ…5dÙ#qYü'Hª­“¾]¯MJ蘕TW/‘Ã')ݾ ‡×M×ɲ2/·„IjƤÓë-2ºÁ†šàEÖü\3Ñ9–dÅç¡ì¦­ ¾uDsû¤\xLà zô m=nåDä5!Oˆ÷Ö½—Ö¡Ö¹¢¦ÁíoPU\Dç9…DBšößošH »-\8í*å ‡ì Â_fh4…›f»:‚“H¤yá…w(,ôÓØX5©}dYÆãqRUULSSº>|_èo;Çâõk‘§°ÞJíªå`š õôåÕBRÃ+V¼ùæI®¾º¯×=)£”$IùY¾¼æ2ÔR¡sY‚qG )2¿—ÊßLìäYÒ]} ZÃ$y®‹“_ùWJ®Û€¯~øB•I§YUÐÍÓ‡{Hj†6ªºIw,CO<ÃÖºBœ²4¦ÅÒ4M’ɤíçÃZx‰$h¬§ì†-œûÙ¯P‡¢ZéõdŠèÑ3´ÿçopV•¡xó EŠà’¸7Åï=N8žVP®išè¦NÀ`yU[·ÂÙ³NO¯NÑ(ìÞ Ãb?ßP$…÷.|/MMtD;Ðü`{N0 ñÚkÇ©¨(Âï¿´  ½ìøƒkinî&Žg?õîêañ†÷àöù&,C’e\—‹®3ÍÃI#òÐx‰$xå•£lßUx<Ïx8 ¥¥A¶m[A&“?³‚Ë‹úsÃ0PUõ¢@OMÓPUø´µÛÚÆîÔq—Õ–$ V6à^PFçÓÏ£Ec˜ãˆýÌ@˜îß¼ˆ§¢”â-ëp‡ý3™ !¯ƒ›–Ó:˜fÏÙ!bã¤QËèá¤ÊoŽõQt³¤dü‹½iš¤Ó3s©K }@ ø)¹vé¾AÂ{ E¢˜úÅéHŒŠŽÐñóßR´a55ËŽüò·Œ‰"+ø]~ü.?̓ÍÓÊ$“ÖÓœì?I©¯”…ee,ZÍÍœ†W‹a@8 gÎ@m-äë’ ’$Qè)dYé2Nô˜ÖÂc3Ét4Wq¹\£âŽ,wMÇ“]:_éí"O±lY-s\±ïó¹Ù¸i)´¶ö’N¿;S–ŒÆh;|ŒÂòrÊêâg8Ù¡àô¸©[»šhßCÝ=99&;Èd4ÚÚû(x¨®.ÁëÛ-T–e¼^WoX©StvÌBmù€ús˜d2IKK ÝÝÝYQm---œ={6'©"'ËD.A®ÒbB›×ÒýìKô>¿‡ÌÀÅY Läû¹—I¶wÓøWÿgqaVÈʲŒ”øœ|öšjš¼rvhÌÛø¹¡4ÿ÷XÝdcm¿kâ›[®[eY¾¤‹”$K¸ÊŠYô?î£ëéßqîÉgÑ¢¯ê˜éÓñäo‘d™’÷nÀ]Vœ“: rƒ[qsÓâ›h´N+¯~{¤'>ÉââÅ8e'ÄbÃbªÝ=†S§àþûóÓš?—â¢Ì_F8Æ0§>ë–«5CòI’Xºt)‹-Ê&p8,X°€5kÖ …ò:?R9s¦‹[nYÇ’%UãZ¯W¬¨Åïs³ë…wˆÇ/žÖJ'¼ý̳W- ¬~lß4o Àâukq¸œôµ¶aèùÉ,Kñüóxïu«xÏ{ãpÈÙyÜn'kÖÔãt(´´ô‹Í~šPÁ쿽\p†ad-å†adWŸÝ»w/étMÓhkk£¹¹™NžB¡%%lÛ¶¯×ÍK/&•Êÿc䎙¯}dJÇñ¶™Ÿ¬ýŸ‡‚Õ8BA÷¦ó™ˆ:‹‰’»¨–ªÜŠwA’,—i˜ÙòÎŽi,,tqÍ »Î„y§3Šß©àsÉt¥¹®!ÄÊr?n¦i ëc«5¡(ʨºN÷ø/Ü_’¤ì¬Ë„ûË2¸œxê«©¸ó&:ž|–³ÿöÎ`€tïZ&ƒ§¼„ÚÝ·fÁp™¦‰®ë(Š‚®ëÄb1âñ8¾Kø¤ f ‰"Oþ Nô`Yé2¼ŽñW¶5MÕPij£Â_Au°:ÛÊˇÅþ«¯/¦ N솣ëøÝݰdÉps§â¤±¸‘—[^fUÙ*|Neâ|<ç펷Qug¾ú&Í˲páB$I"•JÑÝÝÍÀÀ•••Y£Ï磤¤„Ó§O³eË–ìùp8Q^>µ 5¹&“Ñèê$™H ؾý*Žk#* ´,ȉãíœ9ÓI<~i—Ëx8BË;‡Yºu’,£¦R$†"V”sêõ·HD¢y‘Js2X¹Qöí;Ö-ËØ¶m%é´JiiY‘éíbßþ3 %Æ-G–eJKK¢¯¯ï2àr"„þ"ÒÛÛ‹®ëPTTD:FUUTU%NãñxèêêBQ”QVd]×inn&ÐÐЀÃáÈ®ªj‰D§sØÒòý‡aOù¼Ð¶Vwu8¸Î¯¨cÝJ’”µéºN2™D’$<Ϩ߲öw:ÃÙfÊ‹ ݸÿUK|þ5ŠÖ­¢`ÝJÌïpÝÏÏ Xû[ qy½^dYFUU$Ã`Y±‹5• LªtEÓôÇ2l®öSòâ=¿dx:=¼¿e鲂‘5MC–eœNgöX¬¸·ÛÿVýE¹hëø­}­óçt:Q%7\òü†ªë(Å,üîað¥·Q|œ JqV–â*à<¿¿õß[ÿªªœ={–h4JiiiÎÛd¾bÝôGŠkš/B¦ÈSÄòÒåüâø/¨*¨Â­¸‘¥±Íêš©Ñn!’ް¥v˘ە•ÁªUðÒKpãÃ]g¬C5Œa‘ÿÒKPS3œ7® K2NÅÉ­KoåhïQ|.¥¾RdIFbôÁš˜è†ÎážÃ„Sa®¯»ž¾Þù)f¬ëGee%²,FÄívãr¹²×qëg‰;Ã0²3ŽK–,aÍš5=zt¶g¦iÇ ‡ãtw‡ÙzÍrζtó ïL)q‚iÄÃCìöy¼üÅ!Úž Læeàí¥0M‡ãìÜy€ÆÆj‰{ö›”ß2l-]º¿ßÏ®]».C³úsˆšš*++á‘x,ã­·ÞB’$Âá0™L†… ÒßßO{{;›6me±Yµj>Ÿ/œ¥ª*‘H$ká·‚³,ë¼+”,Ñ~!N§3ûÖ¶VÝdYÆÞñ÷Âý­m].8xz|ìCHÙåIfä}Û窪ròäI.\H0ÌŠãá2¡Ðë àVX\âC‘@‘kxô¶ÒEõO¥R455±xñâl]GÓ…Ço-°u¡•päùƒáO__ÙÊDçOQ”wËí¦üæm ¤(  [ýGÎD"ªªª²7ì+VH$ðzÇ·Ïg à g¯ÖìU&“ÉÎt䋨/ô²µv+Ïž~–[n¡Â_q‘ˆ7M“H*ÂsgžãÞÕ÷âwŽíL/IPWðöÛ°e Œ5©30{ö [ò—,™.;#Qd…ê‚j4Cã×'Í—|bo1nÇh6ÍÐ8;x–ÔÛë¶sêÈ©Yªqî±®¯½öZÖØ`K—.¥¸¸˜Å‹Ó××G&“áé§Ÿæúë¯gçÎD£QLÓ$•JqðàAb±@þ.Æ”JexuÏ14MŸqv´Tã f!ôç.Bå÷û¹æškÐu§Ó™µ>¯[·Ó4ñù|Yk¼µ¿e±·¬ö½½½YK]j¦i‰D(..žœ¨’¯ÐMÆÉª¡ë:­­­,X°`Üøùü &{;H$œ={–… Úš?YÓ4:::¨®®ÆårMý<ŸŸ‘0Áš³UvKK ÙÏFÆ^\)Œ´Ö›¦I{{;lÞ¼‡ÃA2™äôéÓ„Ãa$IbíÚµÙ}r F³.cá4–4âv¸Ù×±Š@ Å x&&±LŒÎX'ݱnÞ[÷^üNÿ¨@:&SZZŠ¢(8°f ¼þ:9ò®·¬û½½Ã~üµµÃßMÆ“Å0 ÒétNŽ©TŠD"AQQÑ%Û­µZnuA57-¾‰×Ú_cuùjà膎j¨ $xãÜܸèFüŠ?+~ç+f:“$‰_|Y–Ñu=;{ØÝÝMWW±X,;Ëh™L†t:MUUååå¤RÃÁ›#ÿ;ûËHWI»óÕ[F˜q³¿ÍY–³n’v¶§‘ ,ì¾.tµp¹\ƒAÂá0ééææÌ „ÐÏS¬ àD"Ùš’½±,2–¯¸ªª£ÜyJKKq8Y÷;0M“@ ð®kÖSMÓ¨¯¯Ï榷EQhllåzcº®gE¾ªª¶ pëY__?ª¾#}þgRv¾¥ß³,ôþ7š¦‘L&1M3;óSSSÃÀÀ@V &“Iúúúذa/¼ð‰D]×I$9ÍNÕÖÖ†Ï磬¬lÂíªÜU(… û:÷q¢óë+×Ó:ÔJG´ƒr9¥¾Rê}õ˜“xæÝ<áÑh”ãdzvíÚQׂª*8th8@ ¸=y6nùš6ü˜kÖ¨»»›ªªÉ-^4éîîfÉ’%ñ_HP²ºh5oŸ}›2†iÐïFÕUÜ7*7à6Ü$ÓIâñ8™ÌôƒGÎzæ Š¢P^^NOÏÅé MÓdhhì€å±„eü)--åꫯÎRœN'EEEÄb1Òé´mâV’$ÊÊÊ0M3ënW?t8,Y²„¶¶6âñø¥w˜$ÖÌt]]MMM3jObý—Ñh”D"aëyv¹\”••ÑÞÞžýÜápPPPÀ™3g¦]vyyyÞõ ÁÅ¡Ÿ§X´vt"+P«ººzÔç#/ªv»2TTTälÕÝÊÊÊQ­vaš&5559ÉB4–Ïx®ËÉo†1%Áu9p8x½Þ‹„~4åÀ¨ªŠ×ë媫®ÊZ[–JËÙŠ½°f¶žxâ ~õ«_ sÒV3™LÖºx) Ó@5TÒZšß¦‹×á¥À=œE’$œòÅeèºN*•â·¿ýí¨úkÚðäõQ*5ì—ÀéÓS¾Õ4-§íÁ²6[q.“ÅÄÄ0 tCg09ˆÛáÆç|×5ë tÉ”ˆD"Äb1n¸á†i×ÑëõæeŸXµjÕ˜BªhšFss3­­­£>÷ù|¬X±‚ÖÖVúûûm ²,sõÕW£ë:û÷ï·u°íñx(--eÏž=tvvÚV.@YYEEEìÞ½;;sm.—‹Í›7ÓÔÔDWW—m3’$QXXȆ عsçEßM”™ïR¬Zµ*ïú„àbÄ?”§¸ÝnR©TÖÇ}¦Œ%ºGf±[”[eçj´Ÿ‹A„% eY¶u1ÒEÄ®A„eÍ·ÎïXfB*•Ó¸Ýn<ÏE7ׂ‚6nܘ ô–e™öövb±Ù,T ,àØ±cÔÔÔàñxp»Ý|àÀétŽ936¬†• k* óÝLLŠß´®&æ¨A¯˜k¹麎ÛíÆív“<¿²˜Û}éWGbµ™|Âív³uëVvïÞ=㲬kÔ…B>‘HpêÔ)‰D6!H’ÄéÓ§³3 v }Ó4yñŰ}æwppÝ»wr}²Ã08tèPö<ÛiÑF£ìß¿ßös±uëּ낋ÉUDÚ¥Êë{iÄçÖ³<Æû‘ÛÈ#ö³Þ[åü³ãükë¹0“ɼ:…c™Òé4Ñh4|› ‰---”””P\\lÛÈÜ4MZZZ$‰ŠŠŠ)[é&Â0 ÐuÝÖTp™L†X,FSS „B![ʈD"477 ©­­ñy¶‚ç:;;©®®Æ4Íl*Õºº:[.¼äÕE»ð½9âõH.5¢µÝôʉ֛c¸Ýî¬%-W<ÿüóœ8q‚§Ÿ~:x5S¬HþöíÛÇ©S§l †J$ìÚµ‹çŸÞÖ@¨¾¾>vîÜI?‰Äøy‡§Ã‹/¾ÈÉ“'yýõ×mÉUl­­­¼ð ÑÒÒÂo¼Á‘#G8~üøŒË·R®æ“ ²ÙK ÂdY¦°°ÒÒRŠ‹‹ñûýY·ŸŠŠ <mmmTUUáp8lq{«K–,áÚk¯ÍÆä" §§‡}ûö‘J¥rh‹ÅøáHii©­ƒ_ Ó4‰ÇãÙXGG‡­VGEQ¨««Ëf—9pàË—/'‰LéÚ …²í/Ÿp»Ý466²cÇŽÙ®Šà cÇŽ466æ]Ÿ\ŒúyL0¤¿¿?gå÷÷÷³|ùrR©”í™,X€Ãá ¢¢Â6ë\2™äìÙ³„B¡Qyíí`ppŽŽü~?ÝÝÝ¶Š²@ @[[±XÌ–{dY¦²²’ÚÚÚlÀsQQK—.µeÒßßO0œq9¹  N*ýßx®,Ö{ËM$Wi6-7ˆööv\.WN~ËJ5[^^NNŒÖšN§“ææfÛËF¹m¨ªj«aÀºÄz?•>òºO<øàƒ9+¿¾¾žû￟mÛ¶Ùêºåt:¹û뮻…B¶ºy:N¶lÙÂu×]gë,—Ïçcýúõ|ìccéÒ¥¶• °råJxàî¼óN[V,¶’K|⟠¨¨ˆ’’î¼óN>ö±]29ÀdxðÁó¶OF#„~cå\·3àg$>Ÿ/»È–Ý>éGŽ¡¤¤Äö”|„Ãab±±X̶rÝn7ÕÕÕTUUÙ6»aÇÙ¸q#UUU¶e€0 MÓ²åY«aÎÔ×<‰ ËrÞæà÷z½»´ƒAúúúeÙvÿ|þÚÛÛijj¢¬¬,'Þ0¼¶†¢(¶g·²ðz½466æÄ7ßB×uü~Ö¥ÊîkQ:ÎöŸÏG"‘¸h­‹‰¨¬¬$äuŸX¹r%?üpNÊ¿õÖ[9sæ ×_½­+ ›¦É¾}ûÐ4††ÛÚ¯¢(ÒÐÐÀòåËmmO•••\}õÕ477‡m+`õêÕô÷÷STTDqqñŒË³fË`¸ÔÖÖâv»éììdÅŠ3*ûá‡fåÊ•yÛ'£Á¸yNqq1ÝÝÝ(Šb[`®Åúõë9{ö,ëÖ­³Õ?_Ó4b±‡ƒh4j[½½^/7Ýtétš¦¦&JJJl»9X"¼¥¥…úúz[ES}}=íííx½^ g\žuO¥RtttPSSC?\uÕUÓ.7‰DFåäÏGŠ‹‹QUuÜ´‚“¡²²’t:Ó餼¼Üæ¾kѯ©©!‹¡iZv¡:»p:,]º”E‹‘Édr"ƽ^/÷Ýw9‰’$‰ÒÒRêëë‰Åb¬ZµÊ6W€‘Ä•••ÙþÑÛÛK}}ý¤Dkyy9~¿ßá•KŠ‹‹¹÷Þ{àŸÿùŸm-Ûáp0000åàåKaå¡—$‰öövÛfQ].Ë–-ãܹs,Y²$»°”——ÓÐÐ@oo/n·›ý¯U“ IDATÞÞ^ÛêÉdX´hQ6GÿL1 ƒh4ÊÐÐP6qƒaôõõͨ=ÿõ_ÿ5÷Þ{oÞ÷ Á»¡?(++£··]×m*«¯¯ÏºØe©±rö~àÈ.Üd§¸±–z_±b…­åz<V®\‰¦i¶[xY¼xq¶î3E’$ÊËËùà?˜=¿V>êéþ‘H„H$bË”îåÀª§¢(ÓJŸçñxhllÌIšVGuuuÔÖÖfÓkæÊMÈétÚÞÏ,dY¦¤¤„¢¢¢œÕßáp°hÑ¢lJW»~ÇrÛ±þË‚oÅ\ʸQYY‰ßïŸS}â3Ÿù ÅÅÅüÅ_ü…måf2ÊËËmÏ¡ïp8¸å–[8tè­ 6†‘]_¤¼¼œ`0h›{jOO‡æäÉ“,Z´È†Ú¾KAAGŽ! Ù2h·Ö)**¢°°0»Ä‚ ²™§¦ÊÃ?̽÷Þ;gú„`!ôç²,SQQÁÀÀñxœ’’[Äh.\àݼý¹"¹è­”švNM[جd G;êšÉdèïï϶±¹ÂÈ>áp8ˆÅb Niÿ\®<ÙÜùvþÞÈô’#ÓÛZ‹áMÖUÅš•³VŠ›Ëtëž«\ÜÓùB¡@€@ 0§¬–VŸøøÇ?ÎúõëyôÑGyê©§f\î/~ñ ®¾új~ó›ßØb]sûûû³.žã-î5Ut]çàÁƒœ9s†ššm³ºwuuqøðajjjØ·oŸ­±\¯¿þ:+W®¤§§‡ŽŽŽ—gš&n·›xø +W®œS}B0ŒH¯9ÇH&“D"E! fýësem›OŒ·è%jr)üò+Ov*•"‰dg‰æ²¯¥Õ'Òé4étšT*E2™´=gt¾c±X ¿ßŸ=þ¢¢"†††p8c1www_4À3 ƒŽŽ‚Áàlçt:ñz½Ù4¬n·{Þô‰S§N±sçN^{í5Ž9’“ S‚ùGyy9«V­bëÖ­ÜtÓM466æ]Ÿé5'ús”t:M2™ÌšÙ™©B0Q‡ÃÛíÎZwæ ¢O¦ƒèÁhæBŸBò×9J>ætfÑ'‚ш>!濯‚@ @p"„¾@ @0B_ @ ˜‡¡/@ ÌC„Ð@ æ!Bè @ ó!ô@ ‚yˆú@ Á†išc–qòäI¶lÙÂþýûGíóÈ#Œ¹ý–-[8r䈽"L“]»vñçþç|èCâ†nàþûïçé§Ÿàà—¿üeÎëðÑ~”Ç<ç¿#È_F^‹¯¹ævìØÁ¿øENŸ>mKù“mË“¹'\Žzä3ªª²eËÎ;7ÛUä ŽÙ®€@0wß}7ŸûÜçÈd2;vŒ/ùˆÁç?ÿùì6gΜaÏž=\{íµíÿØc]Îê ¶ñ¥/}‰}ûöñ©O}Š?ù“?AUUŽ?NAAÁe­Çu×]DzeË.ëo ò»îº‹|MÓhiiá·¿ý-<ðÿ÷ÏÍ7ß|Ùê1™{‚@ x!ôyÓéÄëõâõzÙ²e ðÀ®]»FmSPPÀc=v‘Ðokkcÿþýø|¾ËYe`Æüîw¿cïÞ½üä'?Áï÷g?oll¼ìuùô§?}ÙS¸\.EEE¬]»–ŠŠ ¾ño°eË–Ë6Ì=A ¼‹pÝÌ)zzzhhhõÙwÜ‘õ#ùñÌ=÷܃×뽜UfÌ~ð>õ©Où¡ª*ÿò/ÿÂŽ;¸þúë¹çž{xöÙgGmóúë¯óÀ°}ûvvìØÁ£>:©ïÆrgøÙÏ~Æ}÷ÝÇ-·ÜÂC=Dggç ŽV0WùèG?Šiš¼üòË“jƒ<ð;wîäÏþìϸñÆyóÍ7/*3‹ñ‘|„þð‡“ªÃÈ{Âdê“k¿ÖC×u}ôQî¼óNî¸ã¾ùÍo²cÇŽ¬‹ÌxÇf=ö÷Üs7ß|óE¿wë­·òÖ[oeß?~œë®»nÔ9ûÑ~Äg>ón¸á>ñ‰OðÎ;ïd¿×uï~÷»ÜyçÜ~ûí|ýë_ŸÔy\9‹¾ ¯yíµ×ظq#º®óûßÿžßÿþ÷üû¿ÿû¨m<÷Ýw=öëÖ­ ··—_|‘§žzŠ'Ÿ|ò¢rUU%™L^–c¦B*•¢­­U«VMz§ÓIMM _ûÚ×p»Ýìܹ“/}éK¬\¹’ºº:¢Ñ(_øÂøüç?ÏÍ7ßLoo/©T `ÂïÆâ?þã?xî¹çøÇüGJJJØ¿?EEE3>nÁÜÃårÑÐÐ@[[Û%Û Åßþíßò…/||ÚÚÚQåéºÎßüÍß°téRþøÿxÌßœèž0™:L¦ýŽUï|ç;ìÝ»—ÿõ¿þ^¯—ïÿû´··Úo¬cûÁ~Àž={øÊW¾‚Çãá[ßúŸýìgyâ‰'p:—<Çáp˜ï}ï{üð‡?¤ªªŠû·ã¯ÿú¯ùÅ/~ÓéäÑGåí·ßU/`$Bè òš––zè¡ì{Y–ùÅ/~ÁŸþ韎ÚnÇŽüÇü'Nœ`Ù²eüô§?å¶Ûnw:ùç?ÿ9?ÿùÏsZw`:œ;wÓ4 …BSÚïî»ïξ¾ÿþûyæ™g8zô(uuuôöö¢iÛ¶m£  `T¿˜è» ÑuýèG<òÈ#,_¾€[n¹eŠG(˜O”––‡‰Û Åí·ßÎ]wÝ5fY_ÿú×I$<üðÃãþÞ¥î Õa²í÷Âz¤Óižzê)þõ_ÿ5ë>÷WõW<÷Üs£ö»ðØTUå§?ý)>úhvÖáþá¸óÎ;yùå—¹á†Æ=N‹¢¢"þèþ(;ðÿÃ?üCž~úiÚÚÚ¨©©áÉ'Ÿ¼d½W6Bè òšûî»/d•H$xæ™gøæ7¿ÉºuëFMoî¾ûnüqþò/ÿ’_ÿú×üô§?T¹#Ù²e‹ý!L’’ÚÛÛY¹rå¤÷ ‡Ã<÷Üs¼óÎ;D£QÚÛÛ³–ùúúz®¾új>ò‘°mÛ6n¿ýv6nÜxÉï.¤££ƒD"ÁŠ+fx”‚ùB___6>j¢6h±zõê1Ëyæ™g8tè¿þõ¯'´t_êž0Q&Ó~Ǫǹsç0 cTPº¢(í{á±;wMÓ²ƒ ¯×ËêÕ«iii·"IRöuee%^¯—d2I{{û¤ê%¸²>ú‚9ƒÏçãÞ{ïeíÚµìÛ·ï¢ïï»ï>^{í5~øa¶oßNiié,ÔR ˜EEEóÆoLzŸd2É'?ùIúúúøä'?ÉW¿úU1 ¶z~ë[ßâá‡ÆårñÅ/~‘/|á —üîB¢Ñ(@¶\Á•M&“áÌ™3,^¼ø’mðRlذ`08¦«åx\xO¸T&Ó~Ǫ‡¦i†1åvŸÉd0 ]×G}ît:q¹\S*k$–ðŸn½WBè æ¡P(›ýáÂÏo»í6~÷»ßññ|j&ØÃG?úQ~üãO:öñãÇ ‡Ã|ö³ŸeñâÅø|>N:Eww÷¨íÖ¯_ÏßýÝßñý^z‰ÞÞÞI}gQ]]a?~|f(˜üìg?£ªªŠM›6Mº ŽGee%_úÒ—xüñÇyùå—§Tëžp©:L¦ýŽUšš8Ýn¼µ[F2Ö~Öï[®<^¯—³gÏŽÚo2eϤ^‚+ !ôy®ë¨ªŠªªD"vïÞÍÞ½{Çõmüã?þc¾ûÝï²páÂË\SÀ>î»ï>–/_ÎýÑñÔSOÑÔÔDkk+Ï=÷¯¼ò 0lùïììÄ4MŠ‹‹‰Åbü×ýCCC¼ð À°hˆD"üêW¿ÊÚîÛ·¯×Kaaá„ß]Haa!Û·oçᇦ¥¥…D"Á+¯¼"Û¯¬±XŒ£Gòo|ƒÿüÏÿä‹_ü"’$]² N†Í›7ó©O}Šú§º(ÐÕb¢{Â¥ê0Ùö{a=|>·Þz+_ýêW9zô(}}}|ûÛß¾äñø|>>ô¡ñµ¯}£G200À7¿ùMB¡›7o`Íš5üò—¿¤««‹sçÎñ•¯|UU'u¾¦[/Á•…ðÑä5O>ùdv µ°°ÆÆF¾öµ¯±xñâ1·/,,ÌfÞæ*‡ƒoûÛ<ùä“ìܹ“ï}ï{Ȳ̢E‹øð‡? ¾úÕ¯ÒÔÔÄW¿úU>÷¹ÏñýïŸï}ï{lݺ•íÛ·gË‹F£ìÞ½›ï|ç;ÄãqêêêøÊW¾‚Ë墷·wÜïÆâoþæoøÆ7¾Á§?ýiTU¥±±‘%K–ˆ4¶ó+ÓédÑ¢E¬Y³†Ÿüä'Ùa]]Ý„mp²Üÿý>|˜/~ñ‹üà?ÀãñŒúþR÷„KÕa²í÷Âz<ôÐC<òÈ#<ôÐCƒÁì"a#ýçÇ⡇âÛßþ6ù—‰¦ilÚ´‰Gy$»ßç>÷9¾üå/óÑ~”ªª*n¹å–q9ã•?²^·ÝvUUU“Þ_0ÿ™¸…æ®Ü±¾—F|n=Ëc¼¹ú@ Áq%"„þ#™L‰Dðù|ƒALÓœÍj æ’$ iáp€`0ˆ×ëÍjÍ«O(ŠB0¤¸¸Y–³Ç*L„iš†A*•"‰‡çMŸH§Ó¤ÓiR©ÉdUUg»j‚9€ÓéÄëõâñxp»Ý¸Ýî9ß'®d„ПC  ª*ÙÏ„ÀL«½(Š’mG‘H„d2IqqñlVmZ `ååå¸\®Ù®Ž`"IŠ¢à÷ûñûýd2úûûçtŸˆÅbÄb1g»:‚9ˆªª¨ªš5*†B!Òé4@`Nö‰+á£?0 ƒîîîQâL °‹‚‚E¡»»Ã0f»:“Âê^¯—ÊÊJ!ò¶ár¹¨¬¬ÄëõÎÉ>‡ikk"_`ƒƒƒ´µµ‡çTŸ #„þ ··ŸÏ‡Óéœíªæ)N§ŸÏGooïlWeRôöö …²®k݃AB¡Ðœê‘H„ÎÎÎÙ®Š`žÒÙÙI$™3}B0ŒúyÎÀÀEQf»*‚yŽ¢(x<f»*200@0Äï÷ÏvUó¿ßO0œ}"ÓÓÓ3ÛUÌszzzˆÇãyß'ï"„~cO K¾àrát:QU•d29ÛU“d2‰aÂ’/¸lƒA ÃÈë>‹Å„%_pÙèìì$‹åmŸŒFý<&‰Ÿ|Áe§   „•oD"JJJf»‚+Œ’’’¼î±Xl¶«!¸ÂˆÅbyÛ'£B?OI§Ó³]ÁN¾µÁt:¢("ðVpÙq¹\(Š’—}"N‹À[Áegpp0ÛþùúyJ2™ÄçóÍv5W(>Ÿ/ï¦e“ÉdÎ]vLÓÌ>ìÆ0Œœd«0M]×sZv.ÎG®Îs®Ê ƒyÙ'r-´æjŸÐ4Mô‰—k-È&Èo„ÐÏSÒé4‡Xæ@0;8޼³Ô¤Ói<ONÃòÅÖ4ÍÖ£iš$“ÉœÜMÓd``MÓl/[Ó4m_QÕ4Mâñ8ªªÚ.@t]ω+‹ÇãÉË>‘J¥l-s¤°·D­õ_†qÑ÷3yÄb1âñ¸­eZ  õõõ‘Édl/[UUúúú²×;ëFI§Ó¶ŸgMÓó»™J¥ò®O.F(É<%7m`*ä[Ô4 YέmBUU:::(++£  À¶ÕuMÓ¤³³I’X¼x±­«öjšÆÁƒY·ní‹Ù$ Þyç¶nÝj«áA×uZ[[)//§¸¸ØÖóœN§ijjbíÚµ¶”i!Ër^ö »–ØÌd2£>O¥R´´´PQQA0´­š¦É™3g$‰eË–ÙR¦E&“aÏž=lÞ¼Ùö˜žÁÁA^}õU¶oßnkæ/MÓ8zô(UUU”””Øzžãñ8ÇŽcãÆ}o¹¥MË("Èo„ÐÏSt]ghh¶®z½^$IÂ0 TU%‹át: —¼ X£v;ÅÅlüÎå:kº7×¢Ò0 $IÊùù‚©Ÿ3Ë’—Oèºnë¹2M“L&3ê85M# f-ðv P¿ß,˶[õu]§®®Ó4I$¶–mš&‹-BUU[Ë6 #+fì<Ï0 ÀòåËQUUéîîæäÉ“¬]»–P(”½–†¦i,Y²„uëÖåÜMN0»¤Ói:”5( æ/Bèç1K–,¡¥¥e”e*rðàAî¾ûn>̹sçhhh˜Pèç*àéB,Ÿ¿\ WËw1—hš–óÊ,Ëša99éëy%ˆýžžöíÛÇ>ð$I¢¿¿ŸÓ§O£( kÖ¬5é;r¶ÈzowŸ±Î.Êy,v—m]?ìîw²,çäºdÍ’,{ä9ºR°Žu``UUQ…H$Âîݻپ};`óæÍ£R8+ŠB  ¨¨¯×;[U\R©~¿Ÿx<>ÛUä!ôó¯×{‘_¬¦i8œNg6`Òº [7ú 3ƒ}xö<‡RQÚ°½ Ó95ku8G‡t“„ Ý$©›¼'¤°¢P¦À)e­©¹úVT.§ 5M…XNÄýæïÁãE«kD«Z„bxý˜îÉ[»R:DU“þŒISÔàÀ€Fg\ãÆRƒm²J™77ÇbŽÉ²'ãµíææfmý½|¥¸¸xÔ̆®ëèºNii)ûöíÕ'š››ioogÁ‚£®†a‡Ñ4¢¢"œNç¤Û°5«FI$Ùû’ßï§´´tNb±ápǃÛíÆívOyX×u’Édve㢢"JKKq89?7Öà÷Ô©S°råÊœþž`öB?±"Ú­r“Édöf‹ÅH§Ó],ÇòÙ”Ã8OÁñÖï1ªêѮڄQ³£¤\ž o²¦ ½)ŸŸMó³ Y’‘ÐL(t˜|¤Ná–7nCÇéÔr.ô­×öÿ€šŽÔÝrø-ÜoíB1 $”Ão£¸<¤Ô¢/[‹¾fó°ØWÆïBºi’ÔL^éʰ»3Ãñ(D4Ó7» îŠp{›Ú€·ŠçÎôiš6*ÀòWžèºžkšFaa!½½½ƒÁQâÏï÷ãp8.²V›€ªïIPYà¤ØëÀçµþ5¦ ºÝ˜=ç…¾1ü¹×´h)RQSVl¤Ž´ºÛm!×MˆªNô&ˆ¥5 ¼.™¯ƒ"ÏðC–aÂVkˆC$Œ™H@_Èò°…½¦B%àtƒMÁ¾V[yž­6)7Çù„$IÙLOñxësìp8())ÉZ*GºtH’D…ßIÉÂí‘4Ç{¤4ƒk낸” Ο¦aôB×9¤%+  pxmÐuãõÝÛn‚‚BÛ©ÖLžÝî5† Ñ ïô¤X]æau¹E–Hdtú“MI¹)ñ9& šÉ`¾ñ,¨†òJ¤ºÅ (H™ zÓ h;‹´l5‹l³ìå¦#IåååWTÚb—ËEuu5º®“N§ñz½¼÷½ï¥··—U«VeÝseeecdY¦¬¬Œââbº»»inn&N³aÆ Eº¦i´µµqêÔ)¶mÛFyyyvvâÄ ~ò“Ÿð‰O|‚²²²93ø2M“ÞÞ^Ž9Âòå˳÷_+è·­­êêjB¡Ð„×Ût:ÍO<ÁÒ¥KY²d 7nÌÆ•ìÝ»—C‡ñ¾÷½ŠŠŠœ^·eY¦²²’P(”³ßÌ>¹jA—*w¬ï¥Ÿ[ÏòïGn#ØÏzo=”óÏŽó¯­çÂL&óêŽeVhmm%d]U¼^塀åsér¹.)â2É$F&…Ç4PºÚpìùŽCobT/"ý‘Ï`Ô,¾hèMꇶz#ŒáÆ“ÖM¨|úåAÜŠÄgV¸¾ÊW‘pÊ`˜&Í݃üçd^îRIéð¹Õ>¼ÈK±Ûž›ž•~ºB¿¯¯… ÚR;hmm¥¡¡aÂm,Ák¯%‚/t_²¶ ‡Ã£Üß,¡cªn ê&-Ci0aQÈ{,w]Ãìïã‡6\ n÷»3=–¥?A:ziùŒP©í®*N§ÓÖÜÿ† íCiºâ*ëjŠ …ócÓD7!¥¼ÚeSM€wœþ˜Jb¶ž§ ©²œ.†§$IBO§0‡áøAX¼iAÕ„³d“ÁrM™öÏ2‚ÎèÚqæÌ™¼ëmmmã~oµ‰‘³y0lQ¾Ð}ÏÊ_UUŦM›.òÑ·\&-×7Ó4©­­Ó]EUUΞ=ËîÝ»¹çž{ðûý£\ê2™ }}}<ûì³ÜxãÔÕÕ彨7 ƒ®®.z{{ill̦¥9£–J¥Ø¿?kÖ¬×J‹ÅØ»w/‡•+Wâñx²®:Ö€¬³³“Ý»w³uëV–.]š“Yd2ÉþýûéîЯ­­•>Ñ××7á÷¥¥¥c~îr¹®†ÐF<ç_#戇õžïñÙ…ïͯGr©‹´íî ùݳ®p<@€‚‚.—+ë ðz½Ù ÍD˜²Œéò`£7¬$sû'ÐÖ_‹Ô׉ó¥ß E‡àw‚®„Îã'ü¼9I}ƒÿwu€µ%NJ=2…®áGÈ-³©ÜÅÞSÀª“]:?8§'©£s(èÍ4‘:[qüþPBLwE IDATU›ÞGâ¶cÔ6`úàña‚˜¡2Œ¥kP¯¿0qüþW(gO[my×õC7áXXå[‡cDU“‹¼Ü\ã¦Æ¯Pâ‘ º†cjü2®ôó©•üN‰ÿ<“àP¿J.¼’®dYÆápd…þÈ÷SÅ!K¸2‹Cn¢HZG¿ðÏ1MèïƒîN¤÷lÏî\’4ì’ !-^>,zÃý`äoJ:Ý0éŒfh‹dXQæÃïRpÊRvl"KNYÂ甹j}IúÚÅíV×0£CÉ U-µµµÜpà œ:u*'‹Ê ®,„пÒpº0Ced>x/¦?ˆòÎÈÇ€:‰Ô}Ž´nòLK’¸jòáE^Ö–8ñ*Ò„A’NY¢±ÐÁÍ5ÿ?{ïõ$Gvåi~÷º ©µD"¡EªŠUEQ’l6»gÈ™›î^öôÃÚ<¬íÚ>Ο2Ok;ó°ÆÞYn7Å4›M²K@±4!Z¦Ö‘"”Ë»Q„È2Ý…, >37ˆë"ÃÝÏ=÷w~'FÞVüøv‰¥ÊÞ{h߃ï#s‹§‰JepßøW¨dzËâä:š†J¤p_ÿsü}‡Ñ.ÿýò(olðébu’t¨Éà?š¢-&1ähš-É_$hIþþv‰›k•FZO ¨ÊxF[c(¥˜ßpñüU*€®#ZÚý©¡ˆþa˜™€òîv±Ý *^ÀĪMwÚ@ߦÜÉÔ$#Í1 .¶€ëU‡šÛ •©®Œ=ªlKJ°,ÄÁ㨙q¨”ž=L-#?88ÀÒÒžç‘ÏçëÒžíêÊc±Ï=÷/^ܓ͛lÛfvvvG…܆a088Èòò2®ëbÛ67oÞ¤¯¯ööömIn5M#™LòÆopñâE666öìŠGƒ½M#ІQé,þ©oà8Žvó"Á§§™Ì—øÕdU—ÿW# ,M<2W£Ù’üIŸÅpZãôœÍ¹e_íEBQ)¢û9?èy¼“¯n-/xà g÷» †‰öÉûä–øÕtOÁ_ísªÝäaF-õ¡¨&<_h7ùÛÑ$óå€ß*±RÙ{ßg™„!Ù×cjÝÁµXËÃðª&»Åµš±¸ª°þE}ÇÞÀñ·V*XºÄÒä¶ï{!ÀÔÏu'™ßppf&m›ªo‰Ô £»*/Ì-…;‰_*ñxœþþ~æææØØØ`~~ž—^ziG]Øu]'“ÉP.—Y^^þRš;n×u™˜˜¨»Ùm÷œj˜9Rwλxñ"ÃÃÃ$“[;µÝ®ëŒŽŽ‹Å˜ššjú BÑôŸq‚–vœ÷QÉ ùÏ>á?Ÿ'ð}þb8Ngbû/{¨¬Ciÿt2ÍR%àçåªV/>›”B»~ã7OÐÕ÷ê·«AÉNÜP¤FÐÙ‹ûæ÷3ÜúíþyÊæ•“¯m3È¿›¤.øÞ@ŒïôYüjºÂ?M–÷æµ{F‘BÓ%Eǧ¸°€ZÍ!š[·ŸÍ¯¡ëˆƒÇanª^ó¤ L­Ù”Ü€] ô~y5!hMèl¥™y°L0wè.èFÕWqngŸmðDRbY¥R‰ëׯ333³£l~ Ó4yã7¸råÊ=µž$J)æææ(—Ë:thÇÅËš¦ÑÔÔÄÆÆccc$‰{:so!–eÑÛÛËÍ›7wôÙ j4ýgM'hëÂ{ñ5RÅ/_}—?íªºéè!,cšàµn‹—ÚM>^tø‡;¥½'AQ ‘[Âø—@xÎ÷þÕÑÊòPÅâxÏIzÇ~ËÑâ4ÿÛÁmñw•_Hxþv4IB—üt¼Â¹ç«ä`ô”cH8Úãêiœ®þeókY•´¤3¨›WöD ¯P,]ö·Æ0!ÕÛŒš|/GyfqðD8›L!Ù–jñîÌxµñXƒ=®ëŒŒŒpúôi<¸£Ìw !mmm´··óÁ쉬¾RŠ••†††Buª­¹ŒñÖ[oí¸snmœžž,ËbllŒRiïIþìmþ³Ž(Mg~ÿ)Š©Vþzá÷ü‡¶]– eõ­ H’·/NÚü—«Ef‹>Þ“nÿ‘ @û‘[Â=F°ÿØC_= ¥x}L÷"ã–øOÎYޤUèÆWqMðB»É7»MË>ïÎØ¸{¼ÔáYB# ½¼ ñ$¹xKx?|)í]UgûÉêÑ¥(9 C7¿Š^;ÇlS%3NÖÝ0ƒ#¨—Ák¸ìu”R¬­­‘ÍfÉf³¡<Õ4ÿûöícuuuSÛÎ/“Z’ÝèN[,éééy¨ËΣˆÇã¼ð œ9sÛnL~ìŒF ßÁÏ‚^~™¥É+òÒâ‰À =ž&àÛ½1^ﶘ.øœ™·)塞¾k£ý\ïå·Pñ-§ÞB°ŠÁnƒ =Î[sŸ‘t+¡;Ñ Q]ùÛÑ$iCò«é îÈø6¨"l®ŽÑ×ßÁ ?ZýIº Gª.3OÐRÒ `®àО4H™;_‰¾h æ“*æé‰ÁØB 7ì=/eUö“mb!Ü ¾4ŠÅ"ï¿ÿ>Ï=÷\dw˜ŽŽN:ÅÂÂÂuà©ùæ·´´ìHS7J)\×%—Ë‘Éd¸víZh›L)%‰D‚îînòù|¨1<»4ýg/Päì€Ýqø]ö¥Xí g#ki‚ïöÇȘ’ŸO”™.î‘f(®ƒ\˜EÎM¢ºð¾©gÉS|¼èòë ƒ3'‘‹³è8]mB!`8­ñõ®ªÝæé9›õ†ÝæÞÀs­´·fÉÆtÖ*ÞƒM´¶‹+Žº}ìÊîç(»>ç犤­A>€ï£ÖrÈXœ®6ì/ŠäLjˆ¾¡zí{Û¶dppL&ÃÆÆFèl¼”’T*ÅG}D¡ðä&y•J…Ë—/‡ò¡ZÈ;77G&“áÔ©S”J¥H«º®sâÄ )—Ë¡ÇiðìÑôŸqŠžâWS*ŠÎÑÔó¯¢ÍÜA¿nø¬0’Ñù³s.—rîžïˆRãÌ?ƒïã¾ò6*™úÂþoç_øæÿèF‰ÀŒÑ÷Úk]}è§ÿ±<þ¤!x½Û¢=&ù¿®Yn8ðl ß÷ïi¼¶mãû~ô?Û®úß·´™¤,ù 7¼¾‹¡<eWªþó_2 È•=ú²ÖC{e<ßC]:‹hïDÅèÏšäÊ^øÙRV• ¨JC“¥…B *• J)Ç¡P(Ëå°m;ò=Q,™¥¯¯L&C2™dqq1t6^A:ƶmŠÅâ‘ï(¥X]]¥»»{Ûvš›áº.¿þõ¯Ù·o™L†îînVWWCwÖuŽŽVWWY__}\ ž=þÆó<\×Å÷}‚ @)…R ÏóêÊJ%àïï”ɘ’öu`|ïß#…Dûü ¢¸I;ÜÓøÛÑøåd…¢Ò8 ö6áh ;žçÕÔ´}†aðöÛocÛ6Ÿþ9Ùl–¾¾>¤”uYÏýzd×u7ÍPÜYõøÝ¬MwBrª¤ç`£ÇÑÛ»Ñ'nܺŠ;ze>ºÃ¥çyض}Ï>”‚7:$?¹#8·ìp'_f0¥ÆÅ¯æbPËLíðÃhcŸ!gDZŸ¢’ÌlQäçº.RÊ-­Ðà+ÅéÙ2‹eŸÿyÔ"¦\lG /¿Eê'ÿqᜓ_GÜ—/½;»ö°F,q5lò_oØüã"ÇÓæ6}΃ Àó<Çyà\ Ȥ?݋躎®ë,..’ÉdX]]%cš&‰D¢>!BÐßßïû …{î!D}VÛXY‚D ߊݓ]6eÕ%i¹`Ë<|™¿6ö¦ß]ÃDås(ÇÝq®ZPW“øm¥À ªÇÒ™0·¼Ÿj^ൠâ¦ä–PA€ ü{¤~½)OÖ*mK¿÷;[{=ò>Ö4è 8ûQÕŽt«kÏŸ»Ç®M蟺ïýf!H$ø¾O>Ÿ§³³“B¡@,#‘HÍf)‹õk$„ØQ×Ö ˜™™¡¥¥…¦¦¦ú5¯5ЊÅb¬­­ÇCŸC*•ª¯d‡ñ±ß)w¿_ÚÛÛ#3;ûG3‹Úq !èîîfll Û¶CõˆÅbœÿïíŸçzÓ&‰‘~-Ø0 cÇ] Ì[—P© Þþ-Ó¼åµ@«î޾‚ŠpeÕ§-®ñ7Ò4[¢Ú WÓàà TW?úÄ Œreµ>àìÕìä£Î%©ÁŸêüfÎç½y—ÿåHŠSc;rêZðWËôÞMX?罌”’ÁÁAŠÅ"©T ß÷ëÙÁšNþxŸÔVÇ6£äCÕQfvÑÖ÷iv•ª:L­Uô<6;—Úæ"ùpÙg²ðr‡IWÒÀ¼ëÚiÉ4þÁ“H×&öáoª×ï¾s¨e¨u¦¡Ñ‘4x¥Ó¤ìÁÏ&JêÑ¿‹Íd÷ŸãÓˆ®ëd³Yt]Dz, èÿýî—!ªµÉôet¤ Ž„¯¡ÐtH$QWχr»Ú:ß/€ó %Úzèž_ÕeŠˆÎž~,… 5¡Sp"ö¤Ò¨R"gFÑ]ÕBÔW|ãñ8ñxœX,Fwww]£öžRâû>---ünÞaÕØŸ5Éè˜Ú}«é,þs¯"—æÐn\ÜV‡Ê‡=,ºoöÄ8·ârnÅÅ‹(»ÜɃIØeŒ÷þ&þÁ“ÕÀ!ìƒ(¸ŠÿzµHB—¼Þm!Å]à ºN0°Ÿ ¥ã³Óȵ\èc—B×§ÚLÚâ’wfl–ËÛ“gܽdü¬pÿK«ö÷Ð×À÷ªn;¦›tOZâÕlغíDñÔOgQ3Õ`ö1ë’‹ŽOgÒ@F±Ô ÔÔmhn+öÀ=%K“ÄuÍ™HÓ­07N£+èN¨%-„õ?ײ÷aï ×uY]]%™LÒÔÔôÀÏkÁ,@¡PÐÖ& /^¬Ûƒ>NÊå2mmm‘’ ¾ïsöìYz{{I¥R›ú¦ibYV$Ë_]×äÒ¥K‹ÅÐÇÛàÙ èïaî.¬ý½öŽ’•Ýp~9UA øf—EÆ”Üÿ¾WÉ Þ¡çPÉ úÙåh“ޏÆwúc$tÁ;3ŠQ#ý WЮôïÃß$ÒX‚[ëÌ;œh58Ѻ¹.;è!=†È-"g'#íàX‹Á‘fƒ›ë.“…=Ò|ìY RF} Ý}°Åò¶‚lLãÒb9š«”i!@­å»§~Ù øÆ@š”±IÖÕ Õ•Ž-ˆ’¦¸NÙ0 ªeôWWP¥F§Ü'Íúú:ÿôOÿÄÁƒ·Ô‡×üðoÞ¼É ?™Lòæ›oÖíA'•J…S§N‘H„ï”î8ï½÷mmm[þŸš i”É‹®ë´¶¶233ÃêêjØÃmðŒÐôŸ1K•€Oú’:ßìÚ¢€PT¦p?r~ªšÕ€ÐŸÔØ—ѹ˜sùdñKêvé:Èé;×ÁEµtF®à|¼è  x¡Í¤#¾EÁn<à8µÑnŒ!VW"í7kVWVmÅçËy»a7ø¥à¹P( R™‡‚f-|¹j³:ñ¨0¸ÖòÁ6÷QäËK%S“áe;AÅbß¡êµÙMÚ’:ŸÏ)DùÎ ‰Ü¹¥ðc4ØÇaeeå‘Ùït:]7‘ÐZ–Å‹/¾ÈÜÜ\d‰ÊÃX[[#—Ë=PǶj…ϯ¼òÊC}MÓhnnfll,R6^JÉK/½ÄädôDRƒ§›F ÿŒQp«AþbÙç_ Æèˆ?$£—Hâ}\íÚ…ª7Âòi‹%y»×"o|¶èà+{-¹º‚¼>†Ò ‚ýG(¦Ü)>Ÿ.:4[’Sm1m‹—‚¦ãì'è@Þ¾ŠŒÐ)ªŸ/¶›ô&5>Zpr¿$T~ö¬ù LMp¨-ÎRÑŹ–ÕÂÓ €õÇ—¥+º/ÛºŠç¢VW½ƒUÙÎHq]ÃWŠrĆ`¢½»Ú˜«R~ìÒ¦[333Ã+¯¼òHùaìÛ·\.:«¯i±X ß÷«§~¹\~¤Ú£°m›™™Ž?þP÷¢Z1m­×AX„ŒŒŒÏçÙØØx"]„|5húÏK•€ŸO”i±$¯vš$­ÔÊŠã½øh:rêbc5R·×¤!øë‘ºœÏ¹”¼à±7гh—>#ÜOÐÞi,¥àüŠÃgËßê²èM>ä¥ $Ò¸¯ýb=véóHÁ‰& É’üÙ@Œ©¢ÿå­ˆ<Ë~UÞÙÍÚ¶ûˆ’‘Ö8ùоyTg¾®ƒZˇã¬U<† ß ª×%¿²-‡ MÀó=)–Š^ø[@ˆjD¶µ8é9Ô <žçQ*•}¤t4‹188ÈúúzÄÆŽŠJ¥Âü|´dÉÃØØØˆd P,™™™Ù–C¦i=z4rÇîxæH¿&9rþìB¥,Û.J(>^tˆk‚ÿõh’fë¶„¦‰wìk¨Tíâ§Õ:‡Y—˜&øN_ S ~9UÁRàØàá(K ˆXâ‘þíµû¨èlØ^¸B@O?ø~µx—3×JUñ@k˜· |£Ë$õl>P :4 ï¥×AŒÿáT+¸ )x»× àÿ¹Q¤ô¸Šr±–C»üÈ4ì;I¶ã)Åíus+.£YMÆNE i¨æ6Tïbu¥z,nx©)²:½Ik.V\¿ð<6*åj_ÝØ–K“ Màø*¼|GDK{ÕéDZw5 õÅÕ 1]’4#dô¿Ú@¬g´í4°ªÞ÷q]2¿áFËêǨ à~Ïþ_†±m¿ýšO{­ic„ ²¶¶F©TÚÕ€Ö÷}¦¦¦°,+RF?&''9räȶ&@µFt–e±´¾îDJI&“Áó¼gÊ]­ÁÎhúϾRLnx\_õˆë‚ç[Í­õå÷¡ºúz‡ÐÎŒXYŒ”•8ÔlÐèG¨³ IDAT›Ôøÿn—Y®'+íyè>Fl¬á÷£bñmuÕÜ Ç‡Ÿ—)yŠSm&šØF¨!$X1üÁªŸ²þùiD¥út q£ÍÞ™±ßD©AUŸŸiÞ¶«Л1Y,ºøA„úìJT¦ÆwÕ}ÇJ´%#4ÇQ VWªÅ±Ú6²—€&Rºí¥2GÄÓªÖ 52˜_*J)fffèêêÚvæ[JIWW+++¡¥%5M{ww7çÏŸßõ@ÿúõë‘:Ã*¥(•JÌÌÌðâ‹/bn3¡TkÚÅ‚ ›Í’H$(—Ë ùNƒMiúÏNŸ,¹,”}Ž·ô¥4ômzhÍmø‡Ÿ@¿v±ßÁ¬Á«&EOq)çFÓ4o°Ëè½ Râ~n[ƒ­P Öœ€žªÐlVkä²'þ‘ç Z;‘“·…µÐÇÕ˜óí^‹¬!øý‚͆Ûôw¥ªÒ§‚Hg·ý1)IƒÊÅ®‘H¥Q7/Wc—ðE&¦“Œb©‰BÍMA:S]íØIˆ(ÙxM‡ö.Ôå³P)…§Áޏ»ãk{{û¶?'¥¤µµ•J¥‚mÛ‘ÚÖÖVΜ9ƒ±iÚÝxžG*•Š”ÍWJqåÊÚÚÚvÜa¶µµˆÖëÄ4MFFFøõ¯Íúúzèq<½4ýg/Pü~ÞF‚=Ã;xÝêAÏ *Ó„¼>†ÈG³¸K肣ͦ.ج<QXG,Í¢Z:ðŸzdÁàÃð•b²à±\ Îhœh5U›yª¥èbe¹0¹éÏ¡&ƒ#-s.ó%¿!ßÙmuë tõíHîUË\·&tnç*‘T7"‘DtõA¹´+Y}¥ ä 5YÄ}¥`~:ì„û(††6?üä^JD¶gwuÔàá”J%~ÿûßsàÀÅ5;ɨ6MMM>|˜õõõ]Éê׊|ûúúˆÅ¶vŽzApõêUFGGwüÙx¼Z+S,Cgã5M£»»›7nìê$¨ÁÓC#Ðð¬9ŠO–Ó/´™;Ω©ÖN‚ž!äâ rúN$í°p I§7©s!çrkÝÛ]ùŽc#§n#Šø‡žCµu†î„ PôçV\l_ñr‡I[lgúfeZøG_Ú•³ˆˆMÒ¦àOûcT|Åû³ ¬~×uëKØwg!wâå­<f'íÛ’¦ÜOs\¯ÊwT„béX1<ŠZÏïJ@kû¹²GsL{tmÉV(U-Æ·âÕº…¢ èI\˜/†/¢:iïßWm,Ö`K”R‹E–——)—Ë(¥êÅŸ‹‹‹Ø¶½í€Ù¶m.^¼ÈÈÈȶ¥)w“ÍfÉår‘ºÁ¦Ói^zé%æççw% u‡ÕÕU2™ †±óï3üq²J¥B]MÓèèèàêÕ«¡Ï©ÖXóùçŸgnn.Ô žnþ3@ÉSüvÎf±ðµ“æØÎå¨Tÿk¯#ÖòU÷ßì·Ç4þÍPœ›kÕ×Ý4R«9ôßßÇ=y¼ÅrÀ/'+˜Rð|[ˆ‚^M'èì%Eû± žúGš F2:¿œª0[jd6kÌÌÌðþûï“Ïç ‚€r¹Ìûï¿Ïôôôö³€všZ«A~ˆ bÂt& 6ìˆÝ`c X_«jâ#²Vñ[(an£xvK”ª(÷ô#2;w°Ò¤ miL¬:ØQjK„€¾á/V;“Ü­PJñ³ŸýŒwÞy‡+W®àyÅb‘ßüæ7üò—¿dlllÛÁe¡P §§'tC©X,Fkk+Åb1R7Øt:Íââ"årøZ§\¿~=tÕl~¡PàÈ‘#twïܾYJI2™dff'Â}.¥ääÉ“ éNƒMiú{˜›7oòþûïóûßÿÇqêÙƒ[·nñî»ïrîܹz¦æaäůf=z“Ç[ ÌÈv¾@™Þ±—PélÕS¿\ˆ$)H‚¿/NÚüaÉÁöÕ®yê‹•y´Û—ñO}“ ³7ÒX¾‚;WV]~0£ïaÞù#‘ªö$p´ëc‘ŽIͦä­ÞXµSîRÃSªºJ¥Âñãǹyó&år™\.Çðð0ãããõΚAÔÿïý÷Ž T©-í¡‹·-]Ò™2X«xÑêE5 VWÀŽÔ¸¢-¡£íDsv?Žš¬fóCJá Mp¤=NÉ09•OT“ ¹åmûJ)lÛŽÔ¤è«B‹E ÃàèÑ£ÌÌÌÕ¯••¾÷½ï133sÏ=aÛö¦ï“ X__d?iYmmm‘;†ÁÌÌ ¡Ç¨áyÍÍÍ‘šd•J%.^¼ˆeY¡¯aŒŽŽFú^J)Éf³xžÇää䶯±RŠr¹¼+§{—F ¿‡9{ö,…B;wî011çyT*>ûì3 ÃàÎ;,//?ò¦¾]€ÛÅÑfƒ¡´¾#}yMG¥³ø£Ç+ ÈÛW#I L­ê©´Yçښǥ¼‹·Ù¹ÀG»r\ï¹W!• =”_ñÎL…@Á÷â4™!}–­þþ£`ÅЮ_@Ö#M”’†àÕN!àãE‡ ÷ñ7Ûë(¥ê›ïû¸®[yÞ-PJ±¸¸ÈÜÜ\}ÙûîMÆh-mh†ñÀ϶³Y†N2f+(!ï[Êí¥ȦÄÆ:Ú&ǹÝMHù‚˱®¦¾óÏ×YˆéqôT&ô±˜ºÎpkœ²¾ NZ,ŽÔtd¥ˆ¶É5Ýì: !XXX¨½ÏRJ„õ.¬µ þýA©RŠùùy¦§§7'•JÑÕÕµãbÓµ·¹\.Ró,MÓèììdaa!’ÃLí°ÿþÈÝpÏŸ?O6»ý¢ýû‘RÒÓÓS—†#‹!¥deeeÛŸ ‚€ÙÙÙÈõ ö6|ÖþøcNž<Éââ"Éd’ßýîw9r¤¾D¯i}}}AÀêêê=“!²µƒ ªÿ2˜*`z­ÂH‹‰)ï}Ìn;@F¡.|‚êî«Únnµ?)·Ô?—Ü´Æ5PÁŽN©6ò=µ¾F ét% A À’P´=Ö*.™ðª T<«9D÷À=÷xí»}÷u®ÇÀÀ@è`õ«DMbÛ6×®]£§§‡©©)„d³YÞ}÷]†‡‡ë÷Œ¦i ’L&x6H)Š|Lº®³¸¸ÈÐÐPèâWÓ4yë­·øùÏαcÇê™R©TêŽ@aQJ‘Ïç±,+Òd¡¤—ËeŠÅbèIC­èy':}MÓ¡¹¹9Ô>|5xúŸx_a4M«g%-ËBß÷ëÈݹZ±ÕÝY¼Òì£6y­C =›J¶/@ëBkïA¿yga¿£·n³çº.¶moûÁ(øZ ¼›|0g3¿^BKh[®8AP/ªÜ4óøÄ>ý-r~¯­‹²a¡B,‡º®‹çyøJðÓ[e–Ê>¯vèè¾C¥%@–ȃ'ˆ}ò[¸ô9~K7¶m‡Êâ( ¡¯´iœYôøp¶ÄpÌ"¡ÿñø‚ ÀuÝjðz_Ï4ÍH/§½Êþýû¨7ô ‚€ïÿû˜¦ù¥x†&h²È—}Ræö­lïA0ŒêjÚÊ¢³gÇ5ªzç§--Z‹) rKˆS¯‚i…F°tAÅ«vÎD°úM-¨™‰ÐŸÚBðƒü€B¡@:®ÿûÀÀ477GÒ§ï]×éééa}}d2êù#„À²,LÓdbb‚ÑÑÑúApýúuR©ÔŽ÷7¾ï399É_üÅ_L&CS;'Çq"ú===\¼xñ±tnðÕ¥èïa<Èøø8óóó|ç;ßáüù󌎎ÒÔÔÄÕ«WÙØØ`xx¸þÀ¼[†p÷~¸ög’ñX8ÙÎ]ˆžTß0bü±Ùq¼®>ÔnŽãl»cb“û2ïÌÚL•%ýY“­Ô1µs2¾TîôkƧÃ0^¸aDE“p 5Ƨ3EºÓF¸@ª‘qÏL݆ŽîúUùY@ÊŒЭ¯]A4…o,Õú!ª¤ù²Go*ÂdÓŠAS+jn ÑÑýÐg!ÉdrÓ 4J`MÓbllŒöööÐÏ=!GåìÙ³ìß¿?Ô®ë’H$B}¶Æââb½H9*BšššX]]4^2™¤§§‡+W®°ÿþH¶¡ žý=Ì /¼Àðð0o½õÝÝÝìß¿ŸD"Áw¿û]LÓäøñãtwwßóÀ”R> OÕ5‰¥Ktmúà­ôºñjäJ30Ư¡UJá5ÈšFSLçݾ‚óyŸJ°µn·vn›îCJ4ÏE›¹ƒjjÁ{é ¤ §i‚@VßèIê¼Ý#Bß|ÏñktõŒF›ŸÂ,¬¡¡"y¨ÙàP³ÁÙ—¼Jn~½î¾fa—»lM’¦FܬU"º"ix.ø;ï*±tšbÑr:jaâÑ£»éI›¬•]\_…7ÎÑ DÏܸ\í”Û`O#¥$‘H‹Å"Ó†mÛ¸®»ãìµïû¤R©{V9ÂpýúõHÙ÷ûéìì¤X,îÈ ø~,ËâèÑ£œ>}ºQ`Û N#ÐßÃÄãqFFFèééAA[[±X¬î¤ÐÙÙùDŽ+èBµv¢]þre!òxÇ[LÚ,Éÿ˜(3Ö*ÒuS·‘¹%‚áC¨T&R“¬²§øtÑaÕ øf—EJ—‘WC¢Z”{ð9„ç‘=ÿZO}) kJ^î0)¸Š_L”Ywv¿ùXƒð´Äu&×¢5HÙè¬Z[î â:PŠ’ë“¶$ÉÐKQê ÿ|â»—64AKBçV¾ÍSß4Á2þWˆl6Ëììl¤1ººº8vìØŽ›gÕŠ’“Éd¤Œ~ͺw7}]×ijjªo„AJI<'‘H<îR ¶G#ÐßÃÜ-Å©ý½–Õuý‰i¬U¦ ï•·k9äômð¢½d»UOý‰ Ÿ««a½ŠâÆ{?Giþ‘ç#ùy;à¿Ý*‘6o÷ZуüR#è Üyñ3äZ>Òp†n2JküjÚ&÷º 7O6¦¡ ãGhž¥ë`ÅP+KÕÌþ6)¹ŸÎÉX2ì Ž¿š=oi 7Æ&hB0ØcrÕÆb%%tôV-Qºä¯étº^%sJ¥˜œœ¬[„n‡J¥Â… H¥R¡í0k5b¦i200jŒÍдj‡ÛÙÙÙHŽBš¦1::ÊêêjC«ßhú B Iü/C,véˆR´Æ5ͦàOúcXšà×ÓJÞ΃"¹2vþ#‚þ}Ñ4“5§¢¾ÖaÒØÝ •jnÃ?pY\G»}…(fëHWû#L}.çw·ùXƒhd-„!):~xûS!‰ŒßØQæÚö3ë6–á1ïû°²XÍæG°ª½Ÿjƒ[¥Kœ03ûRB& •Jµkoƒ=O:&S*•B{ê !hnnæ³Ï>ÛQæÚ¶mênCap]—‰‰ ššš"¹öÜO-‘gYV¤Î¿º®ÓÙÙI¡Phdõ@¿A¤†J¦ñûGóSȉ‘}] :)Ky—ë«;Våô„çâŸøAg_ècð|ºä |§/F×núñdÕSß÷‘וh¥KòJ§Åªp)ïâ<ë†ú{S—$ ÉRÑ#ˆ”¹ÖP¥Bµkï6§Á¶ÏK½©HÝp•cãø¤¢é™7ÃÔýY7ˆ°Ú!5Dsäacm7¯ÁcÂ4ͺ§~”æYº®“ÏçwÔm·X,rüøñHnC¥R‰¿û»¿ÛÕ ¿†atuuEê5 ë:ýýýLLL°´´´‹G×à«J#Ðo e˜ø‡ŸÏCÿütµP0B°š6/u˜l8Š_MWðw0–È-"o\BiA÷hÑ ÇKp6Г ¤t´Ý®[ÕtüÞ!Ütbúròf¤k×/w˜¤tÁ…œËd!Bö¸Á®"€´¥qi±­!œi"N¾ŒZYÜÖ PÅ X­xìk‰:¡¯x.¾‹‡dk4!ÈXóE'¤TAˆêýKT'B ¾¤R)nܸI¢’H$øþ÷¿Ïøøø¶Æ±m› BË^•R8ŽC,#“Ù½®š¦‘N§YZZ¢T*…Cad2òùhÒÐO@¿A84ÿàIT ž~ƒpè:ÁÐ(ÁÀ~ÄÆ:rvrG…‚÷ci‚×zLögtfŠ>KeÛY}íê9d~ ÷µ?‡Dø&(ŠªSɧË.e~8š m<ž[D饯½I`ÅÑ.Ÿýb’þalHÁ_Ä~1Q&Pä v•¸!ùzšù /J­´Õ¢ÜÙ©Gþ×…‚ƒíÑšdy¸.Úà"‚¦y+„h²šÕÏ•ÂKDÔí«‘ ¾jE§¶mS,F{o´··S.—ëÝâ·B×uúú¢Õo³°°ðX3äBÉår‘ö“H$xî¹çøè£väLÔàé£è7ˆD0°Ÿ oúùÅ D оÙmÑü÷Û%ÖàáYi§‚vácÄÊþð!T¦¹Ú\($e_ñ‹‰ ËeŸ¯wšdL¹ûúüB L ßa”¦a|ü^µ(7$š€Ö˜äd«‰¯¿šªº5xò@ ˆi‚•²m¥¥Ö™Ös7•{ybµâ¡€¦X„"òšw¾nmYàH[’˜.Y,º;ªÍ¹MCÄÕUˆâ§ î €kݲ}ßâr!±XŒµµµHÇÒÓÓS×Îo6Žïûu¿ý(¾÷J)*•Êcï´][¥°,‹•••ÐÙx]×Éd28ŽÉŧÁWŸF ß *Ó‚ÿÜ«ˆUâ×/ "¸tÅ5Þì‰q%ïñÉ¢óPmQ*`¾óSø`$m>Àšð^-`p¢ù1ßBT=õû÷¡Ú:Ñ.ŽÈ‡wH¢*z¡Ý Å’¼7k³P~öß÷±m»ÜA€ã8‘ä»…. dW¬ÐN›é,¤³°¼P]‚º×W|6S¤3e Ã6Pª,¯­Bï3Ò€!%mIñ|e³SÚ>ºÉô–“ g ¥ÌÎÎR©TPJáû>‹‹‹ÌÌÌŸçÿñ™ššz¢Á¾°¯5NÕæYQjOS‚Þ÷Áåx7PäËIC ž«•_¢©5òúQiS‹¤@ÓM-¨¥yTCª@¼ûî»LNNrñâE<Ïcccƒ>ø :Ù|Â})%½½½ø¾©y@[[?úÑ6uªq]—µµ5âñðÎQ¾ï355…¢Þ©þqRËêGÝaôôôpçÎÐ.> ¾ú4ý=ŒmÛ¬­­Q(êAß÷) äóy …“Ÿ¥KIÐÜŽß¿meíÆÅÈžúû³:#K9O—¶Ð­—ËÈ;×¥þðA‚æöÐûXw>]tðkÖhµ¾œ@_Å“x‡ª6¥ÚÍˈõhXM¦ä{ý1Jžâ£›¼ótgqJ¥ ÌḬ̀²²B¹\fÿþýÌÏÏãû~½° ¨/_{žÇêê*KKK(¥R>°Õ:Roö³°[ÂÔ± éu¾(º µ%“hmHÇA~Ñ=»ú3¢«8Ù"nF8v¥×/!{†±«×àîë{÷ß“–NÜÔ¨øŠ€×Æ0݈¹)¤ç>ðs€••–——ŸØ÷õq¡”¢T*qóæMnܸÁÄÄDÝe¦¹¹™¹¹9 Z›H$¸uë¹\®îìây¹\®~ß|YX–…aÌÍÍEz—¥ÓiúûûðÔWJQ,9xð`$Éçy¼÷Þ{:t(’ÿNˆÅb˜¦I¹\ý;Ñu¡¡!ÆÆÆ6­…‚€ÅÅE¢nƒ=L#ÐßÃLNNòùçŸsæÌ™º ™ëº|öÙgœ;w®¾Tù¤33ÄøÇ¾†(ЮUu²Ž©Éª«óeŸæmõ XÏ¡]=²âøŽƒÍ;²àóÑ¢C“%y¾ÍÄørâüª{QÿAw?Úõ1äÒ\¤áâzÕt_Zçƒy‡Ù“—¬áÕW_åÆèºÎ¹sçXYYáOÿôOë÷„išìÛ·L&ó¥e¬k$ zzzX[[£µµ5ÔûL×uÚÛÛëçÖÓÓÀêê* ôõõ…~OÖ&Ao½õííÑVŽw‚¦id2æçç =ÉBðòË/óÉ'ŸðüóÏ?°ƒÒÒÒ²‡Ü`òô=ñž" …–eÑÔÔÄÌÌ A‹Å8zô(“““ Ž=JGGš¦Õ †îόԙǚùÞ¾#$¯|ç>¤ròU‚XxŸax©EðμË?x­C#¡)\ÇÁwâgO él¼ø:¾¨úÃ(ºð›©)Mñ—ýK¹ØQmAíwU©TpƒÑ¿ŸL:‹vácÜW¾×Ò Ùá7ðáTSÀO48³ð7keš¬?:Õ:'> O-3\£££ƒææf,Ë"“Éày---Äb±º|ãîÏlõò÷ŠR S 5YŒ¯Úd-xè> |µ±Ù–ªDÁõiIhád7P3ãˆÃ'A>¾ßÍ®¯ðBw’¥¢Kk\7×O"`³;ønÏÓ†âž{Z)Å믿ŽRªþ~ĶmR©Ô=÷Ä“º6†aÐ××Çôô4ét:T@[»§]×eyy™îîn„”J%šššBwÂÈçó\¼x‘·ß~;Ò8aRrìØS›á IDAT1VVVhjj =YÉf³¼ñÆü{mü´Þ ª4~»{˜D"A©Tbee…t:çyxžÇèè(###u]æÝ/ÍÚïþíQ?¼IIùØK¨D 㽟#+%*ôxR¾Õ#©Kþ+EJ¾rnyû*A[ÁÀ~°¬Ðûñ8½àpsÝãT›ÉpÆ ¦=¦k´Éï¨ÊŽZ;GÁ® Ÿûá:¡Ç6µš§¾Îš76| ŠŸF à ‘H iº®‹ÅH§Ó†±'Î]“‚¸¡QvÊÞ#ìc†²Í°–Gù>%ÇgrÍf¸9~qK©ªG¹ÆãµÜ )Ýi×Wl8~økcU«Íg!©TŠt:M"‘ ™L’L&I§Ó´µµ‹ÅöÆ=¡iÄb1*• ¶m‡žd !èîîf~~×u)•JÌÍÍÑßßÿèoAMã¿¶¶ö¥ÊvjH)iooÇó¼{jõv‚¢þlðlòÕOé=Åìß¿Ÿ³gÏR©TøáÈ™3gèïïgrr’¥¥%‰mmm÷de Ãx`éUJY_ xœöÂÀÁ¡“XïüŒÄÔM¼ö®HÃK]>ÏÍyüÃ2“ÞŒf—I~þ[´ÂþÁIJMU[½+?º] _ŒÇ¨(¿®m|\A€mÛÄb±?fáN¼‚¸>FâÒgh¯¾Mo =~ øv¿âÌ\¡›˜VŒ¸þä_ê ª1º.+%¦XØÌµD îG]:‹·±Î…’I_Ú$iFqÛQ¨ù8p,R?аH1] L­Ùnï‰@´Áã§¶‘ÏçI§Ó¡~ïRJ^|ñE~õ«_±´´ÄÂÂ]]]Äãá¿GJ)®]»Æë¯¿þ¥Kš z]¬/Yóó󌌌4î‰;¦èïaNœ8ÁêYÊo}ë[!èëë£T*‘J¥H${çÆ'ñG£>|ýüÇC:Ãw"ìˆK^h7ùé2Ÿ.:k’$Šëh×. Z:ð^ý6Èð‰¯`ªà3^ð9Òlð'ý1´'x-ýáøCÐÏ~€X˜†æ¶H¥?°x£- 5e`þÿìÝyxÕ™øûï©¥÷n풵ؒ%ËûnÀ6[ ²0 Éä—•›dn&™™ð$d™ Ì/Ï;YÈ23O–I&ܬLn˜,$˜  6†ŒÁÆ‹l[û¾w«Õ[-÷v7’-Y[ µäóñ£GV«U]]]§ê­Sïy¼w—3TE°¾ÄË Q*‚:¾¹çB@qÆ Ï’\½‡Å¡ùùƒ}‹" K@,Î#„ Ð«Ñ3šbagê’rIfüıcÇ(++›s§”‚Õ«Wóë_ÿšíÛ·³víÚyù­­­„ÃaV­Zõª§íd!ÈËËc`` wÎõÒ’"Oÿ9,P\\L^^^ºßÏç#//òòr‚Á ªê@ýi§hz:¸_U‡Òr¥õLzpß¹UÁ¥. < O÷$hî ã:s­¿ sý6ÌšµénÀ9IZ<Õ'œ´¸¶ÜM•_{Úƒl0}ñbÛh/>ƒ ÏkyEn…‚OóÙL’×J™_§i(1¯šú†/À;D© \óùm:Z`Um:•lB¡Wc,eMš—ÒD—0!Döu[[Û¼–•ŸŸO ÀëõÎ+8·,‹£G²}ûv\.×¢žgóóó‰ÅbD£Ñœ˜üOZZd /9Êö‡HÝp+"2ŒzìyD*9¯R›å^…wÖyy±?žcíx÷ÿøƒ˜;¯—›ùôúuŽ™üêlŒ¯Âž2×âÚžž@kÍ&Ôã‡PÚÎpaaQi¹È÷ªt&IÍc­„'@kéV˜Ü“?Û‚D,=®îžÛ2äRu…žï%1×êAÒ’ …èëë›×Z@€ÚÚÚ e6g˲,FGGI¥R šÂ9Sº®S]]ͱcÇæõ¾¤K“ ô%GÙn7æúmX+kQÏž@t4ƒyá´ä3•ïVøè†«ü ±—^@ôvºöMXÕóZOÓ†g»´š|pŸš`Žd±ù¤v_F íȳéàk±çIDG£&ßMÿX sŽŸñhÒdÔ×Ù0™ÛŠÄãØ§O@Y9"˜7·e8HQÒé;!·ÊH”»ÿ%$ QYYÉÐÐМ{®ÇÆÆH$<ÿüó Ìi£££<õÔSÔ××SZZ:§e8)S>5dËKÒLÉ@_r–P°ÝŒWi¢?ñ[D">ç`UW%nÁG‚}¼yàRn/É ;°çQºÓ²áå‘¿iŽ“çR¸j…›À«6CÖÅÙ.7fÝ&ìPJs#Ꙇy](I¹KWŠ}:g‡âÄ kVMÄb)‹³ƒ ¶T„ÐkצSoŒYî+¶ ñŒ !JÊç=ñœ2ƒ•kòÝôަMÊT…K…®ëÐÖÖF2™œu@›H$hkkcóæÍ\~ùåsê·,‹H$’ü:Ÿu’)ƒYYYÉÀÀcs,'-]šd /9O˜k·`” ?„ènŸW°ªÚĚd?‡‚uœõ–‘šã \HZ66Å舚\^ª³Ò¯¢/zÞÎ9ª†]T†¹~;"<Œöìãç.”d Ãr#xuŸ®pz =ŸÂLÙ¶MW$I¡W£$äE¯]‹°m˜ÝEu"ŽÝÞ›v,J¥©(Š À«aØ6Ý£©Y½%Ó¶±dç’”)éñxhnnž0¡Út,Ë¢··—¼¼Ìë_ÿúE©´3UUÉËËò,úúúfõž,ËzÕg<–r‡ ô%ç «²ký6D*vìyÄXtn˲m0 B'ŸgÀvñeoàÁn…‘äÜNä¦eÓ=fò?­qBºàï¶ æHo~–¦’ºñmX+*Ñžßènƒ9N.å6·ª°m…ŸhÒ¢32³ÏزmR¦Í`ÌdEPO-JW`Ÿ>>«ðvóˈü¢yU°rš ]Wm‘‡3ƒq¦ÅLÆåÚ@4aÒ:_èU”ˆËåbÆ Äb1z{{gô7™ ‡‡‡)))ÉNþUWWÇSO=5« †çŸ!97© ¢(ÔÔÔÐÚÚ:ã;™ùvº»»_…5”r‘ ô¥…¡jÛö`­¬C{îI”3Ç!5ûADblíù}h-h·â«^ͯZ4Ï®—/£7fñõ—FHX¼³ÎÇš¶¨%5'%ìP>ÆÕ7cû¸~ó”¾®Å^+i‘NSY_âa8f0¦hc)‹§[#”4üú¸àß+ieee¬\¹’}ûö1::zÑe˜¦™Íï߸qcnU´Çãñ°fÍN:Ejš Ó4åÌ™39wÑ"½zäÑPZ0vñ Rox'"ÁõÈ/ÒÁêln)”®V\ý ;”OàŠ«xëš Ý1‹Ÿ4Ž1œœ]^sÜ´ÙßàÁ¦1v–¸¸±Êƒ[¹߀î¬ۀ¹ajK#êág >6»´ #•ÎÙ¾„ÒlÛžp‹Ú¶mLÓÌùÁkyn ¦Ð6’$u‘Þë„aqz NW£Ä¯£«ãv^¯QS=4€ÝÓSå&›&¤’ØgNA¨Q0÷‰Ùš¦Šý:ñ”Å@Ì iÚ“Ö¡²l›¤ióò@œŠ ‹oî¤\,¦T*…aÙý?Ó’ÉdΗi ¸\®ìL·Sµád2Iss3yyyNhóóó¹ì²ËèèèàÔ©SÄb“_†A,ãOúSöâ WišFAA‰D‚ááá)·eY¤R)ZZZ(--%/oñÚK‹CúÒ‚±}Ì5›0¶ïEénGÿŸ 9ó¹b¨mßÃ(½¤®|=þuÙU¤PT8Ø—äÑö8Æ,¸æˆÁïšc¨>¸ÖÏÚ¼Üîá°ó‹I]s3¶ª¢~µõåYí6JOZwº&u.^Ë,„T*ÅØØXöÄgYápxÚž¯Å¦«‚ò Îáî(]‘Ô”½×íá$qÃbë nm’÷Nj²÷zèMû“‰¥«ì)DYEº7?‡y4…íå~NôŽqv0Ži]ì§L›æá8†mQâ×ñê¹ýž^ ¶mÓÞÞNwwwöâײ,9sæ £££9}¬ë:¥¥¥444ÐÛÛ;eîêê"™L²aÆI΃AÞ÷¾÷ÑÜÜÌ©S§&]Æðð0 ‘HP__¿h“cÍ”ÛífãÆœ>}š¶¶¶Ióï ཽÓ4),,Äí^üÒ¹ÒâGCiAÙ/©›ÞŽU¾ µñhº¶~|šŠçÒ ô}£ž>†qÙk0.»Ûã¥È­ðáõ~4îkˆò|_ŠÑÔÅOV6`Xð_ÍqN ¼£ÖÇ–B=7{òÇSUìò•é»"£#hO=’N·˜î®H2röî_ÿ€àC÷£v·•Û½wó• X9xð ¦ibš&‘H„ææf¦ìÍË~—Êkkóˆ¦L^ìŠÒMaX6qâ/šâÏm£ôŒ¦X[ìEbê‹7!õ›`¨?ý5†X4ÎÓ߃ÝxŠJk7A 6œŠàw)ì® ’4-^êŽKšÄRѤ™N×é‹‘0l6—úq©¹Þ°F¦·Þ4M,ËÊæ­·´´d{}#‘û÷ïGÓ4Ž?žóÕ[¼^/{öì!‹qüøq1 ƒD"Áàà ‡f``€ššE™2ÕFQ®½öZÚÛÛikk£¿¿Ÿ‘‘"‘MMMìÛ·êêj®½öZ<Ï«ü.gOQ¼^/Û·o'™Lfoñxœ±±±lºN2™díÚµ95¨Xzõåv—æ%nüUº2®×-s@Ïä2æ4UÃ*_Eòõ‰ûÿŽë‘_’X±»¬ôÉË–‰D õÐShÏ=‰]XJâÖÛ±ó AQq)oXéa0)øqc”ÿsh„ÿçò<6èø´ ò†á”Å‘þ$¿<;FÐ%øØ¦!ׄÀvy0®¸õåã¨ÇŸG;øGÌ-W`ò&/…˜L  ôâzøgˆÎfâë¶c… P–iŸ~2™dll ˲ðx<¸\.¢Ñh¶íôõõhmm¥®®H·«X,– ~ÆB„(Šâx•ŠÌëLŒèª Ð§àÑUF&ÇzǨÊsMš„&•!åAnM œ·Î™Á‡Ùu†uë±ONWlryÀ€á” [ÁœQ)ÍÌöXˆ\å™.W¤ŸLУ°¦ÈË©þ8 ýqtUN˜X6ä¹Uê =ø]ê¤ë,„Ⱥªª …?‹É¶m’É$===ضË墠 €`0ÈÀÀ@¶êJ"‘ SYYÉñãdzƒT3¹ÜÃÃÔ——/ò»y…¦iäååáv»‰F£466R^^N4ett”+VPRR2£Þꢢ"öìÙã>ŠmÛø|> iooç†n °°0'JiΔ¢(øý~ª««9{ö,/¿ü2º®‰D°m›`0HuuõE'ü²,‹‘‘‘l~iy’~Ë”3:!–e‘L&éìì$//‚‚‚ 9I¬51öÞˆþ_÷£?òËtU™ŠêtI¿Ì Ù¶À4QšNáúõÀã#uý[Ò–…" ¨ ÞYç%nÚüËÑÿrt”Om °¥È… ¤ëå$-~ÛãˇÃxTÁG6ø© -¡Ý^U±ó‹0.{ ®ö&Ü¿ø>©Á>R¯yv(Dæ³·Á¶QúºÐÿêñçI콉èu·àö±•åêÇb1zzzH¥Rg{1ÇÆÆ0M·ÛM__ß„)ìS©ÝÝÝŒŽŽRYY‰¢(Ù;™ 9sàTjCæ¢Ü¶íi—t+Ý…~'z¢”]ì¨tOùùô_¡@(ö\—þ1Å#jëÁ=ó™>3ËVUÕÑ ŸñËf¼ƒ…•:íáMa³W›Pwü…Úøí‘ùìÛÛÛB°yófÇÞK®H&“ `Û6^¯—`0H*•Ê~Y–…a¨ªÊðð0~¿?»] ࣣƒææfÖ®]»Èïd"!^¯¯×K(âÌ™3±~ýúYûE¡¸¸˜Ûn» H§ëôöö²sçN@N¼ ¯×ˆ èééÁívSWW7ã|˲hiiapp;w.ðšJ‹e E<—ž††ž{î9^ÿú×S]]‚h4Êc=Fqq1'OždÇŽ”––æ|ϾíõcìºåÔKhÇ¢6Ÿ"uõ0v_íóƒe!F†ÐŽ>‡öÌ£ˆ±(É7¾sË“./ß­p[½þ¸Å·Åøòá_¾"¿®àѪ€þ¸Å?¿áÑö8~Má®]An¨ÌýÛ²sËå$Bù¸~ñïèûFi:IòíÂ..Ç‘L ¢ôßÿ'Ú±C˜;®Â¸ñ­ØüÅ^û ñù|ضªªD"¶mÛ†·ÛßïÏÖŸÎÜ’w¹\TWWg{1ÇÖÍ÷㿜”¹7*°¾Øƒ*ÀºÈßdÛLÊÆ¤t7–¤KhÎbf¦sá¢Ëžƒñæ\¬ðë¹·­ ÞNæ¢jüvÎ<¶fÍšeY}DßïgÓ¦Mض½Ðikk#‰d;†4Mãšk®áÈ‘#ìÚµ+[¡ÆårQWWG0Ìés‰®ë¬Y³f’ ÛÙ …Bœ­®3BJKKg}÷MUUÖ¯_OAAÁ®´Ø–ßo©¯¯ÏÖË͈ÅbD£Q®¾új¦¸¸xBÏØùÁIæ¶­eY z@»è¤BÁ*(ƺõÿB;øGÔSGÑþð Ê™Xk6"†úQšNÁP?–ÛC꺷Úu ¶Û›ÍIÿ>4E!_‡môM™<Óào QæS)ó©¸$99œbCžÊG7úÙUâ"¤1mÀ’Ù† 9ÁH&‡vÆ™¸½˜Õõ˜ÿë¯q=ñ[Ô¦S¸ø.Výˆ!†CýˆÁ>R«Ö¼ù]ùÅXÖ+ïc²•¥îü~(Ê÷™ áÌó„hš†ªªÙ¯ñm&Ó£¿g›n§Íð©™¶½AZæî†ÓËÎ|vsÙ§[•ñw à•‹!—Ë•Óì|dÞ_†mÛlß¾˲²û¦bKaa!^¯7{Ñ“iš¦1<ß„üÞL-mǃ¦iŽpmÛÎÖñv:?<3#èBä'“I)..v´'ܶmÂá0n·;›–èÃ0ˆD"ôRŽ¿Ø›‹Ì]£\¢ª*º®OZ‘&ÓË?™Éö“LÀ}êÔ):;;³Ÿ·aŒŽŽâõz'¤ÀÍ—mÛ #„ //ÏÑ}À4M:::(--utpmæÛÝÝMEE…£ƒ\-ËbhhŸÏ‡Çãqt;g&+--Í>n###Ù±Ks¡ëzε éB2ÐÏQš¦Fb``€•+WfËZ–EWWWv0ÒøA~n·û‚ƒx¦fòÅå8e|ÞçEž„((„;Hœ:‚Út«fæšh.šªb«ÚøØ¶M"‘¸àà²Ý›Ëm +=ø¶s̤)bâVaW±NPW˜Mµ½Ì o!·W&_6sëx6DíZ¨XIbÇ^Äè0VÑ ìâ2lMGQU|ª†­jÙA§ç‚טÉI$×R4MËöN:A®ëNÖ™q1™Ô©Þ@Û¶éììDAqq±£AM2™¤©©iBz’S‰MMMŽL†a088Hii©ãÛÙ4Múúú&T:ŸínYVN¶ ¯×ëHùXUU)++£¬¬ xe[Åãñl-öP(äXû³,‹ÆÆF„Ô××;Ú&‰gÏž¥¼¼œâbçæ‰È\œ´¶¶²jÕ*€cËN¥R444P^^Naa¡cÛ9ÓɋŨ¯¯Ÿðx&Ík®Æß’r—ü„r”Ûí&‘H°zõêl¾i$¡´´”½{÷2<<̪U«(++» ¡žÀŸ¦±é3®Ð!Dºv·ªa­ß†µvK:°w¹³5½'[ÂT·]*¸Îý… ]‚Ú†t%=é΂¼yÿ³~U¯sÍF„ea+jº‚ÊøÔœy¾†a9WwÙívǧ쥜‹ó·‹¦i”••eƒO'÷’’’ISÐ4õë×ãóùßg}>_¶>¹“ËVU•ªª*\.—£Û9ÓÙ‘Óä¤x<ž“mÂãñ‡ç½¬©Žº®SQQÛív4]EQV¬X± é5º®³uëVÇÙfî’lݺÕÑ^wH·ãêêêlÇŒ“mÂãñPWWwAúæ|y<žœkÒ…*’™n¹“ý^Œ{<ó]™äçñÏQÆý]æçÌ—zî»vîÿ™ïyÉdò™Y¼—E‘™õn²r!Ĭr3麮/hðš9.ÔkdRwæ{ ~:™Ô…Ì[´m›±±1¼^—Ìmf]×gý‘H„üüüœ:ˆ' "‘HN•ÿ“.]]]ƒÁœk===´µµ-öªH— •+Wf;F^mýýýýýTwr\.וÀ`ƸïÖ¹ÿ[ã¾ìq_™Ÿ÷3ã;ÿg{ÜÿÇ›nð—ãƒÃr¼.ã¥+Óp2½]ç÷ÌÎ&ØÕ4Íñ¹É8ÝÃq¾LªÅB—,ýÉi™ž¡…|/™Þ͹¾F.4^Ó4' N—¤WC&ý1Û„Ûí–US¤W]AAAvÿ“r›LÝÉa¡Pˆp8L0\ìU‘.!‘H$g' …B ,X¯þðð0 TTTPYYéXþ©mÛ444`ëׯwôîšaœ9s—ËEMM£Ëíêꢳ³“µk×:LöõõqæÌ<6lp$XˆÅb¼ôÒKlÚ´ Ã08}ú4^¯—5kÖÌ{|ÁÀÀ@N·‰D"ÁÐÐЂ,¿»»›Ã‡SUUÅÚµkë1M“ „`ÇŽŽv|†Acc#©TŠ­[·:Ö&‰---´¶¶²nÝ:V®\éÈrì ÞÁ`;wfKŸÎ•eYtvvrâÄ ®¼òJ,Ë⥗^"‹qùå—“Ÿ?¿ÒË@ gÛ„4‘ìÑÏa^¯wÊŠ 3eš&‰D‚h4:¡^¸“LÓ$266F"‘p|ùãeÒQfZ‹|.2ÓˆŸ_½È)™Ï$óN²,+[ÍÇ0ŒlºSæ³™îý¤R)t]UnÏE&ÕɉœäÉœ9s†¼¼<š››ßÇÊÊÊH$s®?Û¶‰ÇãtwwÓ××çèþ‹ÅèîîÆçó9^Y£¯¯/[ÊÑÉc†Ëå²¬ì ¸ç—'ž‹p8¼àƒóçÃëõìâ÷ÙgŸ¥²²’Ç;ºï¬]»UUéììtlßÍœ:::hmmu´zÚÀÀ¬X±Âñ¸¦¦&B¡£££D"G–™¹ÀM$ôöö’J¥(**¢¥¥e^Ë-//'äl›&’~Ž+,,$Ï)èÈ/½ô /Hà:66ÆÁƒÙ·o­­­Ž/?ò,†‡‡9yò䂤od*v?~œÐÕÕµ %6‰'NœàÀ477;ú™df:+!¶mgÇ¡9Y6WUUêêꨨ¨ ¯¯`0èX»(**¢¶¶–¾¾>Çkÿoܸ‘ææfòóó)**rd™™cÿÀÀ«V­"‘HJ¥¨­­Õr Ù“¿É@ ),,$‹e{1}>_ö$6YEfZs {ën!d.(NŸ>ÍÞ½{ï ÍÌ¢™ÌØÔÔDOO+V¬pôu2¹ó•••”••ñÃþõë×;ädjÔÑßßïèEËdµ°3“¢d&üQ%;,¤{n—j®e¦Môöö¢ª*¡PÇ3çÚì UmI1ïÁu³י㇓“eœ?Q™4M›Ó±Ç¶m,Ë"‡1MsÉ· ¯×‹Ûí&H$ˆÇãÄb±9uô±wï^Ç×S×u®½öZÇ—«ªjvöx§ïDy<Ö¬Yãè23ªªª¨ªªrlyBJJJ&ô¾Ït@}fœV¦N¾Ûí^ÒmâR'ëè/Q‰D‚X,–Ü·ƒS¥åCUU4MÃívgƒåB¶ i.d›¤‰–B›uôgNöè/Q²~­$M$Û„$M$Û„$Ir0®$I’$I’$-C2З$I’$I’¤eHú’$I’$I’´ É@_’$I’$I’–!èK’$I’$IÒ2$}I’$I’$IZ†d /I’$I’$IË ô%I’$I’$i’¾$I’$I’$-C2З$I’$I’¤eH[ìrÓÝwßÍc=vÁã¯}íkùâ¿Èm·ÝÆÞðÞÿþ÷ÏëuÞñŽwÐÞÞ>åïxà¾ð…/ð¶·½[n¹eÒçÌt]’É$–eáñxf´nSmƒ;wòï|gV¯qûí·_ô½Ìv%i>¦ÛÏ'÷Oi¡<þøã<ôÐCœ9s†H$BYY{÷îå#ù>Ÿo±WoVfÛ®$i!É@_šÒ­·ÞÊÇ>ö± iZz—¹öÚkY·nݼ_ã'?ù –eðóŸÿœƒòõ¯=ûû™àgº.?üáiooçž{î™ñúM¶ TUõkÏÔ\ÖQ’^-rÿ”œfÛ6wß}7§OŸæÃþ0k×®E×u:::8|ø°¼¨”¤y’¾4%—ËE ˜ôwýèGyñ¼ÛíFUÕ)_s*N­Ëd.¶ úµ%I’–»|—_~™Ÿþô§¸\®ìã\~ù勸f’´<È@_š“ñ·&ïºë.<wÝuWö÷?þñihhàË_þ2©TŠï~÷»<þøã$ ®½öZî¸ã¼^ïŒ_ïèÑ£üþ÷¿çÔ©STTTpçw²mÛ¶ Ö%óó{Þó~øa^zé%¾ô¥/ÑØØÈøCžxâ ÞúÖ·222‚×ëåþᲯóÓŸþ”£Grï½÷Îz;˜¦É÷¾÷=}ôQlÛæºë®ãé§Ÿæ_ÿõ_©¬¬¼è{¹ÿþû/XÇOúÓ3ÞFÒò3Ýþ4Ýïo¿ývÞô¦7ñøãÓØØHuu5wÞy'7nœôõ,Ëâ§?ý)?ü0CCClݺ•;3òòr¹J âG?úwÜqÇ„ 2“×wìØÁw¾óžzê)úúú(++ãöÛoçæ›oà®»îºè1þÙgŸå{ßûMMMóÚ×¾vÂÜŸÿüçüæ7¿app-[¶pçwR\\|ÑלŒç@Iš+èKSJ¥RÄb± ¹Ýneâî›nº‰/~ñ‹X–•ýݾ}ûxÏ{ÞÀ7¾ñ †‡‡ùÁ~€aÜsÏ=|ë[ßšq044Äï~÷;î»ï>*++ù÷ÿw>ÿùÏó›ßü]×'ý›»îº‹Ï|æ3|ìccåÊ•\qÅD£Ñ iO>ù$_ýêW±m!û÷ïçïxÇE·Ëåš¾3Þ·¿ým:ÄW¿úU¼^/ßÿþ÷'ŒA¸Ø{yï{ß{Á:J—¶éö§é~ðµ¯}ï}ï{TTTpÿý÷ów÷w<øàƒƒÁ ^ï¾ûîãé§ŸæK_ú‡o~ó›|üãçû§ä¸H$Boo/ëׯŸÑóÏ?®ëºNUU÷Þ{/n·›?üáÜsÏ=lܸ‘êêjn¸á†)ñ‘H„Ï|æ3ÜqǼîu¯£¯¯x<ž}­û￟Gy„/|á ñâ‹/’ŸŸ?íkNf¾ç@IšYuGšÒ¯~õ+®¿þú _G޹ày{÷îÅ4Íìïz{{inn檫®"òÛßþ–O~ò“RZZÊ_ýÕ_±ÿþ¯GAAŸþô§Ù¼y3¼ÿýïg``€¶¶¶)ÿæ–[náÖ[o¥¾¾~ÊÏ+¯¼’X,Ɖ'¤±±‘«¯¾ú¢ÛàÉ'Ÿœty‰D‚_þò—|îsŸ£¾¾žªª*þþïÿ~ÞïEº4M·?Ídøüç?϶mÛ())áŸøùùù“2O¥Rüìg?㳟ý,uuuTVVò¿ÿ÷ÿ&òÔSO-è{•.M½½½ÀÄÎûî»={öd¿¾øÅ/f7Ùqýío;µµµTVVò|€ŠŠŠì1ýbÇø¾¾> Ãફ®" R[[›½Óeš&?úÑøìg?Ëúõë)))ᦛnÊöÀ_ì5ÏçÄ9P’æCöèKSz×»ÞÅwÜ1íót]çºë®cÿþýìØ±ƒ}ûöqõÕWãñxhhhÀ²,>ò‘d{T à Îj]Æ÷Ü———ãõz/èioóæÍÓ.ÓívsõÕWsàÀ6mÚĸâŠ+ðûýÙçÌtttt`YÖ„Á¹“õüÏö½H—¦éö§™îoã)ŠÂÖ­['½°ìèèÀ0Œ ½«^¯—Í›7ÓÒÒ2Ÿ·"I“ª¨¨ ­­üü|>ðð®w½ `Ba˜ü¸><<Ì#<‘#GˆD"´··g{æ/vŒ¯©©a×®]¼ûÝïæª«®â–[nÉŽ èììdllŒ 6LºÞ{Íóµ¶¶:r”¤¹’=ú’#nºé¦lž}ûxÝë^Møñ̃>ȃ>Èï~÷;žxâ‰y½^æ€9_7Þx#Ò·to¸á†9/Ë0 ,ËÊVš)§Þ‹´¼L·?ÍuSeÒ»\™Ò™¦iNx\×õió§%i.¼^/åååÙc0¤÷·@ @ ˜253#‹ñá˜þþ~>üáó•¯|…úúú mbªc¼¢(|ó›ßäk_û.—‹Ï}îs|æ3ŸÒ)EÀ¤mk&¯9ÞB%i¦d /9b×®]Äb1^xáNŸ>Íž={X±b>Ÿ/gný†1áç½{÷ÒÑÑAss3‡ž¶3[UUU>|8û˜mÛó^GéÒ4Ýþ4“ý­¿¿Ÿßüæ7khh`õêÕ3z=˲8yò$uuuÙÇäþ)9éƒü <ðÀœîþñS[[‹ÏçãôéÓôôôdŸ3Ý1~çÎÜ}÷Ý|ÿûßgÿþýôõõQYY™Ý÷çòšãåÚ9PºôÈ@_r„¢(ÜxãüÓ?ý×\sM¶'FÓ4Þ÷¾÷ñío›çž{Ó4ééé¡¡¡áU_Dz²2>Lwww6UÆårqÍ5×ðõ¯íÛ·_PJ33wüW2™œtù>Ÿ7½éM|å+_áĉô÷÷ó­o}kÞë(]š¦ÛŸf²¿y<Nœ8ÁóÏ?ÏÈÈ÷ÝwÑh”믿€üü|ººº°mŸÏÇ[Þòî½÷^Nœ8Áàà ÿüÏÿLAA»wïäþ)9ï-oy W\q·ß~;ÿùŸÿÉ™3gèêêâñÇçÉ'ŸœJy¾ÂÂBFGGùõ¯ÍÈÈ?þ8N‰Ì˜ê‡y衇²ƒp_xá¼^/yyyäååqÝu×ñµ¯}––ÆÆÆ8pà±XlF¯9¾]åÒ9Pº4É@_rÌM7ÝDGG7Þxã„Ç?øÁò¾÷½o|ãÜxã|ìc›´§d¡Ý|óÍlÙ²…Ûn»»ï¾;ûø 7ÜÀÁƒ'MÛ™l0îÅrö?õ©O±k×.>õ©OññœP(Ì<=gªu”.MÓíOÓý>pã7òÕ¯~•[o½•cÇŽñoÿöoÙ ñw½ë]<òÈ#|îsŸË.oïÞ½|ö³Ÿå=ïyáp˜ù—É.OÓEáÞ{ïåŸøû÷ïç¯ÿú¯ùЇ>Ä/ùK>ùÉOò·û·Sþmuu5ó7Ã÷¿ÿ}þò/ÿ’ýû÷sÝu×]ð¼ÉŽñ‘H„'Ÿ|’÷¿ÿýÜtÓMüö·¿åK_úR6Míþᨭ­å£ý(·Ür ÿñÿÁÈÈÈŒ^óüv•+ç@éÒ´PÉÁÓ-w²ß‹qg¾+“ü<þ9ʸ¿ËüœùRÏ}×Îý?ó=/™L>3‹÷"-s­­­ÜvÛmüþ÷¿Ÿõd]ÓàÍo~3ûöí“yÎÒ¼M·?ÿûóçy¤KÑBã¥ÅÑßßÑßOú¸ËåºLÀ÷Ý:÷kÜ—=î+ó3ã~fÜcçÿlûÿxÓåóÎ>ßw²G_ºäíß¿ŸË/¿|ANTVVÊ _rÄtû“Üß$éB yŒ—¤\'}é’÷ØcMz»w.ZZZØ¿?£££´´´ðï|‡÷¾÷½Ž,[ºôL·?ÉýM’¦çä1^’–YG_º¤µ··súôi®¹æG–‰DøÑ~Ä?þã?RZZÊ­·ÞÊ[ßúVG–-]z¦ÛŸäþ&Içô1^’–™£/I’$I’$-2GædêŽ$I’$I’$-C2З$I’$I’¤eHú’$I’$I’´ É@_’$I’$I’–!èK’$I’$IÒ2$}I’$I’$IZ†d /I’$I’$IË ô%I’$I’$i’¾$I’$I’$-C2З$I’$I’¤eHú’$I’$I’´ É@_’$I’$I’–!èK’$I’$IÒ2$}I’$I’$IZ†d /I’$I’$IË ô%I’$I’$iÒ{¤¹I$Äb1‰†a`šæb¯’´¨ªŠ¦i¸Ýn¼^/n·{±WÉ1²MHs!Û„$M´œÛÄ¥HúKL,#£ª*¡PˆÂÂBEA±Ø«&-¶mcYñxœp8Ìðð0¡P¯×»Ø«6g²MHó!Û„$M´ÛÄ¥LúKÈàà –eQZZŠËåZìÕ‘– !ªªâ÷ûñûý$“IˆÅb.öêÍšlÒ|É6!I-·6q©“9úK€eYôôôàõz)//—oÉ1.—‹òòr¼^/===X–µØ«4#²MH E¶ Išh©¶ )MúK@__„B¡Å^i™ …BÐ××·Ø«2#²MH M¶ Išh©µ )Mú9nppP(„ßï_ìU‘–9¿ßO(bppp±Wå¢d›^-²MHÒDK¥MH¯~‹ÅbX–%{h¤WM(²,b±Øb¯Ê¤d›^m²MHÒD¹Þ&¤‰d ŸÃÂá0EEE‹½Ò%¦¨¨ˆp8¼Ø«1)Ù&¤Å Û„$M”ËmBšHú9*‘H ªªP%½ê\.ªª’H${U&mBZ,²MHÒD¹Ú&¤ É@?GÅb1y+VZ4¡P(çnËÊ6!-&Ù&$i¢\lÒ…dý•H$¤^­mÛŽ/SÊMó™Çãñ044äàÚÌßBµ Iš Ù&$i¢\lÒ…d Ÿ£ Ã@Qœ»ábÛ6†a8¶<)·Ù¶¦isÞ‡EɹýÅé6!I³!Û„$M”‹mBº ôs”išŽMWnš&:tˆ¼¼ (ªWfØÛeÙ6cI“HÜ`,a`X66ôh”çyPJ;zõÙãàɇà ðä;”„aM F“ôFâùݬ*òáÖ”ß6Š¢ „p,õ+שªJaa!ªªfO\©T —Ë…ËåºèíeMSQ”WNv¦mr6ÜŒeYTVàÕ<(bf9ж ±¤ÁXÜ ž40-Ë¿W£$Ï‹¦)€˜Ín4#éÞjå\oµ³ W¢*Œ¤F8=ØDÀå§ÔW„O÷áÓ½fþzIÃ"7%éŒRœï£²ØŸþ [m¢€ª*Øö+Ç2!Dú½8¼}rÕ|ÚÄù’¤8,1±Xo×ćÆÌΦ£1A8*§6MÈ Àª !fuXÍ66môð‚8IAVÙåä$„eÆ­"–€ð˜ ?,héQ(Ë·Y·ÒÂë¶Q|è… ò/2Ð_TU%™L’H$²ƒ³ ÃÈö芊Š&ül ^þ„7AQ=JÓ­2õ®aZ6 ÃäÅÖ!NõDˆ%M’†EÒ´(¸¹aC•ù^\ÚÌx‹Î¶ÁLÀH;4í‡ø¤bà͇üj(\ «AsÃE?òé‹Äi£'œ y Š®*$ “« X_"äÑðè—Foû«%‰`£££¸ÝnR©tJN8ÆívO™®v~µe¥~±ç(½cýT+(pçáÓ}¨ùÜMË&™²8ѯ]_ŠÏ¥2MòÇ“½iæ[Ê©- ,‹ gš&ñxœ={ö „ÈŽOY»v-áp˜mÛ¶áóù¦ø[ Ó|%úB¡6TM©§„3CÍ<Û~Ã6xcÍëðë¾)ï’Ä“&'[‡8Ûf×ÚŠòmâ|.t®`ë­ž'øµx’$wÚï!ŸÐ”ý×ñ¤à™*GΪ¼ywŠ•%6.,þtBå˸ùô_&X¿ÒB["ýI þ$^â'âaþ—}WÛÛðÚºèç,<~.ø¿ÂÞ„ÉSd-†G_ý…‹-«-öl0ø‹+ ‚^›ž!…‡þ¬ñâË*o¿&ŦjkÉ\I¹k¡š×t»æd¿ã¿Ø÷óÿ?Õ—2îûø/ÏÝwßý¡Y¼—E1222£úÈŠ¢PTTDMM Á``0Haa!+W®$ ¡i¶mF‰F£”””d+0çFÜi(ƒ²MM¶y• M—ÆïŽt¡«‚’ m.„LÓdppÇ3¯Ét†††ÈËËspÍægª6!„ÀçóQRRB(Âëõâv»  QÕÉ+KÄã© ½¼™U¨ä¹óX¬d4¥/ÖO¡·à‚€ÖâIƒÓm#¼xºŸvUQ’ïÁíRÑÎ r+º)É÷òôK]ø½!¿ËÑ6‘@ì\ÕÓ²8Ö‚–HoYû:ʼe¸E(¸Uyî…ž|žê|–"O!WhÒíKòü©>ŠB®ØPJaЃ[WQÇ­SQœî xöxB@aÈ3ïÎôg8UÕ u9—B›H$ŒI/F]èTPÌ6Ö2(†i¬¤ /;>l¢qÁ³'U~PãC7§¨.µðy@×@W¡¼Ð¦¦ÌâgO¸( Ú”Ø9Æcc“Âà1ñg^à$Ÿ°ßÍjðâAEÁ‡2Ѝ¢„Ÿ(ÿÍJ»ŒR &Mmë zV£ªÄæ/®4¨,J÷Ü« xÝéÔ—¿zJGPQ´0BB¤SÜ\.m^)m‹Õ&ÆÆÆ.úû©.dï¹çžÿH>|[ç}?ÿk¼Ùþœ3dþ—®¸11 ŸÈÏh!çZU‡ú›àðÀp”øÒq®%X6 ]aNuG¸m÷*Š.ôq'M!^]¥¾,ÀõëJyæÌšªPWâŸð¼œb¦ óEè:›ÞÁ²‰©9Š–þ –ÁÆ¿€Ó ¯É>Ï)“³}Q"ñ·l«$èÑ&,šªP6V„ÐÁs̓l(OÿÉÜõÈQé@W»`¿ŸO}ñL@« •¥[Ù×þ }cx‚n´sim¶ ¦eq¶#L[ï(7쪢0äFß&¸u•Õå!R)‹£gÀ¶YUœð¼\bZ&/7Ñé`oÅey I&ÌìE„*Ôt¸·€ËËvp¤ï8ª¢Ré/ÏŽ6Lš´õŽ¥xÍö |=»¯ š*ð¹5ê«òÑT…ÍC¬.ÏK_hÉ61/N· @EàÇ‹ ·Ø×òCåw4Ùð¢£#8WžÓ„C§N´(|øæ$•E.}ÂÂðyl¶×™Db‚'«h*l^mâÊш$‰Á³â(/qšwØ7RIé„ÔíÜ¿•”ñ6û:~/þ„n«l`5ʹçÙ6Œ%àX³ÂPDð¾×¥È÷Û‚x—ºj³{½‰G·ÙTeǦÚK殇”{róL#-EK÷â—m†¦}Œd“ZMËf0šà±=\^SHMÑäÁ» « —Õ°cU>?ýS3IÃÙòyޱmHDàÐ`õk  fêü{Õ U—CÉzhø¯tþ¾mž[ŒMûPŒÇz¹¶¾„ÀyA~†¼ºÊêb?Å~7§{FIÎ×T—œ£**ÍêPÇN3âÙ€×´,# 5ö±±¦€ª’À¤Á»]UØRWÌÚU<ú|‰Tn¶ Û¶KÅØßñ  ײÂ_:eþ½®è¬-¨£*XÎs]‡HZI,;½?Û–Mç@”ûØ^_Œ\?žé ¡ª’A7g;GH².w.ÓÑâc›]ÏâyFÅ>×™™É=èYk6¬_u^Ž"À­Ãu[ ._gò݇ub‰Ü¬Šda1B„‹‡¸Î¾Œµ¬š2ÿÞ…ÎÕö66²š_ˆÇ‰‘ÀÄJw”ÙÐØ¡ð?5^¹qAŸ!ø=6ëWY”Ø:­OÊ _iîd /M¤º`åéýc¦+ó`3Mò£gZ¸n] ÕE¾io±ªŠ ¾4ȆŠ/÷Ž’r0wØ1Fz`í¡¸~úç %½mòªàÈÿ±aLËfd,Åz¸iS•^Ôi6ŽÏ­±§®ˆ_l§}èⷥŧ •ukðé^žézŽ”e`cKñès­l_SLE±Ú6¡(‚êAªŠ´õFr²M$Ì$­‘v¶o¤*X1íó¡°¶` ÅÞ"þØþ £©(–e‰¥x¡±]ëJ(/òM›àuklª)à™cÝtÆœz;ÒÑѹÊÞN~.%A›Á¿=¤óúËLÖUÙÓVSRØZk±q•űf…DNý1F‚#â47Ù»ÙDíEŸ+((\eo£šr~ ~Ë #X „ìm5 IDATÿYçÍ» ê+§OÇ úl®Ûfò‹ý.ÎtÉPMš;¹÷H ‘îÕ_sCz€j÷K˜É½‘ºª°®,„[›Ùnãs©\½¦˜ç[†Œ&xÅgˆø0´> U;Ó©K3á Bíué „±â)“Û†©+ °º8}—cº€OS…~¯ß´‚ƒÍém“‹=YRš·êb[ñ&Lˤ)ÜB<•d G‚šA\3hB€×¥±£¾„“-ģɜJê´±MÒ8t†úüZÜS °=ŸOó²¹x‘NFaâ)““-CTû³)J3¹Ê¸¹l})'[†•m"—)üxxƒ½—$‡8IÄLÐÞ¯ *°½ÎÄãšþ‚^›7\nðôq•¾‘ÜêÕ·±`˜gx‰=öÖ)ØŽ'äàuönŽ‹&z$‡ÇTÖWYl®IçàOž€…·ìMñô1•ž¡ÜÚ6ÒÒ!}irRXs#4`l4LS_„ëÖ•àÕ•×gwi ¥A7±¤IÛÐFÎL«nC2 €¯¼…-':¢‚'oÁî9At4Âó-Cl(‘çäõtU°³ºMœîÅ’Gðœ—çÎc{ÉfN œbh,J{ß(;×–àqÍ| y]S( ¹I&]ýQG«ä̇MÜHðbïQ‚® AWUÌ,)X ~ÝÇŽÒ-´G:‹ÒÐ2Èêòþ¶ hšÂÆšB„€ÖÞÈ%S!g)[A1o´¯ä q®±8'ZoÜmà÷ØÌt8€Ç•Å6ñ¤ ±]!•#™[66£Œñ8@ ù”R€>Ãa*y³} Ç8K×XœÇTv¬1)Ìl¿"³í!àx‹ŠÃ»¤K„ ô¥É)jº†|rŒS§OÑ14J}i}†½ùnMå[Ë9Ü6ÌP®ô\Û´ü bC°åS–Ëœ’憊Ü>~ˆ€[%äÝ(2Eü.úÒGÚ†e ¿¨ŠJÀ e¥x¾©‰¾á±tõ,Û„KWÙ½±Œ—;FΑžkÛ¶il$jŒqU帔™_´B:_]A=½ÑAžy¹¿G'àÕgUYH¯[eUYƶa +7Ç1H¯ÐQ)&Ÿ„HòÛænZ,¶Ö¤kãφ×eó¶«R<•;=×OŠC á6û x˜Ýyƒ‹kìíœ5»y ©•‚íYUR•ôÍ5&ÏžPI—Ö\’3d /MA`é~’µ7b4þËWèx]ê¬guU„ ªÀKqÀÍã'{0-kñÓLzO¤+ ¹ükRB—¤§˜ÞöÓüÅöÊ9M€%Ô–ÈóêŠ ŠÅª“yóæÉüå{Þ÷÷tf$¿ø£AµæFlŽHèG<ƒsþY NXóJmê…K×xé@Ž¥j›µºC°—)<¾ õ%°sïP4nh\ׯ8c/ѯ—±„Úšj2fðµ±NÞ»¾L=úÏ>RÃ+ç0 +SSº|„SxŽ wP¬¶)ÕövNxO©]&i&ÈXéu½¿Ÿ†¸Ó¾D´rØ™VÂAÓÔ>S"fðÂpçÇWh¶¢9ñÌãZø—^Ķ}ì#ךÜô$D˜ÂóúIŸù5ÁbQ°—Ym..ó¬“iºeǦE>R@ cN#96I¬ÍT»ž3 É›§<~õ¹A¥®4DÄsL$ô#K¥åó/—W°†_Üý8l,¥{ÈÅùÖ¡.n­Ô÷ÖmÄmÂÔGÐ{ Ò}JC2ìüE5K)}qéÿ sþ¸[˜›OÅX®¶•ƈØ=-ŸO¯®2šf²6‰ø÷¬7K!çähžé¥îÚ¬¶ý6WÖ®1œ¢#–SCJ‰ë¬-dµ.þ0ÿGÚ¾Úõ¬ë‚\:F2nRŒæÄ3O¹¦ñóß%xE¾ÀçÖE\<å91ÚðÖ‹:mwï"×uZüF|ÊKe€n¥1¤„¶#˜»0JOyŒÿ¬ýWê¨9J™ôå%)ÉÜZ$Û"6GtÅD¬K % Çg4Ÿ$?v-U€òL˜ö¢€¡ :¿¹¶Le/£t­\ýyXl¬Ø†Ññ|®-VÉ%ã<ó&”gÁU·É´toêfj­A¥õ úËEaøFÛ£·3Îéþƒ¤¬$+Í5ü@­zP×¹”Åù›+4öpNÔÝçW.“{LwÛàxã³er)›7ždµU¤éµ”É24Îêba­A­͉g߇jC0Öð'¹CäE†IpQ»žM 9ɯ>3(ïQäZk”ùWñ!=2P”I->¹¡Ñ›Öø›Á˜KTQNئäG¯xŒÏ… ·""6J$ô#Ö¥Öò¸±TåHo;ÝÙ˜ý£tBr ÏX©¶ñ÷"U!ðaåô†XZi)¡åü—Ïg9ÖŸ%ÎÀà+°z3\-PÀÔ5†ó VjmŠHÔlÏó¨×ë‹Eêõ/ÕA­Vcuu•f³‰ïoÝÊ£Ñö˜Z¨2Ü›¦#ž¦;ÞÉÒ-¼@MÔhBNXøR²ZiíÉœðŸÙÚÒƒ$Íõ[Æ? )ÃÎÐ\˜g¤7C>•â`n„ùú"m_ÍVW×5º’”jm*Ïœ5ï³Ïn͉rCpþ¶Î‹cV†azùPœ§Ú}LÓ ++ñ|˜YÑØ‹ÞiWÄmNs˜Ò*I;wºà þá×&gFa(ç5y‚kbrKQý#ƒ k‚år$ô#6N$ô¿ø¾ïûw¼·‚ ¸÷ÿUYk8üa|#=i̘ ¹!¸þ6xmå*©¸©óýã=œ›)íMGØvŠðÚÿ¢,ô)™-6h¹>ù¤…°’0ø,_ ]|Ð5AGÒÂÐ5.Í–÷¼0s¿á8|ð÷wǹsçîÙ2þâ¿à'?ù .\Àó¶1¯Ô®N*¤IZ1ºì<V.Óöe+Ș¥sæP׎°»?'jnåæ*o ½m<Ý#|=)Y*6q¼€Ž´mÆ8Úqˆ™Ú5W-,«k‚L2†¡k\Ÿ)EN#›d·æÄrYðÁ%“Ã>YÓbXöñ¶øˆ-åôd ~ôŠÇ§×õ=i U¤Âóü¯Á_‘Bíå×àÖ‚FÛôå2"Áëò gŠÒ˜ÆÕÛ‚?\Ñ£9±a"¡¿Ïñ<÷Þ{ŸýìgÌÎÎ"¥äÝwßåý÷ß§R©( ‰•}Y›Œm†]-]pàë°p>ì(«€ehœ9£Øp™\݃uÙ‰Âb\3¡œ¶Óö&WüÍ×GÈ&¬Ð†4™‡êó«u~ðÊ)Û@i+MÅ©±Ò\U>6!àè³Ëu-wo‹ø÷»5'®LiôuJòY‰®A/y¾&Oð™¸JµÕߘ%yã”ÇJYpujóÎM[åwâ.¤Ñ%R£-¸9«ñþÌ¡#%ÑÑ覃eQdRÌ+›ð<®Nk”ë{[°±ˆ„þ>GJÉââ"ù|ž›7o"¥$™LR©T˜››Ãó<&''ùì³Ï6夤Öö¸ºPᛇòhZ(B1ãpôOaîó0Ï]MlSç`w’+ Õ]³«?xÇNSMÔÌ—š,UZ*¤°ô;ãèô¿K—B~Eúsqrq>¼µJÛîàåndRJ‰Ïóð}Ÿ×^{ÁÁAÆÇÇqœõÓ?LÓÀ² ,K¿·™f¸Ýý¹aè8¾dv¥ÁKG»±c&±˜N*çëƒ/3U›¡Më1ÝŒûÆýr³cédŒ¡BšÙ•†ñèïld3 mSgÞùœU¯Ê\_ø™:wÏ…®?y¬rÃ¥\w8| ƒDÂ"f$ì;‡™­Ï£›ó‘qû>ë£û½» ö¤ééLpuºšØÀg30M]×Ö=ÿª/3û­Ì‰P¬ .Oj|÷Œ®…"4AŒ?—oò9×X¥¬4¶®A2‡.LhøÁîYmJ$ ¬r„att%*€éeÁìªàÅ1Ÿ˜ºRÙ˜œ‘G¸ÀM<Ô‹øGz%CÝ’_ŸÓi9ÏÇõ±5"¡¿ÏB`Û6Íf“L&C»Ýæøñ㌌Œ°ººŠïû pòäÉ ç’›‹5òI‹\üËnA²VŠ“¨ºïôdlÊ —¶ìŽØ|h• /(#%LH@ÓÄ}‹ }ªKP_Qû Sçk£üa|•æ³Òr`Û6RJªÕ*ív›R©D:¦P(<1réºþ#›ç¸npïßÛŽÇ­Ù2IÛ +ÃóŸã ÒzS˜ÌVqœGÇúróÞþ|:3¥j‹ZÃyÊ8ëo¾lê÷ÛŽK©QÁ vÏcÏóÂ4ÀÇýwÇñ™[ª ƒÿÎçó]ÉÁô(•v••ÚŽã­{Ìëû7]ÀÑ¡ÆW©Õ |6×õÖ=fÏSw ÛoleNlχKi8Üܳ^Ža1@81n1«,f¡ÏJYÐl vc1ÇÃg•2/ÈQåq¤„Û ep¯C°†Æëò4+¢Ä+¨vÏHÙ’7_ôxï¼N]½Þ=â9"úûMÓxå•W8pàÇŽ£ÕjQ¯×±m›ãÇcYº®c𿆢Yž/ù|ºÄ@G‚dÌx(ÃE†i*å©-Ym.¤èÉ„v’»R€è6àÒ?AºÒ½JCH ^°VwëN=ç"ÌùÏ„›¿ ëÐ4A6nÒ“‰ÑŠ„þ†Éd2¼ùæ›d2Μ9C*•¶mZ­®ëò­o}‹d2ù˜¿–H)‘’¶ûîy7fJ:âØVØùÞïIÈZ–«ø2L¹zx¬/Ç\ÿçRÂ`WŠÎŒÍr¹y¯#ìf·'ÿðÖöÚ|0÷G:íòvÇ~WÞ…ÿ· ÏX«¶èJÀCÇ’4tÅóœ_¾Œë»=¿ëÿ»›&™¤E*nÒv}åóîïùé*ºµ9ñt\_ðÑUÑÞ€tâÑn¯½ä™ó[Š\?0Ð%™Z»R”[§Éߋ彠Gi )Áñ`~UãØÿ¡ó"è$˨ìçmñmT Õ¡;+Ég¡ˆˆ§ ý}Ž‚¾¾>Ž9B<'›ÍÒÛÛËØØ¹\!ÄÛÓÇÇèÍØèwÈtÏ }ã#×qK§+ãgçæv'ríµáÊ?Cþp˜S¯@ %ņÃJÍádæÑn¨º ='B«M©þ™,Sg¤+Él©IÉÄþFÐ4ÎÎÎ{¹Ç‰D‚T*EOO###d³Yt}3ßû—ÂDÊðßÚ®OWÖ~ä{Òý¸KËk+GJí˜N.ãƒóó8»ð½;¾Ë¹å‹ô& èâéçf½HI±Ú¦ÖtíÔšSÃéÁЂt )m–¡1TH1¿Ú ©ØTîyøwÙþ9ñ%wÏeÓ ô‡T„†à„£E› õÈu\ÒÛ)ù‡ß˜»"h[´ù¯âC1„¡4†ÀšÆZÎòh2) ƒ3ò(“bµy.€¸'†}nÌ ªHìG<™Hèïs„èz˜G«iš¦=ðï›ÉIm{s¥&Ù¸IgÊZggtŽ‚f„î5Šþášôfm.Ì–©4½~K¨-@÷Q°Ô\?à·×–É'èLÅ­åZÕ·3à4”ž¥ u§97]¦yêo!Ľëþî5ÿ¼ØJ^¶ë,®5HÇM2Ië‘ï]A!Þ…! æë‹Š‚V‚®ŒÍäB•jÓÝ–BÉÇ!‘Û%zÝÊ–š¾ðùe  :Rö#çF‚„™À6lZ~[ùܘ†Æ`!Åø\yOû ì'vrN´\ŸÓȧ%…ì£Ñ|`Œ,L®‹)eA«k0Ôpî–ÎZegÓw$’9–9(éjŽlž¿øØ`¬OÒ×ùè¹ÑÐÈ’"C‚*M<Ås³$LJ>½¡SŠ:åF<…HèGÜ£ÜtùÇÏg95%a=&ÚcØé›N)ú‡dã&o+0½ÖÀÛ¢è‘kðÊßB"¯_ÜX¥;÷¨È¿KÚL2˜êg®6㫽¸êºFwÎf­Òf¡¨Þp(b{(V÷®ÁÙÃ>éģש@"A?ÝüLüWQÌt¦%?8ëqkag=õ=|–E‰¿•N'¥1¤„ZS𯟠‚ÇΉ­¯@}Iy¿š§‡r4×¶÷&.%¸Í0šð» ˜¢ ¥d¥æPmy˜Oùw:ôœ ÓšÊ3Jvˆ™}¹8·WêøQDבR2¿ZÇ $™¤ùT¡¯ CÓ©8U*mµ¸¹ÎÒl{x¾ÜÖ9!¥¤á6izmNä>yÕî „n;-7ÀxØret¡1–¥á6Yn®(½À:RuwÄ™]©G«\{@ áÆŒ†ç º2ò·‡ÑÄ0Y¦ÈkÊûÕ4xåh@¹!p¼íuP (S£Jƒ·ä«ÊpƒæW¶à \÷ÐÑyMž LÛÌ*9 ñ˜d¸'àê´Eô#K$ô#*M–mmБA3 ž žbúŽ@p¤'M¹á²Rs¶WÐúÜ~bHõ(Gô½@rs©Æ‹ƒ9Ì ˆ„V¬,]UŽêëš Ÿ´h{áßG²fw‘ÀâZ“dÌ fn¬C¦&tÒVŠb»„§X»"„`¨'M³í³Rim« õ¤ÇåÕ«$Œ8v‡r×Oß—L/×ëÏ`làåWAÂŒcésµe_u]äR1\÷Ë>»‡”p{Q#“$mùÔ•_ÀÀ ‹sbµ³&àäˆOµ©1½¬ám£ uðxWü‘,))(Í ¸>\šÔxù°i>ýÂÔï¸ï$°¹*&ŠQ}C‡ÞNIÓ wfÅ#bÿ ýçIé›\iП³1´ Þê4ú^„•àµP‘¢B@.a2œOð»ËxÛ’ðÛpýmè Å·RB¥å1Sü²vᩈ;é;± o±‰Þ™´ÈÄ Šug{ÏMĹ;'×ä³6†®mè=QÙ!êK8¾£$h…€lÒ¢;gsîæ þ6~ï®ïqaõ*…DÚæD­é²Znqb´ã Êw Í e¥˜¯/) }€LÂ$™0Y«´¶õÜD<)ÈþøœÆP!À46;1Ð9Ían0Mƒ¦òœ(ä$£=>ojàmcŠJ‡_ŠcµU_$¬VÓËß>íñs®,Lòä¸.¦¶ÈéÊJ:Ó’ÙÕpÅ#"âa"¡ÿœ’RÓÅñ;6á©­™Ðó"85¨Îo)¼Ö“µùíå{ÑëmÁmB¼3´U$’O&ÖèJÅHÛæÓkî'Ê/¶©s¬7Í?Ÿ›§¼ƒ.,øa#¨@Jz:ï(ó0º¦3’¢í·Yn®ni¦+ksùö-×ß¶Õœ¶ß&aØtÅÕmf¥”\™X#“û l4ýG…x©¼’³ †{Ò|xiZÔgb×ðü°Û«ÀXïÆïÓ&gå1ê¢Éó[zÉì–üöœN½½}‘ë:M²$–}ÊcÞ¿hЕ•tgŸ\ |?Á˜ [›I[rjÔç§ï™”jQó¬ˆG‰„þsNÝñøíµeŽ÷eHo$¹ð.B€iCv&¿%¡_HÇ8ÑŸe­îlO‘]àBm|-ô¶WFJ.ÏU8ÑŸÙ|æOº'´Û¼·â±yL]p°ââ\™z;ê’»[´\Ÿs7W*¤H<Éeé!‚˜£Ãîàzi\¹#(@gÆf°¤RwÛ0'ÜÀ£Ô.s87FÚRôÎ'´š\ª1Ü›ÞtާÃÖcLUg”=õ M0Ødr¡J½…/w‹zKðö§:'†}²›¸|‚$qeß‹ó[š]a“¨åÒö4Ïjã0'VøºÌÏ7Õ „7ðrÃåd–Þ¬Â8º ¹0ý14Õ'tMðÆá.Vë^t_—Z­ÆÏ~ö3Þ{ï=Þ{ï=¤”H)yçwøÝï~Ç»ï¾K½¾ñ>ñµ¦K:a’Š›Ow Z‡ŽXŽ®xžb»Œ¯Øõ9féôw%™^¬Q߆9Qj—¹´zKWxi½CHª ‡‘¾ é'4Ž{ º¦SHtq«2IÅ©)‡® ÎÎS®9ÛòôUd»çÄZUO‡¹à†B*{?ÝŒÈ>æYÁWlž•ˆIŽ \žÔ)©_>÷˜«¼+>!­œ:a~þ™ƒ>ýùÍߟM ÆäŸp…eŠJÇ`hðÃW<–J‚–™7D'†¡c©„…m¬VÚëü½vç|=ø9t]csÔû—­Ì‰õHØðâ˜i¨Ý€âÄÎs“&êÏ Ë€ÑÞ€+Sº²o¼š´¹Î?àkX¨½½Üm öÉu}C}‡…Éwx™9–©¡úœ€tB·$·´è9ñŠïçϦi²¶¶Æðð0årÛ¶©T*$“I4M£¿¿Ã0X\|°Ý¶eh¼2ܹõ0ìP\·«Psô° ïï៾˜¥íÄ-}ód)Ã&UBƒÁW”Ž#F2½Ö 7ÕêëÏì'¡3QþЦ‡L]£±¹±XåÃ]êÇó%‹Q¯×¹xñ"¦iR,Ñ4F£Á¥K—B`šë§¬xž_çaM^î $A qUýð¹Ú"åf[$î‰+)Ã}n)%§Æ:ùðâõ†‹3ÖBt=Àó‚G,'¥”ÌÖ ‚€ƒ™1¤/p7‘›Š|AÛñ™^¨’ˆè\Wí¼H)è4;¹Ñ¼ÍJ½HO¼ l“™I˜L.Vyq,ÿ@ŠÕ]‘ÿð1†m? h+sâaâ1É›§¶^ø'Ƹ˜¦$kt£ÖÇ!fJþäeŸ¾oÒj Œ¸Üô*D2.fHÞgÔÓv$ܜ䒒d\ýº²î¦ïˆË̲Ì16_,/Ä̰Nàü-?{Mùp"¾‚DBŸco¼ñ¥R‰ÁÁA\×å‡?ü!sssôôô`Ybžð†±’¡ÃÍÊ H÷…>ò›DÓ…L C\˜-óêHÇæ#OÒ‡›¿Ü’Ó€ëL­5øo^$¹'¢‡Ñ4°3à¶Â¡— >™ íã–®¾Êð$Nóãÿ˜r¹L>ŸÇ0Âﬧ§‡µµ5²Ù,ɤšÓŒ*¶as(7Êlmž¼Ý©¯ A¡#ަ nÌ”89–ßôœ¸¼z„™Ø’…Ÿë,•š¼qº[5ƒ;ͳŒ8^à±Ü\¥'^P«·3ÁÕ©–KÒ~z÷âç‰gqN¤Hð5y’+â6d/6›_qÕµ0¢ohðÑUïžñØìb´Ï¯ù„©-͉–#˜XÔø¾ç’Ú ¤v§yV— 1Ç19¢<ÖÁþ€.é”ë‚lR­ž"â«G”º³ÏBÐÝÝÍáljÇãd2Òé4G%—Ë¡©æÞo#cß…™?*§¨Bë¼ý>›,ªå_ÊZeÈ +Ã]¦ÖT[.‡{Òêµ ˆ0ªß9Ö0l\Âä@g‚O'‹´Ü(ó~ à —Ë1<_Ó‚ÍžHVD‰C )Ã]Æç4J5Á™C>–z;å2À ¦·Ôk +#í Å~sœ‰"¾DB?bëè&t ƒ…µñ- •Oƨ;MÇß\ž¡”à9¡ Кd\™«¶Í°KðvÜ+{OA}%LmR¬’²MSYÞ¿±B½ù‡?ëšA_²—˜n1W[ØÒX]Y›FÛ£åø›ÆRJœÀ%c¥ÉŲ[:†É…*qËÀ44¥ï‡J PnÕ¨¹ eac™c}.Þ^¥õ™xæ±09*‡IÊ8WÅä–Æ:ÐP© jÍÍ5Ï ´hS ƒÙ­¼)áü-Ll“Í5S| /ÊC¬‰ Eªø¨='1ÉÙC>¿þ ¦æêñ$úÛGvæ¾`+æ^ý¹8/d©4ÝÍ9ÌømX½FóS½Jû¾Û¨ÜòèÍnÞ>ð±ÄsÐ1ãï†{еÐ}ÇÐÕV$ô÷ ùx'SÕ™-Eéò›áž õ¦»©•.'p™ªÌГ(Ði«7 ¨6º7Ñ%øidbiºì<ç–.ÑöÔ\XtM£3CÀ¶XFìèå<7¶Ü<ëôX@±&ØLfj“6çÅ É!P[å’üV*‚áží[]-ÐɈìãmñå‚eCÏ’b=ŠèG„DB?bûÈ ÿÙ®)G®ã–N!cs~¦DÃÙD”®Y‚óÿ9tRô IËõ‰c]Û˜¿ªÇ`àlè©¿ RCëÍPÜ®Â;Î@ª_4½–²5ªmétçl®N•h9Ék¸M>ZøŒœÁÐÔòê)i:¦¡ÑŸW·!|S39Ø1Ì­ÒmÜ@M¤ßŸÚT©;xÛÑl/bÇ9.Gñð¨RWŽ\§’áž0E¥Öܸ -Sãÿ¿¢Wva¡öœðƒÐmǶàÈàö]s1,ÎÊc|,.mÉ‚Ô2àäHØAx·‹ˆ¯0‘ÐØ>Ò}è„Ú’ró,Ct¥,>¼µFc3w©æZèü³…B\׸0S¦ŽmoD_Ó!– xµ+¨®xºÆÁî$˵6õͼEì¹X–´™¤Ø*áKµïÌÐ5r©W&×hmâ{¯8UꋤLõ—Vϸ:Y¤3m“Wi÷tM#kg0 ƒ¦×T^ñ¸+ôW+­M›ˆ½£.òä˜eµç„e@¡CòþƒZkãwÔe±Æu1EõT6ǃß_ÒéÏ uoŸÐ7Ðé&‡…A™šòœ0 É©±€ÙmS/A_]"¡±}Ä;B±?ý‘rä nÔÚ.KÕG›|=–Ú"œüK°ÒÊûm8>?ùp’|2¶ý®6VúÏB»ŽªÉ±© t&¸½Rg©¢îE±{¤Íñ®®ÝÀS|ùˆÇ ÚnÀJ©¹á•r»Ì™Â)↺@oµ}~ñ‡ ÒIµ.ÁOÂÖ-Ʋ#4½–rQ®® z:â,®5)UÛÛz|;C9†èá·âSÚ¨§\e’F¦7Þ jžUþ­ü ˻Ԛ‚ÿø “îÜö»Ú$ˆsV§²…ÕóN¯[óók‘Ј„~Äv"$»áöoÃ\tŇwÂÒù‹3Ü^©ãn$E¥¾ ÅI8ò§`nÞÚÂÂÅJËÅÐC›ÏmG·B÷ù/ÂÂ\„¤bI“ÉU5w£ˆÝEAÖÊp½8NÛwP]ͱMoœèea­ù€ïÿã(¶J,5Wx¥ç ¦¦–¢ ¥¤Òp2¬Øn‚ån•'©:ª.,‚„m’IšL-©±»h ²“ß‹óÔQ_ÍIÚð×oºŒÏkJQ™c™ÛÌòÁwˆ£v$¬V–Á¶FóïÃä˜æq…JJchrIIWVri2ò׌ˆ„~Ävcg!Y€ÒLèk¯@ÌÐxu´“•j›¥Ê¢t+×Ã&»AQÔ¸¾drµÁ¿=ÝGb >áE3 ;k«¬4„ ì7pj Çgw,Uó¾#v”™$K³ÜXÁW¬]1 £”jmV7°š3__$vCS{Ø{¾dq­Á7Nöß9¡k:ùx‹%ª®ºÝ¢® Fz3Üš+Óv¢9±è$CN&˜ÃCí9a[’ïœöY, fVž.e®‰)|)`*¶r\¸5¯ñ—¯{¤·/“íCôpSL+ ý°vÎôùôºF½…rሯ‘ÐØ^ì,œùïaåxjé%šÄMÛÒ9?³›ÝÂÅð¥b é6µ¶ÇZ½Í[G{HÛ; ô…f2LmZ¾º¥¡ús6 ‹ñ¥:Þ¢»{K܈ó¾WY¨/âúj© š&HÚ¡½åøìÓ_§ª3hBÛRC ZÓ¥XkóÆ™’ñ-…?À6l²±,ÓÕ¹-Õ—OŠ›L-V7´â±·dIñïåŸp]LÑD-åJ× ›”ÄLøôúÓ_fÏs}Ks¢XÌ­iüåë.™Äö_g:i’ôÊ<ÅÖ¬ªäÓpqBÇŠrŸk"¡±½èf˜¢ÒXòì–†îLPj¸øÁweFñ‡¾¶¥}Ý^©³PÞá_!`ô (Þ¯­œÚ”м<ÜÁã+´¢FAÏ<†¦3ê£Ø®°Ü\ÝÒXýù$åºCÈu/ 2@ 8˜ÙÒ¾×”jÎŽvaŽwfµ¹JËÛDMÎCØ–Á‘¡—&Š´ÝhN<ëX˜œ£,°Æ[ë3qd0t˜ñýõo©‰O8'^ã…-ík|NcaU i[Š+= Á·9Ë Ôh(ۦ⒯¿àñ›óQó¬çHèGl/B …w,åe›M€á|X0Õpüõ»‚zíÐiGÓ sLy?”¬ÖÚdâÆŽÝ¼ðÉ †—.«;é}Y›ZËÃñ¢5YóÉ}ß'¸ÏT;‚{?ÛJÖ­¢ S3°„ÅJcmK©%½w,.moÝq¼Àåvy C3èMö(ï'’ÕJ‹LÂd Ч"ÝXzŒéÚ¬rj“¡k:Ô[.n4'€g{NèhİHgZ,âoÁUÿPø·å†`½¸G—OÅbX‘”9`vE#Ÿ vô9!ŒÉ’Ø\ã[r&í (U-g+Ým"ö;‘Ðßçܽ™ûþ—]3}ßÇó¼nð»N²j à»Ê‘ëÁŽ8q>,⬗dè6àÜßC÷qPt‘ÚnÀ|¹ÅéÁÜÎ }˜‰pÅcú#Põ',ÎìNǨ·½çÞSß÷}ŠÅ"Ôëõ{ó`yy™‰‰ *•ÊaHG,ËJc_zʈ…Ž8= .Œ¯®+h۞Çó¤?Õ‹m¨¦;®O±Úf´?³£}Ät‹žDã¥ÛøRMÔ1S#›²h´¢9±_æÄ ¦YÄÅCUŠŽöŒö¼û¹ã=z­Öiò÷â_9&GH¡Ö "Ðh æVgÛÒ ÷q lÆä#.Þ97 ãˆÇ §CR®‡+Ï'‘Ðßçø¾Ïää$/^¤Ùl"¥äæÍ›|øá‡¬®®âïÅì ¼Zl:õ-Eõ{Ò1þÏnSo¯s³kW 2™>åuT787SÂÔ5÷¤wVÔ@詟ÚÒ €mj*¤¸0[¦òœw­V«üæ7¿¡T*ñÅ_àyRJÎ;G­yîeôBw˜ƒ#H!i¸MåãÑ„ —ŽñÎg3ë6Ϫ{ ÖZEºìNå\dÏ—\™,b#=™^êB§;Ñ…ã;[úž,Sg¸'ÍÙÒsß)w?Ì ³ò%ªÊv’š}’ÿø “jãÑ×…UfYæ½ÊsÂõàý‹:1NùˆVN&£ôÓMÅó°$§F}>¾ªSªEé;Ï+‘ÐßgÜà;Žƒã8xžÇçŸέ[·˜žžà“O>ÁqÚíö½ÈÎôô4ž·K9B@"±,L¼§¹èJÇíJ²RsLUü°1ב†ÀЏ^À»W—8Þ—!fìÆtaS±x*³¡ ©¦®q¤'Íù™2•æóUiU.—¹yó&—/_f||œ¥¥%„d2|ß§Õ ‹Àc±SSSŒÓn¯_¡iº~ÿ&ú÷íÙ ]'ŸÈ‘¶“\^» B*UèˆÓÛ™ Twš@ך&" êVy©÷$i;©<~ áüø*#½ⶦíÌ9ÑuíÞØ¹x†¬f¥µŠ‡«4–m ÷e˜\¨Ro=8†a„ÿ;ý"¿GlçœØ-‚òdIóŽø£rä` 0Ò+™[Õ¸!ÛÅc^¬òCùur¤”Æ–@ÛüòSƒ“£>ñØŽf³á¹é’9ºd·˜£š±…e Ã_Œk¬V¿š×~ÄÓ‰„þ>CJÉòò2—.]âÒ¥KT«UÇ!ŸÏ333ƒëº9r„z½ÎÜÜAP©TXXXØÝTM‡î£póÝ;žúŠ­Îcÿþ•An/×h¹÷Ñ®BeF¿1µx %«uýN7Þ]ÃJBßi¸òÿ¢¸® ²q“B:ÆøòóåÞl6™ŸŸgff†……ÇAâ^Úšã8¼òÊ+¼òÊ+LMM=VÔ„ÂþþíaÁÿðWÝ4,Ód(ÓÏ•µë¸8húzûú–Š›¼õò ‹Å&ž/ï ævÐfÍ)rºp‚T,¡4¶ÐÕ¦‹¦ ñ{/Ûw¾<wE¾ah¤¬8c#|¶|G:Jcš¦FG:FG:ÆôbmïUìpjÞÞ±sb7118.GùµødK…§éüßw¸1«Ñh}ù%W¨3Åß—_#­Ø$+`±^;]»· ’&ÉYyŒ¿¥ŠZßC‡î¬¤§CryR‹òôŸSvÀG0b'Ñ4žžzzÂB»»7ô‹/òÝï~—›7oÒl6q]Ç »Ó aYËËË»{°é^è?Å è96Ú$1CçP!ÍÇkÌ—›ì¾#êK“°xÕuT×—,”[ü›S}ôì@C Ç¢›añðâÅðe%Ù­4Œðæ‘n~?¾J åΧ=# ºººR"„ Ùl299ÉÏþsNœ8ÁÌÌ ív›ëׯ³°°ÀÙ³g‰ÅÖÏWw]ÿ!º.ï+nWvƒ ¥NÖÈ2ìgº¼ÀHzCS»u§¸0¾Ê\g=i4Mc¾²ÌDqš;Oà¹üÉ/`~¥Æ«Ç ¤â&Žã#„¸wž¶ !À4 |?¸s®]Vžéòó•eY5Q&¥ä…á®L•hv¢ÝI¦t]#“è_ÁBÛ9'v›A œ’‡¸Å,RÄØ¼•k"&9{ØçƒK:SK‚#áµ:!æ¹(nòcùºb\ÓqarIðWßréÏï^°ÌÂà0C\·™d™WGøþK>¿»¤ãûl{7߈gŸHèïCî_~6M“üà´Ûm2™ Þô[­ÙlÓ4‘R¢ëúî/[[)ý6L¼æ¥'»6=„¡‡x a®Ôb¬+…@†p;FA¡ººZkóñÄýò ¦¾›‹["t&:õ×°v ÇCñ¿ÙQ„` çG'ÔsO÷#š¦¡i_~_ñxœoûÛ|ãßÀ0 lÛ&:„ïûÄãq,ëñ/™Šyù˜Ÿ«sw,Û°9Ùuœ+k×é¶ódc™Mu·qÀr©ÉP!…D2__ 'Ñ­Ü  \s¸Ï †a+Ö"µqþ6øså9H˜\4Z‚\*,üÝM t^—§ù'ñ[fXdŒÁM¿°é„$­f8ñ z¿‹ØY4â°xIÙ7^ׯêB3KEü ÿæ¸g•Óv¼@ri®ÌwucíJîChØ9:Ì}vöx.Ð…N&–f¢2…¯ø½kšàähùœX,ñþäG &èŽo^ßÅó%“ 5NÌcìAèO‚”™B:·*S[pVØoèä3q _é›×4xët8ŸÎMûüƒ|‡Sòc  mÁmçümïŸõˆ™»=êhäÉbbð‰¸²%žˆç—HèGì,z ŽþV®AmQyýÜÒ5Žö¤ù‡oЪ—¡ïŒr4?’ËseÊ —“Yô4E~,"| ê<õ•=ØÄ^ajgºO²ØXfµUT¶9ŒY:C…¿úl‚R³ÎXvXYäR2>[¦Þr9<˜{ mg·­65z“JíQ‹Ÿç‡&&¿É8ÓL³ ÔgB [òˆÏÿñ+ŸÅvWå Ê);~Ÿ\×)Ö_?îcîAn»@``p˜̳‚¼ó¿ˆˆÍ ýˆEÓâÜ΃0ñ;åȵp £Ú"­Ü!<+ƒjn~ÀÓ%^:ÐAÒÚý…{ù1h•¡4 žš…ZÄþBy»“îxž«k7”£tštu˜h‰:=‰^l=¡4#$¡Ðë˰=³¡BГì¦í9,6–qüçÛÿyÁ@gˆFèç}ñ9¾bT_×àÀPqà6#îi/«$ô¥ …þ¯é¼|Ø'›”»ž¶s Á!9D&7™¡…³7±o‰„~Ä. –®@»¦lµY0[ü(qkúaZºš+‡HÖêmšŽ¿»N;ÃÎÂØwà‹ÿ þˆç!ý©>æjó4ÝÖƒ="6e{¤zŠèÍ. Ô\T‚@R®94žNµÓÛIÊLñBþïÏüº«f+±ÿÐÐxAŽrELP¡ŽT|Žu–ɾñ{¬g°Úi¥1ü–J‚jC0Ú»÷é2y2|‡—ù‰ösŠT¢˜~ĦØ)¡]‡Ò1vË]¹žš³(Ma¸~yÛe®ÔRºÈÊM—Ÿ›ãôPŽŽ½5h&tëJÓa#°ˆç‚žDÙ!fjs¸ŠMåË´¼—oÔXZk(eÆÕš.¿ùb–£Ctwì}Åž!tR}Ä ›åæªrCÄþcŒAÎÈ#\·h*F®oŠiê¢ÎÇv31¯+͉µªàÿzÛä/øŒ<BßÄä9FF&™`_Á:7b_°#Úy¿Gô£Šý‚• ½ôoýš¥ÍEõ¥ óØgþˆýâ_ðÍ£ý|t»HÓñ6uød©Úb¾ÜÚÅN¸OA0l8ô=X¸Ö1D<غÍpfˆ +W¨9u‚MÌ ‰¤Ô.s«<Á7‡Îröp/—'ï̉ML ?¬”šk#½é½)L!–nq¦û$“•iJíÊ^RÄ.‘&ÁKò(¿ä#Ö(ão"ª/‘,°Ê'â2ÿmìMþäE÷.TbSsÂóC‹Î…¢Æéƒ>ñgÀ…TCÀæÏä7ù\\cž¨®k—Ù×Zs¯îêûú¤E( ac¨DnþœÆÿP†n=³Ÿ@ºkèe¾}|_J®/Ö6UÈXj8||{¿|i€¸õ u Ñ­°f?»Õßàçòe7£ˆ½E×tr±,™Xšs+iù[é’Hü àfé+Íñ®C|ãD?˜Z¨njNTêW§J¼qªûš†0èKö‚Åq|l¸Ñ ¼h`ŸbbÐKžnrüB|@='$Å tðmã$þªÀóáümÍôz[. ~Iç¿ûŽKÊ~v¤Š…ÉFÁ‡â<þ†æ„\\¢çÄ3Àž\P{¾ÙÏά‹Ø<±4¼ô7aÔzæãýMàC» +7¡ÿ,B×±Lã}~yeÇÛ¸ ßã«äX_ëYê"DØ0kì;0õ{h®m,…GP™…›¿ŠÄþ>%nÄùîàë”Ze®Ç7$ÒPwÌÕ9Ô1†¡éØ1ƒáž4Ÿ\[ çÄ&….ÜZÅó d1Ÿ¡–™B Ýà…üÆK·)µËZñR²T_áó… ›Z!‰xvÈ’â?È¿dž>ç6$f=|ŠT¹Êm¾.Oa ƒ” /Žüü#ƒV{c†oRÂ;Ÿ´=xõ¨ý Dóï¢!°1yK¾ÂÄ%XÅÛ@ $à6s¼-þ°¡ßØûJ‹>Cjg]TNæ¾úž+„6Ñ:ò£°³m³ôtZ_†ßÿïÐÿRèÞsÇCáPwŠÑ|’ÿòù,寓ó›½@Rj¸ë_Ëchb÷d=~¾Ãÿœ:O¼”½6”¦àò?‡ùýâÙiG»›¦R8ÅRc™š[b4:LÙ©ð/·ßæ`v„ÎXâÎÿ†{Óôv&øí³ÔšOÎoö}I¥îP®9œëDן½9!tÅ;9Ùuœç?£åµž(úÜÀe±±Ä'K_´’ÏU·è¯qbüù-n1Ë*e¼'D£ï¦ìüoâ?ñ' Î§úìøÉ¯LV+O¾\/Œæ/oö1 eçC 8@/ß—¯òSñ+j4ž8'Z8Œ3Ãÿ+~M–ú3/ùž ¾rº3úÖ#vŸŽ‘°KîÄ{a Ïã¢×­2Üê·[û5IDAT|2a~¿õ¥ÓN>eñ½c&V||{•Z{ýãT[.¿¸0ÏPg‚±îG»E>3˜ñðs6‹°|íñEN ®¿¾u~öžH»ˆ”Ïóð< øò|ù¾ëºø¾¯ìU¿[ô$ºÉXi.¬\¦íµñn¸M.¬\&Ë2’9€m|é´“MÆxõx « .ÜZ¥ñ˜9ázµ–Ëï/.Pèˆ3ØõìÎ K·É îÖ˜®ÎÑòÖw(ò¥OÓkñùòF³ÃüÿíÝÛs×}ðïÙ n¼€¤HŠ¢dR”Yª%;íhÒ:™¤SwÒØÉ¤MÛéL'>¶/~OÒÊyʃÇùê—¤ÓIÒ©ëØJÄ7 iOÏî,,,àæÍ›X\\„®‡÷‹ºÔö÷Žáâ ®-Žâ†ç|WRבΧñêø×‘P6%ЛPñ½?žÄý… fo.y63¥Ò9œ¹üZQÇá±~DCT›ï& Эvákûþç/cz~=¿%¤fµ \Z˜ 0‘C·Zßð»ÛÅvØ'úуÍgñ¾8ƒ3b«X÷œïwâc ÿ`þ’Ø:œæ`ÒÄ?ÿmWïJ8uÉ{ž{‹þí¿Uä À+Gut…`äe?HâïŒoã]q¿gÁÖ³]«XÇâ,„¦Ì#Ø…­ß¡´34ó¾Ò¡£ûqá˜&\ÓÜ÷ݹ/Ò“‹ó¶}‰ýð‡?üûÚßNk­®®b`` â|š¦áìÙ³¥ùeYÆ7pîÜ9D"tuuAL&ƒL&ƒ¡¡!(ŠÒ‚wPFžR7ÛY5êÑ«¥zé3àÓ_éÀ¡?º†=[¬…d!0ÜÅÅ;+¥Wšn"WÔqýñN]Ç‘‘|õк£J›~·Â:s1tXúx0 ô=c•êä׬R¦ë¿Šà¹ïZ@bóÁ‹®ëH¥RˆÅbèíí­{M–——‘L†çËÁþ7M†aÀ4M˜¦ !4MÃÉ“'qøðaD£Qäóy\¼x±´?ŒŒŒ Ý:Î|.§múâB@’¬Q:‚nð”Ÿô 1|zFäÆ{öáQv×RŸ[¿ô©Æ‘+æqý>~t©Ü2¾4ü<ú¢ÉR‹µŠ"C×­Ú|EèíŠâ³{«(h  ÃD¡¨cîa®-`lw7¦¾0„D\TfŸ°–-¡X ¶Þ]@’¤'Û¹ü†ˆ+1ìéÁƒÌ#ÜL߯P|4CC®˜C*·Œé…h††¯ìy ÝjŠlm'IˆF•Òß¡;aŸÈç7Ÿh§bxÁ<„ëâΊi!D7Öŧ¸‰_HâãÛæ×0‚AH^±Cªbµî|E†UÕ&P4€¼ÀÅ2ÞûXÅÑ ßúrÉ.rx}Xõú=è³æ8®‰Û8/~qìA¤‘Á]<ƯÄYäPÀ_š¯¢=[Êv„°>“"‘òŸ•´kŸÈfËwÔN$¼‡ þñü/òxò[®kûl.ÇqH…ût˜Kß&&êý¹Ó­Ëñ%„˜7Ms8€×i9Ã0Ïç±±±!dYFWWÖÖÖJÎgΜÁáÇqëÖ-ŒŒŒ ŸÏ#•J…«G‰Y¿–K©9àêûVÙJnÅê¬;üðÌ—ŸÙrAØÛÇ7ãW3‘×tôwEŒ«¸“Êâ›Ï`l DT錓–BB±Ê•&ÿ¸öU³éÖ-ô‡^µF1Ú²Ù, ë:EÁàà ` … Ã@.gýÊp__nß¾BÁ»fÝ öîûPçõ”c@ø}©Æ¤öª#è‰vãAæ!.-~ŠùElè9¬këØÓ5‚ÓèV» ;VÚ>8±¯ÑAëÿãß?Æïo-£;® U°°’ÃËG†±w¨ ñ*ö I²–)ËAf?çv6M å?²dH–wajäy\x| ç~‚¸ÃZaCC¬/ý±diÛùé6 î=„IûD˜ÄÅ!Œ£ßìÁq ¸‰ûHc XÁ³æ8¾j¾ˆôz‡|pÞ÷zÌtÝÖ5M»¦(JG}]×1??[·nA–eìß¿ñx¼T‹iEA,ÃÊÊ ÃÀãÇqíÚ5ìÛ·¯Ý«¿™VXíŸýþà…¿²ª¤Ê&»ðߘD^Óñ8Çüz¯|aƒ]‘hÅ÷ $ {7ðÂ_[åMj˜Ü tmiÁßir¹–––P(FÑÝÝ I’P,¡i666 iòù|éàVöi¢SUÙÕÂn‡Zx ³µ•ƒÄ Ú‡]]IŒ'÷áÿ]Æxrô#®Ä|£Œ$ ¨ªðæPU÷%q`oÙ\‹«XYËcêð0v%ãPäêö ;+Šðöe ’HRõËŒ àñ?•…ÏU¢ØïÇ@¼²$?=Õ+¬e«ê濹$IÛ¶n?È}"l$ìÆ. ™xÎ<€_‹p“xÑ|݈W]wUcŽîÏ#¸¿$°°"ð§S:FwP;0 ɰƒø¾ù:ΊKH †½¨9ò¶®ÉD"¾«‘ˆ÷pIš¦]`_íΆNÛ¦5oз»×5\·áqÛ>c7ÍOž#ÐæççÏŽŽ~µ™o YEÁÞ½{±{÷nÖiïO?ýsssصkr¹öïßóçÏãøñãPcccPU©”w{û Ö ~Ío_®L³ˆ"c´?Ž‘d Š,:ÿ‹]Žû^~ÒÒ/ïøX-’ÇŽ+•(†ÙÙYôõõáÖ­[‡$I˜˜˜Àôô4Ž;†®.ïšíBAßT¦`-OzrÐ ÷™. ªv'ÉêάEE _þ"d!CÒeh>#TYÁVly/6Y†’1ìê‰B–ô¢^õ0K’I(Š}UµÊk¬­–m L&@@@ô¢ £4*‹µÏ«ª‰BÁ¹½dÙ@,Ö¯¼Æ¹O„•]›þ]óëP  ¥® +Ð719jâÀ ÊØtV¯ÓQDðŠùdÈ!mëX¥9~A߯lg~~þ<»ÓŠá¸x•ïx]àqÛë:TÚù©Wm™N½å<^€â;ï¼sö?øÁu,³í¬šY¥Tg¯ë:Ž?^ õ²,£P(àèÑ£ˆD"P†a@UUd³Y¬¬¬”ê2ízN{¹A…bÓ4¡ëz©´¨6 Ì¤˜¦ MÓ Ërà-R†a@×uȲü¤¬ ö6¶¿„ƒÜÎö²ë«i2™ º»Ã;šJ#Üûb±ˆ#GŽààÁƒ¥³YB$“IŒŽŽ"úöK[þÖ]!‚ª$t.»ú¿¿,Rõg¶¼Þ‹µ4|V«ÌÖú>ÝÞµ¬KTòo °·ÃÖ¿ëö >AîVÙSX“¯„ÿ\“e@ `mÂB "^q>7ë,WðëÓ Š¢ ¯¯Ùl¶ø#‘‰„ïÿö;ï¼s@Ok3˵ÜW«Úçµí  š7¼¾mË}W:"Óß|óÍ»o¼ñÆ»]]]ßiÎ*7N–åR0¬4___ߦiñøæÞ4ÍR‹þììlé A×u¤Ói$ D"‘@h*•ò\·F†;wî`dd±X°C# ܽ{·t$(†a`qqÉd2Ðí X¡>•J•ÎðØ¯·¾¾ŽÑÑѺ—kšfèNíûíö¯»…²šN籘êêŒkBë *Õ.±kÆÝ%%²;ÕɲäÛÑ·ÑeÛý ‚\®½`;>[}ŦN·öë5`wÆ>!‹©ˆD:!P£ì¾=õj÷>¡(JÕNd2™wß|óÍ»Ø\ºS®åÞ‹×c¡lÅw ÓÞ\©ù¬Üãv™ð´¬Ç}šÅyÉ¿õÖ[?ûÑ~Ú o·Ä±I’„¡¡!¼öÚk›¦çóyܾ}ÃÃÃèíí ¬Ç4M\¹r‘H“““,Ó¦ir¹^zé%ô÷;¬d:F&“ÁñãÇ=­],1;;‹ññq$“É@[Ë2™ ®^½Š©©©MÓý¶ûz„Iû`¿X,‚Ö}N;»uÖ²­ãÞП=á®ì|:½‘cì±OX¢!bŸÒh›S÷ ?o½õÖÏðt´jJrìr?•ö’ÐìEÍ>iSÏ›^×’Ç}÷P›’ǵ묖}Q×ñ .¼~ìØ±ªáý´ÌÊÊ ‰DSë( …òùz‰išH§Ó.·X,b}}sss¥aè‚’ËåpíÚ5ܹs'°!Ní¿a$ —/_Æ£G2/Nz°„VìD~¸OmÆ}Âíþýû?ššú@ÞY°šÒzÃ{(´;è7²‘¼6¸_ÉŽ}ßyÔfؘ˜˜øÅÌÌ̉Ö£)¢Ñ(t]oêXÇŸ|ò ®^½Š?üù|>ÐeK’„éééMãû!›ÍâäÉ“8wî\ A?Nã·¿ý-–——+þG­.]º„ÙÙYœ:u «««,scc}ôÒé4æææpýúuüüç?ÇÊÊJÃË. ÐuÝóÇtÚ©û‘îD›…uŸpš™™9111ñ X-ùÎìg×镳#ÓëÕÖ‚výjUsJÄoš}Ħ;îÛh@fjjêý'N|/“ɼۄu¯[oo/–––š¶üÅÅEŒ!“ÉšMÓÄúú:âñxi´‡ 躎{÷îAÓ4¬®®¢Xôn°…BŠ¢`rr= l¹€Õ¢/ITU l;˲ŒÝ»wÃ0 ‹ÅR‡ê ¶ÉÒÒRC¿¨ÛLÍÞ'ì£Ëç󠚦‰µµ5d³ÙÀÏž™¦YúÒ š¦iXYY Ñ î›qŸ°„yŸÈd2ïž8qâ{SSSïÈÀ»<Ç™ ËeH÷4¯ëPkvwéjž¨pÛïÚ=­\½¿ÀÖš~ç|úéÓ§Wò“Ÿ|¬ëúo<ø ‘HE‰h[ñ£ªª¥_5lÆQ³ªª˜››Ã¾}û0>>X§Ó4qöìY `ïÞ½P%°oš&EA$ªª8pà@ =þ××ס( ‰[n*•‚ªªˆÅb¥8k”a¸ÿ>LÓDww7VVV Ë2Ž;ÖÐÿŠ}¦§§§ául†fï ¸pár¹ûÿ2 —.]ÂÇ}I×uÌÍÍáÁƒؽ{w`ËÍf³˜››ÃÌÌ º»»ýR¿wïΟ?T*…ááá@F¹ZZZÂåË—144„|>ééiܽ{ ÐÅ}‚û„û„%lû„b^Ó´‹<ø·ß~ûí×_ýýÓ§O/Àê|k7ì·Áðý•JÅ+ÍÓv­A5¨¹^aÝkš³3.°¹S®×µû¶â¸¸—Õ¡#ÎmîpnÀê`k_¼‚½îsmx,ËoäF÷4”¹v¯k¥÷Òa©Ò°šîùœ×pMsÎk¹iß®ôÎRŸ"*Ÿ """¢Öó âΰî®Ë÷jÑw0”{ ÷´ZÖ³mÂôýÔz`ßvŽ©ïÜÀö›€õ‡¶—±ùŸDàéó À ODDDÔnÎÀí5zŽWç[w_M¯Ž·îÀß1ÞOƒ¾Wë¼}ßÙJïnÉwß¶9@Ëû’ëÚù¸3ÜÛ,Ý!""" gK¼}ßúÝ­úî–ür#픫Ó7|æóºßv­úÕ¶Ì7²|`kÈ·¾}pà¼v>×tÍçnÑwÿÌ"Ã>Q{xµÀW*áñºí|>àö›Ü›~`ЪÐäè;ÀÖv¯³î²wç\w˽óâ.×qCÊ ODDDÔ~¥6~e<^ÁØ|6À½¯e;ŸÇÊÝ®æ½4EKw€úÎø•óO[éí}›K€œlÑ'""" §r-úöãî{w˜w—ü¸—]O]Ù®}÷|õ´ê—~Óݲïl½÷z¾³ßýÃb ûDDDD­åÓ†Çmwðw×ä{ÍW®f¿Y­ùµÌW·Vµè7³NßÙ’oóê”k3\;[õíù%<™Ço9Î×!"""¢æðËaîŸUvÿJÞ¯.¿‘–ýjµä @XKwïuœÓœÃhºŸãî û^%>öþ ï5o½a¿ÖÇËÍGDDDDíåìá1­šßì_ë¼hg€mEØ·ï×3dg-Óˆˆˆˆ¨ùª öÎiµ|¿yªy¬’¶tâmõ¨;nÍ ûÕN«¶“m½¥FDDDDT›zKaj­©¯4šNG‡| ýÁ´‘ ïžVËãåæe+>QøUÛ’ï5#!ßošŸôÆÃ¾{z£ßùX¶ùó«Õw>^évµ—›Þè¼ C­uê û•æ©ú«™ˆˆˆˆš§Ú¯ª¥Ö¾Þyª±ãƒ>\Øw>DpâlÕ&¨VóZ j9x¨¤í¿¢¦pÚŒ°_ír+„i;QåV÷j‚v½gjYnÛ„-ÀÖ³>Í(¹a}>Qç¨T§ï5¿×íróÕ³ì¶ [˜­w}‚hµoÖs‰ˆˆˆ(8µ´Ø7òÜz;ƒ~Í ûÎyƒ|ïaÜŽDDDD,ÈÀÜH‹­¯a ¨¬W=Ï•x="""" £Žç4ÔCòð} õaßýÜ0o""""zª‘r÷2Zýܦ {˜mtý‚xaßFDDDD;U»Ñe„2äbÃÖ;aÛmÍÓa8HhªN «A­k'½g"""" NPÁ<ÔßÖi¡—#åQ­‚Á§#tbØeUÖrŸ–éä€ÛÌuïäíBDDD´53„wTÀ·m‡@ÛÊ÷°¶Q'keèîÈ€oÛ.Á5Œï#ŒëDDDDFa Ôa\§šl·0ºÝÞµVÇ|ÛvÆÛù½Qp¶M¸wÚ ax'¼G""""ªÝ¶ ø¶‚wÚû%"""¢Í¶u¸wÚéÁw§¿"""¢ínÇ{7Ý͸=ˆˆˆˆ:ÛŽ ön ¶Õáv"""" ú `ƒÇmJDDDT†w"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""¢vùÛöÜM>×ýIEND®B`‚Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/screenshots/sin_cos.png000066400000000000000000003310051520337127000263560ustar00rootroot00000000000000‰PNG  IHDR*6ñh½dsBIT|dˆtEXtSoftwaregnome-screenshotï¿>,iTXtCreation Timetis  2 jan 2024 10:25:17Ã× IDATxœìÝwx“Uÿð;³Mé.mihÒRV)[PU–‚/C´àBÄý".Ä_DqüyEE”aY²AFe–ÙMGJgÆïLLšÝfµ½?×Õ+ÉyÎó<ߤZ’;ç9 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""r1« ¨‡øš5 jWPŸ0T³_'""""""""ª †š0€ÓÇ׃ˆˆˆˆˆˆˆˆœ‰æßz0×П?¹—\6´ ®¡=_""""""""ªÛLpÙ‚»†ð‰ˆˆˆˆˆˆˆ¨þ«×¡e}ñêós#"""""""¢†«^–õ-Ì«oχˆˆˆˆˆˆˆˆÈœzZÖ—`ÏŸ‡;ÖDDDDDDDDDµçŽá ;Öd“ú¦9ó9ԇ׋ˆˆˆˆˆˆˆˆœÇ™b+ërðæÈÚ>>5\j86T¬“e] ãQ³ÐÇ$""""""""²–ÊǬSe] *íU/GL‘»²çˆË:VÖ¥°®¶µ ªÝ:óÜDDDDDDDDÔ°Õ$0TW»uæ¹®.pµ©±¦á¤µýëÂëGDDDDDDDDÎcm(hkxhÐÒ­KwÚjZŸ­¥¥~œÃ’ˆˆˆˆˆˆˆˆjÃÒ”¶œ5 Ý6¬tç ²6!¥¥}Ím˜¸ODDDDDDDDT[j÷Íõ3µ½^…•îÄÕfIkCÈêí5ÙˆˆˆˆˆˆˆˆÈ–BISÛ­ 3k3ÿ¥ÛpÇ®¦!¥­A£#ÂIw|=‰ˆˆˆˆˆˆˆÈqìš -ktÖ´§s·`­¦‹Þ˜)i¬ÍT»¥óXêGDDDDDDDD¤Q›Ë¼m ,k:ºÒmÂJw Ýl©ÇÖÒX@iißš®NDDDDDDDD¤«zhí¥ÞÆK{†• *°5¤´w@i,”t§×‡ˆˆˆˆˆˆˆˆê>c£,­9ik`YçÂJw âR -l·vä$ç«$"""""""" {Îii¤eõÇ*Ž[§ÂJwÓRVïg. ´e´¥¹>DDDDDDDDDÖŒ~47jÒÜþÕCÈzVºCàfK ÕGH;†¹ÒT@i)ˆ4u^"""""""""kX i*ˆ4HZVV?¯9 :¨´wH)4ÑnM@iˈL"""""""""[X2ÚXªL´ÃDK\Vº:€³öü¦.ù¶6¤´& 47Ÿ%GTQm˜ UFÚ–5 +m¹¼A•µMY“ÒR@i*¬´ç";DDDDDDDDTY»hކÊÈ}S+ƒ×&¬tûQ•® ÚìRš "m«Pmin5p†“DDDDDDDDd S£æÖÔeÞÕKkÂJkæ¬të°Ò݃JKóRš )…FúéÞ ìkjK¡™:ˆˆˆˆˆˆˆˆˆ¬¡‚á¨Gc!£æ¾¹°0>‚ÒܪáºuX£A•öMiMHiK@©»ŸÆIDDDDDDDDTÕƒEŒ ´&°¬MXé¶£*Ý9¨´6¤Ôm·%¤i×½¯»?ƒJ""""""""ª Ý`R÷n CÉêÁ¥5a¥5«…ëÖb §•bgž ¶­òmí6c!¥±mÂjý4¡¤¹ R·ˆˆˆˆˆˆˆˆ¨¦tIÝ‘ûºûªÝ×l×ÜÙ#aå¶šô³ g•µa,€4wkMH)ªv+ÀÝ×Dòw›¶ÏQÉÅvˆˆˆˆˆˆˆˆ[B<•Î@îæNê¿ÛßjÂGÝ[Í14Ù“n°iêprØXîTV¿¬»ú6SýMÍWi*¤C?¤”ðذaÃ==zô˜(‹ãÕjµ¯Z­æhJ"¢Z(..F³fÍ\]‘;P©Õê⊊ŠSþù窡C‡îP»¡¥&¤àŸÓTX 臒ÕIS!¥nØé6œ9úϖ˾]Þmnoc}Œ]Æ-Ä?#%E:m^6lèÛ§OŸ™*•ª9¨Õnõ{""ª³ éê2ˆˆˆˆˆˆÜŽZ­¾žšš:gèС»”âŸËÕøg䥱KÆÍw ˜_)¼zØe¬Íd©Vö«w *ŠÔ<6uy·±U¼Í9©])‚~Xéuýúõ÷d2ÙJ""{cPIDDDDDd^qqñ/7~ wÃJÝRs¿ú‚;ÕƒK˜iL•0ÒnŒS3w¼¬ÙÖ²ú~ÕÀ1Rfgg/‘Éd¨Õj†”DDDDDDDDät¾¾¾-àýìJw Ý«‹MMƒhjŠDSW0»g•Ž|âÕç¤4öËÑ]G3/¥ìÚµksD"Q”DDDDDDDDäJ2™¬Onnî2èOY¨›iUϽ„Õ;ŠSBMwQiiK£)–º¿PÝ9*%¿þúk_//¯Q )‰ˆˆˆˆˆˆˆÈøùùÚ¼ys_Ü]ôY3š²z¾e, ´vT¥1n3²ÒY…X;?¥±~º—pëö3µx ÿKC1€Fùùù¿©Õêf *‰ˆ‹sTYO¥RÝðôôLpwWÿÖ]TGóX3W%`zqcsUjöÑeí¢:ÑÜeD¥© ÓX}ææ°Ô}\}žJÍ%ßâõë×÷aHIDDDDDDDDîF(6Û´iSÜl§¹ÜØü”æ®6†‘Çšýq‹Q•Î*íñD- U56œµú/NóXÚ³gωv¨‰ˆˆˆˆˆœàúõë¸~ýº«Ëp¸†ò<‰ˆÈ²Þ½{O …~¦el``>¤´tÙ·-fºËˆJk™ZåÛT›±_¦H*•Æq4%QíA*•¢sçÎÛž{î9H¥R¤¦¦Z}¼ÒÒRA¥úçª4¹\ŽöíÛ£}ûö())1ÙQÃg¬_¿R©ï½÷žÑ퉉‰J¥J¥ðôôDëÖ­1eÊdffÖøœšçÒÒÒZÏÔkDDDuƒ——WôGSVŸöК\¬ú}·çÎA¥µóZkÓL0ª¡·˜ŽZ­ö­}yDDDDDdOS¦LApp0ÒÒÒ´m^^^ˆ‹‹C\\d2™É~Î4|øp$%%¡¬¬ +V¬À AƒP^^^«cjžgûöíáééYë]ýQí_.¦£¡»°ŽÁ®Ö¾Ö:ˆØÕÀö‡l¹þ¾úhJ¡Z­v瀖ˆˆˆˆˆþ&‰°oß>W—¡ç«¯¾BPPŠŠŠÐ§O¤§§cãÆø×¿þUãcºãó$""} …åå娬¬DUU•vÔºP(„D"ÑŽ¸‹í·U_å[wT¥òï>¦21µÎcc—ÛÚî4ŽìlIh-õ5W«±ID«רòíDDDDDdÂÖ­[Ñ·o_$&&béÒ¥µ:V`` ¦NŠéÓ§#** Í›7Çÿû_íöGyk×®tíÚ^^^zû†‡‡[ìWÝ;wðïÿ­[·FHHÆŒƒ«W¯j·ËårL:Í›7GLL ,X`ÓsòóóÃÃ? HOO×ÖúÄOà½÷ÞCË–-qß}÷”J%æÍ›‡: 00½zõ–-[ ^#Íó´¦~¥R‰÷ß;vDPPúõë‡íÛ·Ûô‘e …………ÈÍÍ…\.GEE…ÞÔ*• ËåÈÍÍEaa! …=N­T¦s/S™˜îq̱g~W+î0¢ÒK×Ò›mYýT½Ím‡·¹‹¬¬,Œ;eeeîÎ9‹>}úÔø˜Ë—/Gdd$¢££±k×.¼÷Þ{HLLÄСC1fÌm¸6räHtéÒÅè1¬í?ü0¶nÝŠáÇÃ××kÖ¬Áµk×pðàA…BLž<7nDÇŽ‰ 6Øüœ4T›4i¢mûöÛomÚ´AÇŽ/½ô¾üòKÄÇÇcàÀظq#FމÔÔT“¯©¥ú5ÇŒŽŽÆ°aÃpúôiøøøØô‘yš9mQVV†²²2øùùÕöË"S™Võ6kGGê¶¹|ô¤1îTZÚSw¥¹ë÷‰ˆˆˆˆHlj'´!¥ÆþýûkT@ZZ<<<0oÞ<üç?ÿÁ®]»0tèP<øàƒ;v,Ö®]‹·ß~:t0º¿µýNž<‰””Üÿýøé§ŸÜý°ùóÏ?ãòåË€7¢y󿨷o$ þýïcáÂ…V=•J…'N૯¾‚D"A¿~ýô¶ë7nÜÀW_}…ØØX8p‰Ë—/ÇÔ©SññÇ}M-Õ/“ɰlÙ2DGGãØ±cóZZó‘y%%%Ëå5Þ_³¨™··wMQ=ÓRÁüˆºmnBZÃÕA¥¥y(ÝšJ-Õn*u&"""""3Ú´i‘H¥R©m‹5Ú×ÜÊÒÁ?o¿7n @÷îÝyyyö(×À¹sç;vì€T*ÕÛvûömdgg ‰D¸çž{¬ *ô÷E">üðC´nÝZÛ&“ÉôÂÇ´´4¨T* 4H{®±cÇbêÔ©8sæLê¿}û6”J%l—ÅwˆˆH_iii­BJ ¹\¡PXÓ‘•æ20µÎvMˆ©Kw»æ¾±[cçtYÈéê ÒZu"\¼ÿþûÜ}3ADDDDT—µlÙ‹/ÆìÙ³QQQÇÆ Óëãëë‹FáÖ­[P«Õz¡¤&€lÑ¢…ÑãÛi¡“ýû÷ÇgŸ}¦·-22›6møøøØ|ì~ýú¡iÓ¦ˆŽŽÆƒ>ˆ¸¸8½í5Ò{|çÎЛ¯¬¬¬ À ¯µõk.S7QÍåää`äÈ‘Édعs§KkÙ·oT*ºuëfðÅ9†B¡°ùrosŠŠŠ •JþoŸub”¥#_¡š†‹ö^F½N„œT¿8p)))ÈÈÈ@^^‰'¢Y³f?ÿˆ# “É´sih¾P±•»|ãNomÅ7˜DTMž<“'O6¹]  cÇŽØ·o¾üòKL:píÚ5ìØ±Mš41T£mXPPPã~šà.66"‘ÇGpp0ôúµiÓ’’‚¹sçÂÃÃÇ·ªÎÕ«W#((Ȫ¾ؼy3æÎ OOOlݺjµÚäeÙ–ê׌àLIIÁüùó FUZûZ‘¡œœ <§OŸFBB‚«ËJ¥BQQ8€=z¸Ý{ÉS§NaÙ²eHMMÅõë×èß¿?žzê)ƒ/sê‚’’‡Óßß¿¶‡±5³LÖ4¼tXèYßWÀfHIN¥V«1þ|¼õÖ[8rä|||бcGxzzbÇŽ‰D®.‘¨ÎÒ¼aýôS½Q––hB»W^yï¼óŽÉ¿÷¦ú!''³gφžxâ ܾ}}úôÁ{ggžy'NÄÇÇ£wïÞ¸xñ"zôè‰'bÞ¼yµy)LŠ‹‹Ã!CpåÊtïÞ“&M /¼¼ùæ›F÷ 7[§NpÏ=÷ ##={öÄ«¯¾Š¤¤$ìß¿ßìkDDæåææbÈ!8}ú4Ú¶m‹õë×»º$tëÖ >>>ËåØ¿?***\] ¼¼Ï?ÿ<ºvíŠÅ‹#==¥¥¥(--Źsç°hÑ"$$$àÅ_t›š­¡P( æh¶‡²²2{­^¯³®úTÖë_Õ›6mÂöíÛÑ¡C¬\¹ .Äܹs±lÙ2üôÓOzó¹ÂŽ;jôãjîø†ÑVîú“ˆ¨¶z÷î]»vaÀ€¸xñ"8€.]º`ûöí=z´MÇzæ™gððÃ###Ë—/79£©~ï¿ÿ>š4i‚¥K—âäÉ“øä“OðÎ;ï@$aÁ‚8tè¼½½¡Vß²zõjŒ97oÞÄåË—±fÍ„‡‡×î1á»ï¾ÃÓO? ¹\Ž-[¶ {÷îØ³gÞÜ–ÕYªÍš5˜4i ðå—_"''GûáÚÚ×’ˆþ‘››‹Áƒ#-- mÛ¶ÅöíÛѤIW—©TŠ=zÀÇÇ%%%8pà€ËßK–——cäÈ‘øòË/¡V«Ñ¬Y3¬Y³ùùùÈÏÏÇO?ý„6mÚ@¥RañâÅ5j”Ëk¶–¥/v"##ñÐC!??_ÛVPP€ñãÇ#22²VÇ®¥z‘9òIX:¶©UŠL-˜Sý±±…stoÅ:·"[¿¼¼¼}šÜí©6sT®\¹+W®´ªorr2’““m>9–Z­ÆèÑ£QQQo¾ùÁÁÁfû1÷Üsš4i‚””„††âwÞÁÊ•+qäÈäååÁßßýúõÃäÉ“µÃûGŒx@;2ËËË cÇŽERR’Þ±Åb1 „={ö@¡P`øðázÿÝ8pß~û-®]»///DFFbÖ¬Y5š§‰ÈœÂÂB‹ÿ`›ã®ok¢²²€\.‡··7zôè¡]T‚ˆˆ¶ÒÒR!""ééé®.‡¨Á© ï9Ýé½ä /¼€%K–š5k†#GŽhçÖÕ(((@BBnܸàî(ÿ÷ÿgò˜ï¾û.Þ}÷]«ÎÿöÛoã­·ÞªaõæÝ¾}Ûl¨:pà@œ?111øþûï!0qâDœ9sQQQHMM5¹¯‡‡‡ÁëdŽT*í €€BçV¥s«6rkìf†—r[ Îréw]YL§ÞÓH–ÂJ†”î+33r¹íÛ··RjlÛ¶ мysDGGC*•âÀˆˆˆ@ll,Nœ8µk×B*•êÍõÃ? ""ñññØ¿?>þøc gÏžÚ>r¹þù'ÂÂÂpêÔ)¬\¹mÛ¶E÷îݑٳgÃÛÛÇGEEòòòR’[1bÒÒÒéé鈈ˆ0ÛßÇÇ ÀܹsíŒQ^^Ž3gÎ 77×êË9JJJpøða½Ua‰ˆ¨áÚ³g”J%ºuëæêRˆœºRÿŒ¬Ô„•š9+Vž>}K—.Õ>þ裈””<óÌ3X¼x1† ‚?ü&L,]ºO?ý4bccwÖ¬Y`1¬tdH UUUf·¯\¹ãÇǹsçððÃC àìÙ³hÖ¬™ÅLÇÒ±©n•¦Fb:¥Å(Lm·4ÒÒRXÉÒ½i& nܸ±¶í믿Æ?ü }­ýÖIã“O>A||¼öñªU«´÷333‘œœŒC‡Ld¿téRˆÅb¤¦¦bîܹøõ×_õ‚JÍù=<<´#vOœ8îÝ»ãúõëP(ˆÇO<áê•Çȉêúb:ÖËåøå—_°{÷n;vÌa—ðiܹsþù'ßtQaÚ´iðòòÂ믿îêrˆÍãqqqغu+BBB\]’IÕÃJW|ñ½|ùríÂeÀ?Ÿ1¦M›†[·niï_¾|ÔöS*•øúë¯ñÑG™<¶¥°ÒÑ!%½çfLXXV¯^­ +»ó ÿðÃϵtl;¨¾ÈMXé[—»¥ö ëìuùÉÉÉJ¥X¶l™A;CJ÷æççàî‚­[·ÆàÁƒ¡R©°}ûvƒ}<<<ôBJàŸþ§OŸFqq1Ôj5Š‹‹õú4mÚT.öîÝÀÝÕ5uj¿YÓ|c¥Y¹¬uëÖðññÁž={0zôhtëÖ &L@TTTŸ?‘£lذA»ê¢5ooݺ…iÓ¦á·ß~Ã+¯¼‚ï¿ÿÞ¡õ;wUUU A||¼Áª«ºt/×ñññá¨""4jÔQQQX¾|y\—¨®³eÑ/²Mõi÷„BËK¥Ìš5 žžž˜9s¦^»3BJkI¥R½÷ýžžž®¸ ßžšÛ„™îTÖ ¦FÕfŽJ]ãÇmXɲnˆŒŒ„P(Ä… ™™‰°°0ôíÛ}ûö5TV4²²²0}út„„„`úô鈌ŒÄرcÍžW3aº¹?ŠÕW÷óóòe˰nÝ:ìÝ»üñvïÞÏ?ÿmÛ¶µö)ST—FFj„„„`ëÖ­Ú°rðàÁfÃÊððp,\¸­Zµ2úÿ½ååå€Í!e=´sÏQÃ&‹µS‘ói¾OKKÀÜöÒoÀpžÊÄÄD§×ðøãcÑ¢EP*•€;wbäÈ‘X¼x±Þ¥ßôÞ‹D"<ñÄVcÆŒ  +R …B³#sss1aÂ\¸pA;ØçÒ¥K˜0aÖ¬Ycv*8k‚Ú†Ž¯›?~¼6 dHY7Èd2 6 UUU˜7ož6¼¬Ÿ‡"-- åååèÞ½;:wY}λ›7ojGG=zТE ›ê ”)S´ók¨T*?~ܦc9‹&¬Œ‹‹ÃéÓ§1jÔ(W—d³C‡1¤$"""rCÁÁÁغu+Ú·oôôt 8YYY®.Ë€»,¦‡)S¦h¿ùæ›(((À!CpåÊ\¾|ƒF~~¾6pî.¦cõyf̘Y³faÖ¬YNI)‘HÌnŸ4i’6¤\³f Ö¬Yƒ¨¨(\ºtÉb~céØÄ•neÝóÔSOáìÙ³8sæ &OžŒ¶mÛÂËËK;oE@@€Ùý5ß¼üöÛo¨ªªÒ. blÉ)S¦ }ûö8pàÅ‘—º2220gÎtîÜ^^^ؽ{7 eË–VƒÈÙ4aå¨Q£ “ÉLö»yó&ž}öYÀ€^WãÆ‘••…S§N™U)‰àçç‡nݺ1¤$"""r3š°R3²ràÀn5²Ò]BJ>øéééHMMÅùóç‘€?üP;'å¶mÛ0cÆ Ü¼yÀÝ•²ßÿ}›Ï£™³Ò™¤R©ÙU¿OŸ>ØØX¬\¹Rû~Íš5HNNÆ™3g,›Ìs÷ ²&×Ûsr r///|ñÅX·nöïßË—/C,#""“&MBRR’Ùý;v숇~›7oÆï¿ÿŽÞ½{£iÓ¦HOO×ëçãヘ˜>|aaaxì±ÇЮ];«ë¬ªªB@@RSSqç΄„„àÙgŸå|y @]_L'$$û÷ï7¹½_¿~Úí˜3gŽÃkЉ‰ÁíÛ·‘““ƒßÿ [0ÚFDDî-??«V­BEEF…6mÚ¸º$"r w +Ý-¤îN=ö믿âµ×^Ã’%KpãÆ íêÞº„B!ž}öYÌ›7¯Î„tžžžËå&·_½zÕ -88)))VÛÎj2¿¤[ÍIY#C=KÇ6¶z· Ú6¡‘Ç‚jý…Õîk~Dߊÿ¾¯¹õËËËÛW}BW{°×•DæŒ1øæ›o\] ÕA®* Yãýmqß}÷áÔ©S¸ÿþû1gΧ-U^^Ž3gÎ 77¾¾¾ %‰ˆ\dîܹP*• …ÇСCZ£ã­]»Íš5CÏž=¡R© æý&¢ú)''G;?zBB‚Ù/ÊaïÞ½(**rÛ)„Ξ=‹¯¾ú ;wîDFF€»S“õïßO=õ”M—{»‹ÂÂBízö"“ÉàïïoÓ>R©´€"J [Õß÷U:?ê¿tïC§ :mÕëöGµm¦8$ìtÕˆJŽz$"rúþEÊÎ;]r^OOOtéÒÅ%ç&""}Ï=÷ P(ð×_iw¨IX™››‹Þ½{C @$aóæÍHLL4¹ ÕºS9`œÍÜ} ¡víÚáã?vuvåíím÷ ÒÛÛÛ®Çs—Œ¼t÷K¿-q«À³¾DDDDDu…X,Fbb"är9¶nÝZ£ùßU*•Þ ­×®]C||¼=Ë$"7eiÊ!gâÕ:Î'‹áç燢¢"»ÏÏÏÏèÚâÖ—v[â¨WÉ­D"""""j˜âããqàÀíã÷ß:u‘#G””„èèh¬]»999P(èÚµ+’’’°qãFܸqŸ~ú)BCCÑ©S'dddà‹/¾@\\¾$"ªç¼¼¼ R©ÌÎWi xyyÙ©*·â@´®¨$jp6nÜèꈈˆˆê ???”””h ((o¼ñ„B!Ôj5FÀÀ@”––â³Ï>C\\FŒŒŒ <ôÐC ¤§§cذaˆˆˆpÕÓ!""'òöö†P(¬ñÈJ??¿úR: ƒJ"""""ª·ŠŠŠÐ¸qc½¶ÄÄDí}@€ÊÊJüþûï(((€\.Gqq±³Ë$""7ååå©TŠ’’«ç­”ÉdðöövæåÞ 1q IDATõ_1"""""ª·ÒÒÒ­}¬;ç$ܸq?ýôFÐÐPäää ¢¢ÂÙe‘‹Åð÷÷‡··7ÊËËQYY‰ªª*¨TwÏ …H$J¥ðôôd@Y |刈ˆˆˆ¨ÞQ©T8qâŽ=ŠgŸ}Öd¿ììlxyy¡Y³f(++ÃÕ«WM.\ѨQ#òÒo"¢J,×ÅÕ»ë•DDDDDTo,^¼X;²%22Ó¦MƒL&3Ù¿}ûö8þ<>øà4jÔ-Z´09¦_¿~øõ×_qðàA<þøã‰DŽzDDD ’£Vç¶t\cÛ:íš[¡‘Ǻ}„:ûik~Dߊÿ¾¯¹õËËËÛ§V×Ù•Ú‰ˆê”ÂÂBDFFºº """""¢:E*•öP@ @¡s«úû¾JçG­ó£y ÇÐi«þX ã+x[ Ïì® -w!"""""""""r,•DDDDDDDDDär *‰ˆˆˆˆˆˆˆˆÈåT‘Ë1¨$"""""""""—cPIDDDDDDDDD.Ç ’ˆˆˆˆˆˆˆˆˆ\ŽA%¹ƒJ"""""""""r9•DDDDDDDDDärbWP¨ÕjW—@DdWÀÕ%QಆŒ…“ ,‰¨®Ó”ºÏZ‘30¨´‘î‡wÍ}µZÍ’ˆê @  'öïK""""""r$•6¨LªÕj(•J(•J¨T*íQ]$ µ?"‘"‘HZjK†•DDDDDDä( *­ ;ZR¥RiÊÊÊJH$øúúB&“A"‘@(äúDDT7©T*TUU¡¬¬ %%%(++ƒT*Õ–B¡£+‰ˆˆˆˆˆÈaTZP}¥J¥BEE„B!š4i™Læâ ‰ˆìC(ÂÃÃð÷÷GYYrssQUUàèJ""""""rÿ3ÃXHY^^DDD0¤$¢zM&“!"">>>(//׎(×ýÛHDDDDDDd/ *­  )ËÊÊ€   W—DDä4AAA@YY™6¬$""""""²7•&h>ˆkÈ©¨¨€ŸŸüýý]\‘óùûûÃÏÏz ‡1´$""""""{aPi„nH©V«QUU¡PÈ‘”DÔ A(¢ªªJ;Ò`XIDDDDDDöÁ Ò¥R‰ªª*4nÜØÕ¥¹\ãÆQUU¥RéêRˆˆˆˆˆˆ¨žaPYMõÑ”J¥‰^^^.®ŒˆÈõ¼¼¼ ‘H T*9ª’ˆˆˆˆˆˆìŠA¥*• …>>>®.…ˆÈmøøø@¡PhCJ"""""""{`Pi†fD%GSýÃËËK;¢’ˆˆˆˆˆˆÈ^TêÐ|èV«ÕÚ•J‰DââʈˆÜ‡D"ÑN¡ùxù7ÕƒJ#ªð ù2i…Bƒ/vÈ=mÜðòóo»º """"""«03C3bˆˆˆôé.¤Cîk÷®½(,,´ØO­Vã×_~vBETý²þ'W—@uÔο[õ7ЍºãÇ!#㊫ˠ:èjÆÿ똫ˠ:¨¨¨©©;\]FƒÀ ’ˆˆˆˆˆˆˆˆˆ\NìêÜ#FT¼Rý—Ê‘v³×n+PXzwT’¿—b´o*EÏ(Otoéa÷sÙG›‘½1¨t¢uGï`õá\ÍWÝ^XªBai%NÞ¨Ä÷K$ÆøDoŒIhääJ‰ˆˆˆˆˆˆˆˆœ‹A¥œÍ¬ÂGÛ qòF¥Mû]ÍW`þ–B¤¤•bú ´ ãêãDDDDDDDDT?qŽJÛ~¦ “–çØRê:y£“–ç`û™2;VFDDDDDDDDä>8¢Ò¶Ÿ)ÃÌõ·ív¼»Ç ÄÀX™ÝŽIDÖ«R¨r4 [ÿÊÆ©«Eȼ] ôD|¤†ti‚!]B!ó; """""""[1¨t³™Uv )5f®¿f!¼ œÈÉ6Éœ5gq5·Ô`Û¥Ì;¸”y¿¸…!^˜9®’š¸ J""""""¢º‹Ã~ä£m…uòØD¤O©Rã¿«ÏbÊ£FCÊê2rJñÔçGñîš³P9yeì½{÷")) IIIØ·oŸSÏMDDDDDDT[ *`ÝÑ;µš“Ò’“7*±î臟ˆþ1gí9|¹å²Íû-I¹Œy?¦; "ÓæÎ‹œœäää`îܹN=7Qm1¨t€Õ‡KÜêo¿ý6üqƒösçΡgÏžÈÈȰce†Æ‡+Vش϶mÛðÅ_˜ísþüy¼þú뵨ŒÈ¼ÍG²jRj,úí¶˲cEDDDDDDDõƒJ;;x¥Wóµ>N³1†´÷‚D$0ºýj¾¯TXu¬çž{.\@jjª^û矎ѣG£E‹µ-׬~ýú!&&Æêþ*• ‹/F\\œÙ~-Z´ÀÉ“'qèСږHd J¡Âܵgk}œw~8‹*…ÊY6sæL„„„ 443gÎtÊ9‰ˆˆˆˆˆˆì…‹éØÙþKåµ>F‹ 1–&ÃßKˆÆÞB|wÀøèÉý—Êѽ¥‡Åã…„„`Ò¤IøüóÏÑ·o_ˆÅb:tgΜqÊå¡Ó¦M³©ÿþýû¡T*ѯ_?³ý¤R)þõ¯aíÚµèÖ­[mJ$2r4 9–礴äZn)¶þ•á‰av¨Ê¼Þ½{ã·ß~søy¨îP©TØ¿ÿΧ_D»vmÑ¢e¤«K""""""2‰#*í,ífíæ¦ öáÿ&4†¿—j5pí¶éÑ™¶œëÑGEUUÖ­[µZÏ?ÿO>ù$üüü úž={]»v5úóòË/=þ¾}ûœœŒ>}úàÀÂ… µÛ’““ñ믿ê=^¾|9¦L™‚~ýúáá‡ÆñãǵÛwìØûï¿K—.Å„  T*¥¥¥HJJ† ƒ ÂÞ½{qççì$ûÚr,ÛnÇÚjÇcÙB  ,,‘-"àëçëêrˆˆˆˆˆˆÌâˆJ;3,ZÒÈC€OÆ!ÌOX²«»Ï›¡i˹<<<ð /`þüùH$Ëå;v¬Ñ¾mÚ´Á¶mÛŒn“H$mÅÅŘ1c^~ùe 4¹¹¹¨¨0}Yzaa!-Z„+V <<K–,Ák¯½†M›6A"‘ ##]»v<öØcرc~øá<òÈ#Xºt)Z·n‘#GÂÃÃ!‰pæÌ$&&ZýzYr2£ÈnÇ:‘Qh·c™³wï^í(é·Þz ½zõrÊyÉ} ´h‰¨¨V®.…ˆˆˆˆˆÈ"ލ´³ÂRÓsÑ6bíÔP,ŸŒÀFú/½T,ÀGcƒÐ&ônøÓÑ;øßŸòŸË˜Aƒ¡E‹˜;w.^|ñE£¡#ˆD"ýñññ1蟛›‹ªª*ôéÓ¾¾¾ˆŠŠBll¬É:üýý1sæL´oߘD"ÁŒ30}út›êz·r¹þhÒÀÀ@€L&3Ø·¨¨ÈäèP¢š õ·¼P•õÇò´Û±ÌáªßDDDDDDT—qŽJ;‹£°Ôø"7jóS !£:5BT°«ŸEÀßãÅœ*Ìøñ6*V¤”ŸËl£R#!! xôÑG1nÜ8äääŒ~´ÄÃÃR©YYYhÛ¶-àêÕ«øñÇñ /àƒ>@bb¢Þ%èYYYðõå"d_Zøár–}iêØÒpÑ*Gàªß®£V«±fͬX±7n´øåÉ–-[’’‚œœôîÝO>ù$<= mkûÕQigí›JÍnW©¹› ±îèÝDRæ+ñòš|ÈË­ŸwÒÒ¹jÊÖ9*‹‹‹±aÃäää ¼¼G…L&ƒ¿¿ÎÌÌL€J¥ÂìÙ³1iÒ$$''#&&Ÿ~ú©¶oEEnß¾Ö­[×ìÉ™0¤K»kpçP»‹ÜÏ–-[˜˜ˆääd¤¦¦B¥2ÿw|îܹ7n***дiSÌ›7Ç7˜ÂÂÚ~DDDDDDõƒJ;ëey¤‹À[ ñó±»aeQ™ Ï}Ÿ‡ìb¥ÝÏå r¹©©©xä‘G0`ÀüòË/˜?>¤Òš© 8qâà»ï¾CYY&Nœxíµ×°}ûv>|pòäIøùù!**Ê>O†èoCš Eh£Z'2Ø ƒœTîÝ»IIIHJJ¾}ûœrΆîÉ'ŸÄ£>Š#F`åÊ•ûŸá¥ßvÖ½¥"ƒÄ¸š¯0ÛOVªÔÀo§J‘a¡u‘Abtoiûzýû÷GÿþýmÞÏœ¦M›êr¬®ú‡wcæwïÞ­½?bÄ$''C.—#99ÉÉÉÚmaaaz}7oÞŒ¤¤$ˆD¢Ú<"b‘3ÇÆà©ÏÖê8ÿ™ ‰Ø9ß iVýÖÜß´i“SÎÛ½øâ‹øè£àççgrÊ ]Ÿþ90lØ0m[\\zè!,^¼¯¼òŠMýˆˆˆˆˆˆêލt€ñ‰ÞVõS©ï†•i7ÏiisÔE­ZµBÏž=ñÝwß™íwëÖ-ìܹ<òˆ“*£†&)¡ ¦mUãýŸ…Á]xÙw}??ëç =xð hО””„ëׯãöíÛ6õ#"""""ªO8¢ÒÆ$4BJZ)NÞ°=€´F‡fRŒI¨ý%©îìå—_ÆåË—ÍöñððÀþó„†2"Ç™96‹SÌÿ÷XÝ´¤(¼þP[ÇeÂÌ™31gήúí¦nܸ°°0ƒöððpíöÀÀ@«ûÙK~…U8’s >RO4mo‰{L/B¦•W*‘UXÜ¢ TTÝUæ!BóÆ2ûz@ pqDDnL©V!¿\ެÒBÜ©*ˆ…B„ÈüÑÄË"ó ã‘ë•”+YP¼¢ (Uw¤õ÷– ‰¿'û:f="r<•2}?&-Ïqرë»ððpírS‚‚‚ì~;QuBok‡®­ðîšsÈÈ6¿x‹ÐFx{\;—Œ¤äªßîM¡P ¤¤†ÓvøúúJKK­îg/§ò¯â‰_ TQÿ¥žÔ¶‡ÊüؽšÄ OX;4÷nl·sRÍ—Vá´|ü‘–‡SE¸œ]ªý`VT,DûH_$Dù£o\zÅB$drID —R­Â±ÜËØ}ë4NägàlÁ ”)L,‰ô FÇ èÚý›¶‡¯ÔˉՒ1YØúW6œ/À‰+E¸u»Üd_™[ù£K”îïŒö¾N¬”ˆjƒA¥ƒ´ “`΃˜¹Þ¾—çÍy0íÂøí‘³ éÒ÷w Å–cYØz,'3ŠYp÷ÍQX€':´ðÃ.¡Ü¥ Ä"†dH,#88ÙÙÙÛ4s‹6oÞÜê~Ö¨ªªÂ‚?…P ?ÓËà!ýÑ8øîˆÌù‡Qª¨0Ø7»¬Ù7‹°óf Ê#½½[ ›W$¤Î ì,j5p:S‰íç8v] ¥ùEåµ**»Tˆc— ñÕ¶ øz У¥CbÅhâkß™JËJ±oß^»“†üü<?~¬Æ 0RÕŸŸ‡ììlܺuÓbß\Åì*¹„ýw2 Wþ{gÊUy.®Ês±!ã0D!b=BqŸO4âd¡€ïõœE¡d(°ãœrUPÿ~΀¼Lݧó°ût>Ýp ¡>ôk-F÷¦å¢¥eöûÒ—†ÊÊJܾoõ{ž^½ú8¸¢ú‹A¥ Œ•°_X9çÁÀ¿ID®  0<1 à /É%²FDDÒÒÒ ÚÏŸ?©TŠ&MšØÔÏ‘H„®]»Àß_$~||<|ý|ѳ°ïJ†Åc]ªÈÇ¥Š|l’§cldw<Ø<ž¼,ÎaÔj`ç™B,Ù–‰KÙÖ°6¥¸\mgØqN‰¾±¾˜z8Z‡Ùç=Eæ­›hÛ6Æ.Ç¢†E./F‹-áãããêR¨Ž9þ¼½}Í^uíN–]ú{rÎAemºe‚R­Â©òLœ*ÏDD£Æ˜Ôª/4‰e`é@UJ5~ÜŸ‹ove#O^UëãeËÕX{¬ ëOˆÐ¯µ/ftˆBc¾!ë•”” ¼¼œïyœ€A¥ƒ Œ•¡Y@>ÚVXã9+;4“bú ޤ$"ªãÆŒƒwß}ж¯^½cÇŽ…H$²©Ÿ%B¡÷Þ×QQ¦…zÞo$ä¨ÄÎŒPI„(©*3ûîve –\øëoÁŒÎbHDg«j!ëºZŒ·¾;‹EVõ÷ò!ÈGŠâ2Ê+•Úù*Q©ÕøãtvŸ)ÆC½Â1ct4‚} §°…H$BP§ ÛI¥ð÷0ø2…È™Ì >>>FÿöW–âÓ“›°îÒ~(Õ–‡¡K„byzC©R¡TY©¯Ò”kwòð±îæa¼Þy4º×|áE2.åh6æü˜ŽùæA>R4òA^®„¼¬ ¥é÷1UJ`Ç9ö-8ƒ)ƒZ`ZRKHÅ\c˜,‹%J¥|Ïã * ]˜Ë&cÝÑ;X}¸WóVí$ÆøDïz¿pQ}õÎ;ïàØ±cX·nÄb1žxâ |üñÇ;v,þ÷¿ÿ! ,À¡C‡ðÉ'Ÿh÷³¶Ÿ=ÈÄRü·ÛlÈôĨFC¡RâjI.ÎÜÀ¾¬tìÍ<‹ür¹Á~ÙeExeß ü|ùÞíþ0BeÖ¯~NÆ•U*±`ýE¬H½frîIO©½Û¢_\ctˆôEëðFhä©ÿv.§¨é7KpôR!vžÊÉ+†§J­ÆÚ?obû‰\ÌžƒQݬ¥KDäζ_?9Ç~B^Y±É>±ÍpoÓxtŠDŒS4–éÏ]Xª¨@FqNägà`öyìÍ<‹r¥áˆ¾3·¯crêg}^ê8^âÚ}éC@vaÞZuÛçšìãßH‚þ‚Ñ+&[ú!2X¦4*UjdVàÔÕb¹Xˆ­eãZn™ÁqJ+”øtã%l:’…ù“âÅ/LˆÜƒJ'“Ðcáà• ì¿TŽ´›•¸v[ÂÒ»ßôù{ (Fû¦RôŒòD÷–üÇŽˆ¨.KIIÁ©S§PTT„   à?þÀ˜1cЪU+H$4nÜ›7oF‡´ûYÛÏÄB¢|› Ê· †Ev…R­ÂžÌ³X}aöfž5è¿/ëLyowËÑ•µ~³Ï}y2/ØÕ&ÜÉ÷5Ç=Âàíiþí[ˆŸBüêýbšÙí954¿ŸÈÅ++N£ ÄøUˆ½b1y@úÇ›^$ <ÐážÜ93ÿÕ'3бrç5l8”…J…þ(Û‹™w0öƒÃx~x+;µfžÓëS\YŠWö­Àñ¼+˜Ñùˆ¼„ÊëöÝÂÌUgQ^©4ØÖ*Ô Óh¤„PjøÙ©yc^ÝÏ k…¯·_Å—[3PR®uÇoG³qæºKžéˆ˜fœ/ˆêŽ+ÅÙxqï׸\l¸L,ErÛ{19¦?|$5›—W&–âÁV=ð`«Øy3 ŸœØ`p®ë%yxtǧx­óƒÝ»Fçi¨”*5>øù–nË0ºPN¶xmtktnUó+7:´ðÅ‚ÇÚãÕÑ­ñîwÇñÛÉ"½Åé”*5>Ýp ‡/â³§âäþˆ\‰A%‘ oß¾zm>>>&‰hÖ̺QÖös†¸À|Ùï¤Þ<…yG×!³´@oûwçwáBQ&>éý|¥^.ª²îP©ÕX°þ"¥\1Øæ)Ṥ–˜:¤¥Ù‘#¶ðòáùá­0¾oS¼³:›gémÏÈ)Řù‡±pJ<î‹¶Ë9‰ˆépÎE¼¸÷kW®à|_Óö˜Õu,Bì85É}MÛ£ox,¾?¿ŸÚŒ2Å?£ÿ*”Uøï‘µ¸Tœ…W;?È/í¬PV©Ä‹_¶ã9Û‚}=0{B †u µÛùBü<ðʰÜ#Äòƒ*ƒ©Qþ<›çÄòº :ŒÓ¯¹ ÿz‘Mú7ÇÏC_Ãð] ¶Ì>äß?CN™u Á4TU žûò¤Ñ²}„/RÞî‰ç†µ²[H©+Ø× §tÀ’ià­?jäN¹O}q«vݰûy‰ˆìé¼sxz×bƒÒ[â‰{MÂç÷ߎ^¦øØ€üüF7´ uüˆÔ!C°yVtl©ÿA^¡Tcæwg°tk†Ãk "ª‰mçðÑÅ­¨TêOcÐ ?ž¡]^C³FAXÑÿy<Óè‡]Ü:g÷,eXiBfA9F¿Ð`D£T,Ä»·Ã¢©áßHbboû xfhK¬™‘ˆ°O½mEwªðØgaÏ™|‡Ö@DÆ1¨$""¢Õ²¾ð‚Á¨•ÌÒ<–ú9®—乨2÷TV©Ä ÿBêIýW"bþ¤8üg|ŒÞꥎ艟^MÄèžáÛæþtK¶Žø$"r¥.ìÁ·Ù‡ †þ„†ý›Æã›/¢¹…ÅrìI$bz§Q˜ß+R‘þ¬j‡²/à™ÝKPª¨pZ=uAVAÆ}xØ`%nÿF|÷ï…?Ïꇔ¾^|ûrzƺ¨²»à¥Q˜5®­Áêâó¾€Õ{nº¦0"¢¿mÊ8‚9G2)_ê0¯wíòÅk‚£°ü¾gàá­×~,÷2¦ï[¥Zebφ¡ ¤ÆÕý9EÛ„{cÝÝÐÊ Sž˜ã)á‹©ñ@÷0½öJ… Ï~yÂà2u"r•DDDdþ°ôÞg ¿Rùõ’<<»»aÏÕ5û‡sØ|DNÊ@)¾Ÿž€Î­ì¿ØCM=q$ÞcV¾µêŒÁåêDDÎr(ûfúÁ ¤|±Ãp<;ÐEUjëßËû?‡ O½öÝ·Ncöá5õ7U*LYt—³õCÊÖa°jz‚}=\T™>‘P€o1½ô§C)­PâñÏÿBFŽáêòDd *‰ˆˆê)¥R‰õ?oÀ’EËpâø)§œÓWê…¥÷NCk?ý gn_Ç«û¿JÝð>¤-J¹‚•;¯ëµùÈÄøö¥´ðuQU¦=6 o‹ÑkS(ÕxnéIœÈàˆ"r®‹EYxéϯQ¥Ò_8çÑæ½ð”…”­ý°¼ÿs#+×_>€Ei[\T•ë¨ÔjLÿ__П&:¬VMïê6!¥†H(À‡“ã ænΗW"ù“£È-朣DŽÆ ’ˆˆ¨ž‰DxpôHLö$:vŠwÚyý=aÙ}Ï"Â;X¯}çÍ4,8þ‹Óêp¿ŸÈÅ‚õõÚ¤b!–N넸{¹Þc"ðܰVzm¥J<µð8² ù!ˆœ#¯¼ÏìZ‚âJý9 “ã0®i7UeY”o,ìû”Áœ™‹Ó¶ åÚ1Uå Ö_ĦÃYzmM(Jv IDAT<°êß]âç^!¥†P À“âpo{ý…™®å•aÚ’“P(Þ—®DÎÄ ’ˆˆˆì.ÈÓKî}þÕX™þÖ_9袪œëRÖ¼ôõ)½Q¤Bÿ÷d¼Ë礴ÆôQÑ#JrŠ*ðÌ’¨R4ì¹ÖˆÈñ”jfì[i° Û æ0>8ÁEUY¯cP |Øk²ÁÜ™oúç o¹¨*çJ9–ƒÅ[ôd󑉱â….õwÏRC,à‹§; C ý+_(À;kι¨*¢†A%9D„w0þ¯ÏŠÄzísŽüˆôÂú½8‹¼L§þy™þ¥Šo<ÔCBMìå^àƒIq¸'6H¯ýØ¥BÌ^ˆ¨¡øôÄFι ×Ö9¸æõxÂê麩{ÃãðfÂCzmeŠJ¼¸÷kWÖïù/eÝÁŒÿ¥AwƱH€ES;"¦™û^Q «‘§_?ßÍËôÚ¿Ýy?þY¿ßǹƒJ"""r˜„à(¼“8^¯­\Y…—÷.‡¼ªÌÄ^uß«+Ò  x {žÔÂ5ÕX$ÀÂ)¬ÿ!mÕ.~H#"ÇÙ~ýVœÛ©×æ€Ïú<‘ÄEUÕ̸èÞÝ[¯ízI^Ý¿²ÞÎÛ|§\©‹Ž£¤\ÿ˺w&´3øòËÝûzàËi “ŠôÚßZu§®»¨*¢úA%9Ôˆ‰˜Ø¦¯^Ûµ’<Ì:ø}½\uÕ®H9–£×é‹÷“c]TQíø5’`é´NðòÐÿöö÷çp1󎋪"¢úêzIÞ:¤ÿH‚Oû\é7KôÚ‰þê~«ñæCmж©þ¥—\‘bÏ™|UDDõÅñ¼+Xzz›^[ Ÿ¼ÙeŒ‹*²¿Äh<{¿^[†<ïûÙEÙR¥ÆËËN,"7÷‘XDT[Œ¦®‹ø¿'ãá#Óïõæwgqëv¹‰½ˆÈV *‰ˆˆÈiî ÅøÖú—zŸÌ¿Š/OouQEöqøBþ÷ûÿ³wßÑqU×ۀߩê½YVµ$÷"Y–»q¯²1cc HpH à—ÂJä‹ ¤A€€qBâ`ˆ1.¸÷Þå"Û’»zï½LûþP,é\uifîÌè}ÖÒ wÏ-Û¶23wßsÎÎb#Ã=ð³åƒeÊÈ2œ4Jüõ{cà¤iù iðê?¯¶¹9%"ê®:}#~vJ|h¥Vªðöäo;ÄHÃÖžµcü"„ئ»§pe 'É”‘e„ù»àÿ}K\ó¤²V‡Ÿÿ;Ú‰ÈêX¨$"""«úIìRDz ±¿_Û‹ëeöÙEº¾Ñ€WÿyMèÞê¬Uá½ïÇB«v¼¯ZCCÜñ󇇱ü²¼õÕM™2""{÷×+;]#ŽÌþá¨Ev½.eGT %~?åI¸kÄ%AÞ8÷%ªuö9*ïnA-þüÍ!æï‚×W “)#Ëz`Â<4)Xˆ¹ZŒ¯NÚç÷"[ãxßž‰ˆˆÈ¦¹¨µøÝäoC­lY¯Ê`2â×ç¾°Ë)àØré…µBì•¢ä*SF–÷ä¬pÜ7ÂOˆm8–S×Ù€ˆzærI:>¿yTˆ ˆÆSÃçÈ”‘å…ºùᕸ…X^mþxy›LõžÑdÂÏ>»†]Ëç·J©ÀŸžn;EÚ‘¼ñØp ðqb¿ùïMV4È”‘ã`¡’ˆˆˆ¬n”o8¾?b¾»Vš‰ß8,OB½táN9þ±_œò=.ÚOÍ‹èàÇ Po=1nÎ-7¡&ðÓ]C]«fBDDÑõøõÙ ÂC*g•¿™ø(T ǾU]= “‚ÄÑéoŸÄÙ‚[2eÔ;ŸÉn3åû»s#ã-SFÖáá¢Æšö¦€ÿ+E¦Œˆ‡c¿ûõcz½_|¾|篸tIîtÚøÞˆ¹ˆö»dþíê.äÔØÇ¨<½Á„×Ö§¶™òý‡ïŽ‚R¡èäHÇêçŒÿ[#Ä2‹êðÇ­w:8‚ˆHôIÊ~Ü®ÈbÏZ„pwÇiBÖxc£pU·ŒÊ3Á„×Ï}‰Fƒ}¬ù›WV·¿ «áþ.xùh™2²®ÙcÚL?\„]I2eDäX¨$""rPjµ«[Ÿ¼òâÇÅÉN¥oLX%õêôxóüe̪û>;˜‰Ôì*!ö“¥Ž=å[êÛ³Âå+Ž üÇ ÜÌ­îà"¢&™ÕEX›ºOˆð ÓÃfÉ”‘õ…¸ùâÇc–±Ìê"¬KÝ/SF=óæ×…FjM£íGÀE«êä(Çò«UÃè%Nó˨©·b3‘-b¡’ˆˆˆdç?+c¦ ±y©ØŸ,SFÝSPÞ€?mGõÀSs{Ê·”R¡ÀªÑõBp½Á„_}~ÝO‰¨Sk’6 #ÕJÞïøS¾¥|âü ±µ©ûm~vÁ±”ìºP(ÄVN ÁÔá~ᘼÝ4xýQ±iP^Y=ÞÛ‘&SFDö¯} ‘ÍyqÌýrñb¿¿¸õLuí/®£ºÕh ¥Bÿ÷­áP«Ê·T ›«Š7Ù§o”bëÙ<™2""[w0ç Žç¥ ±o™a>!2e$¥B_&¬ ´õÞJúJƬ:§Óñú†ëBÌÏC‹_<<¤ƒ#[⸠Ìå/ÄÖîKÇ­¼™2"²o,T‘¬Ü5ÎøiüCB,·¦ëRÈ”QçN¤–`§dý©•Ób\´c7èÌF"ÌßEˆ­ùê¦0%ˆh*ÂýîÂ×B,ÐÅ «G.)#ù õÁ£ƒïb‡s¯ápîU™2êܧû3p'_,ÂýßCƒá妑)#ù½ñè0hÕâì‚_þ'µ“#ˆ¨#,T‘ìæ‡ÅaBÐ`!¶.u?rmlê›ÁhÂÿûïM!æë¡ÅOÜÁýƒ³VÕfê[ayÞÛqW¦ŒˆÈV}ÚÎ{û+c„›ÆY¦ŒlÃF'"@2»àí ›¡3ÚÖŸ‚ò†6Ӛ㢼°bê@™2² ‘®xva¤;}£”uˆz…J"""² ¿ˆ_ÞfêÛ.n‘1£¶6žÈmÓ@çÕe1ðq×Ê”‘í˜3&sbÅN½ÿ<‰Ìâ:™2""[SXW^?(ÄÆÆ¢ð±2ed;Ü5Îx%î!–U]ŒÏo“)£öýaó-¡QŒR¡À›ãõW?\4¨Íì‚·6ÝD£Þ(SFDö‰…J"""² 1^Ám¦¾í˾ŒKŶ± }u½Üz[ˆ õÀÊ©ýoMµŽüz•8õ­QoÄᄎÙÉDÔŸ¼—¼uúÆæm•B‰×Æ= Xä€ÄˆxŒ ˆbOÙ‹òÛXë05» _Ÿ×^5=c"=eÊȶ8kUøÅŠ¡B,³¨ÿ<)SFDö‰…JœIkÀŸ÷Wà™ÏŠ0ÿOy˜ðÛLømæÿ)Ï|V„?ï¯À™´¹Ó$""²ºçF-‚¯³»{÷ò6™²}´;…âçó/ •’7Ø÷„û»à;sÂ…ØÎ¤œ»U&SFDd+n–çb[ú9!¶"f b¼È”‘íQ@ÿ‹{P(ÜV6ÖâÃk»e̪Å[_Ý‚ÑdjÞvwV㥥Ñ2fd{ÅbÂ`!öþÎ4”V5vpI±PiE›’j°â£<ÿy1>?SäìF”×¶ /¯5"9»ŸŸ©ÆóŸcÅGØ”dOψˆˆ¬ÁSëÒ¦¡ÂÅ¢»8,SFMrKë±v_†›=&ÓGúwpDÿõ£ÄAðõ§Â¯ùê&ZÝÛQ?ôîå­0˜Zî}Ü4ÎýºNGFûE 1bœûâÖqܩ̗)£&G¯ãèµb!¶za$xbè,!v û RJ³dÉçëSymɽòà`8kU²äcþï!ñïGo0áOÛîȘ‘ý`¡Ò‚ö¥ÔáµÍ¥f;ßk›KY¬$’‘ΨÇÎô$¼|ln}q^B܆—°pëxùØ:ìÊH‚ÎØýQÓDÔ±ùaqí'ŽÔøàÚnÔê­¿†ó·ÞÖäòpQ·1H"µJŸ=,Ž8½[P‹Í§seʈˆä²#ãÅöôóH«,@¾uú¤U`{úy¼xôS$nû öf^’;]"€Á`À毷á£Öâò¥+r§Ó# (ð“Ø¥B¬¸®ÿ¾qĪy$§Wbï¥B!ö̼ˆ6k0R[óbé%ÄþòÍèôòMá'"ë2˜ŒøðªØfˆ÷@,/SFöÃ]㌧†ÍbÇóR‘TdÝQyŸÍF^Y½ûùòÁP*ØH®+Ï.ˆ€‡‹ºyÛh2µ)úQ[,TZÈ»{ËíòÜD$2˜Œx;ék¼pädUw¹fUž?ò1~Ÿôµ0ËŽ?ŽÄÄD$&&âäÉ“V½6Ù&•J…e-ÅêçžAlÜh¹Óé±ñ1˜2JˆýëæaTëê;8Âüþ¸õ¶ÐÆ×C‹§ærM®îP(€—»Áf—ÔcñœŽ "G³-í,2%ߟ~xd¼[‡ûu÷ZxòÉ'ñÞ{ïA¯oº)8{ö,RRRðýï¿ÏùZÒ©S§`00cÆŒN÷ÓjµX±bþûßÿZ)3rtû2/#³ª¨ÏçÉ®.Ƭd3dÔµ©S§bçÎØ±c&Ožl•kYÃ`¯`Ì bÿ¶ð¨Ê÷wŠkr…ø:ãÑé¡»ž£ûÉ1hÝw¡´ªÿ9’-_BDdQ_ß=¼Ú2!öÃQ‹dÊÆþ-‰L@”gû»¤lN5õz|¼']ˆÍ€¸(¯ö N9kUxa‰Xä=}£çn•upQÿÆB¥™]ÍéÛÚ”*üåQx»*a2™¥6èɵ¾ýíoC§ÓaÓ¦M0™Lxï½÷ðÌ3ÏÀË«í‡Mjj*Úýy饗:¼ÆçŸŽ+V`öìÙxñÅ‘››  iTä?þñ,_¾³fÍ^€“'Oâ‰'žÀ´iÓðàƒâý÷ßo~mÿþý˜;w. >þøc<úè£0šÖµª­­Ebb"¶mÛ˜?>Ž?Žš®ßI}gÎ)Ûû­T¨$rdÏZØfTåz ª:R‰£7;5Ù“k999á…^Ànj͛7£ªª +W®lwß!C†`ïÞ½íþ¼ùæ›íó¯ý Û·oÇ›o¾‰/¾ø‹-‚OÓú%ü18€·ß~ëׯ‡V«ÅêÕ«¡ÓéPYY‰W_}K—.ÅÎ;ñî»ïböìÙÍçMOOGttÓ‡âw¿û] lذ¡ù¼ƒÆÒ¥K„J¥BJJJ·ÿ^ˆ:r­4ÓlçºZ’ÑõNfÀ®ßäÈb¼‚1/4Nˆ­·Pðv‰7Á>ÎX>9Øì×éo~´XlÀPXÑ€/³8‘£ù&ý< êÄ®ÆÏq4eŸ- G¸»¸ŒÆ')ûÌ~úFÖí¿Ï€1‘žAÝ¡Q+±za¤;|µÉé•ò$DdÃX¨4³òÚŽGøº)ñßÕAX÷øº‰õZµï®ôà ૤üãDU¯¯Õžùóç#22kÖ¬Áüch4šv÷S©Tðõõm÷ÇÃãÍþƒëÖ­ÃÏþs >X°`\\\ÐØØˆõë×ã¿øbbb‚7Þx5558zô(ŠŠŠ Óé0mÚ4xzz"::#FŒh>wvv6BBB¯½ö>ùä?~Û·oÖáS( AVè§¾+¬­èz§n*¨-7Û¹:îßäè~ÐΨÊ/o7ë5®fVâбÓ÷÷DBÃÑ”}é…é#%kUîNƒÞ`Ù†Dd=“Ÿ¦ŠÇÆøÀ™2r*…ÏŒ˜'ÄÎÞFRѳ^gã‰Ü6kS¾ÈÑ”fñÈ´z‰kU¾¿ƒkUIñ[·Eøié§Æ¨->xÜ>ÿ+V*ÀK}Þô¦uðzÞÙc™ÂÆÊ•+áëë‹Y³f™íœ999¨­­ Œ­_Óëõ6¬eálŒ=ééé4h°råJ¼öÚkB3œúúz”••!00°9‹ àÅ_ÄK/½$¼AAA¨®¶|×u¢žh]X!¢Þ‹ñÐf­Êõ7¢Á 3Û5Þ—,nïï©ÅªûBÌvþþî¹E‘ÂvNi=6ŸÎmg"²;²“‘!Yãû™áseÊÆñÜ™€`W±ëöÇfUi0šðɾt!6s”?F…s4¥98kUxjn¸Ûw¹7rxÿJÔ •fæíÚñ_é¥Ìl¾Ø´~bT€¦©XéªÄ+ ¼1g¸ àBf~µµ Æn .èìZÑh4P«ÕîÓÓ5*ïƶ#<a4›×•¼G«ÕB«ÕB©Tâƒ>ÀŸþô'h4¼úê«xùå—4€ª*qd©¯¯/€¦‚§TEEE‡#E‰z"ÐÕ|‹…ºz›í\a×oê¾?b>h)þÕU`kÚÙNŽè¾Ûy5Ø{I¼Á~zn;}›Ñ¤¡¾˜0X¼É~oÇ]ºóŇˆlÞZÉhÊa>!˜3·´ßœËbß™Ë<ìÏfŽòÇèñ&ûï»ÓåI†ˆÌfmêa;Ò#sBÇÈ”ãrViðäPq¯C9WY]ÔÁÝs ¹¨Ídéƒ%2é÷ ƒÑ„µû­Ó|“ȰPif“£»ÜÇà÷»Ëñõ…¦beE?ú¼•†Îìŵ¬å—¿ü%bbbðÌ3Ï 11ëׯGEES3’W_}S¦LÁ+¯¼‚U«V¡ªª ï½÷ ªªªpðàA|ë[ßœ9s°e˼ýöÛÐj›Š°ãÆÃåËM7ŸëׯG]]üqÀOúSìÛ·çÎ$''ÃËË«¹K8Q_Ì ‹C„G@ŸÏæîÙa£ÍQרõ›¤ôz=¾ø|#þøÎ_q!é’Üé˜Í¤ !mF=K›7ôÔº™BS7gu›d>?”t¿šY‰S×KeʆˆúêRqÎÞbOŸÃuº-䑘©ðÔº6oM&|výpŸÎùÁ.q4åÐwÌÝ÷ïÂÔ–§«Ï¿c|u"¥U2eDd[8LÀÌ&rB„Ÿ%úN÷»W¬4š€Wj‘ÞÅþR~jLäÔõ޳gÏÆìÙ³»Þ±‡<==ñÆo´ûšV«Å+¯¼‚W^y¥Ík!!!¨H©ûï¿O<ñªªªðÄOà‰'žh~-88GmÞÞ±c¡Rq-1ê;µR…Wâ—áù#÷éÝ'N;ówÁ’„}Ê:äí„„<±¶ IDATûÇ‹Çÿ>”]ß×Ü&²w,TZÀòqnj¹QcBµXþ¿<ýÁK/½„Ñ£;Ÿ:ëää„_ÿú× ²RVÔ_¼¿ ÏŒœ×ããž9?û€2ê»~S¢T(Ú¬Uy*ÿnWäõèçH[>e`›Î§Ò›e"²}ëošyh\°Žƒ®GçÉ*®ÃþËâú–OÍ€ZÅá”–öì‚HaÔjQe¾>+_BD6‚…J yy¾·]žÛ 8Ó¦Mët???‹Li'R*x5~þ6óÙn­Yá€f®Æ«ñˬ¾.»~S³$"Aè|j‚ ÿ¾q¤GçØ‘T€ÜÒz!ö̼Hs¤G]pѪðøŒP!¶éT. +dʈˆzªZW-ig„ØÃѓᦱµôÙw‡Íºª—ÔWá›ôó=:Ǻý0[ÖhöpQãá)Í–#ulhˆ;îá/Ä>Ù“£ÉÔÁDýÇã[Èð` ~»Ì¯m6ïÂð¿]æ‹áÁ³ž“ˆº67,3CFaÖeìÏJƵÒLä×”¸ù`¤o8æ…ÅbNب•\'µ?***Bqq1† E'Eê»wï";;»Ã×ãããáî¼<ܺu«ÍëîîîˆoçÈþG«RceôT|puWs워sx~L"ü=;9²Å:I—Í ƒ}06ÊˬyRÇžœŽ÷¤7OukÔñùÑl¼x?×è"²ÿ½}Õº–‡=*…«ß'cFýKŒW0¦É¼ÔæØ?¯ÄCQ“ºõÀ¼ªN¯NŠ#øVÝ*t¤&Ëzf^8Ž^+nÞ¾[P‹CÉŘËFFÔñÈ‚æp`¾båo—ùþïœD$µR……ñXÁ"µÈÍÍÅÊ•+qîÜ9( x{{ãÓO?ÅâÅ‹ÛÝíÚµøè£ÚÄ«««7nÜ€»»;6oÞŒŸüä'ðô n£FÂÁƒÛß_­Œ™‚µ©ûÐhhZc²Ñ ÇWwNaõÈ]{úF).§U±§%ë&’eù{jñàÄ`|y<§9öïCYX½ ÎZ>ô!²e“nbsCcâÆ¦XÖôäЙB¡2½ªÇòR0càÈ.ýR²F³Z¥Àw¸F³UÝ7ÂÃB=p=»ª9¶v •Ô¯qê·…Íá‚Ïž ìÓš•cBµøì©@)‰ˆlL]]¦OŸܽ{·¹h¹bÅ œ>}ºÝcÖ¬YƒÒÒÒ6?<òfΜ‰Aƒh*\:………‹”"gO$†‹¾¼u:£¾ƒ#Z|*MèŠyq¼1°¶§çEkt•T5bëÙ|ù"¢nÙŸ}yµeBì‰a3åI¦›<`(†x‹Sµ?¿u´ËãÚ[£y~\ B|9mßš à{’‡¤§®—âFNµLÉ…J+¬ÁÚ'ðÓ…Þˆðëþ Ö?5~ºÐkŸ àto""´~ýz”——cÆ  ¯¯/þò—¿`Ô¨QøãÿØíóäååá믿ÆøÃæXmm-ÜÝÝ-‘¶ÃùöЙÂvQ}%öd^êô˜ì’zL.bOͰúÚ² èŽ#Å5º>;˜ÙÁÞDd+þuý°°ç?±~‘²äÒŸ) hó9x2ïÒ« ;=nï¥BäHÖhæ¬y,0žNBì³Cü¤þ‹…J+Z>Î Wá½ÇüñØDwŒ ÕÂÛµåŸÀÛU‰1¡Z<6Ñï=櫃úUwo""{óùçŸã Š …=ö¾ùæ466vëùÏ?ÿØuzCÓCÔÚ6žÈÁ3ó#åMŒHQIDDÔ ƒùùùh»¦aPP€¦F;]Ù´iÊËËñÝï~Wˆ×ÖÖ¢¨¨øÃ°fÍÌš5 ±±±8wîœyþfzðH„»‹Ó‡¿è`4ɶsù(«níªPßžÖî¾dJ…OHþ v_(@~YƒLQGÊj°;ó¢{$f*T ÞZÊIúoP­«ÇÖô³íîûïCYÂv ·ÆY4?ê\ WÛƒÌfõ:@DDÔ J¥Z­UUUm^khh*®x{w=…êoûyäøû‹E¶þóŸP´Z/1##?þ8V®\‰k×®ÁÕÕµËsF;rW“¯ ññããáéÕÒMÜd2Áh0¢º?‹=Y6IÝÕ¼½/;™%yðÕŠk}~¶?]Øž6Ì®»ÿóËÅ\¿;‰±žxw« µ M>Û?\È"²£Òëô¨­©š#ÅíÊwŽ¡ÁÐ2%U«Rc~Ðh«¾‡664 ¾®ŽïÛ­x@û‚†áp~Jsìß©‡±$(NX¹¦Á€­gò„cžˆúÚþѼ¥¾® 6ù»óÈ$l?×ÒL.»¤»ÏfaÆHÎ.°µ55ÐëôÝþÝq÷ð°pFŽ‹…Ê.( F(•|BHD4¿l8…BvGMæç7}É móZkIII8sæ þú׿¶{þÖ"""ð—¿ü“'OFRRî»ï¾.s4 8sæ|›sé ðó¿ôÖÕ×âüùöG^Ø‹£Z… ¦¦B—Ψǧ¶b¡[Ëú•·Š€kÙḄ J»ÿ³Ë©¾¾ÎlÃL8t»eû?G³1Î7j~ sHå奸ví 46´&˜ðeñ !§ ÆÝäk¸kÅ<ÊËËQ\\„üü¼®wîGb½q¸ÕvVm þsr'†;µÌþØwÄšcó¶J vÉÅùó]Ïqµµ5hlÔ¡¶®¶ëe0ÈH+iÙþpç ¸ÕñCÐèt:”——uû;ÏÌYs,œ‘ãb¡² …J¥:NN\S’ˆhúV*•,Vˆ‹‹Ã®]»ðÖ[o ñýû÷cÈ!ðôôìàÈ&ï¿ÿ>¦L™‚±cÇvëzZFlvE£ÑàùÿÑÑm×ilÍd2aÛÖÍñ…êÔ™lN;Ó¼dÌÇog~¿y:Üן$h­à‚ç›Ænß}°eóWfûÝ RC¯ŸlÞ®¬ªÝGàÁ‰ltäˆ:€±cÇukô9Ù†c¹)(*GÞ½0m9âüY5K—.ÀÛÛ‘‘Ö½®­› `Ç®4Ü®h)à^s«Âî[0™€ß: ¦ùõùqX¶8κ‰Ê(#= eeeˆ/w*í*ÒæàÕ¶Ì„¹–oBøˆÉˆ êz& YVEE’’Î9Ä÷e[ÇÒ|;Zß|+•JÔÔÔt²7QÿRSS#Œ2ïÏËçž{)))ظqcs,##6lÀóÏ?/ÄΞŸ¾⫯¾ÂsÏ=×î¹Û›R¾nÝ:¸¹¹!!!ÁLdzjð4a;¯¶ Çòš¦ÁV4`×…BáõoÏ c‘Ò† qÇäa¾BLº–ÉçË;âhÊa>!V/RRç,θ8–›‚¼Ú2À饸•'ÞÛ~{V¸Õr£®- _mó¶Éüç?©a¡² … …*• ååå]@DÔO”——C¥R5¿Oög÷Ýwž{î9<õÔSxöÙgñË_þ³fÍÂäÉ“ñä“O6ï÷àƒbúôé(**jŽ­]»¾¾¾X¶lY›ó–”” 44<ð^{í5¼ùæ›X¸p!~ÿûßãïÿ;Gub¤o8FùŠ7]n5u§ýêd.tú–én.ZVN ±j~Ôµ'g‹ÿ~IwÊq#§¬FdËrkJq,7Eˆ­Šéz²®û#ÇÃSëÒ¼m0±éîiÀ¿‹¯˜`7L*>"y9i”xdšøÝäëSyhÐ;8‚Èñ°PÙ{Ó¾U*P[k›kXYSmm- R©8ýûþüç?cݺu0™LHOOÇÏþslܸÎÎÎÍû¬^½ßûÞ÷„†97nÜÀ/~ñ‹v×fóóóÃñãÇ1zôhܺu ÉÉÉHHHÀÕ«W±råJ«ü¹ìÙ*Éh’“yב^Y„/Že ñ¥ÀËkãÙš¹cè%.¹³áhv{‘µ|yû ¦–b‰§Ö‹#ÆÉ˜µÇE­ÅâqæÅ¦;§W^‡½—ÄYÏ¿ÊÙžGï f{”U7b×…3"².®QÙŠB¡€ÉdþW©TB£Ñ ??QQ¯ñEDäèòóó¡Ñh„"¥ôû£+V`ÅŠ¾þì³Ï¶‰}öÙgžsôèÑ=ztŸsë†Å.mAECÓô6LøÓ‘3È,Ò û=6½ófG$µJGî Á{Û[Zs|}:?]>.Zv‡&’C£AÍi§…ØÒÈ pQk;8‚ä´2f*6Ü:Ö¼]TWßí¸½ÁÔsѪðÐ$®ÿk‹Â\0e¸/ާ´tÕùâX×k¦~ƒ#*;poJ£B¡€F£N§¦ìõ7EEEÐétÐh4Â{$‘­qVi°lÐD!¶÷l…°=<Ô±ƒ¼¬™õÀ*Éh’ÊZv%q4 ‘\öe_Bi}Ë (ðHÌT3¢Î ö Ö5ØsV\ÎlÙ¤`Î*°aK¦ž¹YŠÛyìAý •¸·F¥R©„V«Eqq1JKKåN‹ˆÈêJKKQ\\ ­VÛ¼,‹”dËVÆL…M¿£¦F'Ôú ¯s4¥m ñuÆŒQâ¿ÙçœþM$›¯îœ¶' Æ Ï ™²¡îx8zJóKP_+ŽHÿÖÌ0k§D=0/.ž-Ë ˜LÀ†cü¤þ…J‰ÖS[7ÔQ©TprrB~~>GVQ¿RTT„üü|8995¿JGT²hI¶&ÜÝãƒbº¼ÀØò•ÇÕI…9ÝÍæ­ºO,&Ÿ¿]Ž›¹lªCdm™ÕE8_xGˆ­ähJ›· ,®¹©Ž.WlR66Ê #Â<äH‹ºI­R`ÅÔBŒMu¨¿`¡² J¥²yôZ­†³³3JJJpçÎ6Ø!"‡V[[‹;wî ¤¤ÎÎÎP«Õͣ̕J~|í[5 0) —Ü -I.Ómëæ´ÓTç‹c92eCÔmºs&´¬mèí䆙Gɘuǽ¦:ÆF'è‹„פ‚È6­šÎ¦:Ô?ñN³í5ˆ¸7ŠH­VÃÉÉ ƒééé¸sçJKKÑÐУ‘O7ˆÈ~F444 ´´wîÜAzz: œœœš‹”­§|s4%Ùº¹¡±p® ±ÖMˆ?ÊißvA­R`å´!öÕÉ\Ô5dʈ¨ÿ1˜ŒØ–vVˆ=8h"´*>ì±+c¦BŸ ˜Znû”XœÀiûö ÜßS‡û ± \…ú~Ât uçï{T*Uók …jµz½000™L0™L–ˆÈ&Ý{_k=ŠÜÙÙ¹ù¿[¯KÉ)ßd/œTx•ŒDq«˜Ö£cqº›½xlz(>Ü•ƒ±é»Ue­».²S-‘•ɽ†¢úJ!¶,jb{“­‰ñ †² Jˆ†WÀÝ™e{ñØôPkÕýûÌÍ2ÜÊ«Áà`·NŽ"²o|‡êé ¹R©l.d*•Êæâ$ ”Ddï¤ëó¶þß{Ó½Yœ´&“ ùyP«Ôðöñ†——§Ü)YUIU#2Ó4@«)‹ŠàtÏKÅŒ#åKŒºm ¯3¦ðÑ«-åæ G³Y¨$²’¯ïž¶ãü!Ús€LÙPO¹YŠúj­+õ¾Š¼ÚÙvõ‘)+ê‰{MuŠ*šc_ËÆ/W•1+"Ëb¡²÷Š‘­ÿ[©TÂh4B­VÃh4¶)T²XIDöªu‘²õKí)Y°´}F£ ׯß@~~FÕï •_ŸÊ…ÎÐêsYi€&8›îœb¡ÒŽ<:=T(Tž»U†;ù5ˆÀÑ$D–TXWc¹)BlyÔ$™²¡Þ®ë«t«WŽÔ¨‡Ô*œŒ÷¤7Ǿ:™‹—ŒJÉ÷$"K0Á„-wϱÄðx¸ªdʈzjË™<Ô·n>¦4BÜ4Â2«ºI…w‘-SvÔ®HˆñÁ¹[eͱ'rX¨$‡ÅBeHGWÞs¯€Éx"rí½Ÿñ=ŽìÉW'ÅÑ”îFÀ«å þWwNá©ás8šÄN<dUãBÑ]k§F½4d ;by ±’›p"2ŸÍ’&:ƒ½‚1Ú/B¦l¨§®fVâZf•[<ÑOØÞ“u µú}HW'Uó¶Þ`¶3y2fDd9,TöRG7ôDDŽ€ïqdÏö_.By®y[©PàGóF¶éT»-휵S£>X1e °½ÿr*Zý;‘yTëêq0çŠ[=Y¦l¨76If„ú9ã…éã¡R´Üþ×ê°7ë²µS£^rwVcѸ !¶QòïLä(X¨4¹G>ñ‡?üṈ왴‰Î¤¡>ñuƃ&ñ½Y—Po`¡Ë^Ü?~œ4-_]tFl“Œœ%¢¾Û—u uú–)Â¥K"d̈zBo0µyo|xJ]½p_ðp!¾5M\‡”l›ôÝœj$§WÊ” ‘å°PIDDD£iíBq]µ‡§†î$Ž&©ÒÕádÔÙ./7 æÆ±¯Nq4 ‘¹mKG›Ï8ÞNn2eC=uèJ1JªZ Í ðÐä¦׃’uFÏÞA–d-R²]‡ø"<ÀEˆmâç 9 *‰ˆˆÈal:™ ½¡e-J7g5Ä5·œ=1iÀaé 9Ù¶‡§„Û—Ó*p#§ºƒ½‰¨§òjËTtGˆ-•ŒF'Ûöõ)qýÞ ƒ}š‹[3Ž€¯³{ók&˜ø9hG à¡Iâ¨Ê­gòШ7Ê”‘e°PIDDDC:²àþñApsV7o//¼~2ï:Šê*¬’õÝŒQ~öqb_s4 ‘Ùl¹{FSËÃ/'7L0¼“#È–”×èp Y!¹¬UaK£T#1|œðºôßœlÛŠi!P¶Z¦©¼F‡ý—‹d̈ÈüX¨$"""‡pénnçÕ±å“Å‘sBcá¡i™6e0±##É*ùQß) ,›,Ä6ŸÎFÑQïI߇ƒV¥î`o²5ÛÏå £ëœµ*,N°H#åÕ–álá-«äG}âëŒIC}„ØÆ9ìMdŸX¨$"""‡ í~芄ñ˼³Jƒ¹a±BlkÚY‹çFæ³\ÒL °¢G¯q5¢¾ºTœ†ôªB!¶tÐøö&[$U0/6.b¡y°W0†ùˆËhðsо¬˜*þû½V‚Š™²!2?*‰ˆˆ”ÉdÂõë7pþüv}€ÓéØq^Úåt Úkb/þ}«"©eÙ–LÌ(z€⣽…ØæÓy2eCä8¤kFya”o¸LÙPO¥Ôââ]q)“‡$³ îypÐDaû@v²ÐélÛÂø@¸·ZÖÆ`4á›sùAd_X¨$""rP&“ õu ¨­©…^§—;‹:|µå5ºæm¥BÑá ZB`4BÝü„› Ø—å“Åéßû/¡ºÞ±lj,IgÔcoÖ%!&}¨C¶M:š2ÐË ÷ðkwßEáñP)ZJµúʽjÑüÈ|\´*,ˆb[Ïð9*‰ˆˆ”R©DÜØ1˜>cBBÛ/Ú9ŠÍ§Å´ C|0Ð×¹Ý}P`‰d:ãÎŒ$è‹åGæµ8a4ê–¯±uì½èØ£†‰,éPÎU”7´¬ñ«T(°„…J»a2µ-T=01jU;Ó ø9{`ò€¡BlGúy‹åGæ÷À„Âvrz%nIÖé&²W,T‘]«ªÓãàqÂ&è`ï&K#ÇC–¸’ú*Ï¿n‘üÈü¼Ý4˜1R)´å §½õÖ6É…c€«w{“­9}£YÅuBL:ò\jID‚°}"ÿ:Jë«ÍžYÆ´~òvbßœåç 9*‰ˆˆÈ®í¹XˆúƖѵ‹âƒ:9w÷G\À !ÆÑ$öeÙ$q”ð‰Ô–³™QO•ÖW·yP³tЙ²¡ÞNûæa¡3;t4\ÔÚæm½Ñ€ÝY,’™ŸR¡ÀýÄbô–Ó¹0™dJˆÈŒX¨$"""»&î6k”?¼Ý4]·$bœ°}8÷*jõ,tÙ‹9cü…n¶l&@Ô;{³. K_¸ª07tŒŒQO4èŒØ#Yúâ¡I¦šþg‡ˆÿÎÛùÀή<(™=’Y\‡¤;å2eCd>,T‘Ý*,oÀÉë¥BlY7nÐ`aØXh”-…®:}#f_1k~d9ÎZŒ•48ËfD=µ#3IØž2®j§ö&[s0¹Uu-ÍÄÚi×é»ä’ dT™5?²œQáž2Ð]ˆñs •DDDd·¾9—ƒ±ež“‡‹³FûwëX/'7L‘4Ø™ÉioöäÁ‰âÍ8› õL^m.¥ ±Äˆx™²¡ÞÎ*˜4Ô§ÍÚ…™< þΞBlGGUÚ“¥’¦:ߜ͇No”)"ó`¡’ˆˆˆìÖÉ ÚÂø 8kUÝ>^zC~"/%õUfÉ,oÊp_6 êƒI0¡åaO{pÈvUÕéqøZ‰[ÚÍÑ” R(±0|¬Ûž~^ø Û¶lò@(Z5w/¯Ñáˆäw‚ÈÞ°PIDDDv)½°W2*…˜t½¦®Ì#Lq4˜ŒØ—uÙ,ù‘å)Š67å›Næ°™Q7íÌG‘/‹–Ä ÛÖ^3¹cztŽÅ’éߙ՟Z’i–üÈòB|‘ã#Ä6ŸÎí`o"ûÀB%Ù¥¯O‰£)½œ0i¨oÎá¢ÖbæÀ‘Bl§d½6²mÒéß9¥õ¸p—͈º’VY€å9B,1|\{“-Ú.i 6}„|ܵìݾÑ~ˆô×ûÝ‘ÁÏA{"ý<\,¬[JdoX¨$"""»c2[Έ#–N †J©èàˆŽ%JF“\,JC^mYŸò#ëîÁÁnBlói6 êÊÉš¼A.^ˆˆ’)ê©âÊFO§ø>0±ûÓ¾[“ŽªÜy×9´‹‚ Q·”vê Ø+éOdOX¨$"""»s)­™EuBì =›ö}Ï´àáðvj)t™`ÂŽt6°'Ò›ó]IÐ8ÿ›¨3;%ïs‹"ÆA©èùÃ’ÇNÉûœ«“ sc{6íûžÅ‘ Âvq}%ÎÜêS~d=ÞnÌå'ĶŸçzÍd¿X¨$""rPF£—.&ãè‘ãÈÉv¬õФMt¢¸at„g{wN­Ta~Xœc÷oû²tb°ÐL ¤ª§n”Ê—‘»R’Ìêb!&]N¶íÉ´ï¹±puê~3¹ÖÂÝý1Ò7\ˆíμØëÜÈúî/>°;–R‚²êF™²!ê*‰ˆˆ”B¡€·üüáâê"w:fc0š°ó|“®ÏÔS‹ÂÅîß7Ësq»‚Ó‡íE¸¿ ÆDx 1éÚmDÔBú0&ÜÝ#|Beʆz*§´ço‹K”ôvÚ÷=Òîßû²/Cgä:‡öbθh[ Õzƒ »9ý›ì •DDDJ¡P 22#F ƒ¯¯O×؉Ó7JQTÙ Äúzƒ6. \½…› Ø—%ツí= ¡Ós5")£É„Ý’nßK"ÇË” õƶ3y0µZÝÂÛMƒé#ü:> †…-CÓ+kq*ÿFŸÎIÖãæ¬Æ¬ÑþBlû¹‚ö&²m,T‘]‘~ñŽôBx@ßFŒ*Š6Ówe\€ \çÐ^,?@˜þ]^£kÓh‚ˆ€s…·PT_)Ä#â;Ø›lÑÖ³âˆñÄqb3Åf® IDAT•ÞvõA¬¤ãôoûrÿñ¡m{v‰ì •DDDd7ôö^§2-Nê`ïž‘Nÿή)AJi–YÎM–ìãŒø(qTì7MBÔÆNÉhÊ>¡ˆô”)ê©;ù5¸ž]%Ä–ö²™œ”tú÷¡œ«h4pú·½˜=Ú.êæmƒÑ„]IœþMö‡…J"""²'¯— ¤ªeqx…HL0Ï ÚpŸP„»‹Ó¦öd]2˹É:–Œö]*DƒŽÓ¿‰îÑõØ—}Yˆ-b»²õŒ8š2ÐË †˜gy—ác…ÎïUº:œÈ¿n–s“å9i”˜3FìüÎõšÉ±PIDDDvc‡¤‰Nì /„ú9›íü %£*wg^äôo;²x\x“]§Ç‘kÅAÔ¿œÌ¿ÊÆÚæíö–½ Û¶ýœØèíþ „÷½¾pöĸ€h!¶‹ë5Û•û%£kÏß.GA9§“}a¡’ˆˆˆì‚Þ`ÂIË%ãÌ3íûžùaqÂvnM)®–dšõd9ÞmG}s–£IˆîÙ#Ysp¬‚\¼dʆzêzvîÔ ±¥ãÍ3«àž6Ó¿s¯¢NߨÁÞdkîáOWMó¶Ñdâ¨J²;,T‘]8–RŒò]ó¶9§}ß3Ì'ƒ<Åâç^Nÿ¶+÷Kºï¿\„ÚƒLÙٽрùׄ˜ôá Ù¶I⬂P?gŒ‰4o¡y~XTŠ–2A¾ÇòRÌz ²­Z‰cÅ5g¿9ÏB%Ù*‰ˆˆÈ.l—Lûí¾æ›ö}ÏÉû®Lvÿ¶'‹âƒ VµLƒ¬k4àðUNÿ&:‘½Í´ïya±2fD=µSò9¸8aÌ4ë»™“;& b»$ ˜È¶-‘4¼t·™Eu2eCÔs,T‘ÍÓ騹Hˆ-6óhÊ{¤#ŒòkË‘\’a‘k‘ùùzh1y¨¯ûæl^{õÒÑácý£Èißvãzvîä×±Äó.rtú÷ѼTëê-r-2¿©Ãýàï©b;8ª’ì •DDDdóŽ\+AE«ißJ…‰f^Ÿòž!ÞÅéßvMÚýûà•bTÕéeʆH~œömÿ¤Ó¾ƒ}œ1&Â2…湡±Ð(ÕÍÛ Žä^µÈµÈüÔ*æK¦og¡’ì •DDDdó¤#ÆöF·“Å®7_2šd»Û•c¡Q·|ÍmÐq ¹¨“#ˆÛÉüë¨hhÇißög—¤P¹d¼ù§}ßã©uÁ”CÅësú·]¹_2ëäZfÒ k;؛ȶ°PIDDä  #:ŠM_mÁÍ›·åN§×tÖ›ö}ÏÂv¦_.N·è5É|¼Ý4¸o„Ÿã´7êÏöe]¶cýqÚ·¹‘SÛyâ´ïÅšUptú÷É‚œþmG& ñA —ø@—Ÿƒd/X¨$""rPJ¥Æ EBB<‚‚»>ÀF¹&NÛU)XoÙ?OŒWp›éß{8ýÛ®H› ½V‚êzNÿ¦þGgÔã@Î!&mF¶m§d4eˆ¯3bY¶Ð<+d4´ª–éß=ŽH– ÛÕÞw¥Ý eʆ¨gX¨$""rP …‚ƒ//O¹ÓéµíçÄí°„…áñÂöÞÌ‹0š8ýÛ^Ì h3ýûðvÿ¦þçTþ ¡Û· Ì å´o{" —hnßRîgL0Lˆíã;»²(^|`w5³Ù%K¶…J"""²Y :#&‹Å%éH9KY$™öVPWËÅiV¹6õ§«Ó†‹Ý¿¥£’ˆúi3°¸€Aàê-S6ÔS7sÛNû¶T39)iAûDþuÔé­rmê» C|àçÑÒýÛdv%qú7Ù>*‰ˆˆÈfO§ëª” ,k´AžAˆñ×Âäôoû²P2šäðÕbÔ7dʆÈúôFI»}s4¥]‘>`èëŒ8 Oû¾gÖÀ‘P+UÍÛuúFÏKµÊµ©ïTJæÇ‰Ó¿wqú7Ù*‰ˆˆÈfIoÐÆö¿§¶ƒ½Ío¾d·ýÙ—ÙýÛŽÌ €ZÕ2?²¶Á€#×Jd̈ȺNܺ}+ À|Éhq²m;$ËŸ,¶Â´ï{¼œÜ01h°“ŽÐ%Û&]§òâÝrä•qú7Ù6*‰ˆˆú`÷îÝøñŒG}ï¿ÿ>êë;ÿò·}ûvÌ›7¯ÍÏêÕ«û|nG£7˜p@Òí{ÁXë6Z ¹¡Ï¯-ÇÕ’L«æ@½çã®ÅÄ!âôï]œþMýˆtx¬$‚ØíÛnÜÈ©Æ-+wû–’Nÿ>š—‚ƒÎª9PïMîo7Mó¶Éì¹ÈQ•dÛX¨$""ê¥5kÖà‘GACCBBBðÖ[oaÉ’%¨®®îð˜Û·o#55K—.~fΜÙçs;šÓ7JQ^Ór3¤P´`iÑž0HÒý{v²Us ¾Y$ù9\„F½Q¦lˆ¬Go4à »}Û5郕`Ëwû–š2*EKÙ FWS7¬šõžZ¥ÀœØ!ÆîßdëX¨$""ê…ääd¼þúëøüóÏñÑGáwÞÁÞ½{‘””„>ú¨Ã㪫«ŒçŸ^øYµjUŸÏíhvKžø‰ôB°³Õó˜'M²/ë²Õs Þ›e«y’UuzœHåôor|g oµ™ö=…J»²ë‚X¨LL²Ú´ï{üœ=-Äöfrú·=‘6_:w« E• 2eCÔ5*‰ˆˆzá½÷Þøqã°xñâæØÈ‘#ñðÃãÃ?ìð¸ÚÚZ¸¹¹YäÜŽÄh2aï%±P¹ÐÊÓ¾ï™:FØÎ¬.Â­Š˜s“Ù‹™£üàê¤jÞÖL8Ìï1d›Ô]ïBDDD­©Õj   í´™Â¦âGXXX»Ç.[¶LØ^±bF…—_~/¿ü2¢¢¢z}n)N‡·~ûN›ø‚E3àï'ÄjjªqøÐn×ÒÒJ€¬bƒó7¤ãð¡ty`à©tF¥±¾9öÉ‘¯1×-F¶œlEmMÍüîtf¨—­Çÿl?“9s¡”g€(.*Ĺ³§¡ÑhäNÅáì(9#lÇè=ìâÿ§ÝU^^­6éiwåNÅ"Þ4ÁhjYžÂU 4æ]Âagëzj¡€&4åUÖPO÷nÄ­GÚ–ÚÚ46êP^^&w*V72ЈsY-Ûë÷¦  ñº| ÙN‡²²²n¿—Μ5ÇÂ9.*‰ˆˆz!<<W¯^m¿yó&´Z- ÐÎQí[¾|9^~ùe¤¤¤ **ÊlçV©T˜;wüüÄ¢ä¨Ñ#áááÞ¼m2™PVZ†„„ ÝÎÙ’NîÌÓ¼îïŒ玕/¡ÿ™s5›3Î6oßVWág6òw&§½%%6ó»Ó™ƒêñßK›·+êMPúCB´§ŒYõo§NÄÈ‘£šG‹“yÜ®ÌGá±!öèØyâÕvI{•’ržž^ íÞƒ;{óÑù-S÷çŽöÇÄ ƒåKè6OEjEËçsŽ—´ý÷ÿÖr²³PQQ#GÉŠÕ­PãÜú–µE¯CFÄÃÓ•e¡î¨ªªÂ•+ÉvñÇÞñ7’ˆˆ¨–/_Žßüæ7(++ƒOsü‹/¾ÀÊ•+¡R©:9ZtçÎ@tt´YÏ­T*1~âxDGGuºŸÉd‚R¥„»‡G·s¶¤WË…íÄ„`›Èmaä8¡Py­<µj#]äin`+léw§3Ã<<0"Ì)YUͱ#׫03.DƬú7µF W77»øý±'§2NÛÝ|:D¦l,Cëäg‡üÝ©¨ÑáüqÚwâÄP›ø³.ˆ‹Ôä–BåÑüTüz⣲­ÙÎ..¨«¯·‰¿OkKœè‚_~y º¦)ûzƒ ç2ðÀŸ.Ž$0PkÔýòwÇÚ¸F%Q/<ýôÓpssÃÊ•+‘šš¼ñÆ8{ö,^|ñÅæýÞxã <ðÀÐëõ0øõ¯óçÏ£®®z½'NœÀêÕ«1wî\ 6¬GçvD·òjp'_ $÷ú”÷L  OmKCLØŸÍföd‘¤süž‹…0±ù79˜9âú”sÙDÇ®¸R ½¡åÉE«Âô~a=óÂâ„í¢úJ\)Í)ê)wg5¦I~—ö°û7Ù *‰ˆˆzÁÇLJF~~>¢¢¢ˆuëÖaÇŽ3¦å¦p×®]Ø¿?***PQQ””LŸ>^^^ðððÀܹs1uêT¬_¿ŠÿHèî¹Ñî$ñ ó'IJ‹j¥ 3Žbìþm_Ä‹EïÜÒz\˪ì`o"û“[SŠëe9Bl®¤ Ù6iáè¾b9Ex ÆK\~æPNÛ¥jÈvÍ?^+A£žM‘ȶpê7Q/ 2W®\Avv6êêê0xpÛõ£öíÛ‡ªªªæu"7n܈šš¤¥¥Áh4"&&®®®mŽëιÑ.É Z⸰¥esÃb±-ý\óvRá”ÖWÃ×Ù½“£ÈV èþÿÙ»óèºÊó~ôß3j8šçÉò¨Yò„ml0†2LVÒßåÞ ”E/÷†—6鬴)MhRº’@²šBH¨1ƶ$Kò€mlk–l˲­ytt†û‡ësô¾’lYÒÞûœïg-¯v¿Ú[~ȱ´Ïyöó>VÇ£¥kܽvè\rSÙ#‘|ÃG×Î Ç1aسJ™`ÈkV›Çêú„µûãleìN^‹Cî㮞÷×VÁˆÈ{7Äâoõ:8œ7ªvG'쨬ïî¼X…##ò`E%ÑJII™3‘Ф¤$aÍb± 77ëׯŸ5I9ßïík®÷MýàÞêzã\ ‹)Ð}ìp9QÚÎj-Ù+U“ü´[¡Hˆßá¶jáxWr. :~äÓŠ²Ú>ŒO:ÜÇFƒ»óÔ5U{W²8„æêhZ†¹}X+¢B͸km„°vè\BÑÍŽw-"""R…g:…ã˜03¶¦©«Á{€Á„ü„ aí0·kÊÞ bò»áú®õZІhñôN ã|o‹°¶;9O¡hh!>’vlψB„ŤP4³ËN1D 'uÛ+=þø|œlØL*ÂD%©‚üDÿž ±0èU´ïûÈÃNt5aÜ>©P4ä­»ÖE &Ì,¬}ĪJòGÛj„dC¨)wÇûÖ´o_fw¸p¸ºWXÛ·QÃä¦ÓA‡Ý)büÈu&*µdß&±@÷Ð$>½<¤P4D31QIDDDŠë¶áÌ¥AaM~#­E‰Y0é=m¾'S¨ìlP0"ò†^§Ã=RUå¡óÜöFÚ'÷*NʆÙÀ‘ZQÕЇ¡±)÷±N7³U…ZìJ•Õý­è±2Ñ¥©±AÈH{ksû7© •DDD¤¸#Õ=îÆî` 4"?3JÁˆæj ÂÖ¸u«I´eïñÃÿ'Íè±) Ñ™²âTW³°ÆißÚrðS1Q´iM"ŠæÖîŽOC˜ÙÓcÛérqú·ÆÜ»I¼Êà ‰”ÄD%)îÐ9qëmqN4Lê}›"(糖ÃåT(òVQN4B=•f§ G¤-—DZRÞ^‹)§Ý}<[?]R/§Ë…CçÅûà¾Mꬦ£Þ€¢Ä,aí(ËiŠüÀ®µ{Íc EC$Rï'"""ò 6*ëû…5µnw»iWrtðôÏšÃÙžK FDÞ0õ(Ê+vÙ§’´LÞö½#>S BÑ·>½<„îA±×ñ½*¿Ê}*Ov5atjB¡hÈ[y+Ã)þŽ8ȪJR &*‰ˆˆ|”ÝnÇoßzÿôÊOpöÌ9¥Ã™SeC?Æ'îc£A‡]¹Ñ Ft{ ÁÈŠLÖŽpÛ›¦ì•z «ëƒÕæ˜ãl"õ²9ì¨ìûäîYÁmßZò±Ô'7#9«ãƒç8[ ²„¨6‡õ FDÞÐéfnÿf¿fR &*‰ˆˆ|”ÑhÄW¾ú0þúéÿ›ïÚxû "W²mY‰Èóg«Ç®d±šä(ûTjÊî¼ žªX«ÍŠºþ[\A¤N'»š0n÷TãtzìLÊQ0"ò–ÜþDN ©‘Å8cªü©²—Ôm¯4Xî•!tI•½DJ`¢’ˆˆˆãt¹pTê ¸wcìg«‹¼ííúXš‡:І¼a1a[Z¤°vðSn{#í‘{nŒYÈ€9Î&µiíÇE©7à=4r”Øë¨z¥’ºmψB¸Åä>v¹f&͉”ÀD%)æì¥!t‰OïÕÞŸò¦Œˆd$[Ä>‡‡YM¢)ò¿µÃzaw¸æ8›H}\p¡Lj;QÂjJMùHJ ÅE`ýÊp…¢ñήä\èužÊô٦ϓz :ì΋Ö¸ý›Ô€‰J"""RŒüä>#9©1A Eã=yûw)ûTjʾMq˜ö£6œ¾8 \@D^ªë¿†.ë°&W{“º¾ î*¸gC¬ð{IÍbð>z•°Æ~ÍÚ"mª¬ïÃðø”BÑÝÀD%)F‹}¹¦Û•œ+×Î’4 õJŠ DΊ0aÕ$¤%¥íµÂqjH V…jë÷¨?›šñpäžõÚØö}“|©Š÷zß®( ÑüuŽ¢q ]X+NdJ-ùXºeG#ÈlP(š…I ‰Åš°xaí"?$.«éŔݩP4DLT‘B>–¶Øîݧ™¾\ÓíN·½ênÆèÔ„BÑ·2SB±Bê‹ÊjÒ‚Ò¶a‹mD€›bW+ycÊîı:q‹í=µµíû¦Ý)ë…ã£ÜY ){6ĈC‘¬vœhb¿fR•DDD´ìz‡m8{Iìå(oÁÕŠ¢Äl˜ F÷±ÍaGUgƒ‚‘·äaòp "5:Ú>sÚ·AÇwZq¼±#V»ûX¯Óawž6ïƒ;¥Ió‡:Ð6Ö¯P4ä­Ø°lX-îh9Ì~ͤ ÞɈˆˆhÙ}|¾N—§ÈhD¾ÆúrÝl ÀÖ¸4aíðun{Ó’=ÄäÀ…+CèšT(¢Û·Oâ“îfam§4Ô„ÔMÞU°ym8bÂÌ EsgÖG¯BL ˜èb¿fmÙ# q’Ûó-'&*‰ˆˆhÙÉo€wæFÃlÔîÛ’ÝR‚àXG-ìN‡BÑ·¶¥E",Øä>v¹€£Õ¬ª$õªè¨‡Íá©Æ3ŒÈÏP0"òÖ‘ b¢RNi‰^§Cab¦°VÞQ;ÇÙ¤F{¥mýhlU(òwÚýD@DDDšdµ9PÕ n »wSügkÃî”õÐÁÓßiØfÅ™žK FDÞ0t(Ê+z?>ÏjR/¹àÝñé°˜І¼U{u×ûÄ^Ær¢HkJ¤v§º.bŒýš5##9dF¿fÞI)LTù(‡Ã÷Þý^ÿÙ/pþœz¶"WÖ÷ÃjóT :ì̉V0¢;†œ¨ÂZi;«I´äiêie}?&§8õ”ÔÇárâXG°VÂißš"'€VÆc]¢E¡hG~|†Ð¯yÊiGUW£‚‘·vKU½Gد™ÂD%‘2 øâ—>‡ÇŸø&6lÌS:7¹Aû¶´H„[Lsœ­r¸2öçÒ”¹Ñ0è=U±ã“T5ôÝâ "e|ÚÓ‚ÁÉ1÷±:ö§Ô˜ÃÒ¶ï{6hwÛ÷MS ¶Æ­ÖاR[vçÅÇçZ†Ð7bS(ògLTѲq¹€#ÕR_.ø€;“ÄDÁÕÑ^´ w) y+2ÄŒÍk#„5Nÿ&5*•¦}gE¥ !8b޳Imº‡&QÝ:,¬íõ‘û`‰4ýûXG.V¦kÅŽÌ(„zªbNJÙ¯™ÀD%-›êÖat ŠÓ”µ<@`ºÌÈd$G kÜþ­-{Ö‹Õ$‡Ï÷`Úpz"U8Ú&¶òØ™ÄmßZòѧÝÂï•‹ [ÖEÎ}†ìJwoôOŒ¢º¯U¡hÈ[f£…Yì×LÊc¢’ˆˆˆ–\M¹6Á‚UqÁ E³øŠ’²…ãòöº9Î$5’ûTv L þúˆBÑÍty¸ ­#âïÑÉêiíA·'oûÞ•£A7ÇÙÚ’‰´ðDa­Œì4åi¨Sy]?lvVÅÒòb¢’ˆˆˆ–Í‘ ¾¹íû¦âD1Qy¶ç’ÐKŽÔm]¢+¥Ä¹ÜS•HIr5e\P8²"“І¼56aGUC¿°&? Ñ:¹_ª<¡žÔmW^ŒÐ¯ylÂŽý·¸‚hñ1QIDDDË¢{pf_.¹q»ÖmOÈ@Ñì>v¸œœzª1r+‚/0QIê!·“Ø’|£Ï”×õcrÊSf4èP”u‹+´GîSyq¨mcLtiEt¨V‡ kœþMˉJ"""ZGª{…¾\¡AFŸéËuS Á„»ãÓ…µ²6n{Ó¹Oeõ•atMÎq6ÑòœÃ…Þ+š<Ä‹ÔMî÷—Ÿ°`“BÑ,õÑ«&¬qú·¶È‘cŸJZ^LTѲ·}—äúN_®éäíßõœzª!w§G!4È3õÔérá(§ž’ ”µ× ¿K‚Ø—¦`Dä §kæeùÁˆ/Ðët(LÌÖÊ;øÀNKöJ}*Ûú'ÐØ6ªP4䘨$""¢%g³;Q)õåÚí#Ó¾e%ɹÂVÌ¡É1œëmQ0"ò†Ñ CqN´°Æ>•¤òp®ü„ ˜ Æ9Î&µ9ß2Œ¾›°¶ÇÇúSÞT"õ©<ÕucS ECÞÊHAJt °Æéß´œ˜¨$""¢%WÕб »ûØ ×a§” òñAáÈ”†[pú·¶ÈɃŠú>¡¯Ñrs¸œ8ÞÕ ¬É½IÝäiß³%ƒ|EAB¦DŸrÚÙ¯Ycäûàaö©¤eÄD%-9yÛ÷浈 5Ïq¶öÉÕ$eíìÏ¥%»óĶ㓎“z‰–ÓÙžK¶YÝÇ:èP˜”}‹+Hmäû ¯î*n´%Ø·NXcŸJm‘Ûœ»<„žaök¦åÁD%-9ùÚ.›ö-“ûT^êĵQV#hE„Å„Mk"„µ#ÕÜþMÊ‘«²³£V VXBêÕ=4‰úë#š¯ßåŠßcuì׬!;2¢(ök.«éS0"ò'LTù(‡Ã÷Þý^ÿÙ/pþ\µbq4¶âzŸØ›jW’@nT*b‚Ä$·k‹<õôãs=ÂÔz¢åTÚ.#á¶om9|Aüýn1a³ô0Ä×ìJÎŽû'FQÝתP4ä-“Q¢ì(aí0ûTÒ2a¢’ˆˆÈG |ñKŸÃãO|6æÝþ‚%"7`OŽ DFrˆBÑ,½N‡¢„,aSOµåiêiÇÀÚFæ8›hé´õ£e¸KX+æ¶oM‘wgG í%|Qbp$ÒÂ…µ²vÞµDîSY^×›U±´ô˜¨$""¢%U*mÚ³Á·«)o*N+ž8õT[Ò-H Ö>>Çíß´üäÞ~ѡȎ\¡P4ä-›Ý‰ã ÂÚ.ßUp“\Uy”}*5egn ô:OB}lÂŽì×LK‰J"""Z2£6œ½4(¬ùòéòã3fL==ÑÕ¤`Dä-¹ªò0ûT’*:ë…ãÂÄ,!y@êv²i£v÷±A¯ÃΜh#Z>råïÅ¡tŒÌq6©ML˜ׄ kG«Ùo›–•DDD´dJkúàpzs°##êWø‹)[b¥©§Üö¦)rŸÊ -Ãè±) ù#«Ý†S]ÍÂûSj‹œØÙ°:Q¡f…¢Y^ë£W!*PlõRÎû ¦È÷Á#LTÒ2`¢’ˆˆˆ–Ìa©/WQv4LþóöC®&)o¯…“YÁñËg IDAT4ãîôÈ™SOk9õ”–ÏÉî&L:¦ÜÇF½Ûã3Œˆ¼%ßåÄ/Óët(ú5먟ãlR£]yâ.˜Öîq´t+ ù ÿù¤@DDDËÊîp¡\JêøË¶ï›äþ\}#¨í¿ªP4ä-“Q‚,±øènÿ¦åSÖ&VŸmŽ]ƒ0sÐg“Ú\îGk·˜Ôñ·û`‘ôÀîDg#&¦%ßIݲW„">"@X;Â6(´Ä˜¨$""¢%ñIó†Ç=Ft:`—U’@²% kĵòŽ:…¢¡…Ø)ý›-¯ëƒÝÁªXZRõYq"§}kÉ‘óÝÂq\D²RBŠF… ™0èFy+Ã0ÇÙ¾«Dšþ-Oð%uÛ‹ésK†Æ¦ðéåÁ¹/ Z$ƒm3³?¥¦­wì‘~Ÿøƒ0s06ĬÖŽñ¦ÈÛ¿O6 `lÚ€(¢ÅÆD%-‰#3úrù×v·›ŠÅÄBÃ@z&†І¼?KTi ûTÒÒ+“†Ž¤X¢±&,^¡hÈ[#V;N5‹‰æ]ëýkWÁME‰r¿f&*µ¤ + &£'ud³;QÕÀéí´t˜¨$""¢Ewµ×ŠKcš¿~@Û»Zè)ç‚ Çø!MSäžrržh)Èɜɹ EB QQß)»Ó}l6êQu‹+|—Ê`0à‹_úâ›Ø°1oÙþÞª†~XmžjAƒ^‡Â,ÿìËuSLP²"“…µcõ EC ±SUQßÛ´þsD‹ÅárâxW£°V’Äþ”Z"oû^Œ•qÁ E£;â3`6x¶¾O9í8Ùݬ`Dä-yú7ØÑRa¢’ˆˆˆ•¼ÝmÓšpaÛ¬¿’«IاR[væD í Æ&ì8ÕÄ©§´øÎõ¶`pÒ3ŒLÝŒö¤nG¥Ξ q E¢AF3îŠÛ”K•än;sŪà3—18¶¼­…È?0QIDDD‹ê¨”¨”ߨú«ÂÄ,á¸y¨ãLtiET¨ëW‹¡Jkûæ8›háä!#‘Iˆ W(òVï° Õ­Ãš¿oû¾©0A¼–µ×ÁNdÑŠüÌ(™ îc‡Ó…Š:Þiñ1QIDDD‹¦¥k­Ýãš¼UÈ_åE¯DD€EX«àöoMÙ%%ÝåéöD‹AîOY"Uc“º­îsÚ8äÐ #¶¬‹P0"õ(Iÿ-÷X‡Ð4Ø®P4ä­“;2ÅV>ìSIK‰J""¢EÐÓÓƒúúz¸\ó« p¹\hiiÁ… `µZg|½££ååå3þœ={v±C_TGªÅÄM\x²W„*ºtzäÇgkÜþ­-rÒýRçØŒÄ<ÑèÄÅ¡a­(‘Û¾µDîOY˜ “‘»`UhRCÄ>r1©›üÀ®¬¦WHÌ-þÆ$""ºííí(,,DJJ 6mÚ„ÄÄD|ðÁsžo³Ùð / 66™™™Ø²e ’’’ð“ŸüD8ï½÷Þý÷Þ‹/ùËŸ§Ÿ~z©ÿ“îH¹´¶$7ÓÚúù=¹O剮&Øv…¢!oå­ C\x€°&·: ºr5ed@ò¢W* yËîp¡¢¾_XÛÅmß¹ßê±&*µd×zñ]߈ Z†ç8›ha˜¨$""Z «ÕŠââbDFFâòåËhooÇþýûñðÃãĉ³^süøq”••áÝwßE?ÚÚÚðñxúé§QVVæ>ottèîîþ9rd¹þó¼fµ9p¢Qü€Æ¾\¢ü„La ˸}gz.)yC§»‘|ŸŽSOi1UHI›ü„LtüȦg. bÄêyø¤Ó±O³L®>ß{CÓ†G‘º¥D"-QlcSZËû -.Þõˆˆˆè7¿ù ñöÛo#99QQQøñŒÜÜ\üÓ?ýӬה””ààÁƒ(..†ÅbAll,~üã#11tŸ7>>ŽåúOYU ý˜œrº ²¢nq…ÿ‰ ANTª°VÑÉ>•Z"WGoì‡ÕæP(ò%v§Ÿt_ÖŠ¤!\¤nò®‚œ3«°ýÝÖ¸u2šÝÇ—U] FDÞ’«*^`¢’•DDD ôÖ[oáóŸÿ¼PÔétøêW¿Š?ÿùϰÙlóú>z½±±±Âù£££°X,·¸J}ŽJ•e[ÖE",ؤP4ê%W“°O¥¶eGÃhðTÅNN9q¼¡ÿWÍÏٞ˚pëu:ìHȸŤ6¥5bÊÜU0C€Á„»ãÓ…5ö©Ô¹Oeuë0z†'І|•DDD ÔÒÒ‚ÌÌÌëyyyp8hoŸß$Ë‘‘444`Ë–-îµ±±1tuuáü#Þ~ûmœ©¿Ž5q E¤M6Û$àpØo²ëŸEã€øp+78Ñï~¶æËj‡Á`TÕÿ>‡Î¶ Ç[׆`hUf³1X‹–QOrëà¥ÓHÆÒ·¼Õ:®ª;Z´uMœõ—Õô¢«»GhâkFGGa³Ùæýo':š­ЉJ""¢ÐétHNNžµj²³³’’rËïqíÚ5<ôÐCøÎw¾ƒûî»oÆ÷ŸnåÊ•øñŒ;vàÌ™3(**ºmŒN‡çÏWÃ`0ëæ=¢£Å'á““hl\xUßGgÅÞDy .45±Jp.©Sb¢ùtï%T7Ô¬3Ìq…zMÚîìߎVÅXtèó”OýñØE<Ë·ÖÞÁ•+-0›Í·?ÙÇU] žOAz#Œ£hìò¿Ÿ­ùèëëÅððFF†•àtUãÂÚê°q¿üÝ8_éú(´À“¨,½^ƒ{ü’ÿ½£##˜œœ„ |mîD‚Ñî*âÑ Þ¯¨GV‚ïnÚµÙl™÷Ïu~~áG仸nŠˆˆh6n܈àÅ_Ö?þøc¤§§#,,lÎk{zzðÙÏ~>ø žyæ™yý}qqq<›·c4ñ?ñ8Ö®]sËó\.zº»ü†jtÂŽ¦/ÖöïÉEþ¦¸}?39†7ÿx ×)é6—Æ5qÈ×à„ßî®N¿|3¾ïr=þ£ìšûøòHòó·Üâ ’=z7nžWõ¹¯ûcÕ%`Zñ]AR6Š Š• HåÎ;‹ˆˆH¬ZµZéPç¯ aÈzRXûúç·#%šUÖs1uÇãàÏ´ï«¶¤oZ˜ ¹ß;-†Ö+-ÀÆM›—ôïñ¹ÇO ºÕó° Ç•ˆoä§)ÑÒ™3Ÿøå{žåæ»én""¢%öÄO ®®ï¼óŽ{­µµo¿ý6ž|òIaíÔ©SîãÞÞ^ìÛ·ùùùøéO:ë÷žmKùo¼‹Å" ÝQƒª†~LÙîc“Q©w‰Â,È‹^)¬UtÔÏq6©Ñîõâ–®Oš0båfòžÓåÂñ®&a­01[¡hh!äA"k,LRÞÆ¦˜55¹]pÍ(Eê¶+OìE^ÊÁr´HXQIDD´@EEExâ‰'ðõ¯ü1âââðÿñرc}ôQ÷y_øÂP__k×®Ád2aß¾}¸~ý:}ôQüË¿ü‹ð=¿ñoÀjµbÍš5عs'rss€ªª*;v o¾ù¦êªJ«Å7¦[×E $o1n§01 çz[ÜÇ¥m5øÿ6IÁˆÈ;2¢`ÒcrêF’Þîp¡ª¡ûXIL^ªé¿ŠÉQa­€ƒt4¥¬V¼–ä²7ÝíõlOÇ¡ëçÝk•õøüêm FEÞ(ÉÆOÞ¿ä>nlA×à$â#ŒŠ|+*‰ˆˆîÀ?ÿó?ã7Þ€Ëå•+WðÜsÏáwÞA` §’âñÇÇ·¾õ-ÄÄÄ ­­ QQQذaÞÿ}üéOþLNN"::ÈËËCss3.\¸€-[¶ ¦¦û÷ïWð¿vvòô]yü€6ÅI9Âñõ±>\åÔL­0`[Z¤°&'+ˆæ£¢£N8^–€ÄàÈ9Î&µŸÂ¹–!a­8'Z¡h´¥0IlwRÙÕèn‰Bê·qu8",žA.8Xî@DDt‡~øa<üðÃs~ý/ÿò/ÝÿNN:tÛï™——‡¼¼¼E‰o)5¶¢½_œì½SÚ D³ËŠLFl`z&<ýÊÛëðé% FEÞ(ɉƱ:Ï–Ï£ø¼WÕÙ(ËÉR·Êú~ØžAH&=îNg¢y> ³¡ƒÎ=Hjhr µý×°^jBêdÐëP…Nw¹×Êjz±¿ YÁ¨È°¢’ˆˆˆìȱ0)*i‰…¢Ñt(”†ç°O¥¶”HIùŽ \ìS(Ò¢aÛ8ªûZ…µüxnûÖ¹‚l{F‚Ì…¢Ñ–ø p¬ OÖxÔ¹ÍA…”¸'Z&*‰ˆˆhÁÊjŻ׳šÒEIâÀŒOº/Âj·) y+-Ñ‚ä(q`Fi5·ïÓü—¶ºL¸+n­‚‘·Ê¥û`q6·}{£Hz`WÉD¥¦ì̉Nç9›Âù+Cs_@4LTÑ‚ŒXí8}q@XcJïìHÈ€Q塚™tLáTw³‚‘·äj’òº~…"!-ªè§oOC Á4ÇÙ¤6Mí3ÛŸpŽw ¤DeMÿU N²2]+â"™*¬•ÕôÍq6Ñü0QIDDD RQ×'lï1õØÎ¾\^ 5acÌ*aÛÞ´¥XJJœhìÇø¤C¡hHkŽwŠ‰Ê‚nûÖ’2i˜\BdÖ±ý‰WîŠ]ƒ`£gJ´ÃåÄñ®Æ[\Aj³SzH-ÿ\y‹‰J"""ZyÚ÷öŒ(X9§Ï[E‰âöïòöZ…"¡…(ÈŒ‚ÑàÙ÷f³;q¢‘U•t{ÍCèÖ˜¨ÔyÛ÷®\¶?ñ–Io͏uÂÚ±ö:…¢¡…(‘¦ÜW·£w˜mlhᘨ$""¢‘”ä²/×Bȉʶ±~´Ž°Ï¡V„±eXI,'/ˆf#WO'Y¢°:,^¡hÈ[V›§šÅö'%l² …Ò}°ª«Ñ= œÔo˺H„L{Pít¹p¬Ž÷AZ8&*‰ˆˆ|”Ëå•+­¨«k@ÿÀí/ðBcÛ(:&…µì˵ i‰ˆ ÖŽu°šDKв£„c¹Ú˜h6òÐB©W©Û‰Æ~LNy! :dFÝâ š‹6ê Ø*õé#u“+§‹²ÙþäN%f£u¤Ì}\ÙYoeïU0"òÆîõ±]ØEàp9q²«YÁˆÈ[ò}ìh¡˜¨$"""¯°/×Ò(úÓɉ R·âìhôž^\ã“3+‰ m¬WGÅðìO©-r¦$'š½øîP Á„»¤ö¼jK±ÔþàÓËC›R(Ò2&*‰ˆˆÈ+ò4öåZ‰bEÕÅ¡NtŒ3Ñ¥áÓŒ^\r/W"(o¯Žc‚™¬P4ä-»Ã…“ÒCˆbnû^Reñ±v&*µd{F‚Ì÷±ÃéBUC¿‚‘V1QIDDDóv½o‚}¹–HnT*"ÄþNU EC !÷je.šMeG½pœŸX§Ÿ4`Äꄤ×éP˜Åv‹A®,î²áâP§BÑ·LzlÏ[Émˆæƒ‰J"""š·Òêá8Š}¹A§Çöøta­BJhºí”’öm£hïŸP(R£)§§º/ krÛR7¹R:we(bÂÌ Eã[Ö„Å#Å"&}¹ý[[äÁr¥µ½p¹ †4‹‰J"""š7öåZZrÂâxg#ìN‡BÑ·Ö¯Ct¨˜°à0šîLÏeŒÛ'ÝÇznÆ R7¹BŒ» W¾Ô¥’; 4E~`×=8‰Æ¶…¢!­b¢’ˆˆˆæÅîpáD£Ô—+‡ÐSQB–°ttjúZŒˆ¼¡×éP%n{+çöošFn畊è@V¥kE÷Ð$¤¤‹<@„ýût÷%!¹Oê¶:>©±AÂZ)ïƒä%&*‰ˆˆh^N_ûrét¤³Øb‚‘$¬±O¥¶ÈÕ$õý°;¸ïnÛ9pÛ·¶”×ö ÛXCƒŒØ´&B¹€|Ðöøt˜ F÷ñ”ÓŽS]Í FDÞ’ïƒeµ,GÞa¢’ˆˆˆæ¥\z£™›ƾ\K@žþÍ>•ÚR”éÝF¬vœ½<¨\@¤=Ö!4vkñ EC !È*ÌŠ‚ÑÀö'‹)Ø€ Ñ«…5nÿÖ¹‚<€Šèv˜¨$""òQ.— 8}ú,ºººïøûÍèOɾ\K¢ ALTÖ \Cßû;iElXrV„ kr’ŸüSEG=\ð”ã…™ƒ°>f•r‘Wœ.ªú…µbÞ—D¡ôÀ®¼½V¡Hh!vdDÁlô¤šfkDt+ÆÛŸBÓµ··£¯¯cccJ‡âW, ¢££‘””tû“oÁjµÂf³Ánçåd4a6›tû“o¯Ÿ2ëõ#mëžDÝ51YÆmßKcsìXL›º1-ÚéráDW#X¹EáÈh¾væÅ æê°û¸´ºOa‚‘TtˆUaÛã3`бnD+.´ £oÄ&¬•°Oó’(LÌ«çÿì>nëÇÕѤ†Ä*ÍWp€ÛÒ#QQçyHWZÓ‹½ùúÑüðÎ8O¨®®ÆÕ«W™¤TÀØØ®^½ŠêêjLLLx}½ÃáÀÐÐÆÇÇ™äR€ÝnÇøø8†††àpx?½–¯Ÿ²îôõ#åèt:dff`˖͈»£ïul–¾\w­e_®¥`Ò±5VLjÉ R79‰_{m݃áÏ.'Nv7 kòÐR7y HZ¢IQ EãÛÒ#’(V¦kg-‘‡L•Õô( i•óÔÜÜÌ¥ Œ¡¹ÙûfÊ£££Lp©€ÝnÇèè¨××ñõS‡…¾~ää¾\ù™ì˵”äFeg=œ.dÑŠ»ÖF ,Øä>v¹€ŠznÿögÕ}­œ?KìH`J-)¯†KòX¶TtÐÍrä;-‘Û]ï›À¥NæSh~˜¨œ‡ööv&)Udll íííó>ßjµ2É¥"v»V«uÞçóõSo_?ò N— •r_.nw[REIÙÂqÿÄ(ÛІ¼e4èP)¬ÉÕXä_ª:…ãuá‰H ŽœãlR›¡±)œoÖŠ³£ŠÆ?&‰‰ÊS]M˜pL) y+#9dFÅ1ïƒ4_LTÎC_Ÿ€«7¯‰Íf»ýI´¬¼yMøú©_ÿSÝ:ŒÞañu/ÎaÊ¥”l‰šÑ‹«¢£N¡hh!ä!åµ}p8Yë¯äŸß"nûÖ”Šú~áç7ÐlÀ¶4&š—Ò©‡ë„c gº/)yKîáÊÁr4_LTΫ)ÕǛׄÕxêãÍkÂ×O}øšøŸòñåÚ VÄp¸ÒR+’ªIª¸íMSv劉æÁ±)T_žãlòeöqÔö_Öò2ç8›ÔHn²##fƒBÑø‡0s0ò¢W kU]¼j‰üÀîDc?¬6ö»§Ûc¢’ˆˆˆniF_®\nû^r"ãÓžŒL±õ‚V$D =)DXã¶7ÿTÙÙ‡Ëé>2šqWìZ#"o“îƒòÀ,Z…Ò}ðX;whIa–ØÏ|rʉ FDZÁD%ÍiÄjǧ—…5~@[ÛâÒ`ð dq¸œ8Ùåý@9RÎÎ<1©_VËD¥?ªì§o‹KƒÙ`T(òVcÛ(:&„µ¤³, ¥~Í—‡»Ð1ÎD—V„±yM„°VÎû Í•DDD4§Ê†~Øž¾\&=¶g°/×r˜­êJNxº•H½\/\ÆÀ(ûüú\¨ì·«rÛ·¶ÈÛ¾S¢±&>X¡hüKvä DŠ•é¬ªÔ–’\ñ>x´š‰Jº=>Êó#GŽÁØØ|ðA¥C!òI=ôûÿÿÃþpËã¹Î!R›2é åÝéQb_®eS)ô¦¬`¢RS¶¦E"8À€ñÉ=¹N*êûñàÖ…#£åÒ4ØŽž ±7i!éhJ™4Dî»GKG¯ÓaG|&>h=í^«è¨Çþu FEÞØ™‹—ß»è>¾Ò=Ž«=V¤Æ²×9Í•~âÈ‘#øóŸÿŒ#GŽàÃ?T:š‡îînüÛ¿ý{ì1<òÈ#xì±Çðú믣»»[éЈÈÈ[U‹³£ŠÄ?$Š•Wã¸<Ü¥P4ä-³Q™âÏ ûTúùáB²% +C¹mX+Æ'ø¤YÜj¼“‰ÊeU(ÝOv7Ãîä@­È^ŠØ°aM®R&’±¢ÒÜLRÞtðàAèt:ìÛ·OÁ¨èVΟ?—_~V«ghB__:„ŠŠ <óÌ3ذaƒ‚Ò|È’¬˜\:xë­·066†7ß|z½FzzºÒáiVsÇÚûž\%ì˵¬Ö…'"18RèÉUÑQ5añ FEÞ(ÎŽÆáó=îãcµ}p¹î‘Ϩì·}I=÷HÝŽ7ôÃf÷ B2tØ‘ÁvË© ! zN×64cSø´·[ãÖ)͇NeGáÝîµ²Ú^ü¯]+ŒŠÔŽ•~`÷îÝxõÕWa4ÞÈK¿úê«LRªXww·;I¹e˼ôÒKxë­·ðÒK/aÛ¶m°Z­xùå—YY©BøÃÜ–ò8pûöíC?Þ~ûm¸þçìÁƒñôÓO+²œN'Ž?…ÿý®´´z}}¹ôÄ;!2i‰–Å æIîg''>HÝJ¤ê«î¡IÔ_Q(ZNV» çz[„5nûÖ–riÚ÷–u‘ b­ÏrŠ AfD²°VÅû ¦Èíª¤D2&*‰TæÝwßu')Ÿ{î9¬]»X»v-ž}öYw²òÝwßU:T’<ôÐCBÏÉóçÏ£¢¢.\ާ¯Ívyçûßÿ>žzê)üö·¿Ö pöìY…¢RN‡Õ«V";;‘QÞÀ‘? q»›2ä.i IDATÄÆéî‹°Ú9E+VÅÏèÅÅíßþádwl»ûؤ7bk,«À´DþY-bûE&Š•Èì׬-ÅÙÑÐOÛF0>éÀ™‹ƒ FDjÇD¥:|øð¼Ï=xðàFBÞº™XÙ¿ÿ¬_øá‡…óH½FFnTÌ  ÇÓ×èÎÕ××㘱>99)´OðG: ‰ñX¹*ááa^];asàd“Ø—«$‡‰J%ìHÈ€Qï`4é˜Â™žK FDÞ’“üåÒpòMr2eSìjXL ECÞºÖkEk÷¸°¶3—íO” ï,hhCuH¡hÈ[Q¡fä® Öä‡áDÓ1Qéƒ>Œ÷ßÞçøá‡^OKkhèÆM7))iÖ¯''ߨú08ȧPj&ü_Z)))›±þî»ï"33s–+h>N4 `ÂæiVoÐëf ¡åb D^ôJaÛ¿µEÞþ}úâF¬ö9Î&_QÙ!þœ$ðž¤%G«Åjʸðd¯ãlZJ›bW#Ôä©LwÁ…ã]M FDޒÕÜY@scƒ óᇺ+$Ÿzê)÷º^¯‡Óy£Äßþí߀Pitøða ÜÿýË-Í&""½½½hooÇÚµkg|½­­Í}©Ûúõë…ã°°0w%åôä%ûSÞ™GyßùÎw’’¸|ù2~ó›ßॗ^Â/ùK…£Ó®cRÅצ5ሰ˜І â3ðiÏe÷qEG=žÝôE#"oìȈ‚Ù¨w÷ä²;\8Ñ8€½Yå«ZGzpmTü Îþ”Ú"O&.ÌŽæ,…tzl‹OÃáëžÖI•õøÜª­ FEÞ(ÎŽÆkï{ÞÇ4´ {hqá·¸Šü•>Æl6Ϻ~3I `έz= lÕ`óæÍøè£ð»ßýÏ=÷ÜŒ¯¿óÎ;îóH]ä„ãùóçÝÛ½ÃÂÂf$.oºÙŸ’ Ë…yöÙgqñâE÷ÿ¾999 Äw¿û]|õ«_U8:í’ûrçD+ @aR6þ¥æ€û¸e¸ ×Çúbáë¢ÁlYª†~÷ZYm/•>LÞö†ôˆÙwËúLÙ8!·?aŸfE$d ‰ÊªÎF8].¡÷!©×¦5 6ax| àrÝhƒòå|þ^¤™˜¨ô1»wï†ÍfÃÁƒñꫯ _{æ™g`·Ûg¬?õÔS¸ï¾û8 \%¾øÅ/âØ±c8}ú4^|ñE<üðÃHIIÁõë×ñÎ;ïàôéÓÐëõØ»w¯Ò¡’DN8ÎÖ“òfòòV‰KòŽÉd¯~õ+<÷Üs¸pábbb——‡˜~ X¨Ž \ê·Óóš²²#W :0}žß+• xd]‚Q‘7Šs¢…DeiuVØù*y*qaB&t`BE+N5`lÂÓžA¯Ó¡€íOUœ”#LŽ¢nàr£RŠˆ¼a4èP‰g»Ýke5½LTÒ¬XB烼M:îÛ·IJ‰‹‹Ã3Ï<ƒàà`œ>}Ï>û,¾öµ¯áÙgŸu')N'^{í5ö©Ô yÀ-žŒŒ <üðÃØµk“”wèȱš2*ÔŒ¼•쵪$½N‡íñÂZ%§žjŠù¤Ò¡hŽÝá¶§Üö­ YÐëtpºnTŒNMà\ïl‰›9xÔG§»ñ³ôNe›{­¼¶ÿ×&*}M¥´í;7*…¢!ouN¢±mDXcŸfu(HÈÄ¿7–º«ûZ149†pþ|iBBdÒ-hîð´*­ée¢’f`¢Ò>|ï¿ÿ¾ûø©§žÂîÝ»ñàƒ*Ý ‹Å‚ï|ç;xþùçÑÚÚŠ^x¯¼òŠÒaù½›=*ù'r ‰æª˜üÑ~„æææY¿Fs;{y#VO_.(Ìâ45ˆ AFD2ꮻת:˜¨Ô’œh!Qy¼±6ͬŠõ%ò nûÖ–ÒÚ^¸¦íF 6aãj&RÔ`kÜ:ÍîŠe‡Ë‰SݱwÅ…#£ù*É‹•åu}øöçø>†DìQéöìÙƒÏ~ö³îc&)}CXXžþy¤¥¥qb»J=ôÐCÂy–VQQŽ=ªtš#÷åÊJ E\D€BѬPJxTt°?—–eGà÷´Q˜°9ðÉEö›ö%]Ö!\êÖò¸í[KÊjÄö'…YQ0ØþD  &lŽ“ZòƒR·âlqàù–! ŽM) ©³~bÏž=¸ÿþû±wï^&)}HXX~ðƒॗ^R:"Õ¹v톆†”CsähòRV~B¦p\?І+ÿkE¸Å„õ«ÄÅòÃÒ¶ŠŽ:¸à)Ç 3#/z¥‚‘7Nª„5¶?Q—é>(ÿÌ‘ºÝ… i»N*ëûoqù#nýö#÷Þ{¯Ò!ù4yëöl[¹çsyç½÷ÞŽ].®^½ŠýèG~?,ÌápàÀ„°°0lÙºÙÙ™·<¿ĆګìË¥f›c× Ô„‘)+ÀNt5áÁU[ŽŒæ«$7Ÿ^ö$—Ëjzñw§+-&¹º+?!kC´â|ËFmÂZQ6ïƒjR˜˜…—>õ¼÷»Yż.njE{ÿ’¢ŒŠÃÍ~yÓ±?¥¶”׉ÎÉ!üÙT™5añH¶D¡mÌS…WÑQÏD¥†eG ‰Ê›}auì°@ÿƒ÷ˆˆHÓl6ÛŒ?]]]øõ¯ÈÈH¥ÃS\xD8bbctÛsËkÅmßYQ0ùVAmäÄGUgƒ`&u[¿* ‘!faÛ¿}Ã…Þ+šô ‰ÐA7c›*©[©Ôþ„Û¾ÕInƒRÕÙ¨P$´;ób…ãîÁI4µ* ©?}‘Ïêëã‡ÿùr¹€Ê±GPI? ©Q‘”¨˜EôIà¤n½Yâ02é!iSe—˜,I‹HD\§EkÅÐØª¯ kÅÜö­Jò»Ó=1nŸT(òÖšø`¤ÆˆÐå‡äߘ¨œ‡ùl—£ååÍkb4²ÃÚxóšðõS­¼&­­­Ø¶m›ÒahÆõ=ºÅ7ùÅLTªR’% +CÅj„cœzª)%Rï׊º>جŠÕºŠö:á¸Û¾5¥¼®§çç0ÈlÀ¶tîÌP£íñé0ê=Yl;>‘Ú.ºIï1¹³€¦ÓƧM…EGGcllìö'Ò²‰ŽžÿÓM³Ù »Ý¾„Ñ·ÌfóíOšv._?uñæõ[lóí9ér¹P^^›Ívû“ Pß-¾%XŒÔØÛo'e%f£u¤Ì}\ÕÙ€¿ÌáÐ<­(ÉNw£’F¬v|zy[Ó˜ѪÉQÔ \Ö¸í[[Ê¤Š®™l¢V!¦@lŒY…ÓÝž~¿U (IÊQ0*òFIn4þ£Ìó;óTóÆ&ì°2EELTÎKRRúúú˜¬T ‹Å‚¤¤¤yŸ›ÍÆd—JFÍ?ùÁ×O]¼}ýÛÏ~ö³yŸ›‘‘_ýêWK €?ü@ww7 ðÍo~·oº?ßëúý¢±Ç ïd_.UËOÈÀoš<‰Ês½-™²"ÔÄä²Ä… 39õ×GÜkåu}LTjXUg£Ð+6ÈhƦ˜5 FDÞp¹fVtçpÛ·šå'd ‰Ê î,ДüÌ(˜ŒzLÙ€)»'°gCìm®$ÀGDó”––Æ-à*`±X––æõu!!!šÙ®êËŒF#BBB¼¾Ž¯Ÿ:,ôõ[LÍÍÍóþóþûïcÏž=KË /¼€Gy“““HNNÆ‹/¾ˆÏ~ö³½u3ðù^·Ðï¿£v\ßðšºm‹OG Áä>v¸œ8ÙÕ¬`Dä-yHGy ·½iY¥”$¹;. fß»hECÛº‡Äö'|`§n…‰ÙÂqëH®²Ï¡V„q×Úa­¼Ž÷Aº‰Êy D^^RSS™°T€ÅbAjj*òòòTMd0Žàà`&¼`4Œððp †Û_ á맬;}ý|Ñ… ðüóÏã­·ÞÂ믿ŽW^y}ôΜ9ƒ×_ýޝ[è÷_¨Êú~8]:÷±É¨ÇÝìË¥j6Ç®ÖäD ©›ü0 ºu½ÃlW¡E.¸p¼«IX“‡}º•V‹ ®1AX¬P44Y‘Ɉ•†UUv4( -DQ¶8XîÈ……"!µá'~/%%%yµí˜Ô%((HÑm«tgøúÑ­8ŽY[,úßõÚk¯á®»îÂ<à^ËÉÉÁ—¿üeüë¿þ+ž~úé;ºn¡ß¡ä'Øw§G²Gä'd ªÓó¡ìXGÝ-Î&µÙº.!FŒNÜø½åt¹PQ߇/ܨpdä­†6ôX‡„5ÒÑù>¸3Õ”j§ƒÛãÓñç+Ÿ¸×*:êñ•´B£"oìÌÅËïy† ]ëµ¢µ{+ùÀï±¢’ˆˆ4­»»>ø ÂÃÃ*ü ¿ý7X€“'ObïÞ½3Ö?ó™ÏàÚµkèïï¿£ëúýªBîË•ÍmßZ 'B:ÇÑ2Ü¥P4ä-“Qíbåry ·-j‘Ü/5$+B˜èÒŠñIÎ\ÖJrøúiAa¢8°êdwlöµ×Šì¡ˆ‹ Ê8ý›ÀD%iܳÏ>‹––¼ñÆ€ßÿþ÷xóÍ7?ÿùÏ—äï¼~ý:gV=ݬ¸¿~ýú]·Ðï¿—»Æqµ×*¬É½óHÖ…'"!XìïÄaÚ"'CÊjû„,¤ Ó+›™½óHݪúaûŸÀìHò2¡×yZ×Xí6œëmQ0"ò†Nf‰ÇËøÀŽÀD%iÜáÇñüóÏcÿþýÈÉÉAII ¾öµ¯áw¿û;y¹˜ìv;FGGgÝR_ðu ýþ UZ-öŠ‹@z’²C“hþòÄj’ÊNöçÒy{i߈ u×Fæ8›ÔhljŸJ‰‘ü„ …¢¡…(«#[þ§-©_d@²"Wk¼j‹üpüx£øà€ü‘¦ŒŒ !!‡Ë—/cÓ¦MHHHÀùóçýï3ˆEW×Ì-¶ÝÝÝ€+VÌøÚ|¯[è÷ŸÍÔÔ^üÇWf¬ï¹§ÑÑ7˜:¥à©FX1C˜×÷'å…Ú&„ã“øàà0-ã³èÑÑQ|tÿf*.Ä€îQÏñ/Þ­Âg²ü£ª²¿¿•å0™L·?Y¥j¦º`w:ÜÇè1ZsÕ\S0*ß722 £Ñ„¦Æ;OJ}xJ˜hìåï4 I¶šP;íø@Ó)ätÎæ°Z­°Û§ÐÝÍV)jà˜t0àæ]o|Ò×ß>ˆÌ8EÚ•ÝnÇððð¼?Ü»ïþ%ŽÈw1QIDDš¶jÕ*455¡°°………xë­·°~ýz¼ýöÛˆˆˆ¸ý7X€ÔÔTÔÔÔÌXojj‚Ùlv'NzÝB¿¿Ìh4âÁÏ߸8ñÝ^FF,  Ù~ ǯ^víëŸY?c #©×æ)+~óÁ8\7ª¦à„%+;âÓ—-†ÿþàO(Ù¹{Ùþ>_³¯ç"þ½¬Í}Ü6‰’ŒhùTT”#/oÃ’õ^•çÞ¦%šïŠ]ƒ½…3{ Ó⪩¹€°°¤¦¦ÞÑ÷ií±¢ç÷§„µGÜŠÌdî,Њð¾5ø¨ügîãDz·oAl`جç_»zCCƒÈÍ[¿\!Òm¼yá,ª[=» †Ì«P²s‚ÍnxxçÏŠ¢¢¥CñyLT‘¦}îsŸs'õ}ôQlÛ¶ ¿üå/1::Š_|qIþ·zßÿþ÷100€ÈHO«ßþö·Ø¿? Ã]·Ðï/ÓétÈÍÍÁÚµs¿ÙûËûÖbÊ¡ÃÁMø??³÷lâÄa- @^ôJ¡'×'ý—°35oÙbÐét³¶* ùÙµ>NHT~Ú2 ›Ó€Ð ß›®×ëa6›5ýïçdw³p\˜”­éÿ­0 0™Œwü¿õñ&±ª.."ëWGcZÛCR¹-‰i3cØv£-Ž .œîoÁVo›õ|“ɃÁÀŸSÙ½>NHTVÔ໨ïõ1›ÍÐëõü·³ Ø£’ˆˆ4í¯ÿú¯ñÿønT"ž8q?üáqðàAüÍßüÍ’üßøÆ7`±X°ÿ~\¿~cccøÞ÷¾‡S§NáÛßþ¶û¼ï}ï{øüç?»ÝîÕuó=o1 :ü¿®ÁãÛ¬x¤0yQ¿7-©OeE;êhÉöŒ(˜ž·äv‡ U ý FDóÕ2Ü…ëcâ„Ú¢$ÒÑyÂpq6“”ZcÐéqw\š°VÉÁršR”-ÔilEÇÀÄg“?`¢’ˆˆ4åþápéÒ%÷qxx8‚‚‚ÜÇ«V­Â·¾õ-ìÚµkÉbˆŒŒDii):;;±fÍÄÅÅá7ÞÀ|€õë=[‰8€?þCCC^]7ßóˆ  1K8¾4܉Žñ…¢!o°-]œ0,÷ u’‡vÄ…c]øüZsòlv'N6‰¿+åÁ¤ ò}°²³ÁÝ…ÔoÓšpDXÄ^ÅÇêúæ8›ü•DD¤)?ÿùÏ‘••…‚‚¼öÚkèèèP$ŽôôtTWWãòåË8wîZ[[Q\\,œsèÐ!477#::Ú«ë¼9(7*Qb?µÊN=Õ’b©šäè&*µ@NT&fA–ãiÅɦŒMØÝǽ…YìѬEr%ó°mµýh¥½ù™âÏ^Y ïƒþŒ‰J""Ò”+W®àèѣضm^yå¬^½÷ß?~ýë_»+—SJJ ÒÒÒfýZhh(’’’¼¾n!ç‘ÿÒët¸;NžÃmoÚ"Wqu LàRç˜BÑÐ|L:¦pºû¢°V˜˜9ÇÙ¤FåÒ¶ïõ«ÂbV(ºñAáX&V3WtÔ) -„|¬¨ï‡ÃéšãlòuLT‘¦èt:àÕW_EKK :„ôôt|÷»ßEJJ öïß÷Þ{ìmCþCÞöv¼«v§C¡hÈ[É!HŒ ÖJYM¢j§»/Âj·¹ :=¶K HÝÊ¥ Üö­m…Iâ}°ª³Q¡Hh!Jrb„þ°CcS8ß²ü¤¾?Npíííp8øæˆh9 cåÊ•Kò½õz=ŠŠŠPTT„W_}ÇŽÃïÿ{<ùä“Cqq1þë¿þkIþn"5)LÈ„:¸p£ú`tjÕ}­Ø;÷ÄwR—âœhüg…gú÷±Ú>|㞥ùÝIwNÞö½á…¢!ouL¢©}TX“[0¶äÇgâ× GÝÇÕ}­œC.5!!2éI!hlóü\–×õaóÚ£"¥øe¢2)) .ˈ‰ˆ–Ãààà²ü=z½………p¹\p8øÅ/~,ËßM¤´˜ 0¤E$¢i°Ý½VÙÕÈD¥†”䯉Êãý°Ú2ŒŠæ"÷-Hà¶o-)­éÅôƒá6¬W. ºc[âÖ"ÈhvW:;\Nœìn¾›ŽŒæ«$7FHT–ÖôâÛ®U0"R ·~‘¦Ùív>|õW…ÔÔTÜ{ï½8þ<~ô£áêÕ«J‡G´l ¥íßíìÏ¥%…YQ0<ûÞ&§œ8ÕÄéíjÔeÂ¥áNaMn¿@êV&mû.ÊŽ†AÏAHZ`0aKÜ:a­‚ƒå4E®j¾Ð2Œ¾Ûg“/c¢’ˆˆ4Çn·ãСCxüñDZbÅ Üÿý(//ÇO<††TVVâÉ'ŸDBBÂí¿‘+ºê®¡obD¡hÈ[aÁ&lX%Vt•×õÍq6)©¼½V8° 'j…BÑ·NŽ7ô k%9Üöí äû`EG½»% ©ß¶ôHX=›~.ª¤ŸUòLT‘¦<öØcHIIÁ<€ƒâÑGÅ©S§P]]¿û»¿Ãš5ÜêJþisìÜÇN— 'ºšŒˆ¼U,%KÊ8PG•*;ê…ã‚ø tüX¥Ÿ^ÂàØ”ûX§Šs8HÇÈ; z¬ChìP(ò–Ù¨ÇÝé‘Âïƒþ‰wT""Ò”?ýéOøÒ—¾„?þ—/_Æ~ðlܸQé°TÉn·ã·o½ƒzå'8{æœÒáÐ3éØ&m{“*¤n;¥©Ã;Æp­×ªP44‡Ë‰SÝÍ·}kKy­X©œ‘Šøˆ€9Î&-Y‡‹øÀ§‚÷AM‘Ø•×öãEü_Ó!""íºvíL&“Òah‚ÑhÄW¾ú0Ö®e•©¿(HÌBé´m©U]pÁØ{M òV…!&ÌŒÞaOO®cu}øjqŠ‚QÑtçz[0ló$uÐ!?‘ƒt´D®Ð’¶å'fâw+ÝÇU øzÖ#"oÈ?ÝC“hhAVJ¨B‘XQIDDšÂ$%ÑÜŠ“r„ã^ë0Úç8›ÔF¯Ó!?3JX+ç¶7U©ê‡sdD&!60L¡hÈ[ý#6T· kri›¼ýûLÏeŒÛ'І¼µ*.©±AÂZi5ïƒþ†‰J""""‘l‰Âб¡¢ƒÓ¿µ¤Dê•WÙлƒûÞÔ☴´01[¡Hh!ŽÕ÷Ã9mip€[ÖE(-¶»ãÒ`Ò{6ŽN9í8Õ}QÁˆÈ[%RU%Ëù&*‰ˆˆˆ|ˆ\MRÙÙ¨P$´E9ÑÐMÛ©?bµãÌ¥Aå"·ÉQ4 \Ö 2ІBÞö½## f#?û’ÿŸ½;‹âÎöÇÿ®Þhh ¥¡ÙDÄ\AYÔ˜í17 ILb2ɘåfœä7K4¹ùÎ$7÷N–1ÎuÆL2É÷Ž“eîI4Q“Œ_cD‘ÅeWd§Ù—úýÁPPH7Õçõ<`‹2%ÑFOoõ¤ÝnÃ0`2™ ÀeYª®$dœY,´¶¶ÂËËËåª+£££ñ·¿ý wß}7~ÿûßzNww÷8GEˆøæL †^íS·–U]Œ s¨‚H*’£}ñc^=wœYÔ;ËBFσDq¢¶„wœ(èG\Û‰’&Xm}¯)2,Ÿë#bDd¬%Ì…Œa¸XFk7r W¥È‘G0LO”¯OTsk™…xju¨ˆQ‘ñB‰J°, «ÕÊ%){«þ1eʨÕj±CœpL&`ùA‡ IDATZZZP[[ ¹\”¬$DdíííÐjµP(\ã¡Ãl6ã½÷ÞÃïÿ{àÛo¿ÅÒ¥KÅ‹—À€ÁŠ ìçm{+Á†9´íM*’£õúªøšÚ»Qp½óüŠj’ê°˜p¡ño-A0U˜¸¶Œþ´ï¥á>Ш]ãù SÜ4ˆÒ…"¿ñ:·v¢¶©Ú£"ÎHŽöã%*O–4Ál±ÃMIƒ':ú £·R²³³“KR*•JDDD 00’”cD­V#00P*•Ü÷ž*X WWW—Ø!¾ûî;ÌŸ?o¿ý6^~ùeäååᮻ¯ï€7B&+á¶·3õå´íMBB|Õ˜ÀïÅEÓ¿Åqª® V»;VÉXâ.bDÄYY‚‰ÁÂUdb¼Êª¦~ÍR’4ÏrY_’±Û†³åÍ7¹™((Qé³Ù ³Ù »Ý«Õа°0JP޵Z°°0X­V.YIÅb}+õwÜ|qqqÈÏÏÇ+¯¼âr[Ò]…Ífþ½ß᣿ìÄ…¼|±Ã!ã,!`.äLßS½ÞmoD:Rbø[õ3‹‡8“Œ¥ã‚þ”‹õ³á® Ç©¸R×… ƒ‘·–í'R4d<­ä÷k.o­Aƒ¹}ˆ³‰«Ñj”ˆì" ÇÁÉ•7Ñ[µg6›Á²,·Ý›’”ã«·º²wÀNo²’ª*'‡êêêáO"ãJìDeMM ~øá|ñÅ 5W'—Ëqÿÿ‚ç7=ƒ i«Ód£uÓ`žnoMØg¸¶DÁ°óWZÐÖe)šÉ+[¨¤mßÒr,Ÿ?HÌŠæ{Š O1¾Ó¡uÓðÖòZ+DІŒ„ðEÚY09P¢Ò½Õ|,ËÂLJš.‹ÁÇLJ—¤$„ˆGì àçÎÃêÕ«E© moÒ?×j•œ;¶ÚX/¡moãér[-jºøßó•4HGR²X)Q~ v÷“ƒœ‘a™ MùÖëCœM\Q’à»ÒªT7™DІŒJT£wNo’Œª)Å¡V«yÓÖ !â±Ùlß4†”JšÖHˆ£„ÛÞ.µÖ¢ÞØ*R4ÄYj•KÃù/’g4 q6 'jøUÈîZÌÖŠ q–ÙbÇ©R~¢9™¶}O*‰‚ìη^‡ô÷¤T,˜¡Å ÿ¹¿ðÅ2ñP¢rƒ m¡™¸ûYÐÏ„BZŒïtx«ú²°`ôÛ#®-Y0ôC8½˜Œ­lA»ª¦”–ÓeM0v÷½À*—1X©1"2ÞVE‚A_ m‡ÕŒËFÚ>,rƒ•‚ªÊc´ý{£D¥¤ž«­­Emm­Øaܲþ?©þ,¹ƒÁƒx !£GÎȰ<`o-»†úTJI’ ú«¦Ù„òšN‘¢™\L6 ÎÕ_â­%S¢RJ2 ù‰ýØ™Zh5´3c2ñw×b–  :¿“zàKI’à»ãÅM°Ú(0‘Q¢ÒAb%Æ>ûì3,^¼‹/FVVÖ°ç=z‹/Æÿ÷ºººššŠ|&Ó­÷r0™Lèèè­Wäxþž{î9¤¦¦ùöùçŸ[,C9xð 6mÚ„Ÿþô§øôÓOÅgBؼy3RSSqþüùA?žÔÔT¼ùæ›·ôyN:…ÔÔTìÞ½`4ñâ‹/âÅ_äý_¥Ÿ1!äV ûTž¬+…¥žÏR¤A°Žßz(#Ÿ¶‡3ue0Ùú†É–„ßäÄÕodrnÿ¾ØY)R$d$„}eÛº,¸pÚØLd”¨tq?þø#÷~zzºÓ·W«Õ˜={6fÏž •JuËñüîw¿CJJ .]º4üɇøøxÄÇÇC¯×¢¢¢¸µiÓ¦ scëìٳعs' –-[†àà`Qã™höìÙ3èúÞ½{Çäó¹¹¹!44¡¡¡ÜÿUúBFƒpÛ[[w šhê©”$Gñ«*3‹šDŠdr9Q[Ê;ŽÕÏ€—Ò]¤hˆ³jšM¸$¨>N‰Ö‹ S‚ _ós#šL"ECœå?Å s§zñÖ2 © ÊD¦;2´7n ´´©©©øá‡‘‘›Í¹\>üÿI&“á³Ï>Ã('®çŸž{ÿý÷ßGzz:Ö¯_¨¨(£êSPP 'ÎyóhÒh+--E~~>bbb¸µsçÎáúõ±™(“ɰuëVÞýŒ !£!À]‹YÚ\jíks¼¦ |ÃÄ Š8%)Ú_dõUõöÝsW9þœ8/«¦ˆw,Lv×vô"¿òXç¥Bôt¯!Î&ÙbÿYðP¸¡ËjØY§ëËpWhœÈ‘G%Gù¢¤²;>V`À¯þe–ˆ‘±D‰JvøðaÀš5kÐÒÒ‚#GŽ 77K–,áÎéêêÂöíÛ‘™™ hµÚ÷“””•J…´´4455áöÛoGLL >ùäÀöíÛ±k×.ü×ý’““‘••…;wâêÕ«Ðh4˜1c~ÿûßcëÖ­8tèà±Çƒ\.ÇéÓ§Çá;áÚ6lØ€øøxøûû#-- þþþxùå—±{÷näå塱±Z­ xôÑG¹‰Å6lÀÊ•+¡V«qúôiX,Ü~ûíX¿~=wßçÎÃîÝ»QYY „„„`óæÍxÿý÷qæÌÀk¯½xã7…}ûö!33ƒ!!!X¿~=ââânï›o¾ÉÅ£R©púôiØívÜu×]ˆÇßþö7”••ÁÏÏÏ=÷"#ùÛ'&"…B¯¿þš—¨Ü·oÜÝÝa4yçÚíöa¿ïF£Ÿ~ú)rrr V«áå5ð‰ò†  R©ðÉ'Ÿ`ëÖ­~Æ~~~0 xóÍ7¹ŸÁÎ;qðàAüçþ§Ë$Ñ !®geÐ>,ËâÛo¿Å×_Í»]ZZΜ9ƒÀÀ@´µµa÷îÝ8wî ¡¡ï¾û.êëëqûí·céÒ¥P«ÕÐh4X¹r%w±±±X¿~=°sçNìÚµ r¹±±±¸zõ*Þzë-ß4Þþñäää ((­­­Øµk×3Q§Ó¡¢¢Û·o‡Õj»o¦‹X³f ¸ï]qq1Š‹‹qß}÷ 8בïûŽ;––„††¢¼¼ü¦Ÿ°ŸqïÚÅ‹¹?ÞÞÞ“"yL¹„À¹¼ã‚¦ ´˜i ‹Tx¹+;s o-«ˆ¶½¥¬j~5¥Ÿ»7"|¦Š q–ÕÆâd)¿EBR%ö'3aEtvm XÐ@©XÎÎβ8QBmP&*ª¨tQ×®]Cyy9Ö®] …B+V@&“!==[¶lÃ0¨¨¨@FFñÙgŸA¡Pàø¾üòË[ú¼V«±±±xá… Pô]"«W¯ÆwÜC‡á¹çžÃœ9snrO“Oÿ*7øè£¸÷ëêêðóŸÿçÏŸÇ£>Ê»Ý{ï½¥R‰o¾ù»víBaa!-Z„ªª*X­VÌ›7?þ8oËÿŠ+P\\Œƒbýúõ‡Á`ÀáÇ1mÚ4lÛ¶ r¹iiiøðñÿþ‰,a¼Âx¾üòKìÙ³K—.Å+¯¼øÅ/~ÊÊJTWW#44tT¾o®êÞ{ïÅ‘#Gðõ×_ãµ×^ÃÞ½{áëë‹ÄÄD|ñÅÜyŽ|ßkjjpöìYèõzlݺr¹ü180äçìgÜÐЀýû÷ãÂ… X¿~=jkkQ[[‹Ûo¿2½îDÚbýl¸+T0Z»6ÖŽSue¸34VäȈ£’æùâly3w|,¿¯¯Ÿ{“[[‘-Øö½"0‚×땸¶œKÍh7ö½°.c$ΣA:“Ybp$ÞÉí;6ÛPÚ\M/@H„R!Ãò9>8Ò¯¥CF¡ÿ²4ð&·"REÙº¨Þm߇Æ+¯¼‚wÞyv» ÈÏÏ\½z°téR.¡Ø«éHDDDÀÛÛGÅš5kðꫯ¢¬¬ì–îs2P©T’~—.]ÂŽ;ð³Ÿý ›7o˲hooçãííÍmïMü¶µµfΜ OOOœ:u O>ù$¶oߎk×® CEEìv;bcc¹¤fo^e%²Ý`ñ ã ï™jéããÃ}¼wMøuLDz½‰‰‰ÈËËCZZrss±nÝ:îûÓË‘ï{ï¿óçÏçÎIÏI½^ððp”——Ãh4"7·çÙVBBÂȾHBȤ¡’+°ÄŸ?­øxMñgW”ͯ»R×… ƒqˆ³É­°Ø­8SϹ"ˆv.HI†`ÐFÌtoÚ":É…zê1Í“ÿ{ôx-=J‰ðq0«°,ÅNH”¨tQ½‰J8räŽ9Â÷nÿ¶X,FãôýÛíöA×}||ðÕW_á‰'ž€>ŒÇEEEƒžOz¨ÕjÞq}}=^ýu\¹r›6mŸÿüçaïCXçíí?þñ¸÷Þ{¡ÕjqüøqlÙ²eȉë&“ `³Ù¸µîîn0 77·›Æ;˜Á†693Èi"¸ÿþû!“Éðá‡B£Ñ`íÚµÎqäûÞûÕÝýÖ'…ÆÇÇÃn·£  çÏŸ‡—— Ú!C²ÙlØ·÷;|ô—¸—/v8DdÂíß´íMZ¢§{ H´dDŠfb;×p…ºôTã-÷§DRr,ŸÿC˜à “ÓŠ þöïãµ%"EBFBØ—¹¾ÕŒ¢¿€f2¢D¥ ºrå ®\¹‚¸¸8äääpo»wï=z0}útÀñãÇÑÝݳ•«¤äæ¿l{%W®\ánsùòeÞ9z½¿øÅ/°ÿ~<ùä“°ÛíÈÉÉ®rs2TÔÝŠ’’˜ÍfÄÅÅ!&&†œÒ?™åN‡Ÿüä'øàƒpÿý÷s ªÁ„„„rrr¸ÄXnn.X–åõ¡$Ž›:u*–.] ¸óÎ;M4:ò}Ÿ:µgKɹsç¸sz+¢Õ[=™““ƒÂÂB,[¶lÒ%‰ãär9îà_ðü¦g°`aÌð7 ÚJAEXƒ±•7`‡¸¶Á¶® ‡…Ñ!¬6ŽÑM‡Ní)R4ÄYõ­f”TñÿVIަmßdàã`nÃtXL"ECœ5ÍÏÓý=xkô‚Ý„D=*]Ð?þÜ^3gÎDpp0ªªªPVV†9sæ`áÂ…ÈËËÃO>>Üda 'iù›ßüK–,F£á*9gÏž  oëïöíÛ‘˜˜ˆ7B¥¢mB¾¾=O†ÒÒÒ`µZ¹¡*Î$”***ð§?ý 111pwwÇÉ“'ô%¨…BCC‡ÜÜ\lÙ²3fÌÀ™3g T*ñàƒÞâW4ymܸ«W¯FDDÄ wäû>}útDFF¢¸¸/¿ü2¦M›†ãÇ(žÞíßiiihÛ7!Äqa^þÑø¢²³/¹•U]„pmˆQg$Eùaß©îøDI,V;” ª=MY‚D%mû––Œo;¨V£Ä‚0­x—±Ì”29,öžâ«Ý†³õ—°jj´È‘G%Gùâïõ]Üqfa#6Ý5CĈÈX g5.¨wÛ·0Q ‰‰‰úª*ß}÷]¤¤¤ ¾¾•••x÷Ýw¡×ëozÿÿñÿ¨¨(TWWÃf³á7¿ù ÷1‹ÅN‡~øÿûß!“ɰyóf.òðÃãî»ïFUUöïß? “ôˆŠŠBjj* 2331cÆ §JV«Z­™™™Ø¿?†ÁÓO?ØØ¡üú׿ÆwÜÁõ/œ3gÞyçßê—4iùúúbÑ¢E7m±àÈ÷}óæÍXºt)QWW‡-[¶@§Ó(¦øøx€§§'¢£é‰!Äq ‚mo'hÛ›¤$EùBÆô té0Yqîr‹ˆMÎô[ïýW6Èqÿsdýn×{Üû&ÿ翊¾ßû¯Ö`0œ`‡éºÚûñÞ6V«‹K–,æKs-&“ ÉÉÉ Ä·ß~+v8·äìÙ³P*•P(Éd\OG†¡'Yuu5%ZrssñÖ[oaÕªUxá…D‰¡·jØ---CV“±µå¥ÿƒç7=ƒY³fÞô<–eñÝ·ûpï}ŒSdD,G«òñÿeí䎕2Ž?ð6<n7¹ÕÍíß÷5*÷ÇË=ožBþõ6îxÓ]3ðòá7¹…ëJO?‚ØØE˜2eŠØ¡p¾¹rÿ~æKîXë¦Aæ}oBÎP}‡+ÉËËÅ”)> ãWRÙì,ýúZ:-ÜÚ»OEáá4Ù™ôØ~âk|\‘Åktøñž1"âŒ.³ ™ŽnkßÌÿþùBܾÐÌ?wkk+Î;‹Õ«oóÏÕŸJ¥JÐ ÀÀÚï_û?ß·÷{cû½õ£ß1ú­ Ù~ï÷7\CóQoxN¸\nn.l6U]2œ:u ¸þ™„â¨eþáPÈúÚXìVœ­|HqMÂjaõ¹5ÙÕ‚mßs)I)!yW[yIJ†’£hé7…ÿâyug®·7ˆ q–‡›KÂ}xkÔ¯yâ¡GÝ ¬££o¿ý6Ôj56nÜ(v8„Q`µZqêÔ)¨T*,X°@ìp!£Qªëǯ@¢íßÒ’ůh/®lG}‹yˆ³‰3l¬§ëËxkÔŸRZ„ ‹ˆ©^˜2òŠq2ñ„yøÂGΙUS$R4d$„ƒ”hžh(Q9¹»»#$$;vìÀ¬Y³Ä‡2 Ο?ÎÎNÌŸ?nnôÄ›⼄@~¿½¬jêÏ%%q3§À˽o&ËYETM2ò WÑÖmäŽ0Hœ+bDÄY‚ 㔪¦$| Ì×ð[œ¨-)2É‚Dee£ W꺆8›H%*Ð;©™a˜L&‘£qœ\.ÇG}„E‹‰Ê-3™L¼^”Ô—’LVK–,Á7ß|ƒW_}U´œ™^Oq= ±ŠŽÜè íÃR¡3XÁÆ–QH?¿Ñ ¬.Žð™ ½;M‹–Цön^ÿV``Bƒˆ$*ÏÔ•Ád³ q6q5!^òQóÖŽåSUåDB‰Êa0 …B†aÀ0 šššÄiRjjjâ~„q)ŠáO"„¸¬ÈA’/Çkhû·”$ úTf5Á>Ì H2¼¬jþöÏÄ y"EBF"³¨‘÷ÿ@£V n–ë j"®c¾g0¯÷¬ÉfAnÃe#"ÎJœÇ‚vL,”¨t€Z­æ’d•••’ªªœL&*++¹ŸAï´o29ÐÄo×£R©Är 0X0‡·–]CÛ¿¥duŒžwÜÜÑükmCœMÑdê@IKoMØ&¸6á¶ï:¨ôwÈC¦B´.”·FÛ¿¥E8Xîdi3LÝ6‘¢!£~s¡åžJ¥‚J¥â’dåå唬'&“ åååÉd¼ŠJá¿„ñ¡T*)QIȰ2ˆŸ€9]_†n›U¤hˆ³}Ü0;HÃ[£éß·&»¶˜Wç©Tc¡_˜x§ØYv@EUr4mû&C¶Aɦ:’²2R¹¬/`ê¶áLy³ˆ‘ÑD‰Êaô&Â4 är9d2L&òòòPUUE Ë1b2™PUU…¼¼<˜L&Èd2ÈårÚþMˆÈ<<<Ä8©µ¥†Œ]ÆáO&“FB`dýOÖn\h¼*bDÄYÂj’ÌBÚöv+Ž ªŠ—ÌBF=™¥¢àz; mݼµÄ(¤C†¶Bð‚Ý¥ÖZÔtQ¢K*´%Ìà·±É,¢6}5sÃ0P©TÐjµhmmåÖ*++qãÆ K}FMÿjI…B™LÆýÛ[YI^^^ÔŸRbl6Nœ8‚‚b,^‡yóh#éáãæ‰Ÿ5Ýà֎זb‰¸ˆQg$ÍóÅß_çŽó®¶¢¥Ó‚)¥ˆQI“eqª®Œ·¶’úSJʱþ ÙA„ú¹‹ ‘‚h](¦¸iÐbîäÖNÔ– uf¼ˆQg$ÍóEîåî8#¿¿}hÎMnA¤‚þâ¼ †aÀ²,—sssƒÚÛÛa6›!“É`·ÛÁ²,%*GQÿ^” Ãp•¬Â$%%, J¥”¤” ¹\Ž»î¾³fÍ;₃"y‰Êìš"ürþ:#"ÎX>Ww•Æöä²ÙYœ(iÂÝ‹DŽLz š*Ðhjç­ «­ˆkV +Ž ’32,˜ƒ*ÎskÙ5Å”¨””h?üéû¾!Hå5¨n2!X§¾É­ˆÐ_êMœ)•JøøøÀl6Ãd2Áb±Àf£¦­c¡²RØ£’2¶är9 ×£—2ñ$FàÿþÈ—6W£ÁØ:`"8qMnJ–Íñáõ¦Ì(0P¢r„½éfkäá#R4ÄYm]ä]må­%GQJ2¼A‘¼DåÉÚRXí6jû ógxÃ×K…Æö¾¶…<š"bTd4P¢r½U•½ïËd2°, µZ µZMÕ”cD88G˜¤¤„%!„rkúÍ€—Òí–žþ¥,Xœ¨-Ž3–ŠqTb”//Qy¬À–èi’s„Ó~iÛ·´d7Ájëû{L­’ci8%šÉð#Á€‹žë§ÃbB~ãuÄêi'ŠÈ :|¶–[Ë, DåD@Ãt Lõ&,ém|Þ(II!„Œ>9#ò~OJá@âÚRÛ[ëZÌ(«î)ijëîB~ãuÞÚŠ@Úö-%Çòùïãçê VQEžŸ»7§ñ֎וq6qEÂ6Â.ˆ4QE¥ƒ„••¸þ•”8;Âï-}¯ !®ª¡¡ƒý®bY×®]C{{;ÂÃÃáîÎoú_SSƒòòò·óôôD\\ܨÅM&·A‘H«¼ÈŸ¬+ƒeyÁ‰ëšØ30¤Â`äÖ2 ˜;ÕSĨ¤åxm l¬;vW¨°H?KĈˆ3X¶g«gI´í›8aeP$ÊZª¹ãìê"¼}—ˆg$Eù‚az~@»ÑŠóWZ°„ªª%**0Xe½íÛPß{BqÕÕÕX¹r%BBB‹   8p`Èó»»»ñöÛoC¯×#""‹/Fpp0Þ{ï=ÞyûöíÃí·ßŽ|÷¶yóæ±þ’È$²2(’wÜlî@aS…HÑ‘X)HÊd5q&Œ°Šx©8TrªåŠÒªvÔµ˜yk«bhqÜÊ@þã`Qó 4™¨2]*üµnˆ˜êÅ[£ÇAé£Då –H#£¾Ï„Wg4‘””\¹rÕÕÕxøá‡ñÐCáÔ©SƒÞæäÉ“ÈÈÈÀÞ½{ÑÔÔ„ªª*<þøãؼy3222¸ó:::0wî\Ô××óÞŽ=:^_™‚<|0Ó›?|%›¶KJr?)sº¬&«HÑH Çý)iÚ·´¤ ¶}OósG˜¿‡HÑ)ŠÕÏ€‡Â;¶³,NÖ•ˆqVŠàʼnŒÃg© Då-»âp"¿Bˆ«ûßÿý_´´´à‹/¾ÀÔ©S¡Óé°cÇDGGcûöíƒÞ&99‡BRR4 ôz=vìØ   :tˆ;¯«« žž´}“Œ½¤à(Þ1%*¥eE¤ yßó&‹ÕŽS¥Í"F$½“îû£A:Ò"¬œ¢jJâ,¥L¥þ³ykÇk(Q)%Ióø; ®·ÃÐÖ=ÄÙD (QI!„ŒÐ®]»pï½÷òŠ Ãà±ÇÃ÷ßînÇž$Éd2èõzÞùÐh4£3!BÂíßùM×Ñhj)â,Oµ‹gó{qѶ7ÇdÕñŽC=õõ¤D—T˜,,Î]já­ +Œ qÄ Áã`vm1ì, d‘ŠÅ³§ÀSÝײÃβÈ.¦ÇA)£D%!„2BW¯^EDÄÀm‚111°Ùl¨®®äVµ··£¤¤‹/æÖ:;;QWW‡ýû÷ã‹/¾ÀéÓ§a³ÙF-vBz-ÒÏ„F©æŽí,‹µTM"%‰ót¼ãc´íÍ!ÇkùÕä=qm9W;Ñm턤RȰ|. Ð ÎK æWR7™:PÒR%R4ÄYÊAþïÓöoi£NÑ„BH?øË_þ2äÇCCC±~ýzØl6ÔÖÖB¯×8'  §ç_uu5†ýœ[·nEHHRSS¹µ®®.444`Û¶mhkkÃåË—1sæL|òÉ'X²d‰ó_!CPÊX0GúMÿΪ.Â=atIEJ´Ûö]⎯×w¡¢ÁˆP½»ˆQ¹¶¶n#Î7\å­­¤þ”’rúRïxI¸4júó–8/Dã‹PO=*:¸µìš"Ìó 1*⌔h?¤]èûùe5ÂβQK9I¢ß]VŒŽ IDATä„BH?ÝÝÝøñLJüø‚ °~ýzÈd2¨T*´·Ü"k6÷L 2eʰŸïÌ™3øóŸÿŒ¯¾ú J¥’[ÿôÓOyýz¯_¿Ž 6àá‡Faa!<<†`³ÙñÿþßðöâOC\ºl1´ZoÞšÅjAu5ULV1îÁ8‚¾DefunTÝ€œ~óÕj¥kGdS䀯—í}Ct¾=~ ©Ku7¹•øL&#êÑÕÕ9îŸ;£¡6¶¯ÏM¦@ˆMCײD´··ãÔ% omQ¨‚~~dXÍÍMhoïp­ÄzOã%*]¿ˆuS¢„7'.*BÏ"ghëFFîeÌ ½ì:;;a2þ=÷dC‰JB!¤>|xØó†ÁÔ©SÝÞ][[  ¹ù+ñ7nÜ@jj*~ûÛßâÎ;ïpÿýMŸ>;vì@||<Î;‡ÄÄÄacdY;®_¯€R¡ä­ «Ë§ßy,¬ jjÛªN&ž6 0`ÑÓ“«ÃjÂñ«îî?ìm-Vºv\Atý•$L3‰ÑðŒF#êëë V«‡?y”eÔðŽ#ÜÐ\ß0ÄÙÄÕ”Tµ£¡]Å[ ×™èwVkk L¦×ÊLð_À-h­Äåªkðñ¯3âšAZ9jZûÚ$έwÜè=¾˜ÍæA¯¡P¢rä(QI!„ŒÐÂ… qðàA¼óÎ;¼õ´´4Ì™3ÞÞÞCÜhhhÀºuëpÏ=÷`Ë–-}>ÿž¤QoÅæp žÿÙ3˜5kæMÏcYU••X´ˆ¶úNfsšN¡´_O®-ðHÌð×ÄŠëtí¸€lµÈ(뫊-ªµ#fÁ"¨®Û’¾­­ QQ1UŸ&;Ë¢äÛïxkë"â±(œ®c©Ø——  oë÷4?wܳz™xɸ~í*š››±06Ž·>ϺìËF·­ç;Xty!1d¾a’¸£¬Ÿ­àŽ/·¨GõùIkk+L&=ç®ûÌ…Bqq›6mBQQöìÙí]¿~_|ñ^|ñEÞÚ™3g¸cƒÁ€;î¸ øàƒ½ïÁ¶”üñÇÐh4¼¡;„Œ–$Á0Ìê¢!Î$®(1RÇëÅÕe¶!G0™ô(j¾ƒ©·Fƒt¤%·‚¿í{Íüý¢ q†»B…EúY¼µã4XNR’¢|yÇç.· Ýhâlâʨ¢’B¡ÄÄDlÚ´ 7nDZZüýýñùçŸ#>>O>ù$wÞ}÷݇ââbܸqJ¥wÜq*++ñä“Oâý÷ßçÝçÓO? £Ñˆ™3g"%%ÑÑÑpssÉ'••…O>ùdÜ«Èä°2(-êk{PÒ\…zc+üݵ"FE¥óR!fº7.\kåÖ2 ‘áÚ}*Å LÂÏôÀ4O?‘¢!Îjí´ ´–Ÿ¨LަŸ¹u 8Y[ÊgÑ v’¡ƒ›R³¥§ÿ°ÕÆâDI q-TQI!„Ü‚?ýéOøøãÁ²,®]»†W_}{öìáõ\{þùçñì³ÏÂÏÏUUUÐétX°`þñà»ï¾ã½™Íføúú";;111(//ÇÅ‹±xñbàá‡ñ«%ÙB¿кi¸c,²kŠEŒˆ8K˜¬9V`)×–UÃO>$ÓÀ )É,j„­oÔ*9–Ïõú„8(QPY]ÓÕŒ«mu"ECœå®’cI8ÿwAF!=JUTB!·è¡‡ÂC=4äÇÿõ_ÿ•{?**Ê¡a=111ˆ‰‰•øq„œ‘!!`.Värk™Õ…x`ær£"ÎHŠòÅ{ÿ¸Ì—Vµ£¾Õ ­›ˆQ¹–FS; ›*xk´í[ZÒóù‰‡„ÜUr‘¢!Élmܵ¨3öU¦gÕc†w€ˆQg$Gù"»¨‘;>–O‰J)¢ŠJB!„Hô©ÚQºPä7^çÖ²k‹±4 \Ĩˆ3ÖÌ×ã@N_Oµ¬â&t[íP)¨>ÁÆÚq²®Œ·Fý)¥%]Ðw5

Sáï®)â¬Æönä_oã­¥PJ2’ô©, vˆ³‰«زÙYdÑó)¡D¥ŒF#%ȸ³Z­0ŸO×)Î^—„é‰Ò…ÂOÍOteVÓ0)YÃOÞ¾P/R$®EX,ìEG\Û±|’› ‹gO1"2Q¥Læ7[QÜ\%R4ÄYnJ"ùýšRŸJI¡D¥º»©L˜ˆÃ™k®S2^èZ“–eQRRŠœœ\ÔÕQ¢‚8FÆ0HœË[Ë®-âl⊄Ûa+Œ¸Vß%R4®¡ÎØŠò–Þš°ÍqmGóù‰†Å3< ¤Þ«d LóôC¨'ÿ÷hfUHÑ‘¾`w¬À›ªb¥‚~³;€ªÔˆXœ¹öè:%ã…®5é`Y&£]]°ZèçF—(¨4;U[ “Í"R4ÄYQÓ¼0Å·väÂä®&ɬ.ämÝÔºiã;]Ĉˆ3lvÇ‹ù[7—ÍÖˆ ™ ’§òmeÖÐÎ)Y=_~íšÑÒiAÞÕVñ"N¡D%!„2AÉd2,Œ¤ä•˜,v8DBVF@Îô=M4Ù,È©¿$bDÄ ¬T“ä}*…Û¾W ®qâÚr.µ ¥³ïņ–Íò1"2Ñ ûT4UÀ`jâlâj‚|Ô˜ìÉ[£~ÍÒA΄B!„Ç[å~a¼µìÚþ-%Âíß§ËšÐnœœ•Õ»g‰vÚö--Ç ø †™~ øz*DІL‹ýgA£TsÇv–ʼnÚR#"ÎZ#xœì; ¤„•„B!d€•‚éßǨ?—¤¬Œô…ª_ÿ>«Åñ’É9õôlý%tZLܱŒa/èÃJ\›pFÜt¥H‘ÉB)S`yÀÞZFUágW$ÜYP\ÙŽê&ÓgWB‰ÊIÊjµâóÏ?dzÏ>‹gŸ}Ÿþ9¯ïœÅbÁÇŒŸüä'øÉO~‚?þ õ¦"„B&‹¤ ~®ÊÎF\o§j©ðp“cÙÞÚÑIZM"¬žï_µ—HÑgÕ6›QVÝÁ[[<]%R4d2Iæ?ž¨-Õn)⬸YSàãÉÿ]!¬Î&®‰•“Ôž={°wï^455¡©© {÷îÅž={¸ùå—8p຺ºÐÕÕ…àË/¿—Ø  ú"5©©©HMMññd@×6!DJæú#À]Ë[öù#®MXMr¬Àv=ͤ?%‘Ž#x×íáTQIÆ^bP$ôMdi·qÞpUĈˆ3ä2‰ót¼5au6qM”¨œ¤ÒÓÓo½õÞ|óMÞddd¶mÛ†wß}™™9ìýF|õÕWøå/‰G}7nÄo¼‹/6lØ€gžy榷ñÅñâ‹/Âdê+Ë>xð 6mÚ„Ÿþô§øôÓOa6›ÑÕÕv2>Ûžd6oÞŒÔÔTüñð±ßýîwHMMEKK‹‘ ¯ÿõ>ÔµM!®Š3`úwv-õ©”’ÛúóŽë[Í(¨˜\à «NTI×v¬€ÿóK‰öƒŒâdBF‘Þ]‹H]o-‹¦Kа_ó‰’&˜-v‘¢!Ž¢Då$e³õ”¬{xx@£ÑðÖú³Ûí'ív;¶nÝŠÝ»w£­­ ‘‘‘Ðh4(,,ô¾ãææ†ÐÐP„††B¥ê)Ó>{ö,vîÜ …BeË–!88ùË_ðÄOàúõëÝ/{ß|ó ^zé%<óÌ3xæ™gð«_ý ß|ó ïã7;Nvv6òóóG5æñ4صM!®N8pälý%tYÍ"ECœêçŽüÉÈ“­šDØSÎÏÝ{@⸮n«'Kšyk)‚JaBÆ’pû7õ©”–”h?Èû½²Ñe¶áTéäì×,%4*m’Z±b8€Í›7sk+W®äÞONNÆþýûñÊ+¯pkIII7½Ï+W® ??ÑÑÑxã7À0=¿Ìf3”JǶgÈd2lݺ•·VPÐÓ¼ÿùçŸÇ¼y=0Ò„«1›Íxÿý÷a6÷üûÁ 66–K„ß*†a°sçNlß¾r¹|Tîs< vmBˆ«[0J™{Oën›'kK±&d¾È‘G­Yà?^ãŽæð‹{f‰Ð8V?%ò·r×vº¬¦¾>úrƒ¤y¾¨¸\#bTd2I š‡ ~àŽ/·Õ¢ª³ S5º›ÜЏŠ)%bgj‘s©o^z¾ÉÑô‚‡+£Då$µaÃtww#-- °víZ<öØcÜÇyäX­VüãÿÜsÏ=xä‘GnzŸzVV«•KNº¹¹ñγX,øä“OpêÔ)Øl6¬]»ëׯçŦR©ðÉ'Ÿ`ëÖ­8sæ àµ×^Ì;¥¥¥€—^z r¹»wïñ÷‚ŒŽªª*˜Íf„††ÂÃÃ%%%¸|ù2æÏŸ£GâóÏ?Ã0xê©§xIqG¨T*$''ãðáÃøÇ?þ{ï½wÐóìv;öíÛ‡ÌÌL „„„`ýúõˆ‹‹ãÎÙ°aâããáïï´´4øûûãÍ7ßĆ °råJ¨T*œ>}v»wÝuâããñ·¿ý eeeðóóÃsÏ=‡ÈÈH´µµa÷îÝÈËËCcc#´Z-ð裙˜ïmÿðÃøë_ÿ:àœÇ{ ©©©0›ÍøüóÏqöìYtvvbÞ¼yظq#üýý¹gB¥‹ýgádm)·v¬º•²*Ú——¨Ì¿Ö††63ôÞnCßh‚貚q¦¾œ·FÛ¾¥EX¼`†:/*DЇL>ѺPøª½ÐhjçÖ2ª ðXøÍ‹xˆëH‰öã%*^lÀR¯bWF[¿')777<ÿüó`Y,ËâùçŸç%•J%âãã¾¾¾xê©§†­Š ‡››ÊËËñâ‹/âþçPYY9༎Žœ9shmmÅîÝ»qîܹAï³B+66ëׯçUv.]º=ôS_;õõõ€€€„††*++a0ðᇢ¥¥ÍÍÍøàƒÐÙÙ xõÕWñ›ßüÆ¡ûüñÇáííÝ»wsIqa[‚;wb×®]ËåˆÅÕ«WñÖ[o¡¸˜ßS-==_}õÔj5¸õ´´4äää ((­­­Øµk×SR§Ó¡¢¢Û·o‡Õj…J¥BNN–eñí·ßâ믿vèë ý÷Þ‹{ï½ëÖ­ÐS5Ú[5ü‡?üDXX–,Y‚óçÏãÝwߥ¾¬„q'Üö–Y];ý.’Œ¥á>ðrï«M°³,2 EŒhüœ¨-E·­¯O!“cyà#"Î:"˜T¿š¶}“q&c¬ Šä­eVSŸJ)Y³€ß§²Â`Ä¥šN‘¢!Ž ŠJ7¾œ’’âÐ}èt:¼úê«øì³ÏpõêUìß¿ß}÷ðôÓOÃÛÛ›;wÇŽP©Tøê«¯°{÷naÑ¢EîsÅŠ(..ÆÁƒ±~ýz„‡‡Š‹‹‘õë×óMD< =O$ýýý¸qã ìv;–/_Ž––®Ò2((eeeÐjµ7»[ާ§'žxâ |ðÁøì³Ïðë_ÿš÷qƒÁ€Ã‡cÚ´iضmär9ÒÒÒðá‡bÿþýˆŒä?ÁxóÍ7¬À{ï½¥R‰/¿ü{öìÁÒ¥K¹¿øÅ/PYY‰êêj„††â£>ânWWW‡Ÿÿüç8þ<}ôÑa¿žˆˆDDô¼’·wï^Àºuë‰k×®!77 ,à>·ÙlÆÉ“'Q[[‹   ‡¾g„2R¦Fã÷¹{¹ãFS; š*0ßwºˆQG)2¬ŒÔá`n=·väbL1ªñ‘QUÀ;^ê/¥»HÑg•Vu Â`ä­­]H;KÈøKŽÂ·WÏpÇgêËÑe5ÃC1ñ+Ó'‚È/LÕ©QÕÔ7ÐôèÅÌedôQE%’¯¯/RSSñðÃ;|›˜˜lÛ¶ ¿ýío‘””…Bììl|üñÇÜ9>>>Ü0‘¹sç該$ÒÖ[Q©×ëÒÓ¤¾¢¢.\,X°€WiyùòeÀÌ™3þ«V­Bdd$Ž?Ž‹/òª +**`·ÛËõ°ì­ÈVöªTªA“”ÞÞÞ\åpoRÜÇLJûxïZ{{ÏÖK—.aÇŽøÙÏ~†Í›7ƒeYîcŽª¨¨ÀW_}…©S§rízã½páRSS‘ššŠ“'O ÿ+Ä9v»yç/"3#U•Õb‡C$*Dã‹YÞ¼µÌjê-%©§ÙE°X'öÔS;Ë"K0¥>I0Åž¸¶´ õ¼ã`s§zŠ ™Ì# õõÈï¶Yq¦þ’ˆg% ª±æDŠ„8‚** 85}y8 à 66±±±X½z5Þxã  ^/Å¡(dp½•z½³fÍ‚R©DII €žŸs\\¬ÖžíW7nÜ@KKOŸY³oèÏ0 ž{î9lÞ¼;wîäUcšL=¯õŸ0ßÝÝ †aôIU«ÕÃ~®Á®Íþkõõõxýõס×ë±iÓ&L›6 O?ý´Ã_Ko¬ï¿ÿ>ìv;^|ñE.ïåå˜?>ž}öYÞmôzý€û!d( Ã`Š~z?¸{P¹ä©Q¸ÜV˧Wà…˜»EŒˆ8cUŒ2†á¶ì·­È¹Ô‚øˆ‰; "¿é: Æ6Þõ§”–£ù‰ª¦$bñTªë7gûõ¼Í¬.D ýN‘Œ5óõØ•ÑW¼’s©m]x{86ô—Œ/ª¨œ¤, ¯Êñã?†Åb¹¥û´Z­\•\ÿ5˜2eÊ-Ý·Po¨·×!_oE¥¿¿?4 ^xáèt:øøø`Ó¦MðóóãUZ–—÷<Ð;SQ ¡¡¡X·nªªªx ðÞûÎÉÉá®åÜÜ\°,;&íJJJ`6›‡˜˜.¹Ø?Q ôT´ eïÞ½¸|ù2xà®Z¦M›™L†+W®@«Õ"88˜{®W,!ý1 ƒ°°é˜7/:Ïð7 d)ÁѼãÒ–*Ôt5‹ q–Ÿ· ÑÓ½xk½š$£Š_õ;[ˆPOêo(íÝÈ»ÚÊ[£þ”DLŠ쌪° ~ÍR±"Bµª¯èÄjc‘]Ü$bDäf¨¢r’úòË/qàÀ0 8pà”J%žxâ‰ßg^^Þyçèt:Ãh4âêÕ«€;ï¼sTâŒ |òÉ'X¼x1RSS)#²þ=*žm×ÂéÞÂJK…B1èìá<üðÃÈÎÎæ†ê= ̸¸8äææbË–-˜1cΜ9¥R‰|p¤_Ö|}}ô à±Z­ÜÀžþU—ÞÞÞ¨¯¯Ç_|ûî»wûŠŠ nðNï„o 'I™””„µk×âСCø·û7$&&¢©© ]]]zsBÈxXà7O4›ûÚOdVbýì•7¹q%«çëqñZ_…áÑ‹ øÍCw°Ì±j~Ê”©1"EBFâX¾6{_H£V`ù܉[L\_rpþ+ï[î¸ÎØŠò–Ì™2ñûýNj•ËçøàXAß‹tG.6àîE"FE†B•“TFF`Û¶mx÷Ýw™™™·tŸÁÁÁX·n<==qåÊÔÕÕ!<</½ôV¯^}Ë1÷w×]w!99uuuHKKCEEŨÞ?q^hh("""àé9tï þ•–:/¼ðoÈ’£Ôj56nÜ8`ý׿þ5î¸ãFäææbΜ9xçw<úO ¢¢¢šš …BÌÌL̘1 ¼sžxâ øøøàÇĵk×x+**â*Ž¿ÿþ{ìÝ»{÷îÅ™3=ºŸ~úi<öØcÉdØ¿?ÊÊÊ V«iê7!DrF†A¼µcÔ§RRV ªÑ.×v¢¢Á8ÄÙÒVÓÕŒ²~_Þ¤ êO)%iùÓ¾WFêত?]‰xfz`ª†Ÿ,Ï ÇAII<f4r-QˆkaDºßÁ>Îô[ïýW6Èqÿsdýn×{Üû&ÿ翊¾ßû¯Ö`0œpæýþU[Å3Ï<ƒææf.IùòË/C§Óá¯ý«È‘¡Þʽáˆ}öNŽïíwêì1‘G¯KhiiÁôé4X [^ú?x~Ó3˜5ëæ-X–Åwßîý÷=0N‘):tã<^:þ)wì&W"ûþ·qèûïpßý£_¹NF—e±|K&ê[ÍÜÚ¿?Ÿ® -¦ôô#ˆ]4ê-‚¾,ÏÆ›çöpÇ>nž8vßï g(Ñ%«q¿>†v£•[ÛöTZ1•;ÎËËÅ”)> ›!FˆD®_»Šææf,Œsú¶oŸû»ÊûŠ{úÍÀÿÞöËÑ Œ¡ ƒI¯fñÖö½º ±3µCÜ‚¯µµçÎÅêÕ·ExCR©T ZØXûýkÿçûö~ol¿·Þcô;F¿5á1Ûïýþ†Kžz¶—­'©äädÀ+¯¼‚W^y””$fH„Bqa+#¡”õu 2Û,8UW&bDÄ2†Ar4¿šäˆ jm¢HlûN Ф$¥„œ*kæ%)e 3 Š1$ úT^l¼6`hq]¡~î˜;•¿û/íÂÄ|”:êQ9I=òÈ#°Z­HOOÃ0Xµjyä±Ã"&¬Œtö˜BˆkóTª§Ÿ‰Óý’“éUùˆõˆ–е õØs¼Š;>UÚ4ᦞ­ÝÈ©¿Ä[[Eý)%åˆ q°p¦zo7‘¢!¤Ï²€9ðRº£ÝÒÓ6ÃβȪ)Âý3—‹qÔÚ…þ(­êë·v¡[îŸ-bDd0ôÒâ$¥T*ñÓŸþÿûßñÙgŸá©§ž¢a4„B¹©”à(ÞqFu!Í<•Äy¾pL=Í(œX-ŽNÔ–Àl³pÇ ™Ë'îР‰HXéKÓ¾‰«PÈ䈜Ë[K¯*âlâŠÖÌ×óŽK«:p½¾K¤hÈP(QI!„B²*„_™ÖhjG5Û.R4ÄYî*9"ùà ÒòêEŠfl$ –øÏ†—Ò]¤hˆ³J«:pÃÀò´v¡¿HÑ2Ъ©Ñ¼ã“u¥0Z»EІ8kÁ oøkùÚÂá]D|”¨$„B! Ñøb†wo­ØÞ$R4d$„Õ$Gó °Ú&F]¬e‘U[Ì[KT×–vŸ8Ö©ô”#DLIAóx=oÖnœ©/1"â Ã`• J[Øn‚ˆ•„B!ÄaÂj’2%*¥ä¶z0Lßq»ÑŠ3åÍâ4Šò›®l‘D‰JI9rÑÀ;¦jJâj´nÄégòÖ2ª EІŒÄm ø¿WΔ7£µÓ2ÄÙD ”¨t€BA3‡ˆ8œ¹öè:%ã…®5B&·¤ ~â§ší@M×ÄHtMþZ7ÌŸ®å­M”j’LA²`¶6¡žÔßP*Û»qáj+omÍ|úù×#¬ÔN¯*K›%#qžnÂ÷k–:JT:@¥R‰™¤œ¹öè:%ã…®5é°Ùì8–ž‰o¾Þ²²KÃ߀Äêg`Š›†·–Y]$R4d$Ö,à'¯)’Ñ%j‘=Ä™ÄË7ÀfïKöhÔ ,Ÿ«»É-Çšù¼ãc+ ›nˆ q–Z%GB„ _ó…‰Õ¯Yê(Qéwwwª "ãN¡PÀÝÝñæït’ñàìuIÄ%“1ˆˆ˜‹Å‹ã@ÛçÈè32¬Œä­ +Ùˆkn§­l4¡´ªC¤hFGMW3Ê[jxkÂ)õĵ ‰‘:¨ôç*q=Ó<ý0SЯù=JÊm ùýšÓó °Xí"EC„è7¿ƒ<==) DÆB¡€§§óÃé:%ci¤×%Ã0 Àô°PhµÞb‡C&”©üÐéº2šz*!‘!^˜æÇÑé°Ä§l½œâ¦Á|¿0ñ"N±XíÈ*â÷»½úS¶jj ï8½2_¤HÈHܶ@Y¿†Í©_óD@‰JÉårhµZxxxP"ˆŒ…Bh°Ôí! IDATµZÈåòáo @×) ·z]B&ž•A‘PÈú~˜lœ®/1"â,áôï#¥Ý§R8ÌB8™—¸¶“¥Mè0Y¹cà 9ÚWĈ¹9aÅviKª:i¸œTè½ÝÆ_8Ì‹ˆ‡2Nrww§mÄåÑuJ!d,y)ݧŸ‰3uåÜZzeR¨' d¬Y Ç§G+¸ã WÛPßj†¿ÖMĨFÆhíÆÙz~Þä©´í[J„ ‚…3µÐ{KïZ$“Ç|¿0èÔžh2õµÍȨ.ÀcáI"FEœqÛ|=o€×¡Ü:¼¾~®ˆ‘^ô2#!„Bqš0)™Q];KSO¥bùx¹÷Õ,ØYéùÒ¬&9Q[³ÍÂ+dr$FˆqÖAÊÕ14훸69#CRÐ<ÞÚ±*êS)%k}*«š¤ß¯y¢ D%!„BqÚê~.ƒ© ¯‰ qšR!Cr4?$Õ>•G«ø½á–øÏ†—’v–HEqe;*M¼5áÀ'B\‘°OåÙúKh·EІ8+"Ä !¾jÞšT'JTB!„§…h|® â­ Fĵݶ€_M’]Üc·M¤hFÆÆÚ‘Y]Ä[[-H×vèôœ>šûS’í3ݯ9©0…5,tÙŠ!~Žäë(ĸü[,Tu‚Á`ÀÂ… ±yóf¼úê«X·nòòò‹ŒŒŒV¯«ªªBHH„¯7vùÞDRòrpA¤gˆ3ÝG¬›él’ÓÉÅ(®°®Yôµ: ~ÊKbSyÚ·-9pAœM9<ØA^j‰²!ê>|Âádç`lë ˹"aFd.ÓåßÖ~°\oÅB%Q'ìÙ³‡ÂîÝ»ñØcᡇÂŽ; “Éð—¿ü¥Õ몫«áááÈÈHákÈ!]¾7‘Ô¦˜,ÿ>œupƒ'[1y¸'úÙ+Œm­Î€£— %̨¹Ÿr“Q£m*ž*drÄø •0#2×~“þ¦9Ù*•BÙìߣCܯ٦˜*oåTávn•DÙô],TuÂßÿþwLŸ>ƒ6ÆÜÜÜðøãã_ÿúôz}‹×UVVÂÑѱÅïuõÞDR›jr IAm9.q°­P«˜4ÌSˆíM´®eo¦Ë¾ïñw{'‰²!s]Ϫ@F¡x(ßÌh*©÷˜8JhŸÎKF¥¦V¢lÈ\‘!®ðswb\þmy,TZ²²2©S ê2­V‹õë×cùòåxæ™g°aÆ÷2ìh?"kwõêUŒ7®YüÞ{ïEEEòòZ^*RUUGGG#;;†Žì콉¤6À¹?ºˆË‡ò0›bºüûøÕ"T×é$ÊF¤3è›-£4ÅKÖÍô´ï@O t–(¢î7Éo(T ¥±]¯ÓâDÎU 3"sÈdÀôÑâá^,TZ •Và÷¿ÿ=JJJ„˜N§C\\œD™oÓ¦Mؾ};JJJP\\ŒmÛ¶á›o¾ét?")h4ÄÇÇ·úuýúu {HÞ¹s>>>ÍîáççÈÌÌlñ5*++±wï^øúú"$$nnnxöÙgQPPÐå{YÓÙ$2ÏK” uÆÔ‘^P*šEª­×áøÕ" 3jr.ÿ6Šk+mdÍfñ’u3¡;#ªù{‘-s´sÀDŸp!v0“ìl‰éòï‹ieÈ-©“(›¾IÙ~êiwîÜÁo¼7ß|îîî…B­[·vúž555رc~úé'äååA­V#88 .Dd¤´¿ÐÕÕÕA§ÓA­VCv×é Ë–-ƒZ­Æ_|!avÔYÇŽ¼õÖ[0 X½z5¶mÛ†mÛ¶µØÿî~GŲeËÚ}ãÇãøñãHOOGuu5|}}ƒ tËÏÐÚØ¤¾£¸¸111­~òäÉ8pàôz=t:tºæ³Œ”ʆ·V;;»ïñÚk¯áw¿ûP^^ŽC‡áÕW_Err2<¾wKjkkQUU-Ä PðY%õŒiA£ðùÕýÆvFe!n”f#ÌÍ_¬¨£\í01Ü'î*NîKÌì(é—çîÏ‹ÞÃ<‚à×Ï]¢lÈ\™…5¸šY!ÄfqÙ7õBS#q,»iö÷‰œ«¨Ói`¯èøïo$ áðpV“3€}Iy˜«Ä™õ,TZ‰;wîàøÖ¬YWWWèt:,^¼¸SÅJ½^wÞy—.]‚««+†Š‚‚\¹r?üpdožO?ý'OžÄûï¿©Ó¡nÖÒ2ÖöúµWÔétx÷Ýw‘µZÐÐPèõz¤¥¥!==½KùÞc“|||P_ßþ · …~~~ÈÍÍmö½ÆX```‹×FDDÿ[­VcéÒ¥puuÅ‚ péÒ%Œ=ºÓ÷6¥Ñhðç÷ÿÚ,>iò8x¸» ±òòrü°c{‡îKt·ŠŠŠfcÇC¦F±¡iº¿úÓíB-u’¿B @elïIÈÆdÏÛèîç(+-…B¡h·¯Àîšx!T¡ä¿[6äÀ-;M…{r®Ã×Ì¿Wuu5”J.]¼Ð} RŸP__­V‡ÌÌžÛ?¹È!ƒþÿ“«ÖÖáÃÿÂP…W½&u¯Án*ÄW4•Ë6¸ײjTWWuø}ç¡yó{*½^…J+’‘‘5kÖ‹•ÿøÇ?:uŸ””\ºt #FŒÀš5kŒE ºº:³fá™#66Û¶mÃêÕ«±¸¸8,]ºTè·aÆfýbccÛ¼÷?ü€„„Œ3«V­‚“Sæùƒ¡CE%¢ž0dÈœ:uªYõÔSøöÛo;ô”ùnEE Kuêêê ÕjÅI{{{cŸeË–!&&*• gΜ^¯ÇìÙ³1qâD|ùå—¸qã¼¼¼°bÅ Úð „^¯Çwß}‡ãÇ£°°X²d‰ñvGúüùÏÆÉ“'¿þõ¯¡P(ðí·ß¯×h4øê«¯púôièt:LŸ>K–,1~¿®®6lÀÙ³gQUU…aÆᩧž‚···ðs988àÌ™3Ðh4˜1c†pKùæ›o„Ÿ­-K–,ÁâÅ‹{8£žÕøgܸÔ;..®ÅŸ©£ýét:lÞ¼ýúõÃsÏ='Wd2™q\wul´56;rï‰'ÂÛÛ„··7þøÇ?vòO²gõµqÙ“ž|òI<ñĸrå † aÛõë×ã™gž1ö3 ¨««ƒƒƒCk·ÂÑ£G£G6ëÞí‘ÉdˆˆÇ AÍýñˆºdZ`¤P¨¼U–‹Ôò<„ºp?:[àíjÑ]‘x»ÔÛ—TÐí…JsÈgÎ…¹ù³HiCrKêp1]<@t6—}S/650R(T¹s :Ã(dÜzÇLæ~ö ãar:½ǯ•"€»ƒYÿ–X‘5kÖhšY 4,/,((À›o¾‰eË–áøƒñÀ…Ö 2ööö¸yó&V­Z…õë×#++«Y¿ƒ"!!~~~(++ÃÆ±jÕ*ÔÖÖÂÃÃøàƒŒ'2ñÅظq# ¢¢¢ššŠµk×âÚµ¦õíõ™8q¢±ï¸qãðÈ#9UVV">>¾¾¾(++÷ß~‹sçοÿ§?ý {öìAHHÆŽ‹¤¤$¼ûî»Â2âƒïQ^^Þì–ÒÑ"Oo))•JaŸÉ¥K—B©TâܹsX±bV¬X¤¤¤Vûµ&77µµµ8p \\\Zí×Õ±ÑÖØìȽ9‚o¾ùV½l¼¯Ëž‡1cÆ`îܹظq#8€E‹A«Õâ—¿ü¥±ßƒ>ˆÐÐP”——£¦¦±±±xÿý÷±oß>=zo½õž{î9¼ôÒK0ëÞDÖj”W|û‰³äL MdÝLØŸ”oœaiip0S?ÓMm"ë¶ë\.î>îN*Œó.!¢6=h4dhªj•ÖU!±à¶„‘9T Lî)Ä]*–(›¾‡…J+âêÚ´9kFFÓžŸ~ú).^¼ˆÚÚZ\¸pŸ~úi›÷ñððÀ믿ŽÐÐP`ûöíøÕ¯~…?ÿùÏ(//ú~ôÑGxóÍ7'Œ7k׮Ň~ˆÀÀ@#;;………8pà‚‚‚ðÞ{ïáå—_ÆŠ+Û·7ìÑБ>&L0T±dÉ’f…JøðÃñæ›obÑ¢E€«W¯ÒÒÒ˜˜ˆ‘#GâÕW_ŪU«0vìX¤¦¦6ÛËí£>š5kð裮\¹)´Wìé Å ¿ýío(**BQQÖ­[göõÿoÛ*RvÇØhmlšsï?þñøè£°|ùr³NKâ¸ìvvvØ·oæÌ™ƒ7ß|Ë—/‡»»;Ž;___c?ôïß*UÃ~o‹-ÂöíÛñ‹_ü‹/Æž={ðñÇãí·ß6ûÞDÖJ¦ˆ‡÷™šÈº™žSP^‡ÄÛe­ôîYWŠ3‘S]"Ħ±PiKö™œö=mTáty¢ÞÆG튡âžâ‡².I” uÆÌhqÈO7ÊP«‘æ]_Ã¥ß+--m·Oc¡îã?ƪU«„Œ­9r$Þ{ï=œ?ÇÇéÓ§qòäIÈd2¼øâ‹ ?ˇ ÆSÇcYYY¨¨¨@aa!ôz=¢¢¢ŒKÑcbbðÙgŸgkfdd´Û§=îîîÆóáááfY0ÞãÂ… ÆÂj£Æ>¦?WXX4+ÐZÒ’%K R©ðõ×_7‹³Ô¾Æ1™——×jŸž½·J¥2n“` 8.»‡££#þú׿‡ÕÜíË/¿ÚÏ?ÿ<žþùn¹7‘5›‰7ÛWK²p§ªŽœEe x÷Cx€’ï4½×íKÊǘÁíï'Ùݘ¹Cœ½1ØÕÏâyPçä—Õ!á–ø™‡Ë¾©/˜‰«Å™ÆöÁ¬ x5z0Ó’¬×”‘^°SÊ¡Ñêu=.åÈñ Äyõ,TJ¨¤¤Ä¸Ä;((ÈoÜ«²QãÒk û8v„L&CTT¢¢¢0eʬY³ÆXô4ÕÒ>˜wÇjkk4ìب¾¾^Ø#°#}Ìa𓳳3 22²Ùm­,!—[Ǥá €±(Ô—ŠA+W®ÄgŸ}™L†gŸ}Öìë —Ë‘ššŠÌÌLáïJ£ž½w[ûZ«¾<.‰¨çE÷OgÕVc2Ï㉈)fEæ˜í#*w'äâ·‹Â ³ðgì™ç…öŒ Ñ–M€ºÄtÛgµ1Ã<Û¸‚¨w˜4 _ÚelçV—âBaF{ñ([àÒÏ÷FxàØåBcìlgTZ‚uTqú¨7ß|YYY Áþð EÊ5kÖ÷ìËÎγNëÖjµ¸}ûv³€ªØ’ÀÀ†ië ÆBibb" ƒq?¾Žôš UUUfå¹\Ž””¸ººÂßßßøe §™/X°‹/6~õ6Z­ëׯ7¶7lØ­V‹¨¨(|þùçøÛßþ†¨¨¨VûµÆÞÞ³fÍ‚^¯Ç_þò—fË­u:]·–Ʀ­»öôöqIDÒQÈäx `„;˜uQ¢l¨3¼G\öv§¸Ó,»ü;¹ô2* …—}Û–ÝçÄU1ÓFõ‡JÉ¡Ôû tñÁ`WqËžý&^ȺÍ2™ý}1Û`<`‡zgTJÈÎÎxíµ×Œ³¶Ö¬YWWW 6 /^ĪU«Ã† ëð}ÏŸ?·ß~ð÷÷GMM RSS³fÍêT®ÁÁÁˆŽŽFbb"^y儆†">>vvvƽ$;ÒBBBpìØ1|õÕW3f âââ:TðñððÀôéÓ±oß>¼öÚk˜4iŠ‹‹Q]]—^z©S?—¥Iqú¸¥lڴɸ)Ðtª÷Ýç˜ÓïnK—.ŵkךšŠ_| €³³3ÒÓÓ•+WvËØhilö†qמÞ<.‰HZÓGaËíŸŒí …iÈ­.mvÐY§ð' ösÄ­œ¦x»ÎåaT¨kWu¯&ÅmGD¸Xìõ©kJ*ëSÜ_t¶Iœ¨7›4·ÊöÛû2’ðJÔ|.ÿ¶3G{ã÷®A«k˜IY¯Ž_-j¶3u/>Ê’Ð{gµk׋”@Ó:Kd0zôhã)¯žž Ë$~÷»ßµz_Ì;NNNHIIA^^† ‚_ÿúט2¥óË­^zé%Ìœ9555HLLDXXÞ~ûmã’ôŽö™={6&OžŒ¼¼<>>غuk³ø³Ï>‹uëÖAÖÆæ@þþþxòÉ'Û¼ÿ† „öèÑ£›½ÞÊ•+±råJc[­VOñnMGúØÙÙá…^h7§‘#G6ËI¡P ^-1½ÇðáÃ[üs¤žÓÑâÝÝýÚÏ ,X`ÜW±¥ïwul´66ͽ75Pʘì7 ;ÒÎc2/béû%ÌŠÌ1gŒ>ÚÙ´¥PNIÃòoK̪L«ÈGJ¹É²á@.û¶%{ÅÿS"½ V5ߟ¨· uñÁ _Ü.o*níÏ3‚ŃOÎÜBaM¹Dٹœ0È×Qˆí2Ùs°§ì5™Mé­vÅHÏ`‹¼6u]yµ?^/b³£¹ì›úž™ÁQB{_F àÊ,[13Ú yÓÄšÊZ-ΚliAÝ‹…J+¥P(8lÊ’%K°páBxxxÀÓÓqqq-ÎÒÑ~DDÔ;Lô ‡£ƒ±­7pøÎ% 3"s=8F,.íN°ÌòïC&ûSNÅeß6äÐÅBh´zcÛÞNŽØ‘^fD$&€åV—âRQÇ·?#iõw±Ç„pqù7gSö,.ý&¢n¡T*±lÙ²6Å1§uV«Å¦›¡V«ûÀýˆ¾gtûu3{…î÷†=‰ÆØÞÌ$,|Ÿ„Y‘9æÜãƒw¦ÛYE=¿ü;£²×J²„—}Û–gÅ}Ü& ó„“?~Rß3ØÕ]|„­,ögžG¤ç ³"sü~qV|’„;ŵøYl0Æ v—:¥^e`""¢^J©Tâѥॗ_`‘’$5ËdÙÛ¹üÛ\þmC"1ЧŸÛÝÃË¿w§' m/µ ¢ûìÑפîS^­Á‰«EBìÁ1¾­ô&êý¸üÛ¶E:ã‡×FáïKäXóX:pÄu •DDDDÔ£bü†ÂÙNmlë zìÏ:/aFd®9cÅ"Ó®^þ½7C,TÎ  …Œ]lž¤|Ô›,ûž>ª¿„IkføÀ8§º—¹ü›¨E|·'"""¢e¯°Ãä€áBÌô ²nsî÷©Ì*ªÅÅô²y­Ôò<Ü*— Ï Šj¥7Y£ âŒÛØ^pVsÙ7õ]Ë¿ï¶?“ìˆZÂBe(•|S%i˜3ö8NÉR8Öˆ¨3L MI©È©æ©™¶""йÙéß»zfù÷.“Ù”>jWŒò í‘×¢îW\Q¯‰Ë¾ËeßD3L–ïÉHäòo¢°PÙ*•Jê¨2gìqœ’¥p¬QgÄø …«}S¡Ëd^0#2×l“Y•=µü{¿ÉlÛÙٌ=‰ùÐꚆZ¥À”H.û&šØüôï+Å™eCd½X¨ìµZÍDdqJ¥jµºýŽÿ‡ã”,ÁÜqIDÔH)W`Šÿ!fº!Y·9cš/ÿ¾”Þ½‡"]+ÉNÆšÆDÖmg‚¸lê¨þèg¯("ëææP.ÿ&j •äääÄ"YŒR©„“““Ù×qœROêì¸$"jdZpºT”ìªb‰²!s tF¨Ééß»LŠR]µÏäC{€£†{uëkPÏÉ/«Cü qK‡¹\öMddz¨Îžt.ÿ&2ÅBe) ¸ºº¢_¿~,QQ*•èׯ\]]¡P˜ÿä™ã”zBWÇ%Q£ ¾áp·ozàa€‡êؘ9cÄ¢Óg»où·ìMgÙÎ Ž† \öm+öœËƒNß4 œ”ˆî)aFDÖeF §'¤J” ‘ubŸˆ IDAT%ÃLjµšËIàéi}¿|qœ’5ŽK""…LŽi‘Ø|û”1¶7#O *aVdŽùãýð×])Ævvq-ÎÞ*Á¸!î]¾÷å¢ dU‰‡°ÌŽîò}Ér~8+ΰ1º?T|ÈIÔ(Ì̓]}q«¬éïÊžŒDD÷(aVDÖ…3*‰ˆˆˆÈbL—_-ÉBFeDÙ¹û9"<@ÜdG|÷,ÿÞ›)ήàÜîÝroêy¹%uH¼]&ĸ웨¹Y&`öe&AgÐK” ‘õa¡’ˆˆˆˆ,f¬÷ôW» ±=é\þmKæ‹O»Ïå §û쳿_SSƒU«V¾úê+888´Øz½^K—.!==‚#F@.!¾|ù2ŠŠŠàææfök¤¥¥!##¥¥¥Ðh4prrBpp0†Úîµ:z½J¥2gƒuÅáãñù•Æ“N‹j+p2÷býGHœu„»“ ±#>Û¶mëp""j]°“¢ú‡ ±í)gZéMÖ(îÞ¡}æF12 kµå8•#ì5'0Úb¹Q×m9%î;<Øœ%ʆ¨÷™ g;µ±­3è±+ýœ„YgTÚ°ââb@xxÃôðˆˆaé7㌰Æ>×´å‡~@BBÆŒƒU«VÁÉÉ `0P__ßmùw†\.Ç;ï¼#idYiiiÆ„ „XddÃé°:ñññ0 :t(<=;¾GÒ7 Œ?ÞXü6 Ðé¸ÔˆH óCÇ#± ÅØ>–}%u•p·w’0+ꨩ#½àá¬BqEÃýtV͈©ñÐôƾ2%î÷iõY‡Š-ö%‰§µ/2)LQ×8(ì0-h¾K9mŒíH;‹'"¦H˜‘e±PÙ‹¬]»¶Ë÷Ðétؼy3úõë‡çž{ÎX¤™L{{{ 3Ѿûî;?~……… Ä’%KÝôT|Ù²eˆ‰‰J¥Â™3g ×ë1{ölLœ8_~ù%nܸ///¬X±BXb[[[‹÷Þ{çÏŸ‡§§'æÍ›‡iÓ¦ ÷U©Tøê«¯„×qppÀ™3g Ñh0cÆ ,Y²ÄxM]]6lØ€³gÏ¢ªª Æ ÃSO=ooï.ÿ™‘eÉd2îÚÁ]¡PàÁ4û>z½W®\Æ'ÌЕÉdP*•¨­­Å÷ßOOOãLJJÂ7ƒŒŒ dddöíÛ¹\ŽGy¤‹?!Qß6#h4ÞNÜŠmC¡K£×bWú9<6Yą̂#ì”rÌãƒõG2±-?eãù9ñ½É²ï(8(ì,"uÒ΄\ÔÔ7=ȵSÊñð8_ 3"êæ…Œ •7J³qµ8Ã<‚$ÌŠÈrX¨$Ann.jkk1bĸ¸¸´Úï‹/¾À¾}û0`ÀDEE!>>k×®ÅÿøG¡èxðàAx{{ÃÏÏW¯^ÅÆ±qãFDDDÀÃÃøàƒðÙgŸA©lŽåååÈÉÉATTΞ=‹Ï>û nnnm.ém|___\¹rß~û-Œ{î¹ð§?ý çϟǘ1cЯ_?œúo¾ù&âââãÆÃÚµkñá‡"00ÅÅÅÈÎñi¼ï³Ï> سgO»¹ôÑGX³f }ôQÀ•+W4,NLLÄÈ‘#ñꫯbÕªU;v,RSS?/Y¯#F ""ùùùÈÈÈfS¶§­"tee%tºH 6æ9|øðNß‹ˆˆš<"ž}­$ É¥wZéMÖfT¨+ÂüÅ¥ú_IÚÁNý1PÅ|¶"5¯‰)¥Bì‘.û&ê 2È0?t¼Û“žh\i@ÔÛqF% g„åååµÚ'##z½QQQP(€˜˜|öÙgÈÊÊúº¸¸ÀήaIÏ!C„×hŒeee¡¢¢Âóöö6Þ÷Þ{ïÅ_ÿúWܹÓö‡“»_',, @ÃÌLÆœ.\¸`,–6j,V‘õ’Ë刌Œ4îIÙèܹs¸uëÜÝÝ1mÚ´f§€·G­nؤºªªªÛr%"¢î1Á7¬Ùl’ïSãñ›¨fEæX|Ÿ?þ¸ù†±};E‰~~vÙióŽƒ,«ZlÅ–SÙ¸ûYq{Lî%]BD½ÜÂA±îÊ>ã¾¾šȺ€y!c%ÎŒ¨çqF%  —Ë‘ššŠÌÌÌûÔÖÖ€pØH}}½°‡eK‹íÅîVWWÆeáaZ°rvn8‰022ü±ðÒáû’õÈËËÃíÛ·!—Ë1nÜ8³‹”@Cq[&“¡¤¤¤Ý»Í™ÅIDD]'ƒ …г*w¦'@£×J”™+î^¨”MïÏÚ¼†xr™ óLfÍ’õÒ Øö“¸úiÁD?(,4õµ+îõ‹bÛR~’("Ëb¡’ööö˜5kôz=þò—¿4[­ÓéHHH€FÓðT<11ƒ¡[ ùùùÆÓÅÏŸ? a/ÀÎ ‚\.GJJ \]]áïïoüjœ…I¶C£ÑàìÙ³0 ÉdHOO‡^¯oÿB …ƒ†Á`ÀéÓ§…Y½@Ãa;wï›ÚX˜oœ©Û¨±HÚ8f‰¬MYi QS]#u*Df™224BŠk+qøÎ% 3"s¸;©0}t!¦Énør¢o8|û¹I‘u±˅È)©bqý%ʆ¨ïˆ8QhŸËOAzEDÙY—~S3K—.ŵkךšŠ_| €³³3ÒÓÓ•+W"::‰‰‰xå•WŠøøxØÙÙaÑ¢Eݒïýk 4 éÏ›7¯Ó÷òððÀôéÓ±oß>¼öÚk˜4iŠ‹‹Q]]—^z©[ò%˹|ù2ª««1`À@rr2`Ô¨QfßkäÈ‘(,,DII öîÝ 777ØÛÛ£´´~~~;v,ÜÝÝQRR‚ƒÂÞÞ¾Ù¶nn ´ÎŸ? :´Ý™ÂD–¢Óé‘”t©©é9aaƒ¥N‰¨Ã‚¼0Ög0âónc›oÂÌ ( ³"s,‰ À®„¦÷M}…+t®˜ïø6®"k³ñ¸¸µÓ¨W„8µÒ›ˆºK¬ÿpx:8£¨¶aB…lK9_zHâ̈zgTR3jµï¼óüq 4ÙÙÙ¸uë¼½½ûL¾ôÒK˜9s&jjj˜˜ˆ°°0¼ýöÛð÷ïúÓÕ™3gÂ××ç΃··7^}õUá$ñÎxúé§±téRÈårlß¾7nÜ€ƒƒ—ôÚ ´´4c„ ˜0a‚ƒƒ‘––Ö©{ÙÙÙaÚ´iˆŒŒ„‡‡***P\\ GGGxzzÆOOOTUUÁ`0`ìXq_˜Áƒ#$$•••HIIiw9‘%)rÄ>p?âÍg‘’lÒ¢A÷ í3y7‘QÉÙ$¶"f˜'\œÅßµäy¡˜ÙÊdmòKëpäR¡{ô~¢Cd J¹¢Ùž”ß§ÆC«×µrQïÀ•6ÌÃÃÅÅÅHNNFxxx›}¯_¿ÆâK{ ,X€ ZÞ´^­VOún͆ „öèÑ£±uëV!¶råJ¬\¹²Õk:r_ÓöðáÛ½ŽB¡@\\\³ÃtÈö´4[±­Ó½Û#—Ë1tèÐV‹á®®®˜6mš8p ÏøñœBDÔ¦FÂÃÁ ŵ ‡ß5Ì&9ƒ#çJœu„ΠƒÜ7¨`Œirü¡ÓÉ.>° ÿ9‘­®©Øìè ÄCc}%̈¨o‰4ÿ¼~4ü=,¬-ljœkx `„Ä™õ*mXll,¶mÛ†ßþö·f]CdËBBBŒ…w áúˆˆˆ6® ""[e'Wb^È8üóúacl{Ê|<ò¼½½áää„^x¯¼ò Ö®]ÛbÿÌÌL$&&¶x­V‹gŸ}ðã?âƒ>ÀÔ©S…~åååÝÿCY¹Eƒî •§ó’‘UU„@ÇŽí½M–·åö)ãžjJ¯<(ìë¡«S à룙¸ßGÊ ©-y-¢óØýeCÔ·©•*ÌŽÆæÛ§Œ±Í·OaÅðPȸH–z*‰ˆˆ:)77?ü0^~ùe¼ñƀ͛7ãñÇÇÈ‘#ñè£6»æé§ŸÆÓO?Ý,>uêT£ÿ†YG••• Å–-[zö‡ ²ÓGá»ÕÑ Øvû4^ˆœ#qfÔ^‹ïSã›r=F—ãÜ]Ïh¶œÊÆø‡,ŸuÌ&¢CdU#*ókÊpøÎ%Läêê}X~'""ê¤uëÖ¡ÿþøïÿþocì‘GÁ¬Y³ðñÇwø>/^ĉ'ðË_þÒ«®®†££c·æKd«T %æ#Ķ¥ž†V¯“(#jËá;—PT[!Ä^~p$ò¦½F+j´ø)Í`z)Y¢Cd}ÂÝ0Ú+Tˆ}só¤DÙõ,*;@©ä›2Iܱ'—ó¯3YÇZ“Ý»wcþüùÉdB|áÂ…8{ö,ªª:¶Û'Ÿ|‚±cÇbìØ±ÆXee%œœœº5_"[¶hнB»°¦‡ï\’(jËæ[§„öXï!˜8 ±#½„ø‘›zK¦EÄCtˆ¬Ó£ƒc„ö™¼›H-Ï“(¢žÃO› R©¤Nú(sÆžB¡èÁLˆšp¬5ÉÌÌÄ€šÅÈÊÊjö=SÅÅÅØ´iž{î9!^UU…¤¤$üêW¿Â³Ï>‹wß}iiiÝ’7‘-èâƒ{úbo—(jMJyžñF n(2?>9Hˆg”Ò+-–uÌ¿ð"k4#h4<šb`À7·~”0#¢žÁBe¨ÕjΪ$‹S*•P«ÕfõçL7êir¹¼×ÿ{XRR‚‡z¨Õ¯ßþö·Fƒ¢¢"¸ºº6»‡—Wì¡ÂÂÂfß3õüÎÎÎX´h‘ ÁŒ3ŒïAÿú׿0|øpüóŸÿìúId£2Ih'ä߯Òl‰²¡–üçæ ã!:àéàŒi‘€É#<ì%þnóí©|‹æGmKϯƱËâ{×ÒûƒZéMD–¤R(± t‚Û‘m½DõŒÞýi³999¡²²Z­VêT¨P*•Zò©R©P__½žK©¨ûÉåò>1Ã\¥Raܸq­~?$$`gg5ëSZZ ðóókóµôz=Ö­[‡åË—7û³m,ˆÞÝwåÊ•xá…0gÎã¡;mÑétغe{³½.ï»oÜÜÝŒmƒÁ€úúz¤¥¥¶{O"SõÅÆÎƒ ï•××à߉û0Ó{„Ä™õ~ÕÕÕ¨®®êðØ m¿µˆ¿tB¡€««+jjjP__Ï‚%õ¥R •JeÖLÊ»Éd2ØÛÛC«ÕB§Ó±`IÝB.—C¡Pôú™”ñûßÿ¾C}‘šÚü—•ÌÌLÈd2´½§×Î;‘+V´ûZr¹¿ùÍoðÕW_áܹs˜5kV»× ¢´´Lˆ—–”B¡g`ëõzT”—·{O"SeÇήC°¥ ÉØ>Rx ‹Ü#ᨰ·XÔ²½ÅWQ­kšÙ#‡ 1Ž¡Âø˜ûèô:¸¹¹sÆ™-=-%%%6ý;Ïr/%~yüsc;½¶:—f§‚S÷*++CEe…M[Á 툈ˆ:éùçŸGAA°LûàÁƒØ¾};^xáclçÎxÿý÷…k¯]»†#GŽ4;D§Ñ¡C‡ Ñ4-k«¨¨Àoû[„††bÔ(þ‚D}——ÚÓ#…Ø7·~–«’åÊ¹Ž´ q¿IÓ=EýùäDFFâ¾ûîkvߢ¢"<ñÄ@LL ¦NŠAƒáæÍ›Ø¼ys»35‰z;ÓXfe!Nä\•(€ÿÜ?$‡¹ùc¬÷àûŽ uEdˆxŠô?¦÷XnÔ¾ÓÉŸ‘-žÀþ‹)\JJdä2ÜŸyù5e­\Ad[¸6”ˆˆ¨ -Z„ñãÇãøñ㨩©Áßÿþw„‡‡ }¾üòKdddÀÇÇÇ8p /^Üâ====‘’’‚#GŽàæÍ›ÐëõxõÕW1eÊnë@ ªÿ@ uĵ’,clã͘ì?\¬ú®¬ª"Ͼ"ÄZ›MÙèã×_]6¶O]/Ƶ¬ tî‘©mÿ<œ!´ù:"f¨g+½‰Hjq'à³+{'~kôZüçæ ü¿È¹gFÔuü´CDDÔEAAAX¶lY«ß7n\³“Ä_zé¥6ïigg‡3f`ƌݜ˜ IDAT’#Qo³tÈ$ü>þ?Æö©œë¸U–‹Á®¾fÕ7}|LXzï¢ê‡¹Æ´yÍCã|ñ‡ÿ\FYmSì‹éxÿIž\ki™…58x¡@ˆýbJ0dÜ2”Èj¹Ú;b^È8|s×löÍ·OaŰP+UfFÔu\úMDDDD6gö€{àáàdl`À¿’H˜QßT^_ƒïRϱ…'´ûAY¥”cJ˜X û!>ù¥uÝž#µí«CÐé› ÍÎj%Nô“0#"ꈟ…O†ü®' ¥uUØ‘vVÂŒˆº •DDDDdsvX28FˆíJO@÷貨ooD•¦iZ¤B&Dz°û;tíCä°·kú8R¯Õcý±Ì6® îVV¥Á7'ï±Çî„“ÞY»goLò&Äþ|„‡Ë‘Íc¡’ˆˆˆˆlÒ£ƒcà °3¶ëuZ|sëG 3ê[´zþsó„›¿~îºÞÙ˜í%ÄÖÉDM½®Ûr¤¶}},UµZc[©á ¢Cd3~+´Ó+ p’‡Ë‘c¡’ˆˆˆˆl’§ƒ3æ˜ì…øŸ['‡ PÏÚ•~y&3X›lÖ=~6ÙWØ ±´JƒïNçtGzԭ΀õGŬsÇøÂßÃA¢ŒˆÈ\|Âî ÄÖß8&Q6D݃…J""""²Y?ˆ… M•®²º*ìH‹—0£¾ãßÉG…öXï!é9À¬{„ôwÀäáâ¬ÊLW.ö¼ïÏä ·DÜtù óþÿ‘ôν¥ÙeCÔu,T‘Íäâ‹Iþ¦{tå]=ì§Üd$—Š{þ"âNÝë©iâRã[9U8t± •ÞÔ àïÒ…ØÄŒv‘(#"ê¬9Á÷ÀË¡éï®|yí „u •DDD½”^¯Çù¤‹8~ì$îdñÉ:õ^¿ha®£Ù—¥I¦0=a=ÔÅ÷›êÐQ“†y!<ÀIˆ}²;¥Ó¹QûN\-Äõ¬ !öÌtΦ$²E*… ™$Äöf$!«ªH¢Œˆº†…J""¢^J&“ÁAm~Žý ´ã ®Ô{÷ C„»¸G×çWöK”Mïw­$ ?æ\b?…üîÍ&Í “+g‡ ±¤”2œN.îtŽÔ¶u{Ó„ö?G<0²¿4ÉQ—=6díšö—ÕôøêÚa 3"ê<*‰ˆˆz)™L†ˆˆpŒ o©Ó!êQOFLÚ—‹3šÓ¨{|~u? hZZïéàŒy!c»tϹc|ì¥bŸîIëÒ=©e‰·KqêºX~zz:Yg&"+à¢RcÉàû„ØöÔ3(¬)—(#¢Îc¡’ˆˆˆˆlÞ¬à(;‰3¾¸v@¢lz¯”ò<ʺ(Ä~6ö ».ÝW©aÅÌ!vüJ!.¥óCvwûxWªÐöu·Ç‰~eCDÝåçá±Â¿Åu: ¾¾y\ÂŒˆ:‡…J""""²y ™OgUžÍ¿…ÄîuØ>¿º_8¨ÈÙN%CbºåÞ‹càíf/Ä>Û“ÚJoꌫ™8zY<¨è¿f†B¥äÇB"[çåàÒlvû¦›'P^_#QFDÃw$""""êæ…Œ…o?7!öwΪì6™•…Ø“ž(ÄŸ g;u+W˜G¥”ãÉ)â à{óq+§ª[îOÀÇ;oã®:3¼\TxtR@ë‘MyjèT(dMežJM-¾¹uRÂŒˆÌÇB%õ vr%žˆ˜"ÄNd_ÅÕ’,‰2ê]¾¼v:ƒÞØv´sÀãCîïÖ×x<6.ýš–.ê ¬ÛËY•ÝáfNö%‰³)Ÿš6j•B¢Œˆ¨»9yaFÐh!öï䣨ÒÔJ”‘ùX¨$"""¢^cÑ {áéà,Ä>¿²O¢lz¼š2|ŸzVˆ-|\í»õuœÕJüü !¶ýLRóª»õuú¢Ow§Ëö]íð³Ø 6® "[´|Ø4ÈÐt:VI]%6p¯J²!,TQ¯á °ÃÏÂ& ±CY—p½äŽDõ_\=^kl;(ìðóðØy­§¦ÃÑAilku|øÃíy­¾"-¿?œÍbON †³ZÙÊDd«ÂÝð@À!ö¯ä£¨ä¬J²,TQ¯òèIpQõ3¶ 0ௗvI˜‘mË©.Á–Û? ±¸AáåàÒ#¯çá¬Â“SŽ*8›Ë½*»àÏßß‚V×4›ÒÉA‰'Lö%¢Þ㹑³…Y•euUXŸ|Tº„lÜͲã=X¢Œú*‰ˆˆz)½^Ÿ~ŠÇžÝû‘–š.u:D·dð}ð6™ùgúƒZw£4û2“„ØÏÂ'7›©ÚSœÕJ.¤•Yäõ{ƒ÷¾»‰»&SÂÓY…'§qoJ¢¾â—#fC!k*ûTjjñŵƒfd[v¤Æ#µ\Ü:cUäáÏ”ºy#""ê¥d2BC 00nîn-ö1 (//ÇÀACPVÆÿ}L&ƒ³³3dw- ëMìvø¯á3ñ? ßc‰)8‘}“ü‡I˜™møèâ.aɰ‹ª~>¥+ºß“Ó‚ñC(©¬Ð0«òí-7±éå1ÍÃN.Ɖ«EBlå¬89ð# Q_1Ðų‚£±+=ÁÛxó2 þŽffýêuZ|zy¯ Vº5Ûû“ºߥˆˆˆz)™L_? i}öLII \]]WמÝsެN§Cii)ÜÝÝ¥N¥Ç,8ÿ¸vwªŠ±.ìÀ½~œцĂ;,Äžˆx.*µEóprPb嬼µå†1v:¹/`Ú¨þÍÅ– À;ÛÄm|Üìñ³8›’¨¯Yù ögž7î«X§ÓàË»ðÎÄŸIœ™uÛtë$rªK„Ø\§á4uêü팈ˆ¨ÒëõP(P(R§BQ(P*•Ðëõíw¶Qvr%~9b¶»Y–ƒm)§%ÊÈú`À{ç· 1Og<6Y’|ž˜Œ@O!ö¿[o@«3´ríLÈERŠ8Kþ…¹ƒ`oÇD}M £'#Äödœkv@ 5)««Âº+û„X´g("T|@f |§"""ꣴZ-T*•ÔiÄ”J%´ÚÞ}zåC!c1Ô=Pˆ}riª4µedÝv§'âR‘¸¯í Ÿ~J{IòQ)åxea˜»•S…oNfI’µ«ÓèñÎÖB,Ô§–ÄH”ImŰÂŒx½Á€÷/ì0#ëöÙ•}(¯¯6¶eá¿Â,s±PIDDÔg ÈåüU ¯“Ëå0z÷Ì4¹L†ßDÍb…µåøòÚ!‰2²^u: þrá!âìŃî“(£óÆúbTˆ¸=ÅŸwÜFEMï.²wÆ—Ó‘U$áW?¥‚ˉú*7{G,:]ˆÉ»ãÙW$ÊÈz¥UäcÓ­“BlvpF¸I”QßÃO'DDDDÔëõ‚XÿBìßÉGší?Õ×ý;ùh³?“—£æC)—v‹™ x}Ñ!VX^Ï÷§I“•*ª¨Çg{R…Ø„pîçIDXv?üú‰{Rpa´zDY§?%}/ü™Ø+ìð⨇$̨ïa¡’ˆˆˆˆú„—£ nµ-ÌìË jËñŵƒBl¼Obý‡K”‘hB¸¦FŠ·Ï÷¥!£°F¢Œ¬ÏûÛo ³Lå2~·8¬+ˆ¨¯°WØáÿEÎb·Êr±ñæ ‰2²>§ón4;Hîgá±}ß~û-ÂÃÃÛí+“Éàçç‡ßýîwM³OxvøL¸¨úÛð? ›ûüÒ·3y7°'#Qˆ-€wë:€e°Ÿ#~ñ@°;t¡‡.H”‘uÐ øýÆkÐߵ߬“ƒ¿Y0¤«ˆ¨¯‘ËdX}Ï"ÈÐôÀ§RS˃uþ{÷ßTõÿqüîBéÊÞPdo ˆ Qp‹€ ¨ ¨ ˆT€â@ù‰2ä ¢‚,ÙY2 Èî.¥mÆïlMÒt›´¯çã‘Gî=÷Üä“4búî9÷Hš}`µŽÆshÞøùTQÉEP Š•ûî»O;vÔ³Ï>+«Õêpì­·ÞR@@€^xá…"­)**J§NRrrr®Î{ÿý÷Õ¯_?Õ©S'Gý_xáýòË/Ú·o_^Ê,BýKëÉÆ·8´‰=£9×S0[-šà4Š$Ä¿´F6½=“3ŒõLﺪâ¸ùkßPrª5“3Š¿ykOiïqÇQ#î¨£Š¡Æ¬ÔÀ}5-WK}j·qhûßñíÚyá¨AïÌåhMßÿ‹C[£²5tWë ª¨d#¨ÅÎÔ©Sµoß>Íž=;½íøñãúøãõöÛo«téÒEZÏO<¡'N¨jÕœN»xñ¢–/_®‡z(ÇçÔ¯__mÛ¶uxÝȨDÇ Sß>ûóg½cPEÆšspM†Q$#ߦ0ÿ ƒ*ÊZP€^ìçxÝÅÈ‹IúÄi™’âR|ŠÞ]|Ä¡­~• ¼©¦Apw#›Þ¡`¿Àôý«³ ¾+±³ ÞÞ¹PIæ”ô}o“—Æ·º[^&Sg¡°T€b§qãÆ6l˜Æ¯¸¸«£ŒÆŽ«V­Z©ÿþW—3ëÖ­“ÅbQ§Nru^×®]õ믿RUŃ·ÉKã[:þrÙœ¬·vþ``UÆ8™pQŸþ¹Â¡­QÙêW·½AåLŸ¶•Õ¦žã굟ütLO'T‘q^›@±‰©éû&“ôú}×8\Ëì• (£ánuh;{F_ì/yßÖüó‡VÚëÐvwD{]W¶F&g °ù](‹E?-ÿEÁÁÁjÕº…6¼&GçMYú·¾]wJW žFéãeR¥0íW_®-—ëó_yå-X°@o½õ–z÷î­E‹iÓ¦MYžÓ¸qc+ _ŠOÑS3öiÛ{s<„††j„ >|¸–.]ªG}TÍš5Ëòœ9sæ()))×uŽ9RÛ·oפI“T§N;vL¾¾¾Yž³yófEDDhüøñ Öäɓշo_íÛ·OÕ«W×™3gT»víôþ­ZµÒ믿®§žzJ;vT•*U4tèP5nÜX/¾øbz¿ÚµkËf³éܹs•ÙÙäv­:µW—®Ä§·MØñ½Z‡×SÙ€âÿÞ}wd£¶?ìÐv_½ÔÈCF‘\S­Œ†õ¬­iËþ»®Úžc±úrå îQ˸ŠHÜåTýz¿C[XŸÆÝS?“3à?Þ&/½Öæ^ øå}YlWÿ8b1ë•­ó5ç¦nÿ«‚ðî®EºpÅñú¾Ï7ëã°èŠA%ÅXHhˆÊ‡—ÏqÿK ©Ùw*b±‰©J5[åíçëszè!͘1CÔk¯½–mÿæÍó6’n×®]jݺµî¼óNIRÓ¦MstÞ¬Y³ž;<<\¿ýö›~øaÅÅÅ©råÊýŸ}öY­ZµJƒ Rß¾}µcÇmß¾]^^ÿ]ͧJ•*’®®pެû•Ò¸–ýôì†/ÓÛ¢®$èÍ ôA‡VVøÎ^ŽÑd§U^«–.«MÜsÌ›˜Þöþ’¿Õ£yEÕÌâLÏ÷æw‡t>Öq®ñý(<˜tä̵aÕ4ðÚ›¦|ï¾xLó¯Óõ;XYáûýÌ_Ztl‹C[ç*×éöZ­ ªi¸F%HwS“òº¶Z£ËpðØÍµ‡R’L&“Zµj¥Zµj©|ùœ¶¹õä“OjþüùjÖ¬™F­]»ve{ŽóhÇR¥J)<<<}zx`` .^¼èÐÇd2iÖ¬YZµj•†®yóæ)<<ܡυ ÒÏGözTo¦ÕGÚþrr·~9¹Û Š ŸÕfÓø­ó”z%½Í$“^ks¯}ü ¬,÷ü}½ôÎÃ×9ŒüIJ±è™™ûÒ§„G¿í½ O;´ÝØ$\}ÛUÎä pmØu7«fÇïSö,Ցس™œáùâR’ôê¶ùme|õJkϸŽyqLjJ.(ÀGK_j§=Çc•”lìÊ>Þ&U P­ E7ý&¯×¨|øá‡Õ§O-\¸PË—/W—.]Ô©S'-^¼X>>9ÿºe² [BBB´sçÎ }BBBÒ·]Mé?yò¤¤«Sß‘3ãZöÓ¶óGüßB,¯oÿNMË×VÅÀ,ÎôL³®Ö¦³ŽŸó¾uÚ©]EÏœ2Ü*"Tv­®Ù¿E¦·íø;FÓ–ÕÈ^u ¬¬pœMÖ ³ÿ”Í.‡-裉44®(+ÀÛW¯¶ A«§Éúï?,W,©³yŽæu{V~ÞÅ/6zuÛ|½ãÐö|ó>ªP ÿŸï‰Šß'ä‹·I-ë–Ì+¯×¨”®ˆÔÀµvíZuïÞ]ûöíËótò hΜ9²ÙlæÓO?­n¸A 6Ôý÷߯-[¶8ŒÎŒŒŒTHHˆ*U*Â/åÊh\Ë~znãWém1ɉ³i޾è:\Þ¦â3 iô)}¸w™C[¥R¡z®yoƒ**£ûÖÓÚ?.êøùËémÓ–Õ ×•S‹bôï™Í&=ÿÕŸºçøG“qw7P¥0¦|È›Ö"ô`ƒ.š}`uzÛèÓšöÇr=Û´—•¼EG7g˜5Ñ¡ò5º³N[ƒ*‚3‚J€å5T|÷ÝwU½zu]sÍ5²X,š7ožJ—.­š5kæ¹–6mÚ(99YÇO_T端¾ÒâÅ‹µsçN…‡‡«]»vzúé§®uù×_©uëÖá&²×³Fs­<µG+"ÿ›¶¿íü}þç/z¼QO++8IæÞ4G©Vsz›—ɤ·Ú=¨2¾ž}©€RþÞš:¤±îz{kú”o³Å¦‘3÷iÙøëU&°xüÚ3kå ­ýÃñ’=šUЀNU ª@q1¢ñíÚtö Åü“ÞöÕßt}ź¾R++8ÇãÏkâÎÚBýKë6÷É$¾7¹‹âóçaƒ$''ë½÷ÞS·nÝÔ£G>|X?þø£Ê–-›çÇlÓ¦ªW¯®~¸ú…zïÞ½1b„¦M›¦êÕ«+ @_ýµ,X ¹sç¦×±lÙ2ÝsÏ=òºJšWZ÷WÕÒŽ?³ÏþüY;.ümPEëõíßéXÜ9‡¶Á×vWë UT°šÖ ÑÈ;§zG^HÒ¨Y8L“öT{ŽÅê…Ž«´Wñ×Û1å@þùyûèë’¿·oz›ÕfÓèÍs2L“öDW,©z~ãl%™G¤¿Þæ^¦|»‚JP¬M™2EÛ¶m+Ôçx饗´}ûv]¼xQ—.]Òo¿ý¦N:¥ðÁÓÉqµŸæØ±czæ™g$I^^^4h¾øâ ™Íf5iÒD±±±êßÿ¿ ½7nÜXñññºÿþû%IóçÏ—ÉdR¿~ý ë¥ke|5©ýÃS½-6«FmüJç“<{õ¹‡ÖiéqÇÿ—«©'ŠÉhÑ4ßR[mê…9´ý²û¼>]qÌ Š ÆÅ¸ ýt·RÌÖô6/“I“5RÙ2žµ÷U/¤²F6¹Ý¡-êJ‚žÝ0Ëa4¾'zmÛÿé¯èSm÷DtÐUT2CP ঞ~úi%%%iÞ¼yÙöµZ­š8q¢^zé¥ +Š#çš–«¥áoqh»˜§¿ÏT²%Õ ªògç…£zw÷b‡¶2¾zçú‡äãåmPU…ÃÛˤ)ƒgïÞ_|D¿ï¿dPUùc¶Øôäç{u6:Ù¡}hÏZêpm9ƒªP\=Р³ºVmäж÷Ò ½½s‘Aåß7‡Öføc]DH%½ÐüNƒ*BV*ÜTPP~øáõéÓ'Û¾^^^úâ‹/ôøãAeÅÛàk»«cåkÚö]:¡×·gPEyw.)VÏnüRf«%½Í$“&¶{@5‚ÊXYá©R6@n,o¯ÿ®7f±ÚôôûtÂn±O1aÁAm>è8»Ãµå4ªwñ˜²À½ü÷ÿˆp‡öÿ;ò»¾;²Á ªònÛùÃzw—ãë‚|4¹Ã£ °›æ÷AP àÆZµj¥àààõíÔ©“|}ùÒ_^&“&]ÿP†_Ò–Ûª™­4¨ªÜ‹KIÒÐ5ŸêbRœCûÐëzd-SÜtlXNÏöv¼^eT|ŠšºS—âS29ËýÌ\yB_®Šth«Z6@ i,o~P8ÊøjJÇGèã8:}ÂŽïµîŸ? ª*÷þŽ;«‘¾”ÅæxÙŒ·¯Pµƒ+X²BP 8 ö+¥n¬Ò¾íSöüO‹m5¨ªœK±˜5â÷™:{Æ¡½S•†z¢Ñ-™œU¼ùB{vï3ºÀãÔ ®¤·Ú= /Ó¿¤ÙdÓ+[¿ÕZ7QbµÙ4vË7ÚvÞq…è:ÁõN»^Oqf2I“5R£Ž#’wÕS3öÊlqߥÀ7ŒÒ33÷Éj·\¹É$½óðuj\3g#¬ ¿n«ÙJÃÝìÐvÙœ¬'Ö}®ñ ª*{i3 Î\Žvh¿±jc »îæL΂» ¨ ˜òööÖ}{i؃մ+yqcÕÆ.¶uDÉWÚtö AUeÎb³jÜ–¹Z¹Ë¡=< XÓ»<®`¿RUfŒÒ>šõTsU-ë82ö×Ýôäô=nVn9­AÓWø–¤çﬧ>m+T€’ê‰F=Õ«Vk‡¶ I±øÛGŠL¸hPU™‹KIÒ°µŸê°ÓŒ‚fåkkRû‡KÌë<A%…êwÖà†ÝÚ’Ì)zrý ·Yi±Y5vóÜ +›ùèÓÎÃT¹T˜A•«B¨¿¾ÙR!¥¯ßºb×y=õ¹{…•›Dià‡;•xÅìÐþP×êzâ–ÚU $3ɤ×Ú PÛŠõÚÏ'ÅêÑß>Ò©ÄKU–Qlr¢¯ùX{/ph¯\QÓ: añAP dcD“Ûtgí¶mÉ–Tü}–VžÚkPUÿI±˜5zÓ-;±Ý¡ÝßÛW“;<ªkªT™{¨W¹´¾ÞL¥|ÚÚy^Ã>Ý­ËÉÆ_³ríõèG»2ÔrK‹ zeÀ5U’¯—¦t|TËÕth?{9Fþ:E¢OTÙ.^‰Ó 5kÔI‡öð€`}Þåq…ú—6¨2äA% “LzµÍÝR£…C{ªÕ¬Q¾Ô7‡ÖTÙÕ$C×~šaº·¿·¯>ì8H×Wj`Peî¥u½0}ùtó aåÊ=4à½m:›lPeÒüõ§5hÚ.%9-òÓ³y}ôXSy{1U€±ÊøjzçÇu]Ùí®Äéáß>Ôïgþ2¨2éHìYÝ÷ëä iÅÀ}uÓÓ%vF§"¨rÀÛ䥷¯P}j·qh·Ø¬z{çB½±}R­æLÎ.GbÏ辕“µíü‡öo_}Ôi°:T¾¶Hëqwmê…iÖSÍUÊßÛ¡}ïñ8Ý9q‹öŸŒ/Òzœ›‡ IDATÌ›Þøî ÆÌù3Ãô[[VÔ´¡MåãMH À=ûjF—ÇÕ0¬šC{bê _÷¹æ^Wä5­9ý‡\9Eÿ$F9´W.¦¯nzZ5Ë„yMÈ‚JòéŸþÑã?®ÀÀ@%'g="'55UãÆS³fÍTµjUÝ}÷Ý:vìXžû(ZÞ&/½Þæ>ÝÑ!ñÿ;ò»X9U'‹hqÅǶêÞ_?ȰòjißM»á1µ¯ÄtaWÚÖÓœ‘-äçÐ~:êŠî|k‹¾Ys2“3 Ö™è+ºçÝmšùë‰ ÇîlWYiBH Àíû•Ò]‡«u…zí›Uwü g7|©„Ô+…^‡ÅfÕ{~ÔSë¿P|j’ñj¥ËiöMO«zPùB¯ €<ŠŽŽÖرcuÍ5×hæÌ™²X²¾Æ™ÍfSß¾}µ`Á=ZŸ}ö™Î;§.]º(222×ýP2MŸ>]ûöí˶ŸÍfÓ„ töìÙ"¨ªdñ2™4¾ÕÝz²Ñ-2É1Hú3*Rý~~Wó¯“ÕV8‹´\¸§'×ÍÐK[æ*Éœâp¬b`ˆæÜô´Ú9-zG­"BµpLլภzrªU/ÍýK?Ü¥ÓQ…ó‹¶Í&}»þ”z¼²Q;ÿŽÉpüÉÛêèƒGRp[Á~¥4½ó0ÝV³e†c¿œÜ­;z[ë q±¹¿¢OiÀ/ïkÖ_«d“ãÿk›•¯­¹ÝŸQ•Òe íùQ¸*È£AƒiëÖ­Z²d‰–.]šmÿŸ~úI«V­ÒòåËuï½÷êŽ;îÐ?þ(“ɤ)S¦äº\[´h‘ºwï®'2ŽR²X,0`€¦Nj@eùwòäI=÷ÜsŠŽŽÎ¶¯ÉdÒš5k4a„"¨¬ä1ɤazêÝögXE41õŠ&îøA¬œ¬ŽØs&[R5ë¯Uê½|¢ÖüóG†ãÊÖз=F©AhÉ^8'§jW,¥EcÚ¨UDh†c«÷]PW6êãåG t¡ÝGcuÏ»ÛôâœýŠOr¼L€¿¯—Þ}ä:=×'B&2JnÎÏÛGo_ÿ †^×#ÃíÎ\ŽÖë>׳¾TdÎ2ˆº’ ·vþ ¿¼¯¿¢Oe8~kšÙu¸Ê”)°çDÑ#¨ ¾þúk­\¹R]»v•)¿UΘ1CÝ»wWDDDz[hh¨xàÍž=[V«5WýàZÏž=uìØ1=:ñY³fé§Ÿ~Rß¾} ¨,ÿÞ}÷]µiÓF7ÜpCŽú;V3gÎÔ™3g ¹²’«gæú¶Ç(Õ ®˜áØÞK'ôЪ©z|Ýtm>w(èœJH½¢ÙVëöeôÁž—’”¡Ï€z5禪’§ç(©Ê–ñÓüçZkHZÂÁÄ+f½»èˆº¼ô»für\±‰©y~ž-‡¢5äã]ºóí-Úv8ãj„jᘶº»!3Ïa’IO5¾MuìrUí_NîV¯åõòÖou$6ïßEÎ^ŽÑ”½ÿÓ-ËÞÐÜCëd±9~öóöѸ–ý4©ýÃòwúã!§K—.ªV­š¾ùæ=ÿüó…X]ÉV/¤²þ¯Çsš´k‘¾ÿ{S†@rý?ûµþŸýª\Q=k4W×*Ô ¬ª¼M™ˆK¹¬íþÖÏ‘»µæŸ?”˜Éõ¾Êë¥Vw«[µ&úšJo“ÆÝ]_í¯ ÓèÙû3¬þ}>&YÒKþVfẹEEu¸¦¬BJgþ˰ÅjÓÁÓ Z¹ç¼–m?§ƒ§\ö3™¤~í«êåþ T&_Íx¦.UiÁÍÏë•­óµñì‡cf«E nÖ£›Õ"¼ŽºWkªÎU¯S ¬¹9Ÿ« ghåÉ=úýÌ_ÂÉ4õC«èͶ÷gXàž‹ÿà$55U»víÊôxpp°®¹&w‹TØl6>}Z+fu•:ž«­[·ÊËËK“&M’¿¿¿Fetyy²nÝ:EGGë¶ÛnËñ9&“I·ß~»–,YBPYÈ}üôJëþºµfK½¶íÿt<þ|†>ÇâÎéÓ?VèÓ?V(ÐÇO B«ªJ©0•ýwŠÚKŠ.^‰×ñ¸ó:!˘^&“î¨ÕZÏ7ëãr r¯kãp­z£ƒÞYxXóÖžÊpѤ‹–l=«%[ÏÊd’j†—RÝÊ¥U!Ø_!¥}w9U WÌ:}銞NP•¬W€¯Q>Po>p­n¸ŽÅx¾Ê¥Â4½Ë0-9¶Mïî^¬ØäÄ }v^8ªŽê]‹æ¤ú¡UT10Dåƒe’IQWâuþJœŽÄü£sI±Y>Ÿ¿·¯†\ÛMƒv——wa½,€ 'QQQêØ±c¦Ç;wî¬_ý5WiµZe±X\.¸ããsõǾ¾¾9î—S±1±ºxÁñÚ@!¡!Y>ÆŸQ‘ú߉ºâ´HGQóöòR…Àõ¯ÛA!yb&Ož¬æÍ›kÖ¬YêÙ³§¦NªÙ³g+000Ós}ôQ<™ùŠ¿YýÜ­V«¾úê+­_¿^111jÒ¤‰†ª*UªH’Ìf³fΜ©7*%%EmÛ¶Õã?.ÿôÇX¶l™-Z¤óçÏ+""BíÛ·W¿~ý$I[·nUùòåzõzz;vìИ1côî»ïªY³f’®†ì<òˆÚ´i£#FH’"""4cÆ ¥¤¤ÈÏÏq•c¼Ö"´è–ÑúþïMú|ÿ¯ºÉ/ZIæí¾xL»u,×ÏѶb}jÚK ËzÞÈ`wW&ÐGoޭšÞ]tD«÷]pÙÏf“ŽŸ¿¬ãç/çú9‚üôä­µõP×êòõáJ\Š“LêS»n¬ÚX3ÿZ©y‡×eXô-Mtr‚¶œ;”ëçð6y©W­ÖÞøVU*•ñÃð|•8©X±¢RR 6¤óööVåÊ•]®ÀœÖV­Zµ÷ˉÔÔT}òñŒ í:·QÙ°Pùùù©eËÖºâë+‹Å¢Ø˜º|Iþþ‰R¬Y*J¿Ø£é×ÉõyÂÃõø°a?~¼-Z¤Ö­[ëÆ®]“q•Ý4M›6U,¦…gv®ÙlÖÝ÷Ü£ÈÈHÝu×]ªX±¢6oÞ¬›{ôPéR¥”’’¢^½z)6.N}ï¼S ‰‰š8q¢¾úê+ý¼b…ôáGéÃ?ÔÝýú©c‡:~â„öîÙ£îݺI’:¤5j¤×Q·®*„‡ëÁÔª•+åï﯉o½¥­[·êí·ÞJïW±B%''ëÐÁƒ.§¼§¦¦jÇŽmyþÌÇÇÇké‹ótnq$éI5ÕNß³Úd>­ó¶Œ#KrÃK&5ô)¯N>ÕU#>Dÿ¾CkGÁkøøxÅÆÄÈÛÛ=GÂô­%µ ñÒšc>ÚuÆG–|^¸|i›ºÔNU»ê—埴K+–g>rY»|ù²||¼µoï£K‡III–ÙlÑÉ“‘F—RìEHzÖ·µ6™Nk›ùÅÛò÷ÝÚßä£Þ•ÔÁ·ªÊ+¥mçÖH9e±XtùrbŽ¿óÜÑ«O!WT|TPDêÕ«§7fhß¾}»Ê•+§ððð\õËŽî½ÿî ÓÄkת©ÀRJN¾z6ÅÄÄ($4T¿Et«R’þˆ=%ß @•òñϾ³“W_{Mßÿðƒ~ûí7mß¾]!¡Yÿå=mbnM›6Mÿý·öíÛ§ààà Çß~ûm¿pA{÷îM¿¶éÓO?­-Zè«Ù³5zôhýøã:ãìÙ³*UªT†öÊ•++2òêô³I“&éæ›oÖܹs5xð`™L&9R/¼ð‚$)$$DÌð­[·Nß¾óÎ;3O{=!!!™Ö‡¢U6 Hª4T'£ Ažøx›Ô°z5¬^ÆèRÀ#U.¦Ê¥ÂŒ.nŠ €BR¥J>}:}Tœ¯¯¯~þùg=Z¯½öš®\¹¢N:iíÚµªT©Rúy9íWX®+[Cו­‘}Çb¨]»vªW¯^®Ï«Q£†vïÞéñ̦óïÚµK]]àåå¥îÝ»«{÷î²Z­úä“Oôì³ÏªW¯^ºæškT£F }ÿý÷cÚ´iªV­šÂÃÃ5xð`-^¼Ø!˜ŒŒ”¿¿¿Ë•äwBP @èÑ£G†ÅHfΜ™¡_éÒ¥5mÚ´l/§ýP°{ì±ýôSmܸQü±$iÍš5jРAú5EÓV'O»oÕª•âããuéÒ%•+WNÒÕ•ÀÇŽ«åË—«víÚjÑ¢…¦Nª‘#G¦×vìØ15iÒ„¿àö¼Œ.ÀÓ=ðÀ7nœžzê)…‡‡«bÅŠºá†ôÇH’n¾ùf}ôÑGzçw¦°°0M:U‹/VDD„$iêÔ©ªU«–Ê—/¯ððp5Jï¼óŽjÖ¬)IêÔ©“‚ƒƒµlÙ2IÒ¥K—tï½÷jĈêØ±£ªV­ªO?ýTãÆÓŽWWƒ¶ÙlZ¶l™n¿ývÞ wQ е§žzJ=ôP¡?Ï+¯¼¢çž{N‡’¿¿¿êÔ©“¾’$ :TÔÁƒ¤Zµj9LÑ^´h‘¢¢¢)›Í¦ˆˆ•)óß5ðJ•*¥þýû뫯¾ÒC=¤ääd}ùå—ºþúëÓûôíÛWU«VM_´gõêÕ:}ú´~øáBý@~T€b­nݺEö\¥K—ΰê¶=???5nÜ8ÓãeË–UÙ²e3=>zôh5jÔHkÖ¬Q—.]T¥J• }Ú¶m›¾ýæ›ojÈ!.ûÀCÔ¨QCS§NUhhh¶}­V«n¼ñF=þøãEP•$m±žìxyy饗^*äj€‚Ãb: GP ÀpLý ˜2›Íš?oÕ¥ë jѲ™Ñ%@¦*(¦|||4ྻU·nLûØl¶"¬îÈf³Éd2]ÀÔoJ*ooo¥¦¦] f±XäíímtA%%•Ìf³ÑeÀ`)))òña’ ŒÇ·RJ°   EGG+!!AF—ƒ"d6›•’’¢   £K$1¢€Í××W¡¡¡Ú½k‡Ñ¥ ˆùûû+,,L¾¾¾F—HbD%dµZåïïotJ0FTPÂ%]NRlLœ,‹Ñ¥ÀØÍfÅÆÄ+))ÉèRࢣbŸ`tð@ÑQ±Š‰‰3º x ˜˜8EGÅ]ñòe·ùY?w^ÑÑÑnSÏ… ”t岂‚J]Š$É&›[½?îôÙ±ZmJLLt›zNŸþGQQQnSOjjªÝç矯cÇŽËŸ3HIIQBB‚ÛÔ“˜˜¨ÔÔT·©çRT”J”ÉËdt)’®¾?G“···Ñ¥Hr¯ÏrTT”l²å¸žÐÐP•+W¶«*ž 뿆ì×Õq“]{Ú½—‹}û>^vç¥í§Ý¼ÿ½÷ùw;í>äâÅ‹m6[.^ ¯bbbT³fM£Ë(‘†?ñŒüýü²ý²i³Ùd6›åëë[D•eÏb±¸Í—d«Õvõ‹†›üáNït50ðññ‘ÉäïÙl‘{¼?6›M6›M^^î1‰ÉjµÊd2¹ÍÏ*55UÞÞÞnóþ¸ÓgGr¯zÜí³l6›e2™ÜæßBwûwÙ>;’{½?‹E6›M>>î1fËÝþ]v§Ÿ•ä^Ÿe«Õ*‹Å’ãïË7tî¨;zÝšïçõóók/)V’E’ÙîÞúï¶Õîf³»¥íËn_vmÎû6»m{Ù…g®¹Ç À}üÉd£K€s?‰(Ñ*Ž €á*Ž €á*Ž €á*Ž €á*(Á6mÚ¤^½z©bÅŠjÛ¶­¦NjtIð¿ÿþ»î¼óNÕ©SG*TP=´iÓ&£Ë‚úä“Oäçç§­[·] }ºÑeÁMmß¾]7ß|³:uê”áØÙ³gõðëvíÚjРž~úi%%%PeñEP @ µfÍõìÙSµjÕÒ·ß~«>}úh̘1?~¼Ñ¥Á­]»V÷ÜsZ´h¡O>ùDŸ~ú©uË-·èÈ‘#F—røða½ð F—ræÌÝpà Z³fyä-Z´H/¿ü².]º¤R¥J]ÜØ½÷Þ«Õ«Wk̘1Z±b…úöí«#FhÚ´iF—7rèÐ! 0@7ÜpƒV¯^áxÚ¿AçÎÓǬ±cÇjñâźõÖ[e±X ¨¸x2ô¸®Ž›ìÚÓî½\ìÛ÷ñ²;/m?íæýï½Ï¿Ûi÷!/^Üh³Ùrñry£š5k]\¸þúëuíµ×jÖ¬Yém|ð^~ùe9rD•*U2°:¸«ääd%%%)444½-&&F9r¤^zé%«ƒ§°X,êÒ¥‹nºé&Mœ8Q¿ÿþ»Ú´ictYpsÆ ÓÁƒµ|ùr]ÆŒ£ÿýïÚ¶m[ú¿AÛ·oWûöíµ`ÁõîÝ»Àëòóók/)V’E’ÙîÞúï¶Õîf³»¥íËn_vmÎû6»m{Ù…g®1¢€hçÎÚ±c‡žxâ ‡öAƒÉd2iîܹUwçïïïRJRhh¨"""tîÜ9ƒª‚§™4i’4tèP£K‡8s挾ùæ;–¹b6›%IQQQí¥K—Vpp°%Á ùùùiÿþýš9s¦"""2·X,š5k–èðoP«V­Ô¶m[‡?ü#*(þúë/y{{«E‹í!!!jÔ¨Sx‘+V«UGŽѵ×^kt)ð»wïÖ”)S4cÆ £KÙ¶m›$©[·n’®ŽäŽ7²$xˆ:uêèúë¯×O<¡-[¶H’–.]ª9sæpù 8(]ºt¦ÇΜ9£˜˜µmÛ6ñ:èðáÃ…YZ‰BP @ tòäIU¨PA^^¿ TªTI§N2 *xª9sæH’ú÷ïop%pwÉÉÉ8p ^}õUÕªUËèràANœ8¡J•*iÛ¶mjÓ¦*T¨ òåË«sçÎ:xð ÑåÁÍ-\¸PݺuS§Näçç§|P .TçÎ. âäÉ“’¤Š+f8V©R%>}º¨K*¶*(RSS3½è·|||Џ"xªsçÎiüøñ7nœÊ•+gt9ps¯¼òŠÊ•+§aÆ] <ÌÙ³g• gžyF“'OVLLŒ¶mÛ&‹Å¢~ýú)%%ÅèáÆ–/_®eË–éæ›oVß¾}•ššª©S§êøñãF—‘öoŒ«ïÏ|w.X•”@Õ«W×ŋӯÛdïܹsª^½ºUÁÓ\¹rEwÝu—:tè ‘#G]ÜÜï¿ÿ®3fhÆŒ2™ kMOWááኊŠÒ‡~¨:¨T©RjÒ¤‰fÍš¥ƒj×®]F—7µ~ýz :TóæÍÓÒ¥K5þ|+U«Vuhˆˆ···.^¼hDYð ,PÆ Õ±cÇô¶jÕªé³Ï>ÓñãǵqãF«ƒ§¨Zµª\~^¶oßÎwçDP @ Ô¡CÕ¯__ü±Cûüùóe±Xtß}÷T<ÕjÕÀuâÄ -_¾<Ë‹Ïi~øá8pÀá¶råJIÒìÙ³uàÀuéÒÅØ"ᶺwï®°°0}öÙgíÛ·o—ÕjU“&M ª î®T©R:uê”âââ\ *âŠà‰üüütÿý÷köìÙ£p>¬Õ«Wë±Ç3°ºâ…Iô”@&“I&Lн÷Þ«aÆéÞ{ïÕü¡_|QãÇWXX˜Ñ%ÂMY­V 4H+V¬Ð‚ ©ÈÈÈôã 6ä:Mp)mÚœ½€€IRݺuU§N¢. $((HcÇŽÕ /¼ äädõìÙSgÏžÕøñãõØcqÉdê‘GÑ_|¡›nºI£FRíÚµuòäI½ùæ›j×®Z·nmt‰ðÏ?ÿ¼–.]ªÞ½{kÔ¨QJJJÒ¸qãÔ£GuëÖÍèòŠ ¾EPBõîÝ[ .Ôû￯~ýú©Aƒš:uªhtipc[¶lÑܹs%]áäìäÉ“.WÄ€ü1b„Ê•+§éÓ§kúôéªQ£††Ê5r‘¥k®¹Fk֬ф ôâ‹/***JÕ«W×wÞ©Q£FÉ×××èá!êÔ©£µk×jôèÑ2dˆÊ–-«>}úè7Þ0º´b¥°.&”Ýãº:n²kO»÷r±oßÇËî¼´ý´›÷¿÷>ÿn§Ý‡\¼xq£ÍfËÅËäULLLúu¥9ãçç×^R¬$‹$³Ý½õßm«ÝÍfwKۗݾìÚœ÷mvÛö² Ï <\ã• GP Àp• GP Àp• GP Àp• GP Àp• GP Àp•àAêÕ«§É“']Ž AáJãÃIDATràå—_V™2etøðá Çn»í6µlÙR©©©í©©©ªT©’{ì1—i³ÙT³fMM˜0¡PjÀ“T@Œ7Nµk×ÖðáÃÚ¿ýö[­^½Z_|ñ…|}}Žùúúªoß¾úñÇe6›3<æÆuæÌõïß¿PkÀT@øûûëóÏ?׺uëôÍ7ßH’.]º¤çž{NÏ?ÿ¼š7oîò¼(**J«W¯Îpìûï¿WëÖ­Q¨µà * ‡Úµk§áÇë…^Ð¥K—ô /(<<\ãÆËôœN:©jÕªúá‡Ú­V«.\¨vÙx‚JÈ…×_]AAAêСƒæÍ›§3fÈÏÏ/Óþ&“Iýû÷×’%K¦oذAçÎS¿~ý$Iqqqzíµ×Ô¢E ………©fÍš4hΟ?ŸmM~~~Z´h‘CÛ€BÐÔÔTMœ8QM›6UÙ²eÕ±cG­X±"·/€BCP ¹PºtiMž}ú8ô‰ŒŒÔ›o¾©ž={ªeË–zà”’’ârÅðÜØ»w¯$©iÓ¦òóóK¿-\¸P‰‰‰ùzl A%äPrr²† ¢|P½{÷ÖG}¤Ï>û,}„eV   .hýúõúþûïuË-·($$$ýøñãÇÕ¶m[ÅÆÆj„ Zµj•¾ÿþû×f³Ù2=V¾|yIÒŸþ©¤¤$‡Û—_~™ãç 0T@½ñÆŠŽŽÖ;ï¼#IêÕ«—úöí«!C†(!!!ËsëÖ­«Ö­[ë»ï¾Ó¢E‹tï½÷:ÿõ×_•œœ¬·ß~[-[¶Thhh¦éJ†……éäÉ“mIIIéÛ7V@@€æÎ+ooo‡›—¿ÜÿG€عs§Þÿ}MžÓÊ*snsuïÖŒ¾F¥sŸ¬Vw¾N¥É©-³•ÀÓ®Siï#ÇëWzIò•ä?gΜvݺuëÐÐf³Ûl6O sÀ-ÅÅÅ©ZµjF—nÁd2¥¦¦¦žÙ¹sçÜŽ;.ÕÕ…sRå8°Îª«×¦´Úí§Ýg7Üùz•imrÑžÕvf -ô,Š¡ƒµ Ž}鼟٢:’ã¢:®î·}ìnÎÅPKä†s€˜B¦Ýìgÿ:o;ß[]<–«©àYMwuï\kv¯¥PøæƒçM9 ÓúÙß˩;¯UWÆ´íìžÃ~ª¸Y™¡@Ne$Ú‡Î×¥t'íIûí̞ù-7uÆ‚ÊÌä6ÀLÛN (ÓöÓ¤%Î&]ýA§÷–ã‡Ä¤ÿ‚MûšA%rÇ>0t5eÛÕâ9Îk­¸Z8Ç9°ô˜@23îTº™¶o?JÒy$¥óvš´~i?\ÉqZ¸œŽÛ‡“i¡&S¿®®éZ:ªtI™ÕJß®¶ŸÓ¹Ÿ«}ÃEP™Ó‘‘ùy|)cH™P¦…›ö÷öçÚœú9¨´Ÿfnÿ<@V\€Ìn ¸«mûó%×aea…lUèV«KÙ¯nßæ¼j¸—ÉÉjÅpçÇÎék2›ªÕÊÝÎa¥ä83³U½s2šÒ-WûNãŽS¿¥¼ÂÌl:¸ôß(É´•69N!·1Q €‚ՈʴãÎ#&ÃHç)ãΗÑí¦}Kî5¢Ò¹_^FU:¯Ðíjån/§ãÎûÎýœ·ëœ9‡VÛÎÁ¥ó5)]õËêš•…5š27ýò¬¨FTæu*íGR¦qµ¨N«ÓqûQ•iý½ôßÊà™=ŽýóRæ9’5‹ýìÍÉlW!ea(’˜î:õ[r½¢·}[ÚTnWç8/¨#û®¦ˆ§õ±f±ŸÂK€’!7^V บÞ]h™Ùóçf4¥[)ÊP­ ¦;o;OwÕæjÚwf÷®Î!|@~¸ ]-‚“Ù4îœLïvÕ–Óí¬I¸é]Ob'·«;ïg:·Û\´9È̬W ‚Jä‡ób:™öÛ¹ )3 ó;š²ÈF`u——Q•öû٪̬='‹ñd¶mA%ò'³)ÛY”ömÙšÌn4¥sàèV£)%÷Qéª_va¢ó¨Ç¬FV¦m;¿É9a äTf á8÷‘²3óRz#F VX)e?²2³s]šÌì9²ª%[^¦`çd´e~BJ·M)¹wPéªoNÚÉm™Ùâ:™Õ‘[šž-¿¡]V£(ç4ˆÌË‚9¹]©¼È ô¨JWÇòdº:îªY¢tÕ'» 2§a¤GŒ¦”Ü?¨tÕ7¯aengÕÈ WÁ¤\´å$„,ì2·} „‘\Q„•iû99?³2'm€³œ“öm¹ (3ë““cÙ1dž¢^õÛYa…•9mËé"9yª€â-¯S©s{MÉìVóöèR2>XËOPéÜ–›ãYõe% ZNGRºêŸŸ2³¶Ì”Ø RÊXéÜžßÀÒþ˜;¼?(>2»V¥ýñì¶sz<«öüö-pîÄ嶆¼†•ÙõÉ.´ÌI? MN‚DWÇr@DH™—þÊ]B·‚ +íDðX£=P¼Ô¨ÅÜ›¹ ?³chH)¹W¸VaeN7»pÓÞ'xžìF=æ$(ÌëÍÜ<®aÜ-€ËK=…1e›ëS °dwJWý]mgÕ//m(w ãòZOAŒš,¬sPråfÄd~ÎÍkàHP™… +íûäkwÇ÷E§ ¿üŒ¸Ìíó¸ w ØòSW^ÎõÊÇóùeÍÃ9ù Ý*¤”Ü7¨”Š>¬t>×ßx®üLw~Œ¢>·Ð¸{—ßú âõ¹û{ÏPa~Ã-CJÉ3B8w =á½@Ñ+Œ0ÐBÎBåIa[AÕêI¯%WA‹nP¦ñ´ÐŽ•ºPÜô âÁÃ:¦q ¸q×éâEÆ“ºÂ¬Ý“߸¿Â =* LS¹¢| Åáý@Ñ)ÊÐÐ#Ê4Å%xsÇ×áŽ5 ÿÜ1tÇšr¥¸…iÅíõYñø€2MqöŠók@ÉUlÂI{%!Ì+ ¯Å_± (Ó”´¯¤½^x¶bNÚ+éÁ]Iýp/%&˜tFPçˆ÷E©Ä“Îær†÷ ùA ™ ¸‚Ç{ P2>Pœü?Ä!H%ï5IEND®B`‚Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/screenshots/sin_cos_dark.png000066400000000000000000003152341520337127000273650ustar00rootroot00000000000000‰PNG  IHDR*6ñh½dsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timeons 10 jan 2024 13:17:18´%Æ8 IDATxœìÝwxTeÞ>ðûœéÉ$“!ZH¡7•eQ‚uÅîÒA}qPqËëêoW±½ëÊ«Â*(–Y)k‡×…EX•Š@-H =“©çüþ3d’©É´$÷çºrÍÌsž9ç;ƒÂäž§DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD&Dº€vˆï)QÇ Gº€ö„¡šø>Qk0Ôôœ+¾DDDDDDDDN 0/éèÁ\GýDDDDDDDD]:lpÙÑ‚ºŽöz‰ˆˆˆˆˆˆˆ¨më0ÁeGî:Âk$"""""""¢ö¯]‡–í9Äkϯˆˆˆˆˆˆˆˆ:®vX¶·0¯½½"""""""""oÚMhÙ^‚½h|ÑXµ^4†ƒÑXS@ÚC˜Î×ÐÞ/"""""""" Ÿpˆm:¬lËÁ[(kB|~""""""""ê¸d„6Tl“e[ ãBQ³‚sùK Á9ÛT`ÙÖ‚Ê`ÕË“DDDDDDDD­‚9â²Í„•m)¬km­B“Ûp^›ˆˆˆˆˆˆˆˆ:¶–†r“Ûp^;ìÚBך[NúÛ¿-¼DDDDDDDD>þ†‚†‡Á-£:°Œö ­¥õPúêÇ5,‰ˆˆˆˆˆˆˆ¨5|­AhÀÙÒÐ1jÃÊh*[Rúz®·ã‚‡ûDDDDDDDDD­%{¸ï­Ÿ§ãí*¬ŒÖ ®5ëHúB6moÉ󈈈ˆˆˆˆˆˆüá+”ôtÜŸ0³5ë_Fh àZR4†"œŒÆ÷“ˆˆˆˆˆˆˆˆB'Ø!¡§Ð²¥AgKë»h ÖZºé·‘’îÚ<µûºŽ¯~DDDDDDDDD­™æh`ÙÒÑ•QVF[èH=†”îJ_Ïmé®áDDDDDDDDD5 ýêí.° fXÉ Ò@CÊ`”îBÉhzˆˆˆˆˆˆˆˆ¨ís7ÊÒŸ‘“–m.¬Œ– .T!¥è㸿#'¹^%9s=H_#-›>–8o› +£!L EHÙ´Ÿ·€2Ñ–Þú9ø3úÑÛ¨IoÏoB¶‹°2·@jh:BÒÝ9¼…”žJ_A¤§ëùÃ×HHOA¤§@Òß°²éu½éÐAe°CJÑC»?e #2‰ˆˆˆˆˆˆˆˆáoÈh`)yh‡‡>¾D,¬Œtçïõ=Mùö7¤ô' ô¶ž%GTQkx %7íîË–†•LïAekGS¶$¤ôPz +ƒ¹Éµ_þnšã ¹¹ïigðÖ„•Q?ª2RA[0CJoA¤»cMJw£-½íÎp’ˆˆˆˆˆˆˆˆüá)ptÜzšæÝ4°ô'¬ôgÍʨ+£=¨ôµ.¥§RtÓ¯ñ­è湞ֱ½ÔADDDDDDDDä ÍG=º ÷½…•€û”Þv o\‡?:DP¬Ñ”þ„””Ÿ'Âý9‰ˆˆˆˆˆˆˆˆZ¢i°(ÁýJËÖ„•Q;ª2šƒJCÊÆí„”¢›öÆ÷?ŸA%µFã`²ñn ÍCɦÁ¥?a¥?»…7®Åa *•á¼ÛåÛßcîBJwÇÄ&ý¡¤· ²q;QK5$ÿnî7~ŽÐä¾ã¸ã¾èæÜ<†ŸÇZÒ/(ÂT¶†»ÒÛ­?!¥¢É­€†÷Du©MDàkTr³"""""""¢Ž!Ojôc``CCî$_j.Ý:ÂÇÆ·Žs8²§ÆÁ¦§[ ÌackDcPÙtZwÓcžú{Z¯ÒSH©„kH© éÛ·ïèØØØijµzB¡ˆE‘£)‰ˆZ¡ªª Je4þsCDDDDD^²,Kv»½Z’¤F£ñÇŽû€ ¡¥#¤p9ÀôV®¡¤óM.é)¤lvFpŽþ dÚ·»éÝÞvðv×ÇÝ4n—GJ*µÅôíÛ7×`0<­V«»[­VØl6ØívÈrTýyµ9P©T‘.ƒˆˆˆˆˆ(âDQ„(ŠP©TP©T°Ùl§ëêê^ŸN§C\\Dñò¯)±±±Ø°a6lØ€˜˜ý`ß¾}رcG _ pã7¢°°sçÎu{ü«¯¾Baa! ‘ŸŸÍ›7ãå—_FçÎ[|MÇë\¿~=t:]«Ïçé=""¢ègµZ¡P(Àu4¥»M¤ßújk¢ù_-ÞHO[«;upÙLG¡PÄsmJ""""¢èòÒK/aÏž=ÈÎÎv¶™L&   Ž¥›Üõ §M›6aË–-Ðét¸çž{ðÑGA£Ñ´êœî^gkDú=""¢–“$ …"Í7Óqh¼±NS-ÍÓ¢‚2Ò ð‡™ßt4¥@EQäNßDDDDDÑÏn·ãî»ïŽt.þð‡? ²²qqqøä“O‘‘ë®»ÎíÈREãë$""W …jµJ¥Ò9j]’$Øl6X,cãfI’ BÓ]¾ªt\ÀS&&7zì. ´=lBT’Ðúêëmô§»ED›ž×ÝöíDDDDDäAnn.æÌ™­V‹•+WbåÊ•->×¾}û°nÝ:Ô××ãú믇Z­ÆªU«ðÆo^{í5L˜0°víZØl6ôë×Ïù\³ÙŒ#Fxí×”N§Ã“O>‰ñãÇ#>>;wîÄóÏ?3gÎh˜nýÇ?þãÆƒÑhDeee@¯©¦¦_~ù%žxâ ddd8k]¿~=Š‹‹1qâDcÊ”)P(˜={6n»í6¤¥¥áèÑ£X¼x1¶lÙâò9^§?õ+ <ôÐCÎsæççcñâŸûî»ý~ˆˆÈ7…BØØXhµZ·ÇEQ„Z­†Z­†^¯‡ÉdB]]]«K¸•€ï”žBF€äå:”! 3£5´ó5—ÞÛh˦¡eÓ¶¨ÞJDDDD-:uê„7ß|Æ C¿~ý°`Á\yå•­:çĉ1~üxœ|8víÚÕªóÞxã°X,xä‘GðÄOà¿ø¶lÙ‚ 6`ݺu˜0a-Z„#Gޏ}¾¿ýúö틱cÇbûöíxä‘G4ü²yÓM7¡G€ñãÇãìÙ³¸ë®»`³ÙðÌ3ÏàÞ{ïõëuˆ¢ˆ~ýúaòäɰÙløñÇ]ŽO™2Åù^¥¥¥aòäÉ(,,ÄwÞ ›Í†‰'âÅ_ĬY³Ü¾§¾ê7™L˜4iNœ8 &4[×ÒŸ÷ˆˆˆ¼‹‰‰^¯oñóãââ ŒFcKOÑ4Ó’à} ÄÆmmrÍÃH•¾R_w·žÒcw[µ{J‰ˆˆˆˆÈ‹ãÇÃn·C¡P8ÛŽ=궯·¥¯ _QQ‹ÅÈËË$&&£Üf233W_}5 ]Ž têÔ °cÇØl6ÀÎ;ý *wîÜé¼o·ÛñÒK/áøñãÎ6“Éä>æää@E|ÿý÷Îk­[·/¾ø¢³Î@ëïÙ³' ¶nÝ”ÍwˆˆÈ•N§kUHé ×ë!Ë2êëë[òto˜Ü踻©Ý;î»»uw͈…œ‘*ýÕ&ÂŽ{÷† áJˆˆˆˆˆZçôéÓxæ™gðøãC£Ñ`Íš5Ø´i“KŸÚÚZF¤¦¦B—PÒ@»=¿#° •ŠŠ Aä³Ï>ërìÌ™3èÚµ+ ®®.àsÿøã8wîNž<‰ 6   ÀåxÓ_FSÿ‡¾Z­²,{eã«þ믿€÷˜ˆZ.99ï¾û.L&¦L™ÑZ†Q±ÿ~ç—=Z …qqqA;_\\,K0Ö¬l61Ê2”AeKÃÅ`o£Þ&BNj_rssqÇw 33;wÆ… °wï^¼ûî»8yòdȯ¿}ûvFçX"Ç*Š–/`¢éc ø“ˆÚ¢O>ùŸ|ò‰Çã²,ãðáøâŠ+0uêTüãÿtëÖ ×\s ÊÊÊ<•î8ÂKƒÁÐâ~ŽàîèÑ£°Ûíèß¿?ÊËËQUUåÒ¯¨¨0f̼òÊ+°X,èß¿¿_uΙ3' wŽ;7nþú׿Âl6c̘1Áã´l_õ;FpŽ;ÿó?ÿÓlT¥¿ï%5—œœŒåË—#;;ˆt9Eñññ:t(òòò¢î³dNN&OžŒQ£F!-- pöìYìØ±«V­jöeN[’sVWW·ö4æa¾‚É–†—! =Ûû×o ))¬AÀóÏ?7Þx£FBUUvíÚ“É„[n¹%ÒßžµiŽŒ„F£‰t9S(Θjµ:ÒåÍ«¯¾ I’ðì³ÏbÍš5Xºt)Ö®]‹ØØX,X°Àe”¥/ŽÐîé§ŸvŽä ¤_yy9’““ñøã£¶¶kÖ¬ABBþùÏbîܹxá…ðúë¯òóó±k×.ôêÕ Ÿþ9^ýuçZÁVPP€ï¾ûÝ»wÇ_|… âÙgŸ…ÅbÁ[o½åö9çÏŸ÷Zÿ¡C‡°sçN¤§§ã³Ï>ÃSO=…¿ÿýï>|¸×÷ˆˆ¼KJJ‡~ˆììlaöìÙ‘. ûöíCmm-ôz=† 5Ÿ%5 ž{î9¬]»Ó§OGFFt:t:úôéƒ3f`íÚµøóŸÿ55ûC¡P´qŽ¿´Z­ËÈúVh×YW{ *Ûõµ÷Üs&L˜€={öàÖ[oÅŒ30gÎÜsÏ=7n\@# ˆBaذa-ú‰´hüÀ¨¼¼¼¨ü€IDÔZ»ví¤I“°cÇôêÕ Ã† ÃÁƒ1}út—ݧý±bÅ |ùå—HOOÇĉ‘••P¿W^yeee˜:uªs§ò×^{ ’$aÖ¬Y2dŒF#¡áׇ¹sçbãÆèÒ¥ zôè9sæ ´´´uoˆ?þ8>þøcÄÆÆb̘1ÈËËïýk—µ-›òUÿ£>ŠO?ýƒS§NuÙ•Öß÷’ˆ.KJJÂòåË‘““ƒ¢¢"LŸ>eee‘. V«{÷îEmm-bcc£â³¤F£Á»ï¾‹©S§B”””`Μ9:t(†ŠGyEEEEÓ§ODzeË"^³¿|}±³}ûv,Y² Î6ƒÁ€Å‹cûöí­:w+µ‹l,”/Â×¹=íRäiܦÝmœÓøVÙèVÑèÖ››»#Ãm›iÍ•?ü°ß¿x/]ºo¿ývÀ× ÐE›7o†F£ÁwÜsçÎyí¿}ûv|ûí·8sæ î¼óNœ={O>ù$fÏžQ£F¡sçÎ(//ÇÆñæ›o:‡÷oß¾«W¯FBBFºº:,_¾Ÿ}ö™Ë¹­V+Ö­[‡ñãÇC©TâÓO?ÅÒ¥K}rssñÐC¡wïÞ¨««CQQ~ÿûßc(:‘‹ŠŠ ¨Tª??Z?0¶„J¥Â°aà×ëQWW‡½{÷FÝÔ""Š N‡½{÷âìÙ³7n\¤Ë!êpÚÂgÎhú,ùì³ÏbÚ´i€’’Üzë­Í–¨0 X»v­s:øŠ+ðÜsÏy<ç¼yó0wî\¿®¿hÑ",^¼¸…Õ{—à5T]±bz÷îcÇŽaÞ¼yeo¼ñ²²²pòäIL:Õãs-‹ßK‡ ìÞ½{€*v¶F·R£[ÙÍ­»xy 4ŸÊíkJDH¦~·•ÍtÚ=G€ä+¬dH½ºvíŠøøxäååù )n½õVÀ‰'ŸŸ³ÙŒÜÜ\aß¾}¸òÊ+1sæL˜Íf—iA÷ß?Ž?޽{÷"77ÿïÿý?\¸p[·nuö1 ¸öÚkQ\\ŒáÇcöìÙøùçŸñý÷ß#-- .DMM >ýôSh4tîÜ™!%E¥÷Þ{999€ŒŒ ìØ±Ãkÿºº:lß¾ýë_qâĉ0TØðÍhVV’’’ Tú÷Okll,ì²+,u\W]u öíÛéRˆ:œ¶R—GV:ÂÊaÆE$¬ÌÎÎvY/þÅ_DUUÆŽ‹^x²,ã™gžÁwß}‡—_~‹-L™2ü1 Ýž×ÑÏWXÊ€ÏÏóóçÏÇâŋѧO,Z´²,#33%%%xòÉ'[unj›A¥§‘˜aãk3 OÇ}´ôV2¤Œn½{÷—éBóæÍÃý÷ßï|œŸŸÉ“'»<ïÀž={œõ«_9ï§§§ã«¯¾Â5×\Ólý¢I“&Ájµâ¦›nÂË/¿ŒÉ“'»•p×]wÁl6;Gì^qÅøþûïÑ»wo(•JìÙ³‹- ù®›=Úúf:þˆÅ 7Ü€#F`„ 8þ|H¯ƒ+®¸¢U£F‰ˆ¨c‹‹‹ÃóÏ?úúz,Y²$Òåu8Ž/Æ 0sæL\¼x1Ò%ydµZ‘——‡¡C‡B¯×Gä‹ï‰':7.€mÛ¶žþy¤¦¦:ïçææâûï¿wöS(˜4i^xáçöV†:¤àòÚÜ)--Åܹsa%а®ð¼yóPRRÒªsAÓMnÚÄNßE[P¬Ð±ÍÎË_ºt)Ìf3æÍ›×¬!et«¨¨téÒÅÙvèÐ!|õÕWE&Lhö³ÙìRÀ€0uêT :ƒ‚ 4Û­ñôéÓ°Z­€Í›7¸”:\¸pÁ¹ûãþýûñññ€Ã‡£ººãÇÇ–-[°}ûv¼ÿþûÈÏÏoñë' •|йë¢?SSSñ /`ìØ±øãÿˆÇ{,¤õõéÓ*• .\pŽŒöD­V;?TÖÖÖ:ÿß$"¢ŽÍh4âÔ©Søýïß&wÇ%jëÙô‹ãXS×A’$ŸÏY´hL&~÷»ß5kuHé/«Õêò¹ßb±Db~03´¨ùŸ Ú‚Ê6ÁÓÈ¢Ö¬QÙØ|ΰ’!eÛPTTI’зo_¤§§£¸¸ß|ó ¾ùæAe}}½ËãnݺáÝwßEII ž{î9;v ß|ó×ëÆÆÆL&“Ç>MGLVTTàž{îÁôéÓqíµ×â†nÀu×]‡™3gâçŸö÷%SÔ–FF:\¼x3gÎt†•Ë—/÷Vž?úÓŸ°uëVŒ=:äõ%&&@À!e^^×§$""€ÝnÇŒ3"]Q‡åøb<''üqÔNýÖ©t|¦¬««‹ÈßkÖ¬ÁôéÓ;X5 7nÄ3Ï<ã2õ€Ëçq»ÝŽÕ«WûuwÞyœae8CJI’¼Ž|LNNÆo¼Þ½{ãäÉ“€ž={bÑ¢E˜;w®×Aþµ]{Ùõ»ÝùàƒðöÛo;(úF|öÙgP«ÕxñÅѹsgç1w7:t(´Z-¶mÛ†Ÿ~úɹÈnÓu,ºw¸8ÀÈ‘#ÇŽ ¨Þ²²2¼öÚk¸í¶ÛðÁ@E\uÕUƒ(\aeAA²³³±lÙ²H—°!C†0¤$"""ŠBååå˜9s&òóó‘‘‘+V S§N‘.«™hÙL§  +W®t>þío ƒÁ€ï¾û£GFnn.¶nÝŠ„„<õÔSÎ~+V¬è÷ÖwÞy‹/vþ„‹¯¥Ñ^}õUgH9wî\Ì;'OžDÏž=±páÂV›8¢2ª5Þ¡™Ú†×_ƒ ÂàÁƒñÅ_àСC¨­­ÅÀ4LÇöƱ–ÞwÞ ¥Réýæî/³5kÖ87Ó‘e~ø¡ßufff⥗^ÂÎ;QWW‡ë®»<.jL aå²e˼Ž\ìÒ¥ ,Xؾ}{È모¨@§N““ãuT¥ÝnGuu5öïßÏ’ˆˆˆ(Ê8ÂJÇÈÊ+VDÕÈÊh )^~ùeddd`Ô¨QÈÈÈÀÚµkñòË/;פÌÍÍÅSO=å\mÛ¶møË_þðukV†“Åbñ:Ø(;;………xòÉ'£'ç΋… "++Ëç¹É»h*[2߾ͮOIm_]]¦M›†éÓ§#77YYY°Z­8qâ–.]ŠÏ>ûÌëówíÚ…÷Þ{wß}7n¹ålÞ¼§OŸÆ€\úUUUáàÁƒ5jΜ9ƒ7ß|ð»N•J…òòrÜ|ó͈ŹsçðÊ+¯„%Ô¡Èjë›é\¼xwÝu—Çã«W¯ÆðáÕ••xõÕWC^Ó±cÇ€””¤¤¤ ²²²ÙڳܶQtKLLÄí·ßFƒ7¢¨¨(Ò%QEkXm!%и͚5 ÿýßÿiÓ¦!--Ím¨(I>úè#üå/qî³íÌf3ôz½ÇãW_}u³¶‹/â¾ûîóëÜAÖ’õ%£jMʦBêù:·»Ý»…&ÇD7…&ýÅ&÷?ŠK·ÊK÷·†ÜÜÜÕÕվ߂µF%‘7Û·oÇÅ‹qÛm·Eºjƒ"TVTT„mGì•+W¢o߾ضm^}õUçš1¡¦Ñh••…¤¤$ÔÖÖ2”$"ŠG}¢(B–eȲŒóçÏcË–->gµx2a”””`÷îÝE‘k‹uÉÉÉÎõÑ8àõ‹òp¸êª«µKeffbòäÉøå/‰ôôt@qq1þóŸÿ`åÊ•/S âãã¡ÕjƒzN“É„@²(ƒÁ€Ý»wPÀÀÖèVºt_jô#_úi|ÚШ­éãÆýÑä˜'! ;#5¢’£‰ˆ" ½‘2eÊ”ˆ\×l6ãàÁƒ¹6¹Z¾|9ªªª T*1`ÀLŸ>+V¬hQX™””„]»vh4nÜ8ìÛ·ÏëF DÔöù»äP¸DûBGÅ /¼é2‚ª®®.èAe]]]PÏyíS¿}‰ªÀ³½DDDDDm…Ífþ}û‹ÜÜ\ŸKð¸Óte×®]qäÈ‘`–IDQÊ×’CáÄÙ:ág·ÛQSSãÜ͵jjj`·Ûƒr.?DõÔn_BTFU€HDDDDDÓ‘#G\üæ7¿Á¡C‡0xð`lÞ¼'NœÀ„ œœ …B`óæÍ?~<ºté‚ÿú¯ÿÂ… ðóÏ?#==3gÎDaa!>ýôÓ¾*"" µúúz‚àu½JÔÖÖ¢¾¾>HUE•¢m}D%Q‡ãná^""""r¯¶¶111Îǃxë­·`Û0Á‹ IDAT·Û!Š"Ö¯_ÊÊJèt:Üwß}(((À·ß~‹îÝ»ã믿Fii) OŸ>Ø´iΞ=©—CDDad4!Ër‹GVÖÔÔ´×2dTQ»¥×ëQQQáÒ¶ÿ~ç}I’ R©põÕW#>>z½¾Õ£gˆˆ¨ý¨¯¯‡ÅbAll¬ßëVšL&ÔÕÕ…sºw»Á ’ˆˆˆˆˆÚ­œœœ8qÂù¸éÎÝiii¸ùæ›±~ýz\¸p)))Ðh4a®’ˆˆ¢™cC£ºº:h4¨Õj(•Jˆ¢ áߛ͋ųÙÌ€²TQ»#Š"úõë‡Aƒaùòåû¥¤¤ ¾¾ç΃F£A·nÝÒå…”V«…V«Emm-L&ÃJ"""""" )ÎSö“#¤Ôét )‰¨CÑëõÐét$‰ëñQÈ0¨ôCã‘”±±±‘.‡ˆ(ìbcc¡ÕjVQÈ0¨ôƒ,ËÎ5)‰ˆ:*½^…BÁ ’ˆˆˆˆˆˆB‚A¥ŽÑC:.Ò¥EœN§sŽ2'"""""" &•~E‘»{¡aƒQä?DDDDDD|ümÓ ÇhJFéRˆˆ¢†F£á¨J"""""" :•>Ȳ •Jé2ˆˆ¢†J¥â:•DDDDDDt *ý T*#]QÔà߉DDDDDD *=h‚X}ˆ3¡*ï~üñGLš4)äס¶C¡ñË‘¿@vVŽäçãøñ‘.‰ˆˆˆˆˆÈ#ލ 2ÉкižâxcJ bDÈ2pªÜ”k­Y³*• ·Þz+AÀC=„>úÕÕÕÍúfggcÓ¦Mn^|ñE·ç1b–,Y‚¯¿þ+V¬À¬Y³œÇ–,Y‚_ýêW.§M›†×_ë֭òeË0hÐ çñ1cÆ`Ë–-e÷Þ{/Þ}÷]( #Òt:V¯^›nº °yófŒ9111~¿Dþ¨‰ Þ”mNÿ¦H‘$%çÎáÄÉ“¨®jþ÷=Q4áˆÊ “bº´ø¹±¯MJFš¡!”[ú]5¶˜‚r-³ÙŒ·ß~=ö¬V+ôz=>ÿüs·};†»ï¾Ûí1«ÕÚ¬-.. ,À[o½…Í›7#%%jµÚc-ƒ<ð}ôQ”””àþûïÇŸÿügLž<6› =zô@^^àÿøÆŽ‹»ï¾kÖ¬Á½÷Þ‹¢¢"¬_¿pîÜ9Øíväää`ïÞ½~¿D¾˜Õ©A;—)ˆçòfäÈ‘˜?>dYÆÂ… ñÓO?…庽dYƉ'qìXQ¤K!"""""ò‰#*ƒLVÅy<–+bÍéxÿ¾NHŠu}ëÕJ '&#;Uødw>Ø^Óâk¹³yófœ:u óçÏÇÒ¥Ka³¹­i·ÛQQQáö§¶¶ù4ô””(•Jüðè©©ÁñãÇ‘ŸŸï±Žªª*,\¸‡Fee%V®\‰¤¤$¤§§ºv튒’€ÍfÃÂ… 1sæLŒ97Þx£ËÚ{²,ãܹsÎç‹M¡Þ¹”ý¿ÚRÜõ›ˆˆˆˆˆˆÚ2•aÔ3Y…^ÉJ ì¦Æ[ÓRx)¬à¹Û1¼‡°éH=^ÝP’¾øâ TTT`Û¶mA;çÉ“'‘——‡>øÏ<óŒ_›ÛȲì¼îÜ9˜L&èt:h4$$$ ¬¬ÌyüàÁƒØ´i^zé%,Y².\p9Wii)bccƒözˆ‚®ÑïDDDDDDDäƒÊ ¬žGAæ2ãó½u€ŒNª†°2FÄooLÀø~:ÀžSfüéË H~äÞ®å‰Ífó8’Ò!Ð5*%IÂoû[<ýôÓ°Z­X°`AÀ›ôÈM‚œ¸8×h€úúúfÏw;%¨5”v÷›XEú\Þp×o""""""j˸Fe‰Æs°ÜOó”üå_•àö¡±èÓI…U³S‘Ó-µâwÿ,‡Åæßè+Ñx.Xe»tJ‡¼¼<äååaÍš5xï½÷’’Òlô£/f³V«;wFaa! {÷î¸ýöÛñöÛocÞ¼yØ»w¯ËôÔÔTÔÔÚy£µœ‡E™´s…wýŽA0aÂÜsÏ=xà|~!4fÌŒ;ÉÉÉØµkV¯^ ³ÙÜâ~DDDDDDíGT™XuÔëqI^ú¿J|º»ad¥#¤,­¶ã‰ÕQc’‚v­– tʸ¸8ÜtÓMHIIF£Á!C`2™Üî("¤¦6l>"Š"þð‡?`ÕªUX½z5 ñðÃ;û:¦Šq£ .½1xÿéëCóÿ*E‡1cÆà«¯¾ÂÿþïÿbÔ¨QEïÿ´>òÈ#øÛßþµZóçÏãÑGÅû￘˜˜õ#"""""j/T™òâ~Ÿ}d¯¬¯Äg{Âʪz s>¾€óÕö _+ôz=rssñÎ;ïàË/¿Ä-·Ü‚gŸ}‹¥EçÛ·o˜8q"´Z-þùÏÞxã \{íµ6l ÿþ¨®®Æñãǃóbˆ.Ñ×BmkýZ±*[ôõÇ‚P‘o#GŽÄš5k°zõjŒ1",×ìèþò—¿àµ×^÷ß~ë×F}ûöÅO<Ç{ O?ý4^|ñE̘1ƒ ´iÓîGDDDDDÔžpêw)ÊB4–@ŠIóÚÏVJ2ðõ#N\ô>M°)ÑXEùÁ€ëÛºu+¶nÝðó¼)))ÁÿøGÇó›ßx} ·Ür‹óþúõëñÖ[oA¯×cÕªUXµj•óØùóç]úÞpà ظq#ìöÀB^"_YBJåVœM¹­Uçé\±‚žÿ>»~;îOž<9,×íÈ>øà¼ð ¨©©ÁèÑ£}ö¿ï¾ûpàÀlÚ´ÉÙVPP€¯¿þÓ§ODzeËêGDDDDDÔžpDe¨Noð«Ÿ$7„•Ï>òÐßk´E'NœÀ®]»0qâD¯ýÒÒÒ0zôhçhK¢`‹3"©zW‹ŸŸTý§}·sGŽ hÜ¡C‡bÛ¶mÍÚ7oÞŒ®]»Â`0Ôˆˆˆˆˆ¨=áˆÊP [—«a7d…äüŠªB¨Š¿ ɹ£Å’%KгgO¯}Ìf3^yå”––†©*êˆ:Un £<þª€ž—T½*›M¡´páBÌŸ?²,s×ï(•––æöï¬óçÏ;WUUùÝ/hôj”'È@DÀl*M€9°‘þ¢ ²&²*²Ðð‘N­L!XjÐ0ƒˆˆÜ V Äkµ È2Pc\UØüß;€"CVh kUdÁn„`®‚`åf«DmƒÊÑ|ãU Bvîö®¤¤%%%^û”——};Qs2:Un…Î|e‰c`Q&xí­¶U¢SÅwIÉ]¿£›B¡@LLŒÛõ{•ét:¿ûM×x3¯DžZ†8àÊËíÕ&È%Õ@Q9䣀Šúà]“ZF©ƒ-¡ì‰ý ë»CÒu“c$ĺbˆÕÇ¡¨<EU! ó—n"êÀDèž!+H7@H‹T ·]òÅ: ¸ ò‰ eë­á­—š‘Õ °'‚Ý Iߣ!¤ôÄVEí)ˆ5Ç–g«-_¡DÔ* *CD¬>íÁ7aøhPÏ«=ø&ÄjnCnúú£ˆ5¡V—‰Z]&LêTØ”q¥­ZËyèëB_ÃrÃn·£¼¼Ü¹ŽhcÉÉɾ¤ñ·Ÿ?T*~ûä$×ÿ&¿Z»¥¥e€ÓCcP®vó‹Z¼B¼Èé @L¹ ÉÅf$[!Ú9R/|TŠ]pN•rE7Èþ®Ú#*!Åõ‚× ¶n×B%›b?‰®¶#ÐJÁe¢Õê0lØ•¾;5‘„~ý¶xF긓œ’‚NR}öµÄЏÐS‹Šî*ØÔþ¯|&$Çɱ†t… q¥V¤œ0#®ÌÊëa$CD™¢'Î)³Q£H.œôI©ƒ=!ö„X»ß­T‹Tû1tSŸ…^-C£Ñ†´njÔj5 ‰~æÙ»·åKˆut *CHyþh …•ÚƒoByþ‡ œ‹ˆ'È⌈3Dºj£Îœ9ƒìììfí½{÷†ÕjEYYY@ý|‘$;víÚƒŠ ×ìóBUuCXeîÒèî}80&)aLRâL¦ ê½ç 9p°r#³ÐPß5ÆÂªéÔê³Y-J”9(QdC[[€øÒÍP™ƒ³tJjjœ8Q”sQǧ×ãLñiÔë"] µ1‚  ®®¥¥ç=ö‘µ¨Ù¶>ñ€àg¸å,Õ©*T§ª V˜ ù©êÂr–¡$*Q›0µ)×À®Ô·út&Q“✒ µî8P¼ [m ¥Ž"&&†Ÿy€Aeˆ)Ïÿ€˜úó0gÏhñš•ŠªBh >âHJ"¢6î_ÿúæÍ›ƒÁà²Æäm·Ý†uëÖÁn·ÔÏ»]–ï¾Ã±c^>P}SQ%CÛ¯+ê%+­Òë/tRŒ¦«Óa”yc!äŸÏùU ùOÒw‡%ã×âzøÕ_,¬µZ@T5üxì,À—“>ÊÒŸ :µîÒz–-g·ÛQQQÞªsPÇd±XP]]…êšêH—BmLZ—®¨««uûw SAŸ íÚ0ÝÛ» Ô™þíÓ(ëUz"%jQco' ŸªhéË ìÉC`í};$M’_ýk-»²R(µ^gÈ‚ç”Y2ç@Y¼ ª3ß×å&ßl6+¬ ?ó„ƒÊ0«C·k¬éãaí~#¤ß#W@4–@uzC»ß8‡ˆ¨½züñÇ1`À<üððÛíX³f fÍš…7ß|¿ûÝïPYY‰Ù³gcÈ!X°àòºÆþö «òÚCU—Žo¾ÝY€ä]‌d™) › 4¯…p÷ úAúêg Úܺ:"…Ö·Àš6ÚËÚ“V(ª  ¨8±æc ÉuÚ¬¬Ž‡“)¾7ì‰ý!éÝž‚[ê/`OUѧP–íÁ "" /¡_*ps ×xîTR ¹àp¦ 8W¹Öìz\­h˜ön€Ð; è“ìv-K!-¸÷ `g1äM…€…³ ZKV`ésìIƒ<ölFˆå?CQU±öDÓ× Q!« ôÝaë {ò ÈÚæËéÈ¢Ö7ÁÞiÔGWqPQaPFªâo¡*þö¤°%†dȄӲªa;ÁZÑxbÕQ(/ü`„+&"¢Ö3f úö틸¸8TVV¢ªª “&MÂÒ¥K±uëVØl6TTTàþûïÇ‘#GœÏó·_HH2PV¹¬8p®!¸ÌLpezChÙTF„Ù#¯pte+H1i°äÜ )¦‹Ûã¢ñ”%ßCQ¶ ‚Ý춃`©†ÂR Ee>T§ÖCÒ$ÁÞe¬]FÊ—¾²2–ì°' ‚úè*vÎDÔ©ÕÒÕýq“òÞ³wåFïç²Ø6“+©†¼ó4 R@ ü¢„Ô8×¾‚aDwY)>Ù”ptpKÙÀ’= r“§ÄʨÎ}Eù!@ö Ësæ (.îN| Iß¶´k`Kˆ®ˆ¤K…ià\¨Šÿ Õésã9¢(À 2åBµ3û÷ïÇ´iÓ`µ^ÞtúôéÐëõ¨¬¼¼FäñãÇqã7"-- Z­Ç»ÿßß~!'É@A䂲†ÂÇeÉ.] ¸{n€¼± á9ä7{ç0÷ùµÛ)Ûb})T§þÅ…<´t14Ñ\ñä:(Oÿ¶®caKYá:ÚÈž2¦ØnÐæ¡îl‹®CDÉ1' Rb›³Ú!ÿpòN¦NïµÚ!çòÎ6l07>³ùµuï¿ Òú#Àž3-»NG%ˆ°öœk·kán£±ê(Ô'×A¬9ÑâKˆµ§ .üª“ë îûkTÇ p.ˆ°v¿ ö¸ h –C°ríJ¢HbPIDDUUUøé§Ÿ\ÚêêêPWç~“wîö·_8Èg«!¯Ø¡og7æ×3…_ô:ëOöC®·z8 9 BÃTïôëš“¬Pþ7Tg6y9Èå$ TÅÿ†²ô?°ô¾ ö”a.Çe]'˜?Mþß!– Ê5‰ˆBªg"„‰C]ó/zäüRÈ_j¼B„œ_ ¹° ÂUݾ¸k<%\)BœÐrg=äóK;¿(Ô0gÍ€=¹ùToÁRõñÏ ¸°7h—,Õè|ñßH— qX¼²ÙÒ(RB6̃Ÿ€úÐ;ë=oÔDD¡åy•Y""""7ä#¥ÞþäÍCT¡wpï•@œ—õÁ0gßë6¤k‹¡Ëû+TŃRº\ÚRMþ‡Py‚Íu ¤,ªaî÷ ¬©£‚~]"¢`ªïqúð†Qý™m?;yõ¾ †”N’ ùÇS–þòéÊf‡…= Nâv]KºLVÅÁ4pŽÛRq!Ú½/5¤lLg/‡vÿëPXÛìßYI› ÓàÇ`ï’k‘o *‰ˆˆ(p&äÏBþògÀ溞“ÐYñ¿F4lF@͉*˜û={ÊÐf‡T%[¡=ð:„úÒ—¡¼¸Ú¼¿B¬=åÒ.C„5s"lÝÆ…¼"¢–¨ÈŒEEnW@Ñä×Ù’jHïüù`ÖL®¨‡üá.È;N4_™#»„)CVz k`üXóÍÞ$ÔÇ>&ÿï;H ~Tg¾…öàß ˜›Îʘûφ=!'´5‘[ *‰ˆˆ¨Åä}g!¸«ù¨ƒÂÌ+€D]d ‹V 5ÌýgÁžØßµ]¶C}tTEŸ¹î^b‚¹Úýo@Qº³Ù1K¯Û`eXIDQF¸ª;Îo¶œ¡|¤Òßwõá+F’!Séó€½É—v½’ N¨V6&«`8§ÙNÜ‚ÍÍÏoAyn[Xë«C»!ÄÚ“® 3 ì‰ýÂZ1¨$""¢V’ÏTAzÿ'àB“õ8ã4f\!a%@TÂÔ÷AØ Ù.Í‚Ý íÏK¡<ÿCdê’íÐ~ ÕéõÍY{Ýk·ñ(Šˆ¨9áÊînêÛ<¤üñäOöÖà/—á—ƒç }´»ù†==!LÆ‘•—ÈjLƒš‡”¢é"4û_‡¢º("u –hü Ê‹û]ˆ*˜û>ÐüËE" )•DDDÔzU&Hì„|¦Ê¥YHÐA˜q׬˜³¦AJp )a«‡æç%« #S—“ Õ©õPÿMç0Z{Ý [ê/#SÑ% 47» )¿-„¼!?ò›×œª„ôáNÀ躙œÐ#Â=ƒ±ùŽÖ‰¬Œyà£ÍCJã9h¼1 Kžx%Y¡Îÿ;”e»]ÛE%,}ïk>MˆB†A%G½øx/PRíÚž¨ƒ0¹c¯Õån—mÁVíÏoB¬9™¢ÜPýª"7aeæ¯9¢„ˆ"Fè•á¶ÍCÊMG!o?‰’Ü;_ ù£Ý@Å¥YÈJ0¡³ú; Qs¿!é:»6ÏAóó›,5*¬ Y‚ºðP”þäÚ,ªaîÿd]§FÔ±0¨$""j§”J%î¼ã6<<{n¾«f(ÈõVH+ö@>ïúK‡ᮀÐñ~K³¦_[Úh—6Án‚æàˆµÅªÊ3UÉÖKaåe2Ć%qQBDaÖIaâ`@áúïGÜî ·PQžÉçk -ßÕ|dåЮÆtÀ¤欩â3\šÅúóÐüüVô„”²ÍÑ•ÍÖn–Uz˜û? Y¡Âˆ:•DDDí”ÍfÃç_|…¥o/ÃþýÂwáz+ä{ _tݱSÈé áú¬ðÕì‰`íq‹k£dƒæð{ë¢/¤tP•l…òô¿]ÚdQ sß!« ªŠˆ:½âÔa€VåÒœTP‡¸}"T”Êê ­ÚÛlÍL!7ÂÀ.**2¬=ni>£ÀR ÍÁ· Xª=<+Âd𣫠¨8ìÒ,i“aι:î ¢p`PIDDDÁWgVím˜Þˆ0²'0´k„Š /I׿ì鮣Heš‚¢`MJßÔ§þÕ|D‰:æ¾ü%ˆÂ@ Ü50h]šåCçÑi_”\WAúô@³µ3…[ûCHí£òlÉC`MwÝM°› =ôK•‡gE Ùõ‘ Öžri–â3`ɸ3BEu *‰ˆˆ($ä‹FH«ó»äÒ.ÞÜHÕG¨ª0Qê`é÷  tÝñ\}ò+(.î‹PQº4¢¤2ߥUŠëKÆÝª‰ˆ: a\&„^‰.mòéJÈ_l;K=”Aú××6•ÂÄ!t*÷Ïi'$]gX³¦ÂeaÎKáŸPw6buB,Ð^Ñ\îÒnër lGD¨*¢öA%…ΩJÈk¹¶©=Ð*#SSX2'7Û4@Y¶Ê3›#TQ Évhò?„`rbië2Š¿¤QÈýR!ü²—K›\Yyu`“Ü?)Zí.†¼»ÉR‰:àÎö»n³,ªaéû_—vÕ±O›}ùíK Ô‡ßì®$Yúü’¾{„ª"jßTQHÉûK ÿä:u I1ÝìàÚXSGÁ–<Ä¥M¬= õÑUª¨€Ä…¹ IDAT•lFh¼AjòKZÆ=t©*ŠˆÚ­D„Û›üû`“€Oö7Û ¦­×|ºÒ¥MÈLðËžª(´¬™“ Ÿ®Å©,ý ªó;"TQëˆug >¶ºI£ æì™EudŠ"jÇÚïP† :þ|¤K "Š*¢Èï¹(0òÆ] @z£Xúv†pE:ä]Ñ»©L ¤˜.°6Y»J°ÖBsä=@j›¿`€PwªÂU°ä̼ܨPÃ’3{~"Q D⃵ë:¸òú|ÈgÛÀº”žØeÈŸì‡0k$ ¿l ×fB>^”´á×Ö„­Ó°uºÂ¥M¬+†úØ?#TQp(ËvCÒw‡­ëXg›¬ëkŸ{ .ü8r…µC *ýšÊÑDD•••Eºjkì2¤OöC|h$sy].áúlàxä‹u,.HD,9÷bãuÇd¨ ?†`®ôø´¶Bya¤øÞ°¥v¶I±é8d±E°*"jO„Ü ×/´Èyg!ïi_hÕ˜!}ºâŒ+ñÒpQ…ñ®AÞù¡Ùám‘¬M‚%ã×F›ê#´é/ëTÇ¿‚× R\/g›­ó(*Cqaoä #jg8$†ˆˆˆÂ£Úù‹ƒ@ã PU w ¸üK[fí9RLšK›ªä{(*yxFÛ£>ñU³MŠl½`OȉPEDÔ^Ý \ÓÛµñ¢rÓÍhÚ²“·wmKŽpc;ø;TaÉšÞl9ͱB4]ŒPQÁ%@‚:9`«wi7÷™Y“èáYD(•DDD6òÑ wvmìf€0º·û'´R|¬i¹.mb]1T'¾ŠPE!"Y¡)øÈedŒ À’5¥Ù/§DD~S) Ü1ÐõK+I†üùv1Ò°1ù»"àL•K›0¼„Ì”U֮ןáÒ¦(ý©Ý4ÍåP}âÚ¨ÔÁ’9 írám¢`PIDDDa%S\4º´ £3€Ô¸UÔJ¢ æÌ)®»·JÖ†QRû›-K >¹Ö¥MV'ÀÒóÖUDDm0.³a'ìFä-ÇÚöº”žHòÿgïΣã8«¼ñŸªê–ºµ«µË–wËvo±guH 9˜¼d–óÂL~ÄÀÀof2óB8Ày3¼’°dØ&0ÄaXÂ8 „8! qâ5¶¼Û²-/Ú[«µtWÕóû£c©ŸjI–äî®®Ö÷sçÐWUÕ×–ÓËSϽö¯÷Ãêûƒ¸u)ãÍÎlv Ѻ›•XlAï×.e”ZFûmÛ”˜U¼fÅ:—2"Ê.\¨$""¢ôŠZ±p;®\ï[æÉðÈœ[!åJÌòhƒm.e”zÆÙW¡wRbfÕ°‹¹”yÖ¬"ˆu³ÕXS7äŸO¸’NZt B¾pDåB¼Ûƒ¯¡B ºð.µ?³´á?ü3kȽ¼RÌü×µÿtdÞ!ý….eD”=¸PIDDDi'Ïô@¾ªöé5…—×¹”ÑôØsaVoTbZïqÍr)£t‘ðÝaGâbà ïtÿ¸g)tÍy“*jAþÏ>õfV’»NC6ª½ÅšYsKÝIhšÌÊ+J¾æW õ6º”Qš˜ƒð}JDÜéN>DY„ •DDDYÊ0 Ü}×øüý÷aÍšÕn§“@¾Ö´«Ó¾Åu €boô:”ÐYpGbÉ÷Ñ_2»¿`±²>ß G xn"³oq)#"òqõ| <_‰É?5B:Úƒd% ÈÍ€H\NàÖ¥€î¯é2§ѹjÛm¨þ¦g]Ê(½ô®ý‰%ॗÀ ­t)#¢ìàW@"""š2Ó4ñ‹'7ááÿ¿Ø¹3›Ù[ró~uQϧÇúty€Us-ì¼%æoz.«K¾Œ–×ÒÕÒ7³æZØÁ*—2""¯¡ ÄÕs•˜lî…ÜzÒ„ÜÐ=¹å¨¡ Ä•s\Jhj¢ó>©çÆE$üÇ6VdÜs²ïøo "j/ÕȼBj¬. š..T‘kä©nȧ•˜X–T¸”ÑäH¢uêÎAíÜYèg^v'!·H‰Uþe 8„Žè‚ÓO‰hB7Õ«;m ù»ýY_òí$·‚<¥ÞðWÏËøê«¸¦cç Ñú&´îÃ.eäaÀ\$sŠa:† Ñäq¡’ˆˆˆ\%_< ôª ÷µ›êŸîRF™÷AH=g4 %ü¿„€í^R.Éçà;³E‰Y… `–¯q)#"ÊtbIÄÂ2%&·žZû\ÊÈERB>{@] õéÐn®w/§ :¢óoWCÑ~øOüÎ¥„Ü¥wì†Þ}P‰Ek6²º€hš¸PIDDDî6!ÿàØQ” qå\WÒ¹»x1¬²UJÌhÛ ­÷ø8gd?ßé?B+±è¼Û%DDˆµø¸É±×7 ùJ–_™Hk?ä¶Sjlq9D}¹;ù\@´f#ì€Zùà;¹0g@oÑqøØæh@èˆÌÿ_î%Däa\¨$"""×Éý­'Ô….qå (ú„†Èܨ!ó\ÂP™ÇŽÂ×ø+%$}…ˆÎ¾Ñ¥„ˆ(S‰«æ&¼¶Û/V‡ÊÌ@òåc@¿ÚÛQÜXè™ÕFCú‹Êšµþ“0ÚÞt)£Ì Ûá;«VØE 9X‡h¸PIDDD™áùC‰¥o7fVé›YqyÂßÉÍ3xÉyzxô®}J̬¾vnÈ¥Œˆ(ãä@\¡Š‘'º€}-.%”A†MØ8¤ÆJëêÜÉgÑ9·ªƒb¤„ÿدÔÁx3”ïÔ Õ‘¹ï4Ã¥Œˆ¼‰ •DDD”dÛ¥oK+ f»“ƒÔsèˆsga´Îì]$ñ|¿VKß4Ñ9ïs/!"Ê(Ú»ªý‡m ùÜA€k\1ûZëàšy@ÀçN>v^ ÌòuJÌh{Z“Ke; ãøÓJHæ–Á¬¾Ö¥„ˆ¼‰Kû.°J—à ­€]´v° ÒWÑ>h-ÐzŽÂèÜ=Üàr¦DDDé%ÿÔqiŒÛ­ñîEÀ·¹—Ô;ÌYï†ô*1ÿ‰§9óèŒGê„Ñü ÌÚëGbVÙ*ØÍó¡õÎàþsDQY¬¨Vbrçi ½ß¥Œ2äïAü?—ïT|‹€Ø8òùCŸ›ѹ·b´]XÃð5=çbF™Çè|Vo#¬Âù#±È¬÷@o}Â<çbfDÞÁ•iu®xƒ«¿„hÝ-°Š,R€ôÀ*Z„hÝ-\ý% \ñ¢³np1c""¢4Š& T³‹!–TŒsBzÈœDk®Sbz×~èÝîqÌ4þÓ/$|‹Ì}?F¾uÑŒ$Þ³Ðâ^"ÖÌ 3ž³½ j)¼X;(Ïs)¡«¸V±ÚŽÅ8ýGˆÈ œÔ~¾¿…²MØ êèëIDããBeØ…ó0¸ö_0\ÿqØÁê Ÿpþ¼`5†ë?ŽÁµÿ»p^ 3$""Êrûi ¬ö|78¾à¦Ytέ€6Zz'`Ãwü·®å“ÑÌAøšžWBvÁÜ„IéD4ƒÌ/æ«ýjåë'†ÇPŒÜrˆÆ ÒD¬lÞ-BÄvSƇ"Ýð}Ù•t2Ö×£}‡3«®„Ì-s)#"oáBeŠ™•0°îAXE‹¦} «hÖ=³rC3#""ÊP¶„|é¨ U5cŸêt‚Õ0Ë.SbzóëÐÛ\ÉÇ Œ–?'üýDënäGO¢™Ghïq Fë†ÜzÒ|¼ gr«£ïc}DuáØÇ§˜Y¾nŒArÏvÔ•|¼Àwr³ú÷#ô„>×D46~ZL!³r†–ß›´ë -¿—‹•D.’šÀà¼B„7Ö õ/æãì_-ÆÙ¿ZŒÖ¿˜ðÆ Î+€tqÇQ6‘û[³½JL\·ðë㜑:Ѻ[”ž\cí$iÁwò”¨€U±Ö¥„ˆÈ-âÒ* 2_‰Ù/Uw RùçÀ`üB€w-H"šѺ÷*!qî,Œv÷{Gg21Ü _ó«JÌ,[3¥ K¢™Š •)bÎKê"åyCËïe8‘ ç í/æ#|] çÂ,òC¤¡Á,òcp~!Â×Õ¢í/æcpNÁ…/H”†aàƒx?>sϧ°bÅ¥n§35°_8¬„D~ÄåsÒš†_+¤þÝùξ̆ø“ w6@ëSw™u7"ý‹ÍDäM@\;_ ÉÖ>`O³K yȰ ûµãJH,,êŠÓšF´ò Èõ9ý'~HŽj¿ãôsp4 D¢/%âBeŠ /þ+O^›ˆг®áwÕÂ,ð]ðp³À‡ðõµèYW‘ö¹6lÀSO=…M›6aýúõé}rÊH¦iâ7¿ý¾÷ýDZgÏ^·Ó™º“]À‘%$®˜äiK!V¦7áÔ<ãìŸÒöüÞ&ákzF‰Ø9¥0«®t)"J7±¢( *1¹å(`s‘kR¶Ÿú†•výô[ŠM™æƒ9ûÝj¨û0ôîƒéËÁÄ9ÐÇÓ -‡_çJ>D^Á…ʈκá¢zR^ˆU´ˆÓÀ‰Ò¤gmú——Nù¼þå¥è¹¬<ïþûïGYYÊËËqÿý÷§õ¹‰REn9ª ÎD®±~vZžÛ.œ«d©3N¿a ¥åù³Þ}ZÚo4:û=€îw)#"J›1vSâLO (š@Ô‚|UÝU‰ºâØÎÊ40«®‚ô©}1}§Øúd*Œ3/ADã'£‹Ø€>"*S :û¦ŒzŽø‡Àw¾ó„ø¢E‹ðûßÿuu™}Gçúë¯Ç'?ùÉ Y°`þ÷ÿþßiʈfŠÁ¹ÓZ¤<¯ÿÒ†êXNt1dkpPÊ"®˜ä^x‡óÅr~‘Ñ^øZ^KùófÓ³Êcé+D´êj—²!¢t«k″_:æR6Þ%wžºÕ໤¾rG÷#Z«nŽÑ»BïmLñgaGà;ý¢³Šëa§pc‘×q¡2ɬÒåIi;«ÄÀÍ˃ðéc¿ÙÁjX¥Ë'u­Ç ,Àµ×^«Ä?ýéOcóæÍhjjçL÷iš†O|â8xpâò‚¦¦&,[¶ kÖ¬ISf”í¤&л¶â¢¯Ó½¾"mv~øa´··£­­ ?üpZž“(ä+j/¬\_ÊwUZE‹aªC |§^¬HJŸ7i½Ð»ö+1sÖ wUe-]WÍUBòT7ÐØéN>^fËØû`Q]±8µ•;Ѫ«!ýê wßÉçRúœÙÊhy"Ò£Ä"iØÜDäU\¨L23´â¢¯17dàG/ǃ·•àÎuyý\øÅ/~O}êS0ŒX_¯5kÖ ¾¾?ýéO/:ßTZ·nt]Ç믿>áqÑhO?ý4>ð¤)3ÊvCs &Õ“òB¬†êò/|`¼ù書óÎ;q×]waÛ6Nb¤ì![û 8vUn¨Ké®J³Ný!†Â0ZßHÙóe;_Ósˆ¯á—F¬jîª$ÊVbu-„c7%þÄxÓ%÷6ê7qÍüqŽNÂói~˜µ×+1-¼ZÿÉ”=gV³£0š~¯†ŠÂ.LÝïÈ˸P™dvÑ‹:¿¼@Ç·ï.CqPƒ”@SØLÊs=õÔSðù|xßûÞ!>ýéOã‰'ž@ooo±‹/Æ–-[Æüß×¾öµqŸãöÛoÇüc<ýôÓøú×¿Žªª*€ù—‰ÿüÏÿÄï~÷;åg°~ýz|÷»ßųÏ>‹ŸýìgøÔ§>5ò³7âå—_†”ûØÇðÿñÐõØ´Ð@ €M›6áæ›o¼ôÒKذa‚Aµa7Ñt ÎIÞâ"Ë¿‰’`¬]•—§¦u‰]8?q7åé{ü÷dš˜Ö z¸A‰Ek®´Ô—ðQšéâêyjìd$wSNŸ-!_u,ôÖó§ß¢h"fõ5¾øÏÂ~ö¦¼(¾¶7!†»•XtÖ{\ʆ(³¥olæ a«.|Ð8òr¾ugÕE±…¸ïý©¯¿aÿTžkxxßÿþ÷ñw÷wˆF£ÈÏÏÇo~ó›1=vìn¿ýö1FÇŒßu×]¸á†ðo|áp+V¬@wwì…øãÿ86lØ€/ùËÄg>ó<üðÃøØÇ>†@ €|=ö^zé%”••Áï-«««ÃîÝ»?ÿùÏqÝu×áöÛoÇSO=…}ìchllÄóÏÇÞ4[ZZ`Yêëë±k×®IÿÝ%ÊMÚµ"eÉ»ÖD6lØ€ûï¿RJ<üðÃxë­·Òò¼Dé Ûúým—TŽÄÄå³!·ž†“»€¥N8ÃÝ0ÚøßÓÅò~Vé¥#¥¿fåͯº˜%›XQªŸ}ì—Ù›òbÉ}­(SÔµkæÃn '÷‰4Ìšë”Þ­?sÛ…y‚´à;ó""óG¿g[%Kaç×ñï–È;*“LúÆß9Uš§á©ÏTâG/GižúWï7¾#„Å•±ÿ½ã~üzßX—™Ôs套^BSSî¿ÿ~|ï{߃iŽýÅβ,tuuù¿þþþ„ãu]LJ?üa|ë[ßÂáÇÑÑÑ-[¶`hh>ŸúЇðïÿþïhllDss3¾ño //W]uÊÊÊ`¶nÝŠ¾¾>?~‡¹vMM 𛛦iâá‡ÆG?úQlذ7Ýt“Ò‡OJ‰––Ìš5kJ/Dc±É»cÓsOˆS¿)ÛÙ«rmr_óíüY°J–)1ãÌ@ZI}ž™Hëk‚Þ}H‰EkÞÝ¥Œˆ(é4\9G É]ÀÉ.—Ê"¶„|ý„›SÔ'õiÌŠË{Sr7eR­[!"jE#wU%âBeÍ ù07d`y­}¸ %ï,VjøÊûK°¦.°åà þÏï»'ºÔ´ýö·¿EWW^{-ySK«««”Æójjj`><Âþýû1{ölœ‹IÝ囀9û=@üM7sFËëuMJdœ~Ö²{FËÜ2Xe« ·ït1+"ºXbA¢ºP‰ÉW7—è¢É]g«çAä猯š <õöE^YÀœuƒÑzCïeÑdvÆÙ?!Z÷Þ‘˜Z_î³CœI4sðöu’i=G'ü¹-¯?Ó_íˆÝE9¿HÙÖkás›:Ñ7d'í¹¦kª=*{{{ñÚk¯á³Ÿý,fÏž`0ˆ+®¸@xî¹çpß}÷¡¾¾%%%¸÷Þ{ÑÕÕ…íÛ·£  7ß|3ÊÊÊ““ƒ•+Wbhhhdycc#*+cƒ4M×¾ô%<ù䓨´iŽ9‚Ï|æ3#yœ/ollLÈ‘hªMÉ[ðÎMⵈ>¡JƒK+Çÿüóxì±ÇŸŸ'Ÿ|O>ùäÈÏZ[[që­·Ž<¾ñÆñ /À²8™•.ž°% ··#|}íE]§è­Vˆ‹,G¬óS¿Ïÿÿ»îº+-ÏK™Ë4MüâÉM8v,ûvšË?Ÿ€øÐÊÑ@UÄ‚ä±iôB3°*7¨¡Ö­æÀEfIã1Â{l‡ ”Ä¢µ×!§çˆ‹YÑt‰+çªÞ!Ƚͮä2#D,`ç¥'¨XY ùòQ``êýú­Âù° æ*±XoJ.4§ŠqöOˆÖlÄ;³t?Ìê«às #š‰¸£2|§~?©ãl[¬l83õ][“}¯;qâ¶oߎ;î¸cÂ㪫«qÍ5׌ì¶$J†ÀÉ>ä7„§}~ÁÞδí¦$šq¶êB¢¸bî´.eVn€ÔsGÒ†~æåéçF&%|g_VBVÉ2Ø‹+á'"” —+!¹µ °¸È•Jò-Çß±O‡X;{Z×2k®SkÃaèí».";ºéIèÍlV]h>—2"Ê\¨Lßé¡§pG€Þs¾Ó/¦ìú™æ»ßý.öì`xx=ôÚÚØ‡’«h{ò÷N}±2o' w´§ £ñqê7Í(R&öªœW Q‘?µË@C´úZ%¦w¾ mxú7)hrŒöm “O_–‰(ói—Ï´¸AdC&äÎÓî%4Sô C6¨»Vźـ1µ¯øvN)¬ÒåJL?ó2&?;¦Çö%ÄïZ•þ˜kÝKˆ(Cp¡2Er?áÉkg¢ææflݺuÂcÂápJJÚ‰ c‹•¡ÏLªg¥ÑAèÅÓ(ÚÞžöj™óS¿ïºë.lÛ¶-½ONä¹§²x4 ¬¯›Ò5¬òÕ9j_5{S¦‡I˜ªnV¬ƒôŽseœX©¶¼’;OÇJ“)õÞ8©~ÞÌóC¬¨™Ò%¬Úë×£Ù‚ÑöVrò£ ‰sg¡wVbfÍ»b=G‰f0ö¨L­÷8rÅÐò{“zÝ܆G¡õrX Qºå6õ!çt?†êò1TW€HY.¬`ì%T0áïBnSr›úÓÖ“’2Kii)JKKqìØ1È †ÔÕÕ¡ªªjÜŸ744```ååå˜7o^ÂÏÐÐ0õÅYɲg€óGB#=ºú'×VŬ٨<Ö{¡õHf–4ã쫈ּk´ÔM3`V] _Óóî&FD“³¦6¶Xyž-!·s7eºÈ¶~ ±bAh$&®˜¹ë̤I=f…:€QoyÂJz®46ãÌXÅõ#í@¬âeлö¹˜‘»¸P™BFëVäI[¬ÌmxFëÄ; ‰(u„-8чÀ‰>·S¡ RYY‰G}+V¬€”}}}øâ¿ˆ-[¶Œyü]wÝ…øÃ ñ`0¸þúë100€›o¾<ðúûÕ>§‡ÆÝwßü?ˆGɧ ®ž èïìÑ5`u-ðê…oêÙE aç«;0³/'=GŸˆöÁhß3n˜‘Yuu¬Å=õD”Fšˆ•ǑڀîA—š™ä'”…J„‚ÀÂp¤ã‚çZŽÍ6|-¯¦ KÞ}âÜYȼѰÑÚë¸PI3*SÌhÝŠà`+†ÿ¬¢EÓº†Þs9‡ŸàNJ"¢ “››‹M›6áØ±c¸öÚk188ˆÏ}îsxì±Çp÷Ýwc×®ÄFô=ôzè¡„ø·¾õ-”••áÔ©Sb —¸å–[Rþçð´þÐЬý€¯­ ûÏ'.8È!êØM)Û¡‡÷¦"Kš€qöe˜•—#V»H_>ÌòËxs–(É¥l•F– IDATÅ%&ß<éR63Øñ0dkDeÁHH»¼ö*ÇêѬuìbæô’ðŸ}Ëþr$b-‚¬†6Ð<þiDYŒ=*Ó@ë=ŽÀö‘sè'Sz±Ñš‘sè'l‹”DDèøŠŠŠð·û·hiiAOO¾ò•¯àСCøä'?9éë”——ãæ›oÆOŒö ƒ˜à,:ÏÞêøb\±lüòzàá%—(1_ó+“*•£äÒZ wTbfõ5.eCD“%.Ÿ£N÷ÄþGé%ùf“›Ší¬œ€]¶2·T‰ùšÙ£Ù zûˆˆZ±eÖð}f..T¦‘ïô‹¾ñEv}¾¦ç ÷ˆŽ¾ ‰h_l¢wÓsìú&‚o|qFM÷&"òšÛn» øÃ”E)%ž~úiÜpà ðù|“ºÎÝwß¶¶6¼øâèk>*§ µò„cȆ‰‡êXÕW+Ã`Bo}3ÉÑd8K í¼ZØ…óÇ9šˆ\WSÌ*RBÜMé¢}­À@\» „²|§„Ý”ý'¹9Æ-Ò‚Ñú†²ÊׯċÍDÙŠ¥ß.Ðà ÐÄ@Däu³gÏÆK/½”?xð t]Gee%NŸžx¨€a¸ë®»ð“Ÿü–5:%5 ¬¬ 7Þx#rssÑÔÔ„½{÷*ÇPœ7›€¹£;CDu!PWÙÔ•x¬æSz"€¯}„=¹<”|Z׈¡Èܲ‘X´úäô6º˜'¡7e÷`¬?%¹#jAî:qÕÜ‘XY¹åè˜Øí¼š„›A¾3/§8IšˆÑò¢³n„šfÅzöΦ‰;*‰ˆˆ¦A×u”——#NìåÔÙÙ 6hçBn¹åâ—¿ü¥…B¸çž{pï½÷âÉ'ŸÄsÏ=‡+V$çeäá ¬î@kgy¬Y¾RÙ¥ a4¿–Âì肤„Ïñ;°ËVBú‹]JˆˆÆðA\âh¯±ã4`³u†›äöSêï Ç€XU3æ±fÕÕÊcí…Þ¹'•éшHâïÀ¬¹V­þ š!¸£’ˆˆhlÛF4E^^^ÂÏü~? ··÷‚×ùèG?ŠÍ›7£«KÝù÷…/|2®_bmm-¾ýíoãÑGÅ7ÞˆÁÁ OUÕu ×\s5–_¢öbܶm;zârB@Ó´1ÿ,^bîiCôº¹£¥•Vœ‚8§NîªQËÝü½‡‘¯<þçw‹¦‰¤üÛ‘ý{Ñi¿R‹ý÷#¡A̾y-lƒ“­ CG €es§¸—˜ëj5âO,ÃÝi| õû}ÈÉÉñüûVR™@¤± ÖÂÑêíò¹ÈÝߥô_–zË/SN vnG0˜‹™ 77~¿/#ÿíø»¶¡»lõÈc;§¾ªÕð÷œà,J—@ ÃÐ'ýoçܹs)Î({q¡rBˆ‘/ˆ¶mCÓx'ƒˆˆ½&ž'„p1wI)ÑÒÒ‚ªªÄ¡-åå倿扨]zé¥Xµj¾üå/yýxgΜÁW¾òüú׿Æòå˱mÛ¶ æ¨i:._¿Nù€eííJ,77€åËW^ðš™Ì´öØ€uþ-[ݰ 5£%Ý=¢ íz­rÞ’¼6„<þgwSNNnÒþíÂ)œÅ‚‘ÇfÕ•XV†{‚³È« ‹±hÑDÍè…¦Ì €=—©}óB­6æÏ_–Ö4 ‹P\BYYEZŸ7Óõuéˆ_Ò’%¹˜}íjuŽÞ 8­-B‡–3òXÀÆÊ²sÈ)›ïƒ@>Ÿ99 ì‚££‹Íú¼±ÜÊ™à JÃ0PPX<éÏBÜpýYñJ ]Ä•º©°pjÓ#åp‘ú£m!†:ptç¯q”Ó¾§í=ï¹%iÿvìàq`õ—FG‹7a´ïHÊõ)³l¸üJìß߀޾ ï>§Ì –Aä­VbíÏïD{š§}/[º½}=8}úTZŸ× Äœ+ *òG.ê‡ýì®ó?ÅÐêk¸µf½s/vœ9;×kkg£¨¨û÷gæÌ³ÂýåÈã°¨À{ŽBdX·`ù%+²âór¦ã6ÁIˆDØ\Ÿˆè<¾&Žzâ‰'°hÑ"Üzë­#±ÚÚZÜvÛmøÉO~¢ÄV®TニB!¼÷½ïÅÏ~ö³1¯=VYÉwÜÁÁAìÝ»79€,$·;¾´åB,Š­LJ!Ìú{ðµ¼®”Ä‘»´fh=G”˜³—¹'a’tkæEJš˜|«I ,E±²n»h!ì Z b´¼ž®ÔhŒŽ]f|ɰ€Yu¥kù¹;*/@Á/åDDq"‘ÈŒ.ùŽ·mÛ6<ñÄx衇pÕUW¡³³·Ývvî܉_ýêW#Çýà?ÀÂ… qÅWŒ ß¹óÎ;ÑÓÓƒçŸ>áºÅÅÅxõÕW±uëV>|‘HkÖ¬Áúõëñ÷ÿ÷“ê}9Sɳ½À™ˆÚ¢ÑàÚÙÀ¡v˜ëG¦i¬ŒÖ7ÓŸ$MÈh~‘¢E#íÂy°ƒÕÐ&n¥@D)V”[ôŠ#·v)×ÞàÝ‹€\_ì±& ÖÌ‚|é(¢UW)‡jƒ­ÐºŒqr…ѺÑÚFBVÅzàä3€Í643pGå8Î BÀ², ¹œ‘û†††`Y–ò9Ó=øàƒøâ¿!fÍš…Ç{ ý×ááá‘c~þóŸãÉ'ŸTæ,X°<òȘ¥ôÝÝÝøÐ‡>„C‡aîܹ¨¯¯ÇÞ½{qã7bóæÍiùsy™Ü®~qóC¡|˜•”¸Ñ±0ÕIáä>½³"¢.Æ›•W¸” 'Öδ¸÷ý¡(ä^Þ@È8Q ro‹«k!s‹`….UâzóëXUiŒ–7ÔHFfh…‹¥wTNàü@!›;3&¡g``€‹”cxæ™gðÌ3ÏŒûóÿú¯ÿJˆ}þóŸŸðšÄÁƒœò8-û[›êÜw>æÀZu9äP™r˜ÑÂC™HÀ†Ñ¶ÑY7ŽÄÌŠuð7m,V¹¹B× V×(!ùv3åÄöŒ´ó _¦Ÿï‡¹ôÝ U¾öíéÏ.H u@ï=«hñH̪º’ýšiÆàŽÊI8¿«’¥vD4“õöö*»)‰2VÔ‚ÜuF ™yk”ÇÚ¹³Ðú}¼(c­[ÕÞ¡FVhfL¤%ÊDbYŒä&Çè LC:z‡J[À,¸L9ÆhßΪ‚ f4«½C­Âù°•.eC”^\¨œ€BÙ94<<|Á ®DDÙ¨¿¿ÃÃÃÊk",)“ɧGªÙd$fWµòsî¦Ìlb( ½û€‹²ü›È5bÍ,å±<Þ tr‘+“Ù;FÛ ØárH+¨üœCt2›n€ˆôÅEÌ*¾ÒÌÀ…ÊI:ÿ¥|pp;+‰hFéííÅàà 'É[Â'cƒ‹¢Íµ€=ú‘GØ,ŸÊtFëVå±]8?aZ-¥žº5¸óÌØSæØß ņ¯DÏÖ)?ÒúN@;ÇßaF“Œ6uàŸU±Ð|.%D”>\¨¼ç®Êó;+Ãá0ìQVB8ÙIÉÝ”ä9»ÎRÀt|AÓÛwæ KIÑdic Õ±ª®t)¢lU-ÿ¶?…<ÔîZ:4Iï Õ±#90;Ê•9oQfÒ[9T‡f&.TNÂX_ÐmÛF__Âá0úúú‰D`Û¶Ë™MŸmÛˆD"Êk›mÛ\¤$Ï’Ú`µÁÈSâFë.eDS!`Cw|™Ž–¯tÿ8gQÒib…Ú:Cî> XüÞã ;ÏÀ<; qUˆBïØåbR4YÚP'ôžÃJŒ7ìh&àÔï)ˆŸ~žmÛÂà wfQv8¿é\”ä%yŽi#zH-Ö=ÐÎt)!š*_ë0g½ï|É60C+a´ms71¢B,. r”˜ÜÍ’a¯­ý0›j•˜‘Âv)#š*£åϰŠëG[… `«  ´¸˜Qjq¡r’œ_Ð –üODÙd¬×7¾ÎyUUU0M ]]]3®Ç²ôåÃŒÌQJ}³O BÀ‘÷£IÃ]Ð{Ã*^23+¯àB%QšˆÕê"—<Õ ´Ÿs)š*»hìhóÕ·[s¶1ó‚óCu¤ô÷hVn€ÿøo]ÌŠ(µ¸P9EÎ]•ÎK"¢lÁ›1Þ§i–,©GUU%öìÙ;ã*­Šu€ˆû¨£YðUŸ†\] É…JÏÐ[þ¬,TÚ…óa*  ¶¹˜Ñ P»±owSz‰Y©N‰Öòú¡wC®¨†|õ¸KYÑ”¼3T':ëÝ#!«ü2àÄÿÒr11¢ÔaÊi«_ÛXe’DD^1Þk_׼Ͳ,¼üòŸð«_ýGŽu;´3+.W•Í€aB,.‡ÈÏç,Ê4Fx_âPŠõ.eC4sˆU5€÷ bAîou/!šš1¯øjšÂ9 ‰2ZløQÜP_¬Òeî%D”bÜQy⿼˸i\üROD^Æ×0ÊvAì ÚŸÒWs*ö4¬¬^?‘þÄhꤽ};ÌÚëGBfÅzøšž$z¥„ÄÊ%$÷6îàò ³ü2@ó4Fõ;;bKÀì ©ËähJÄP´Þã° çÄÌŠõÐ;÷º˜Qêp¡2IøÅžˆˆ(s˜ŽwšÞ½hô ™X3 òÏ'â7(P3ÚÞR*¥¿Vq=ô®.fE”½Ä¼PTb’eßžbV:ª NCø"#µU5°¹PéFÛ›ˆÄ-TÚ¥—@ú *ˆ²K¿‰ˆˆ(»h¬²5JHï܈¸UÉ’0»8͉Ñti-Ðú›”˜s1šˆ’G¬rì¦líÎrAÄ+ìüY°óf)1£{»zвJÀ¯§1+ºzÇn{t¡YBKø¬C”-¸PIDDDYÅ*]iÄí’ƱW&ÕŠ5 ï0ZßT[¥Ë#8ÎÑD4m9P_®ÆvŸu'šg_m8 }ï[€wÃίK+ÓœM—°†¡uìVbQÞ°£,Å…J"""Ê*ÑrÇ´ž#CaÈ·Õ/ÚbY%àãn¯0:vvt4 ù`r7 QÒ‰¥êk£%!÷4»—MÐ^õÖ· û†€£J\[Åv^âk{Ky,ój`ç×¹” Qêp¡’ˆˆˆ²†ôB–.QbFû¶ØÏö6«»Ir ç®!Ê\æôpƒªän¢dsÑÁ‘v`0:öÁ”q¬’e¾ü¸ˆ„Ñ+û¶;cëJb­PÈ´žcCêb³Y±Î¥lˆR‡ •DDD”5Ìòuqo„ÞñvìAß0p"¬ž°¢:ÙÑÅ2Ú¶)íü:È<î"JQêÔþ½ÜMé-VÅZå±ÞÛ8º¸u¤ís8ÖtwÊdF›ÚkÔ*¿ Ð8#™² *‰ˆˆ(kXŽvzûµù¼³ü{~È÷§%7ºxz÷ˆán%f–¯çh"š²Õ€£‡LÈ#ãOEA˜%—(1=~aË’@C«z’ówNÍh £Õ!ÒÆz6e.TQV°óçÀ¨ƒœ;ðäÁv`È hâRîªô 9ZÂxžY¾VÙEKDÓç|=”{šËv)š*«lµº»ÎŽÂèT°È]g”Ç¢81¯4éQˆ¡0´ž#JÌäPÊ2üTGDDDYÁ¬¼\y,Û¡õWŠZÛÔË¿=EwðÂ.Y2ÎÑD4Ybv1 ªÁ½,ûög¿B½s/`*1ÙÚ´ö©'ò}ÐS Çû U¼Ò_èR6DÉÇ…J""¢,¥i–,Y‚µk/CUeå…Oð2¡Ã*[¥„|íÛÈ„CÊ¿+ €ª‚TfGI¤ ¶Aë;¡ÄXþMtñzvœƒ<ÓãN24e2P»`®sî@9Ö1TG,qLz§Œf„÷@Xã¡Á,[í^BDIÆ…J""¢,ÈÍA^0×ÝÖ­’eFÜN )¡;ʾG4u]êð–„Ý$¥Ë!õ—²!ʺ–V(!çMÊlQÇ é…ÖupÌceC `ÇÝÈóë@}y*Ó£d²"Ð:ßVCå—¹” Qòq¡’ˆˆ(KÙ¶]»ßÆŸ^y§OŸ¹ð f:> ë}Ã]c,ßù’G,¯4ð ½c7 ­¸€vh…{ yœ¨¯¾Ñ€”{[Æ?2Œ€íœöݾãô=lìTBû5{ŠÑ¾Cylç×ÁV¹” Qrq¡’ˆˆˆmä vzç%dr¡’hê.Uw“ËCí@Äç`Ê4VÉ2H=w40ÆN»q9nØ¡¶"”—¼ä(¥´þÓÐÔÝÏ|¤lÀ…J"""ò,«| F?Îkz×þÉØŽIðD^Â…J"""ò»`dn™s´cÀ`\_Kàîªôç—s+´’s‰&$¯sr_+ YöíVÙ*åuNØèá†i]K68vÒæû9%“¥‘0 še«\ʆèâñQ–Ò4 «W­ÄÆk¯Á¬Yµn§“TÎþKÚ`´þSÓ»˜-mjŒÓ¿=EïØ e˜€/vñ"÷"Êt5…±^„q«(£™Î²ïp„çè @žíUBâ¾z‰Þ®Q²Šë!à8Ge6.Te))%ºº»ÑÖÞŽÁA·ÓI¡Á ©;œý™¦*¡ü»²¢"œ£)ÓhCÐúÔ…jgï6"%.U‡è <4÷Ž}0eœX/ÞyJlºeß#Ó¿±´ÐYþíz¸°âª…«l¥{ ].Te))%Nœ8‰¢3v;¤±‹Bú ”˜Ñ±sœ£'©©;ÖŸ-wUzŠÑéØMZÝ¥lˆ2˜Ëeߢã)fh5b}Jbb¥¿/êšr_KüÆtˆ€b~袮Ié#ìHbùwˆ7ìÈ›¸PIDDDžâüà­õ5A u\ÜE¥L({—TŤ §wì‚RþmM æ–9JL64}0e$gû½Ã1Le:z† O;†)-c¿f/‰½ŽëÆ.‘p¡’ˆˆˆÇ »ú @ç’W]û!¬¸ê1Zåy_uˆˆˆÈ3ìâE¾øÞ‘ZGr*ÑÒëӇüŹ›Ä*]h>—²!Ê@ºˆõŒ#÷µŽs0e"«|­òXDz¡õKÎÅ´©“ßs ˆ…eɹ6¥ž…Þ§„د™¼ˆ •DDDäÎÜZ´áäõßLøÂ¾¬’åßbtìV¿dX%KÜKˆ(ÓÌAâïÇh{A™Í*s “ëØ©¾î]Œ¾áXÏæ8â–{‰îØ]k̃ô¹” Ñôp¡’ˆˆˆ¼Aè±)qŒö]ã<=Ò9õ´(`ù·gˆhâÎ" 境S=‰ƒÄ(cɼØuG¬Ñžœ²ï‘çp”£¾ðq0™Wè݇sp4 wU’çp¡’ˆˆˆ<Á.©‡4‚q ½óíä>Ik_B¯¶„/ö”Ñœ½Ú¬Òåšß¥lˆ2ˆ&€ÅåJ(áæ e4Ó±›RCë?•Ôçû[;n‡¦O‡XÄòoϰMá½JÈ,çB%y *‰ˆˆÈ¢Ž†ðZïqˆá®ä?‘ã‹»XÎéß^¢w¼ ;.à‡]ºÌ½„ˆ2Å‚1ʾp¡ÒKœƒQôŽÝ’Tö}Þ@8¡¾·²_³·èŽ]¶vþÈ\.6“wp¡’ˆˆˆ2ŸÐcƒQâèÉ¢ã°Ã¨0¨e'¯æ9hÝG”ËÞˆÆ)ûîv'š²±Ê¾õν:Ë¿•9FJž‹’Oë> íSbfh¥KÙM*‰ˆˆ(ãY%Kø²o)a$»ìûü¥[û€ŽsJŒåßÞâœþm–,ƒÔs]ʆ(h¢Þ1í›eßžâ,ûÃÝÐú’[ö}ž<ÐXñƒÉ4ˆÅÜ‘ç6tGù·Åòoò.TQÆK˜rÚ×éIÙóÉmÊcÁéßž¢wî¤5Ð|°J/q/!"—‰! 7nG˾=Çr숋ÝIrÙ÷yCQ ±S ±üÛ[œÃí¼YòqŽ&Ê,\¨$""ÊRº®ãºë6âöÛ?ˆE‹ºÎôi¾´•}p–½±üÛS„9›|ǹØM4“ˆ¥ê®pyšeß^b«aÔß¡‘â÷Á„òï!–{ˆÖ{ "Ò«ÄXþM^Á…J""¢,eÛ6<„íÛw¢µµíÂ'd(«d‰Z¶+íäOûvmý‰åßÜMâ)†£üÛ*^©ç¸” ‘‹tYïØIŲoOqÞhCahýM)}Ny¨°â“i±^•ä c|VrîÊ%ÊT\¨$""ÊRRJ´´´àäÉ“èíí½ð Ê9e¬]© ÷9¦/­뿽B7$”Û%œþM3˜ïœöØÞ‚2[Bû“η‘²²ïó†M 1¬„4ökö£sòØÎŸ;§Ô¥lˆ& •DDD”¹4¬µ· s§\ªÈ†f5P˜ 1‹åßža&”³ìf"ç00yºèr)š*;X•Xö⪂‘çvî¼]|zZž›.žÖ{ "Ú°Ëø>H™ •DDD”±¬âÅj¹®´¡wîÿ„dêÚû•Ë¿½Ewî&)]h¾qŽ&ÊBšÓ¾Yöí- eßÃ]ÐúN¦çɵvÜÎMŸ±åßž1Æg&Þ°#/àB%e,çj½ï8D´/mÏ/_è—”sú·‡è{ 0ÚcMj~X%K]̈(½Ä|ç´o–}{r”}wìFÊ˾Ï2jù7–VŒ},e$gŸJ»`dN±KÙMÇv]„7âºë®C(ÂöíÛ±iÓ& ?Iõ†nÀ'>ñ‰„øÉ“'ñOÿôOuí¬#tØŽißZGzÊÝΓû[!6. æÕ…ÀYïöüœI„9Ñ}²xñHÌ ­LØiI”µXöíiv°vPÝÉŸêißNò@[lÁûbq9¤¡¦=ÁY”)ôž#æ¤|'"`…VÀ8ûŠ«yM„;*‰ˆˆ¦éoþæoðÈ#Àï÷£µµ÷Þ{/~ô£! Ž{Μ9s°páB¼ð Êÿ¶nÝzÑ×Î6VႸÖ a„Ó¼ÀÔ~.VG,å0/qör3K–ïÕÓ   ˆ%,ûö2ç”f1ÜòißNò £üÛ¯C,eiA 7(!Nÿ¦LÇOiDDDÓ°dÉ|îsŸÃ=÷܃-[¶~ùË_â¿ÿû¿ñá?þø˜çƒA´µµá§?ýiÒ¯m,GÃw­ÿÄpwÚóû[!®™7XR¼x$íyÐôè{ùÿktb»€]¼Zx¿»‰¥ÚÜ–}{œZ¡<Ö;ÓXö}Þ¹dS7ÄÜ’ÑØ’ àP{zó i3:߆U±~ä±U0Ò_I_+¢©àŽJ""¢iøøÇ?޽{÷Ž,$ÀáÇñì³Ïâ#ùȸçƒA Œûó‹¹vVVèR%v‡†D IDAT¤§¹ì{ÄAõ‹½!* ÜÉ…¦LD{¡õWbf)w“PöK»¿Ïô°ìÛCdnd^K×´ï;q—:6{…Þ}Šûo_h0K.ÿ"—q¡’ˆˆhV­Z…×^{-!þÒK/¡¦¦EEEcž088˜’kg»`¤¯P‰éá4Mûvͽ@·ãw¶¤Ü•\hzœÃ¬Ð¥üLÙL$–}ÛXöí%ÎÝ”"Ò ­ï„;ÉìoäèNNðAÌcù·gØQè]j]Æv”¹ø ˆˆhª««ÑÖ–XB×ÚÚ:òó±ƒA\}õÕØ¼y3þøÇ?âG?úÞÿþ÷CÓFß’§{íl’ðíÜYhƒî•,JÇ®J8û¾QF3:ÞF|¹¤4‚°‹º—QЉYE@¾_îp)šËYöÞ«,¦“ì†<Ý£ù>è)Îa„vñ"H#Ï¥lˆ&Æ•DDDS¤ë:‚Á "‘HÂÏúûûÄvNŽeË–-عs'ZZZŸŸ«®º =ôÖ­[‡þ羨kgÛñÍpyJ³<رaÎÈcQY„ò ;Ϲ˜M–ˆtCë?;¿n$f•­‚ÞsØÅ¬ˆR¨^Ýõ-[ûøzå!Ò_;ŽÓ]~Ä6`vñÈC±¤òÙê ÊXF÷Dí¤»!¡Á*½FÛ[.gF”ˆ •DDDSdYÂá0ÊÊÊ~ ÅJ¡š››Ç<÷÷¿ÿ½òø™gžÁ¡C‡ðÀàñÇGSSÓ´¯íä÷ûñÿßâ¿ûŸçÐÚª6ÁópùåWN꺩֋Rì0J•ØêZ¼÷ò“Þ–ˆæŒöäª{ÏZTº–S¦óog"MZŽat¡R«\ƒõeg Ò=˜‚F”–†°bÅjDMþw”l{Wß²¶?µøït² ‹P­Bmíl·SI‰3b!‹Ñ÷Q\Q_÷Ê­#¹oKçÓ ú°ô¦«Q¶\Ëi: |> /|p–Ù'ÚІY# ¾ +æqIh² Ã@QQñ¤?ó¼ùæŸSœQöâ¿J""¢i8sæ /^œŸ7o¢Ñ(ÚÛ'? óùçŸÇ<€E‹¡©©)i×6M/¾¸J|oÃ>ôõNzB ¨° .5éw8Wý n„ ãøþWÜKè²z°b4±3ùÃèhp§of&)..Θ;±üMÀ²Ñž\‘‹Ý'zàë?>ÁY”J«W­Á‘#‡Ñ®ßíT²Š,ÏÃPPí?×ùútµgÏŽÊE £¯¿--“»qç5= /òGáìkÚå^BïÐêW®->æï†¯¡ÑÅŒ¦®ªª8rdæí¨.0玑ǨÀÞ‡!¬‰{§SL^^ê/ñÄg¯ãB%Ñ4<÷Üsøìg?‹¢¢"ôôŒömzÿûßÍ›7ò&¿Ã ®.¶ËëäÉ“I½¶mÛxkÛv;6ñ—!lÛÆ¹s™ñ%v¨p™òXkß¹í9-n¡Ò®.À9Íú†]LÊ}¶-3ã÷s!çÎA;wv^íh(o1|­ .&5³™¦…ÁÁAoüûñqY%”yÌ=C<á^ßTˆD¢ÎÎ;F‘¼¹JÈnÛ•VÑp¢rÑÈcs~ "®õÎœŽ¡¡aäääfÄßgºÉ¡Àìš/:zsæÀhßánb¡iLÓš‘ÿvÒÃtˆˆˆ¦á©§žÂàà }ôQTWW#à¾ûîÃÊ•+ñ£ýhä¸ûî»?þ8t]‡¦iøÜç>‡+V 77º®cíÚµøÚ×¾†×_ÇŽ›Òµ³‘¬‚PôërçúDr0®DUb)‡ x‰óß’Yz) .éyžóuIrÚ·§˜¥—B Xè]ÝK(ÞAGEGAP;óJ¨½JXà ½™­ÒK]ʆh|ÜQIDD4 ===¸óÎ;ñ½ï}¯¼ò LÓDWW>ñ‰OààÁÑ/7nÄ’%KPPP)%.\ˆ{®ìŒüÍo~ƒý×…|gGÂd¯¬RÇ´ïH7´þ&—²q°%p¸XY3[R¼uʽœhJôðDç¼wä±Ì)_ ­ÿ´‹Y%QQ.PY Æœ‹K”Ñœ Gz÷!;qÀždç9ˆö~ |´.]ÔW$N§Œ¥wî…UrÉÈc»d) €mº˜‘Š •DDDÓtüøqÜtÓM¨®®Fnn.ŽOìu÷‘|ùùùèîîÜ{ィ««ƒ'OžÄà`bo É\;Yej_µØ´ï *);¤.TŠºÈ ÈŒ/‘41m b° 2n×®Uz)*)kˆe•j ?yºÛdhêt?ì’%j(ìò´oy°"n¡K*€¸—M‰Þ¹Xp bŵRÏ]¼Zx¿Ë™bé7ÑEjnnw!ñܹshmUËîqèÐ!è}¶HkÚÇ:”XÂ>•^b8*e^ ìœR—²!J¢|?Ĭ"5vˆeß^b;˾{A˜.e3ŽæÞ„!r|ô=¼Wyl•.û5SæàB%e„„¾\á@Ú.e3>yÀ1=w^)à×Ç>˜2ŽÖw"Ú§ÄìЊqŽ&òQ_¡.6 ™ÇÃî%DS#ôØ 8zGf•}ä»*ë¹Pé%z§ºP)ý…° 溓 ѸPIDDD®“¾XŽÉÎÒãh`Å•R° ä^>45R&”[!–Spîj;ÚX™w³‡Æf-ŒøêÄתL!šj |ÿØSÆCçÎ*1Nÿ¦LÂ…J"""rUºl¤±;;½'C›ó™ÀÉ.%ÄÝ$Þ¢w:* æAy.eC”¹Ä\µ…AÂîoÊhVHm¢õ„ˆdè ¤aÈÁèèc!€Åì×ì%F—£_3+ (ƒp¡’ˆˆˆ\g•ªÜµ®€çh÷%”½-.4öwò ½ç„×cMh°%—D^"•zÜkÐýt)ƒ +¤¾êXö}ž-!Žu*!ö©ôç ;™[;XåR6D*.T‘»4ìâz%”©ånçÉCí@ü Ý\¢®Øµ|hŠlz÷A%IJ7ò4ç"Qc'±ÜÉ…¦Ì.˜ é+TbÎÁ_™&á†Ý¼R Çp)š*­ÿݺc—)¸PIDD”¥ ÃÀÝw݉ÏßÖ¬Yív:㲊Cj£½­lèá}.f4 ½C@K¯cù·§hÎ>•Åõ€ÎkäAº± L ÙYöí% U̓™ý;”G=Pu baÙø'P†‘‰Ó¿Ù¯™2*‰ˆˆ²”išøÅ“›ðð¿ÿ_ìܹËítÆå¼ƒ/z!Ì—²™ìXãnòõæÈè0âþ¿4c®›#æˆÇß7¯XýíF|7`´Š&rÑ}‰J"""ÒÄ®k]çÜyá¹ ´qÈÉÂøºXþí%jOT»éBM‘•¯hx‰Ú3\Íj|ƒ³Ý„•™êŸÿn¤N˜o¨V‡ç>—\GؘÉ>ÇoØ‘nLT‘Eeß™Œ´7úråÙèw–ªsê©·øÔDeM#dýMÑ•!\ ´8xÙLTzŠ{ƒãØL쬌¦hFŽL'Çk¢›åß^¢Þ$¶c=€05ECÄD%iâé¾\…ú”²·@OS0T.1~Æô¨c-Ç©§äb“Rb;™%´ÅCe&ìX·cÉôXû“Ó¤š g¿fO1ã¯9†"I³V¤ScDT혨$""¢e'ý °”¾\ÊÎ6¯{O–=»`Mú¢² `¢’¼@Ù½-ûNÌìò&O°"fAOc)aŽîšÿ.VÔ§²%D9Å+Df Fú€cMÝíK´œ˜¨$""¢eg5žˆÙ­@3=’öjŒèd,Èýqç§žzŠÝql‡Z!ì±F.0!ÚbŽ%Éißž¢Þ1ÆöAdÇ4Esާf&€ÜUé)æ¨ó}7ìH'&*‰ˆˆhÙ] ¾Ø9MÑ,u7IW`pì©WÉ 7Y°"`ÅÎÓÑÙˆÎfÀ,Âb#ó?€\ÇnTúS*‰"O‘8éX›8XÎK|Ê ;YÛ;¸ZS4T혨$""¢åe`EºœK£ÞìËušÜsÂÙ^³Ö±!6ïùä2Ò‚™èu,Y,{#Sv«É}£@ÆÒ •Ë®_»¦Ñ±æõ÷A[ÝÑ»¡p ‹WÌÕ¯™ïƒ¤ •DDDÊçóáo¼qÛ­¸ð t‡“gE6f ,`Ãß­1¢E06 y$é\cÙ›§¨»™ìèfÀðkІè Ñ¥ìVë;9÷¹äJjHL„1y\S4‹d`Dé×,ököC-ÿfŸJÒ„‰J""¢ •ËåðãŸ<‡ÿõkxõU÷ ªQ?øŠD?›ÐÍâQûÃ%ÈÕÌø.@Î^dK#;Úu†Gi². Ô$Ñ%ûSzš¨ôúnJ3;z8û5³O¥·ݰkØéiІª•DDD´Œ¬Fgï?u‰g©;šƒ@SPO,T6‘›€1¶ß±–ãnr!¡Nû>–RSš¢¡rÉ@v¨Õ±fޏçf⹘ó†û5{†™ê‡°¦g„›ýšI&*‰ˆˆhÙÌLSŽ8Ö|ñ]š¢YdÇÇ “Ž%Áéßž¢îjšÙýË‹lruH wSzŠÕx ÿ®ˆÜŒÔ>}-"¹GùY  ÖFæ>™ÜÇÎÁLìq,±O%éÀD%-u7¥19 1YAÙêÔÝN–{‰Zö&k¢°ë×hІhÍõMõŽ%Éþ”žRTöß{ž³=&9y|̹Æ6(žbݰë Ÿ¦h¨Z1QIDDDËÆRJˆÔÄ^WTö¶^é%G®fL‡˜r&}8L€ÜD-ûÆØ4p,¥'*›4°"ÎÞ·ê ÏÛ«$ÎÙ§ÒSæê×l…;4FDÕˆ‰J"""ZÒ_Ü—«bʾOÛ²Öì±Á©§^£þLZMçkŠ„hJÒGX¨l3»Ó !Y0½úZE7ìZB@´NS4T.‘MÃHt¬ñ†-7&*‰ˆˆhYÌ”»ôûËMVL_®¼¬5“¬, º¸›ÄKÔ>•v}+d ¬)¢uþâ~,ûö”¢²ïd?›œçl:œÒǧ{‹ºË×jä ;Z^LTѲP˾ÍD/ ­yÎö.{ϰã˜SO½ÅH8Býìé 6­pþ-ÉXûFõDå¢h‚²zc¤"H 8èBE®æ‹+ýškaWkІª•DDD´ô ìØfÇ’Yieß§õ8K1k}À:N=õŒ9J1YöF® ç¬ ÂRìÐHȱfTZÊSluý†F `ê †Ê&ÆÀ˜vÞáôoZNLTÑ’³"]F`vAÚ0G+4Q™š”©§,ÿö5‰nÇ6;ûÊ-7C@t4:–Ô^€än9u˜ÜÄÑ¢dPÅP’è&û5{šDgù7-'&*‰ˆˆhÉMûÛ‘×ÍÒ“{YöæeæèëP¦ž*“z‰–“Xj ‡°r`D_@T6[íOY©U±€J¿fö©ô”¢~Í¡ MÑPµa¢’ˆˆˆ–\U] aŽN+B@ŒSO½Bä& RûkV#ûT’FJÙ·<šƦ5Cå’0ìú5޵J-û>­hú7û5{Š™ì‡° þÆ+Ú£/ ª*LTU(ŸÏ‡?¾ñzüÅm·â /Ї¬_»ÆY²¨N”¬8GRigåßÞR4õ4v>S뉖‘ØÜâ\ØËiß^2Ó߯àïGn†r3¤ÒÈ=Ê »` xj=¹×ýšÕ›ÎDK…‰J""¢ •ËåðãŸ<‡ÿõkxõÕúâPʾÅÔ(Œ‰£š¢Y&RBô;Ë2Yþí-¦:õ´& »žSOIƒhÐt®õ3Qé%jû3Þëh/Q‘’SJ¿ftñ}ÐKŠúTÆzç)ª<Ñ’*¾@«ðÝ”§Ø{9õÔËŒ‰c0¦œÉæ™]•DË«¨·ßxòHJO0T>Ã;²É±d&vk f™õ) uö©ô3¾2,¬p‡Æˆ¨Z0QIDDDKFú‚°Úk•ÞŸ2oŽ©§¢SO½DMª[M,{# :7dÿIGò€ÜÍ w@š5³ Ò†9ZïƒR¹a'ZBQökö ‘ƒ‘>àXcù7-&*‰ˆˆhÉX±ó1ûqCؘÉ~-£ŒH8׸›ÄSŒeêiýzHHS4T•ü&D›³Ç/ûSz‹šØ1Ò!r㚢Yf‡SÀDƹÖÉv^¢ökVÛù-&*‰ˆˆhÉXêZ¼°³š¢Y~vß°ãXt5‚Y¼ÂL O=qê)-ÑÞø .Ùl 98ª/ *›šØñUKUH ©ökæ`9O1ãÎ6²¶²®ež³‰•DDD´$$ XÑnÇZÕ”}Ÿ¦ö窫ôÄB哌ÄÇ’e¢’–Q§søˆ<¦ªçf×Ùu-µÎ×PPRé¤:ø©-øÙ¯Ù+ŒñÙ¤c-Çv´Ä˜¨$""¢%!#€¯°•¬¾Deb8á,ñ+ŒA®¦½°bÝüMËD(‰J–}{‹­ì¦ÙŒñ#š¢ÑC ŒvAOU¿ ±!¦/ *Sñg7õçšh±ñS- µÜÍHAdªoRmÑ0&*=efèEÁE¶/nÓU“•! RëX’LTzŠú>h޼Çß“* '³‡”~ÍìSé)jù·î€4š¢¡jÀD%- u€@µL9UIµü{eÐP3÷Éä:"“,Úeq7 -ƒ¢›ñIàd• a©Ò¬…ép¬™‰ê|ûTzš‘ØH«`Á;ºY_@Tñ˜¨$""¢Eg×6ÁVš­WíÚ¡„³§œ˜£œ“\M-{c¢’–CQ2‡»)=ÅŠnDA/F;#¾gþT0µ²±: )¨'*›°¦a$k,GK‰‰J"""ZtÅ}¹Ò0ÒCš¢ÑlŽ)½LTz‹Zöfׯ† D5ECU¡Ö¬ ;–ì¾óœLnTTU€°3š¢ÑìxHN9–¸«Ò[|j¿æÆó=ÁPÅc¢’ˆˆ¨‚ÕÖÖ¢¾¾~¿Y¿oN™ŒlÄw²ºúr*šzÚÞü€ïÆØ~ˆÜDÁŠ€ÕÈÝ$´tD× ç߈¬Œë ˆÊ$`E»+Õ6í[%œïƒ¢‹7ì¼Dýù•(dýjMÑP¥c¢’ˆˆ¨Bù|>\wíÕøàÍÿzzºÏþ€ÅbøaG:±(wâ«èqÎO¨ñA¬çŽ<Ï6ÌD¯cÉŠ2QIKHIâÈÁ gk †Êe‡Z!α¾x•¶?9MéS‰õ1 `Î}.¹Ž19 1åL6«Ã¢ˆ •DDD*—ËáÇ?yÿë×ðê«;—íûZ‘.À,˜)mñÞùPdz8¦L¼ÿýï_Ê¥sb+‰Ê™IÉüðzšÜ{¢ Q)Ú› MÃ9`€\ËHAdRŽi¾VãyðùµÆ¨¨¢(»)1‘ޤæ>—ÜG˜ÈE69–L–};Èþ“—¬Ÿ]èl~»O_@TCùy–þìúõ0Ò4ED•ˆ¥ßDDD T[[‹ï~÷»H&“xë[ߊK.¹O=õzè!üÁüÁœÙ²e .½ôRÜvÛm¸è¢‹°uëVüøÇ?Æg?ûYlݺ5^0Äàà .¾øbÇ?nNR À w8—8@ÀAŒ8wL`}T_@T&y*ù>ËŠöÌs.Qù„2\DŒÌìÆ&O°Ú_aïaY4€¤ê)ƒåĺ(PËýS^aL˜8æX³ù>H‹‹‰J""¢ºñƉDpÇwàØ±cH&“¸÷Þ{±gÏ|ä#™ó1/¾ø"n¹å¼ôÒK˜œœÄèè(î½÷^ ãŠ+®ÈŸ 11á­IÙV¤ 0f'Õ Ø0“}#r¡‰ pṯ$ÔTäjêî(+Ò ˜MÑPE1D[£sÓ¾=E­*0Ò‡!2Ü[Hî™~š! :ù>è%ê®J+Ê>•´¸˜¨$""Z n¸Ï<óŒ#¡(¥Äã?Ž+¯¼~¿ÿ žeÛ6FGGç{2Q©4T7Rû€Ü¤¦hÜ«hê)/Ð<ň÷:ûÍ~XáN}QÅëc@MÁÎ2)!G湎ëv› î¦,’³ýqçß=ŧì¶C­MÑP%b¢’ˆˆhZ[[100P´ÞÛÛ Ó4±råÊ’ž§¾¾xõÕWókuuuhnnÆÕW_믿o|ãašæ¢Å¾ì¨óÓ¾çV4õ´¹ˆÕÍ}2¹Ž°¦`Žíw¬YÜMB‹ C)û>:Œg4Cå’ØõkkF¼wž³«›ú>(:›“ÒÉ݌ԠóF´°Ù…•DDD `š&V¬XÑÑÑ¢¯ŒÌì€)5QùÑ~GÅÓO?_«««CSSn»í6|üãÇw¾ó<ýôÓ¸ð ç_`‘ÙÁU°kÙ>î$™ÛÉÑÁÝ$^b(½W­Øæ9“¨tjJ °ìÛKfnÖÍ&Û„5]tSƒfÈ>åg;èÖ„ç>™ÜGZð)­}r1&*iñ°k-Ñضl6‹úúú¢¯3ýêR©³÷¥ºè¢‹ð¡}·ß~;r¹\~ý“Ÿü$dÁЕµk×âÀƒ>ˆ«¯¾““g/©6MÛ®¸]x‘c}ÇŽH¦fû$ !`š>ÄbêS”,Ýt1¦ ¿w.…ÆÀ4XøsV²‰¡4²Ý³ÿmç­Fp`\cD gšæ9ýìxQÖ:‚á‚cYChÕfø§OÌû*G`úxI"ƒ~¤Zœ¥“¡á,|Uö»UªÚº:X¶åª¿=ñçÄÚ‰}ˆE#š¢q¿ôè$¬ÆÙj‚º ZQ;±ô•#õõ!ÔÖÖ¹êgÇ‹&2ÇìçK;ÖƒXã gk”  áJþىNj73Piø©€ˆˆh¤”8vìV­ZUôµ+VŽ=zÆçX³f ~øa|å+_Á¯~õ«¢ç/tøð™aG IDATaÜ{ï½øÑ~„óÏ?Û·o?kŒ†aâ‚ /€e9?4¦Ç'pâÄlß3!ÚÚÚÏúœóy­æÇñ G[ÛÆ?_¥‹Op°àØj c}G Ë{Ó}ýþsûÙñª¤=ŽicöFE°u+ÖæØî Á`k×µ"“ayóhk R•¯fN¢£¦¢­E[LnÆP__`°øf¡Àp]—cmMM«ªðoc©ŽÆ† ò=Ʀ´¯]òï[_:çÏ<dDÛ!qz±4kÛx "öq½-¡@ €`°¾äŸ&*މJ""¢Úµk®¸â ÜÿýŽõ·¼å-Ø·oÒéô¼mllÄ#<‚gŸ}_ýêWKú~§KÊOïØ<›l6‹‡ÿõk<ãyB4Æñ¿ÿûrIÏ«’f &·¾ß±ïÿ þwäÕyAØíƒñÆm€1óß6^Mìƒôà„ßææ þÙñ2«£XuYþøàd†_«¾ÿçâÒ­—a÷®×ãTdcã‚ùc«ÿ~¿ãÿôärçõœÔX‡ é`7¬GöBg’íð«ÿ…£ÓLTÌGÄcoÊOFLü~ïNÈôô’~ßµk[‰D°k×kKú}ªqÑ%°C­ùã=#&üû+÷}°¡¡ç¿áªüÌ³ÜØ£’ˆˆh{ì1tuuáï|g~míÚµ¸á†ðÍo~Ó±vÑE³å1±X >ú(^yå|á _˜ó¹ç*)ï{ß‹ÉÉIìܹsñþ%݈‚r-iÁHìÑLå 'Kœþí-fÜÙ§Ò·CšK¿ˆ*@»2H§ŸÓ¾½ÄŠ(Ãä&‡a0IyFò`˜šmy¢Rän¦2ý;§ U$Z(î¨$""Z íÛ·ã±Ç×¾ô%¼å-oÁÈÈn¸áìØ±?üáóç}õ«_Egg'Þüæ7#—ËáÑGÅêÕ«ñÃþ·Ür‹ã9¿÷½ï¡¦¦¿ùÍoð / ¯¯™L[¶lÁ%—\‚»ï¾»¤Þ—ËÉR&=ÉkiwDTÙ¢5:»ÐÕ ü\_¾:Èp›cɈó}°rà$DA¢Í3-Qlïõk®FÆØˆÜ¤ïtÛ +Ö ßñµÆEÞÇD%Ñ9úéOŠŸþô§ó~ý?þã?òÿ¿¯¯7ß|óYŸ³··½½îß‘!ë×@ÖÄk¼@+ѱ06 4Ôä—dGÀD¥g˜ñÝÎDeô<ÑW‰gÛî¦ô+² ²°£š…™Ð‡ÈþˆÙy,@­XsGž'HFb¬æ?È/YQ&*éܱG%-XN)ûÓqÇ4Eã1À€³ûTz‹¡”wÊš(캕š¢!/uþ™ÒïìOé-Eeß©Àâ$û’¤¦ O8ò}Ð[Ô6Vt³3qO´ü """¢³;ÈÌø.M‘x“:å[´5~sî“ÉuŒ‰cSÎ¶Ò èŒÚgJ]OËZÀPB_ŸIV’'ØÁUlr®•éèkÂ@îsÉuD6cü¨cM²HT.&*‰ˆˆhAìèf@ìþ³s3“©tS9às÷ËÞ¼E-ÿ¶ÂF@S4ä5¢½Ñ¹0À²o/QwP‹LÆäqMÑx“<0 d ’ó†à®J1•!Šê.c¢r1QIDDD ¢î3S6ûr•KîUÊÞº˜¨ô3ÑÈ‹lìHçü :E¬lµŽ5µ¹[QÙ÷(wS–Í’À~eW%•žb*»ˆíP+¤¿AS4T ˜¨$""¢Q,û^upF´¢©^O,T6aMÁÛïXãn*‰šŒIN#zb¡ò™XávÇ’‘`¢r!ŠHu4ÍN'×3Rû ¬éÙ!`E7ë ˆ<‰J""¢ %„@[Ûôôt£©±ñì(ƒ\ ˆ:ÖÔ;êT9<ŒM;×:÷õ¢¥¥ö¤cŸJ*‰RöÍÝ”ÞbG:c¶—¢€ _’íO¢h°\¨XÉyž!-‰>Ç’ã ;Z8ŸîthmmE:ÖQUˆÅbÒFU2 Õ«V!à`jj #££gP‰ŠúrM˜^´ç¯*3}éÞ¸&¿$:š!_âïW˜ñ^d7¼+,ëV@Ö6CL1ñDóð›”ÁYìOé)êÎi#µÈMjŠÆã“#ãŽjÑÙ ylLcPT3±VÓùc+ÖHy†GÍ­*•CCCH¥RºÃ "ª ñx~?§7ê`Y6~÷‹\üçVî”›ÉÞyΤRȈÂDe[ Òorú¯Gã‡!2)È@8¿fÅzà;úQ‘«µÅ³ ¸Í–jŸ>rµœš¨Œó}ð\ˆQÀ‘¨l‚üí>Q9L¥ýôÕîo…‘>¨)"ò2–~Qy̬g_.“hçfp° vøM 5¢/*“„©NÿfÙèP†f %€©œž`¨lvM#d]‹cMý@å‘ÊôuQ ¶*÷Uy’˜.žxÏ~Í´PLTQY¬p'`Ì^<Ø0Ù—ëœÈÉ,pÄYíQ”È WS“v¤Ëñ{BTHt:éH–}{Š;Ïq,²iã‡4ESäþ¸³ŠÀ@û5{Iq¿f&*ia˜¨$""¢²°/×ÒPj"ƒÜÍŒ÷ÒÎK£xç1 Z4K¤ã-EíOâ»Ù‹ï\e-ȃ Çß½E­®±Ú }ÁyÎ&š•DDDTõ}¹GQÙÛŠ©Õ •/7QÔ‹‹»Ih.¢Ë¹[Z¦§ã✙ø]À`Ù÷â(ºaÇÊ/1S€•™]ìè&}‘g1QIDDD%c_®%t$LfK¢ƒ»I¼¤h7I¬GS$äfE¿×#7ãy†n‡4 n"I 3ѧ/  R´³8\;sÓŽ¼ÁÎÂHö;–¬(ß©|LTQÉÔċȳ/×b±%ä Ò§Ž‰JO1•þ\vp5dMLS4äJfqß=ö§ô–¢ª‚ñ!ˆ,wÄ.Š“ã@ÜÙJ†åßÞR4X®±€Ð y•DDDT2öåZZE}*Û›f 'ã!²iÇË¿©ØÐÌÙ)}£ú¢²©;ÄXU°¸Ôv,ÿöŸòû ýaÈúÕš¢!¯b¢’ˆˆˆJ#Ì™IÆØŸrq‰~¥´Æ±.ª-*“”0“ÎP;ÊD%Í**û>:Œgæ>™\G°•¤‹ÚòΑºÃx}Ì™Ü'W“ÃSÎþß©LLTQIìðFg_.H˜‰=Úâ©D2= ;wä±O¥·¨åßVt3 x‘M3d;˾½ÌŠv£°ŒUXS0Æè ¨ÉÁÀ²gLl` /)zd¿f*•DDDTK¹#n¤±/×P§«‰ r·™é¿³Ûb¥Y «aƒ¾€È=Bˆ–çš:<„\M}4{iiЦBe,È¡¤c‰åßÞ¢¶C(@EtLTU(Ã0ÐÝÝ7½éb¬Z¹òœŸ¯¨?%ûr- µOåš0PÐ •KdÆ`¤;Ö8ý›€Sɖ–³SYÈÃÉyÏ'—vt“cÉàûàÒPn؉.&*½ÄHììÜì­ƒˆÎħ;¯Y·nZZZ …t‡RUÒé4†‡‡qèйM–­««Cmm-|>þè/§\.‡©©)LNNžýä3àë§Çb½~äm2л~­cý)—†<‡ÈX³=¹„€ho„ÜyLo`T23±vh]þØŠöÀà§#"Wèp&[äà(`s™WØõë!ýÎk@ö§\²ÿ$Ä•‰­hDSrdB_PT2ag`Ž ÂŠÌ&ö­XÌÑ£"/áŽÊÕÕÕaË–-hoog’RƒP(„öövlÙ²uuue?Þ4MÄb1„B!&¹4ðù|…BˆÅb0ÍòûtñõÓë\_?ÒǶmôööâå—_Á±ãÇÏí¹æèËeŽí?·in–„T§wp7‰—¨I|;´ÒÖ ¹‚1sÃÁý)=Eí³gLƒ˜ŽkŠ¦Â §±içß=EMâÛ1Ô¡Ò1QY¢žž&(]  ¡§§üò©p8Ì— ø|>„Ãå_¨ñõs‡…¾~TŠúS&úØ—k)©åßM€óœLnc¤ö¹Â]èvl³¶xÈÖ„:¿cI2Qé%jû–}/!‰âD>ËyŠ¡ Ô±ka×µhІ¼†‰Ê¬[·ŽIJ …BX·nÝÙO<¥®®ŽI.ñù|eíŠåëç.å¾~T!„€¥öåb¹Û’’ê€`XÕ0÷Éä:6|É>ǧžV7¡–}§ä”¦h¨l¾ ìÐzÇ’:Ù˜—:XN´Å?+{¼Â˜8Z´ã˜ïƒT*&*KÐÒÂ̿۔óšÔÖr˜۔óšðõs¾&ÕǵBúI2ÒYb‰É¢^\¢“»I¼DÝmeE»ÁÞÕªè÷—Ó¾=ÅŠnvþþÚY˜©A}Uµ‡«ßZ£ú⡲—3QI¥á§¥p7¥û”óšp7žû”óšðõs¾&ÕÇŠ(ån“Ã0¦Gç9›º›„eožbŽ:w[I_v}«¦hH'QçV;[§Hö§ôµý‰™Ü ØYMÑT9™…<œt¬ñ†·ݰ wf@S4ä%LTÑ©}¹¸›ry%2ÖEZÞ(ð ‘IÀ˜pNjgÙ[•êhŒ‚³Y 8˜Ð•ÍŠ:{̲ýÉ2Qv‹NÔñ3±ÇÙÏÜðà wê ˆ<ƒ‰J"""š—4ka7lp¬ñm™ì9{öØ@[ãüç“ëñ]Žc5éOÕ¡h7ôþ8`ÙsŸL®#ë×@Ö8KŽyÃn™ *ÕÍõQöJ÷ aMÁ;àXãôo*•DDD4/+º Íëí,ÌT¿¾€ªÉ»®Xþí->%™a‡ÖCú‚š¢!-€vçï-˾½E-û6¦GaLkЦºÈ#)`"ã\kç ;/QoØå¢¬, ³cýP¹òÊ+Q__'žxBw(Dé™gžÉÿÿ«¯¾úŒÇóCä6¶òÒL Vfž³i±Éþ“e¢³ò ç“»©A;iœêÉ% رn˜'vè Œ–OKh¨q®1Qé)95QÉÝ”ËGJÈQˆ Vå—Dg3äŽÃƒ¢r˜ñ^d7¼+,ëV@Ö6CLq ͉Ê*qå•Wâúë¯d³Y<ýôÓš#¢³Y¹r%nºé&lݺÑh‰D/½ôþó?ÿÇ×U‰¢þ”ñÝóœIKbPIhDjæzà丞x¨¼òÊ+#¤R¨;$¹cré¼éMo 7Ü€`0ˆ»ï¾¶mcÅŠ…BØ·oŸîð<Ë®‚¬‰9Ö¸“dyÉá4Drj&AyŠèl†d¢Ò3Ìx¯#QiG»1S̋쪠´kýÜEä%v¤ 0 .™¥3Éö'ËIö@H ˆS©&ÐÄõF%’0½Èµüa~ÅŠ1QIgÆ•Uà¹çžÃwÞ‰l6 ¸óÎ;™¤t±U«Vå“”/¼ðn¿ýv\ýõ¸ýöÛñüóÏ# âóŸÿûÙÏjŽN/Ó4ðæK·âºk¯ÁÆme?ÞVÊÝæšbLK¯¨ŸûTzŠ:tC°ë×hІ–•ß„huaaÙ··UŒír“z‚©VàØ˜c‰ýš½E½ÉmG79o)˜¨$r™›nº)Ÿ¤ü¾€¾¾>LMM¡¯¯ó7“OVÞtÓMºC%Å3Ï<ãè9¹e˼ímoÖ-[Ç…ks=ŽÊsÇwà‘GÁwÜáXå•WpþùçkŠÊl[bßþص»##£g€‚eß.¡$6Ćà7ç9™ÜFLž(êÅeÅ8L ˆöFÀ,¸Ü²$ä¾òÿ“>êïªÁ÷A-d¿ò>¨¶T W3ã½€œ­"FvÃF‘Û1QY¡®ºêª’ϽöÚk—0*×%—\øö·¿=ç×O¯Ÿ>Ü+‰Ìù¿êÿ§sÓÕÕ…_üâEë@µµµs<¢zH)qìØ18p©Tª¼~XáÇ’gÙ·rpÄÙ‹ËgÌ$+É3Ô$¿:E˜*”Zö=2–¦`¨\vM#d­3!Æ÷A=Š* V6¡€ž`¨l"7c|ȱ¦Þ '*ÄDeºêª«ðîw¿»äó¯»îº²Î§¥Δ ÍùõÓë±/RÝ.™L:þ—–ÆÑ£GQWWW´~íµ×b``@CD•ÁŠt†vAÚ0’{õTͦs‡•¿#,{óµüÛo„4«ûFJ5Ê®/–}{ŠÝøDZȤ`ŒsÚ´‡ÀTnöXÌñûE®¦¾ZQVÐüØ Â\wÝuù’<ð@~ݶí|ß¶/~ñ‹àÔrÕUWÁ²,üìg?[Æhi.ñx+V¬@kk+úúúоÞÚÚš?ÜmÇçT×d2™ßIY˜¼dÊsóä“Oⓟü$Ž›é¸~ýzÜxã¸í¶Ûð©O}JstÞ¥ö§4ÆöCä&4ECè?93<àÑÙ ù_{4Då0{;7Û“K˜°#]0Gwê Œ–ŒhªbΛh¤ã-êÎg#±‚¥‰-!÷Bt·ä—DGäÿѕÌ÷"»nöšÇ®_ Cdʬø¡ªÀDe…Éd2s®ÆìæÙÂe!Û¶—$&*ÏK/½„w¾óøà?ˆÏþóE_¿ùæ›óç‘»¨ Ç-[¶8“jâò´Óý)™°\˜‡~mmmù!aÏ<ó ¦§§ñÏÿüÏxüñÇ5Gç]j_.õN8-³ÁQàmÇMÁ™$HœC¼@Ø©Á™§X±n&*+™Zöž†Óš‚¡² v´Ë±Ä÷A½dÿIG¢íM3“À%“Ç^ RûgQùNßÀ°¢Ýð óš–Š1QYaž{î9\{íµ¸óÎ;_ûò—¿ ¿ß_´þÀàé§Ÿæ$p—øÎw¾ƒ·½ímغu+î»ï>|ûÛ߯Áƒ±~ýz|àÀ¥—^ Û¶¹ûÕ…Ô„ã\=)O'/Ï”¸¤òär9|ò“ŸÄC=„žžŒŽŽ¢··—»ŽÏ¬‰Â®kq¬ñM/y$1žê zrµ7¯Ò•ÅLô:•6êT4u*±a>ÅCìH¤Qð÷VJ˜‰âJ'ZFÊ@ýkÂÅ­QÈ•lø’}È5]”_c¢’æÃDezúé§Ë:ÿç?ÿ9“”.rüøqüíßþ-¾ð…/`ë֭غu«ãë¶mÃ0 Ü}÷ݸçž{˜Œñ˜¹ëÐâÄàà î0*B.zžãXäÆa¤çî›KËDJÈÁQˆ Vå—DG$•žáKô"‹ëóÇvM#d] Ää°Æ¨hI˜Ðæì%^4 „\­¨ì{|";¦)¤¦€“ã@sýìZ{#ÀD¥g‰^ 0Që„HVv’•ªœde¹‰MZz;vìÀŸÿùŸã}ï{¶nÝŠÆÆFŒŽŽâ¥—^ÂSO=…»îº ]]]øò—¿Œ{î¹##üðëFsõ¤<½Æ;‹ç+_ùÊ¿~Çw,S$•ÃV&1šñ^–V¹ÁÀI 0Q¹±ÒΉàäZbü(D&ç×rÑnø™¨¬<룀ߜ=¶%•“‹Îñ>HÚɈÂDeg3ð›}ú¢²˜£»Ž‚_v}+Œôm1‘;1QIäRÃÃÃøÊW¾2gæSŸúî¿ÿ~tuuáK_ú“•.¡ö˜œ«´{®5ö¦\|µµµØ¶m¾õ­oéÅs$ Xöår#Ù?!åLO.¨ñë¢ÀAî¬÷ 3Ñ‹\Ë%ù+Ú ÿÑ_kŒ‰–‚èT¦I“Y=ÁPÙ¤? Y¿Ú±Æ÷A—¶®ÏеÈZŸs"8¹–È$`Lƒœ½éjÅz˜¨¤"LTV«®º ï~÷»óÇ<ðž{î9<ñÄ£¢s‘N§ñ×ý׸ÿþûÑÞÞŽûî»ûØÇt‡UõN÷¨JO>.ä1ä4ߎÉ|ä#ظqã2Gã}v¸­ Ñ9HqN—v…‰ p< ¬jÈ/‰Ž&H&*=ÃŒïv$*íh`ø›I¬Š¢ÒánJO±{ˆÙ…ÜäÌ ÒNî…ÈZ³;– ±± r÷q½QÉŒD¯’¨ì†ˆmèÈÉ8û)äuÏ>û,ž|òÉü1“”•!™LâSŸúöìÙÉí.õÌ3Ï8þQ×himß¾o~ó›u‡á9Å}¹Ž@dSš¢!•ì?é8MóœInd&ö8{q~Xáv}Ñâ ×B¬9–äÀÉyN&7RßÍÄð³¶+älȃ çZ߽ČïvÛ¡õ¾ ¦hÈ­¸£²J<ûì³0 >ŸÓ¢+H2™dÿ=¢y¬Y³ápøì'’ƒ:‰Xý@IzÉˆË v ¯ ¡Îè ŠJ—›€‘>»¡-¿dE»g˜TDg“c3žœÌΔ~“7vt³c‰eß.30âHNŠÎ&H€íš=ÁL V03 §~çÌ“ÿ«70r&*«wp--µt{®RîRΡò\sÍ5Žc!Ö¬Yƒ[o½¿üå/õå¦iâÚk¯A*•ÂË/¿‚Ý»Ï|±%}õ°ë×9Ÿƒhî2”˜éÅU{ê#œD{ä«GõÆE%3½ŽD¥ëö?®/ Z\êî®Á¼ò¹vwñF‚»Èþ“Woš]8µ‹Y§õE¥³³0Sý°bçå—¬h7•äÀD%yÚ¿üË¿­%“IüêW¿Â}÷ݧ!"÷°m/üî<8„ôøøYÏ·b=³ƒZ;clÿFHe³åL®î–ÙµŽf€‰JÏ0ã½È¶^›?¶ƒ« kbÓì5êy§úåbJo±bJû“‰£üÝt›“ã@bˆôÓîh˜¨ô #ÞëLTæûÂò¦Í`¢’ˆˆ<­««ëì'U))%É$Nœ,­?š­^ %ö6'iºq$*EG¤€ä|/0Ò!rŽ][V´¾ã¿Ó-±62»Û˜¹æf¢ÒS,¥ý‰Áö'®$F .ž­Í¿ãäh¯0½(!'ýaÈúÕãG´ÅDîÂa:DDT±¢Ñ¨îþ¸»A.—ÃäädÉçóõs—r_¿ÅöÁ~°äsq×]w-a4ÀW\mÛ¶¡©© /¿ü2¾ûÝïbzúìe~¥>n¡Ï¿'lçŽþñãšk®Á­·ÞЉ‰‰s~ÜBŸ!¤YƒQÛÙÏ“hî&÷Ç!²à?õß@[#Ð[zÅée&z‰ÊH7üø™Æˆè\5I²o°l=ÁPÙìúÕ¥ý oعšìx[gþX4ÕCÆê€¸ž€Ë IDAT¾êT:aMÃÛ+Ü‘_³bÝLT&*K699‰;v`ݺuÜ]©A:ÆððpY;) Y–…x<Žºº:îÎÓ —ËajjjÁ;ñøúéu®¯_%êîîÆ_ýÕ_á¶ÛnÃ/~ñ À÷¿ÿ}üà?À>ð|ík_;§Ç-ôùÊŠl‚,l[--ÉþEý´È²0”tôÄMLTz†™èEvíÿËÛ¡VHDvLcT´ bfêp¡¢aäjVT™ö== 1yBS4T’c) B³m~DG3äËCƒ¢rñÝŽD¥Ýø`ð‡#"·àÕ~™:´àdé799Éd‹‡ñõ£31M¦Y<Œ"“Yü^7þð‡±sçÎ|úúúð³Ÿý 7ß|ó¼‰ÄR·Ðç_(uâ°™` '! •]Íg8ŸÜÅH@XÓfÍÌ‚°¢›à;ñŠÞÀ¨|+Éýì•ç%êû ߥ)*™äàÄ…«g×:š&*=ÃŒ÷"»á]ùc»¦²¶™=Ò‰S¿‰ˆÈÛšššðÈ#`çÎxýõ×ÿìܹsI¾çßøFüö·¿-ZÿŸÿù¬Y³‘H䜷Ðç_(;²ÙqlÆYöí ꎭp-ÐÔ •OZ0’{K6§žz’ètî¦ÄèËO=DØ k|ôˆgBK´7ÎL'O0ÆCdm¥¬XÏè)êÍq;Úå¼q@U‰?DDäi¡P(¿ûpddëׯÇ믿Ž'Nà¼óÎ[ôïgYFGGÑÜ\¼s­©iæÃñѣʼn¾R·ÐçŸK Àg>}OÑúÏž~'NÌ\Hï´·àHÁ×Ö8ÿ®(éùI¿‘€ÂøæÆflݶ †µ|1ƒAüÑm[¾oXa~ccõùãÖ7¾í¢OcDË'Ž`ËÅËZÆØE6ºÂÀncv¬°ËÖžs•Æ ª@}}=r¹6nì8ûÉgñû+8îŒf°‘Ó<ã`ÆDaWÊÐEðÆÌü7|jjjàóùÐÔÄ 7ÈÈ~)‘ï±-Þð–?F#Ü7ÌÊ4M„B¡’?óüæ7¿\Òx*•DDäiCCChooÇË/¿ŒíÛ·ã†n@oo/®¿þz$“É%ùž‡ƦM›ŠÖ7n܈l6‹'æþpUêãúüª\.‡'žüiQùž=}L¯ëÖç¿–è}/¦ª#IRj}@ÏeÀ©D‰m/Ù c|ÙBضí*¼øâóËöý*µ~°ò-ùã}©Zœè­ŽÿžoºøìÙ³ciïN:·®é°fvá`/?ÿª¶xªÅæM=K§päÈász»¶ÜèX;úÚ3ž`eWÈàíùãñzw½ŒÍ½+võ굇Ãسg÷r…Hgaœw¬úÖüñ«Gr¨rßû`(BO÷°ýåu‡Rñ˜¨$""O{öÙg±yóÌ0˜ýèGxüñÇñ¾÷½Á`÷ßÿ’|ϧŸ~ù—‰H$âH†^ýõxê©§æÝTêãúü*Û¶ñúë¯c``pþ“<‹€4m»‰=ÏBž| œ÷í!™ Äᤣ'—ÕA®ïø²… ¥œ³U•häuG¢2Ú€iË€°¦Îð Ê`Û6²Ù¬§~Œ¶˜ãØÚ{–‡ÿ}¼Â²,är¹sþÙÉ59wdŠl Vâ ,ÈyA®³ÿ$Äd¢Î?s,€Ìºàÿæ¾’Ëå`Y–§ÿîTct—#Q™iè‚éÂ×'›Í¶mþì,ö¨$""Oûú׿Žø‡0³ñÆoÄ¿øEÜrË-øú׿¾$ßó{ßû&''ñàƒbõêÕ¨««Ã'>ñ \tÑEøÆ7¾‘?ïŸø¾öµ¯Á4ͲWêy‹AÀ†èç¸Ô¿¾ã/,êsÓ2QúTŠ–³y‰‘ìì‚ÂSaÎ ÷ ÷k 1gÏ`18ª)ZuÂðÌ€+&)=Å–J:àŠÜÍL8êÈú55ŠT͘¨$""O¹ýöÛ±aÆüñØØ¦¦fw:tßùÎwð»ßýnÉbH&“xßûÞ‡+Và׿þ5vìØ÷¾÷½øÓ?ýSôöÎv ¼âŠ+pùå—£¡¡¡¬Ç•z0Ç@õ@¤VO0T6ag`Ž9w=«Ã=ÈD§rS ön{Õ1|°#Ž%u°y܃å zÇ’»cû!rŽ5+ºYS4ä,ý&""Oyÿûß;O¾ú*žxâ üìg?+¹gãbÚ·o®¹æ¬^½µµµØ·o_Ñ97ß|3B¡‰DY+ç<"I È/‰Žfȇ4Eå0ã½°"³»(­èâ£% ìÚ’ý'¹ÏC¬p¤1ûwÒ†g¢Ò‹dÿI¦%Eru8¼4½Êi‘IF¢Vól¯Q+Ú ßqö‚¬VÜQIDDžrùå—ãýï?~ÿûßã¶ÛnÃoû[|ë[ߟüÉŸäw..§£GΛDÇñãs÷ <ÓãrU1)!•rS–½y‹wu5QØu-𢡒ø ˆ Îþ”8©'Z+êܹl¤íê"HM'ÆK¢“ïƒ^¢îf¶¢›ÁtUµâ+ODDž"¥ÄË/¿Œûî»—_~9n¾ùf â®»î /¼€|×\s jjjt‡J´lŠÊÞÚYöæ!ÆÄQˆé„cMíGî"6Ä¿9»`ËâßCr5[i±À²oo“Êökö–¢þ°¾ ìÐzmñ^UYúÝÚÚŠt:­; "¢ª‹Å044´$ÏmÛ6¶oߎíÛ·ã¾ûîÃþáâïxî½÷^ƒA¼øâ‹¸õÖ[—ä{¹‰™ù|:7YãƒXJœéaä"f¢¹•—æíh7päW#¢3R˾'©Ü<'“ÛÈ@vp•cÍdÙ·§ÉþˆKg{˜cM¨ó“Y}AQÉD&câìàêüšë†1¶__P¤MU&*‡††J¥t‡ADTâñ8ü~ÿ’Û¶ñòË/CÃ0pÓM7aÛ¶mKþ}‰Ü@¦§á1ˆ•í:›&*=CMTZ‘NÀ VFcT4Ÿ¢ÝZÜMé)3;– vç&`¤j‹‡ÁÁ8µfw:¢½òõ¹[ðûñÝJ¢²þƒ?×éÂÒo""ò4Ó4qÙe—á¾ûîÃóÏ?Ç{ çwþîïþ—]v™îðˆ–Ï\åßäfbìÙë¡]_@4¿p-°¢Þ±Ä²oo±ŠÊ¾÷Òžçlò„œ y î\cù·§¨»šíúõþ¦hH§ªÜQIDDÞfš&Þüæ7ãºë®ÃÕW_h4ŠÁÁA<úè£xòÉ'qð wEP.kËŠ5aÈú0Îyž›„H€ oÌ/Y±nöÍs!Ñ¥$?¦rÀQVky†0`GºK¦2ЊŸ¡P~¿ ¥„m³äc± ! {Ѳ2M¦i¢¶¶Ùlét¹œ{šÍŸúÑÎyNW›oSNcÓ@CÁ”ÌŽf`ä ¾˜¨,fb·#Qiźg¹ðs§êÔ`10Ê]ÊbG7¢  NZ0’{õDKo`dæïåéëH¿ ±!Lë ‹J%a&z‘k¹$¿bE»á;òk1Ñra¢²D>Ÿ‘H$Ÿ ”R"" ¢¦¦æ,¦rMOOcbb‰ÄL-)% ƒwÀˆtŠD"ˆÇã®ÙYðáûØÇpâÄ Üzë­øýï¯;,"wGGÙ[äKLTz…¡ìö’¾zØõ­0Ò| —]Xq,Éö6ô+ª”}' lwÝ|¥E6™ŽŽkfw䉎&`wB{EQ¢2Ü ~ÀÎjŒŠ–•% …Bù$¥išhiia‚r ÕÔÔ ¦¦Á`ÃÃð, ¶m3YI¤Y(Êß@Ðéío;>ó™Ï ¹¹=ôyäd³üÐBThÞ²7N)öczÆä0캖üšíf¢R‡€QPÝcÙûãú⡲ÙÑÍŽcu`U&Ù¢ Q)Û]ìiîf¼6 Nå̬†0“}z£%ǬO @~`Ž”’IÊeTSSƒ–––|8ûéå÷ûÎ~âzôÑGñÐCáµ×^Ã5×\ƒ‡~˜IÊyø|>üñ×ã/n»^xÁÙ@EöŸì‚âÔÓeoäj2EZLËC-ûƵôCe³ëZ`×:_C•ÕAx%V6Àª÷k †Ê–›€1î€Ä÷ÁêÀ•%8””R"3I¹Ìjjj‡‘J¥Ø«² ­[·‡Ò¨©©ÑÚ«²¥¥úЇðüóÏk‹Á+r¹~ü“'000¨;Òa*+.{“ƒœTìF¼XýÖü± ·ÍLϱtqY)‰J–}{‹u&6D61~TS4´œäá$ÄT¨M{dÖモ²˜ñݰCòÇv¬Øÿ„ƈh9pGe |¾Ù?l¡PHc$Õ«ð¿;‡éå÷ë½ý®w½‹IJ¢É~gBE¶7jŠ„ÂLîuôâ’0‹lÒQZQ­s,É~&û½ÄVv`™£»ŽBª¶,º97µ–×ó^b*ýšíàjÈV‡T:&*Kpº/¢”’»)5©©©É'(™¨$Òët+ ]Ü2Ì‡È ÔD¥hipN'w³³0SÎÑjÒ…––hWʾSSÀ‰´ž`¨|†fGö§¬2ÊûàôÚ $‹ô<ÃH„ÈM8Ö,¥ç,U&*KÄä˜;0YIDDT†#)ÈÉ‚®bŽ~{äjf|·ãX^LK¬³ÙqÈÝ”Þb…Û³ ·¶´a&öè ˆ–üÿÙ»÷ø(ê{ü¯ÏÌn²»¹în®@¸%p(rU J›Ú‡h[)*(å§GýµZõ´ÕZm±ç/U« ­—¢ôˆJK ŠQ ‚R¹ÊpI$ÙìæºÙËÌçûÇ’ÝÙ„ì†$³“¼ŸGd>™™}'²»ïù|ÞïR‡b-OÑbÓ¶Þ:‰—!¨þÏJVzìí(QÙØl6Øl´Ô‹x—••…¬¬¬Žw$„hÉ8Y«ËÏh{_—Õì/ž˜Ù’£Q4}ŒQ˜®RÏR&ñMÐÊÕì,ÒË5xÀU³ ›²iežD4–KN©¬^~»q®¸¸¯¿þ:^ýuŒ3¦Ãý¯¼òJ¼þúë¸ñÆ&“ K—.ÅÒ¥K»¤SoBBÌfsŸhjóÎ;ï`ãÆí~,Z´Hë1gμõÖ[X³f /^¬u8½Â«¯¾Š7bâĉm~ýÛßþ66n܈§Ÿ~ú²gúô騏q#,X0›Íxã7ðÆoÀlÕ¢ß1!䲩ºžb¨ zÿóxo!4WƒyœŠ19–÷6Ø ÃÊÈ(¯mwdU¢’–}÷Qª M94£RO"êÊÌ੃ÚÝŸè%*ã\x²äÊ+¯Œùx¯×‹3gΠ²²>Ÿ¯ã:°páB¼üòË0`ÀeŸ+ÞíØ±[·nÅÖ­[qî\ 5ÜþýûƒcåååšÆ7uêT,Y²~¿_}õuÆîb·ß~{›ã?þñ»åñ<ÊËËQ^^Ç€~Ç„®¡^öÆÌFE'pÿÔÍhÙ[Ï`êÙÇ•. …ê$ëOL‡lÎVŒ©ÿ/‘¾«nصØ %+õ‚ùêÁšÎ*Æ$ºa׫:Þ…h%++ ÄæÍ›1yòdŒ;‚ @–å¨Ï!Ë2–.]ÚQö^/¾øbðó‡~³gÏÆÛo¿ýû÷kUÈØ±câ#GŽÄ¸qã°wïÞàØäÉ“1tèÐny~ö³Ÿ!55øÃPVV†ßÿþ÷3Ä®¿þz¼òÊ+Ø»w/ÆŒƒo¼¹¹¹p»Ý8sæ V¬XùóçcÒ¤I€ßüæ7$ ÷ÜsOü$âÛºuëðå—_¢ººÅÅŨ®®ÆSO=… `„ °Ûíp¹\زe Þzë-x½Þàq›7oFKK ®¾újFlذo¿ývðÜ“'OÆüùó1pà@477ãÔ©SXºt)~øa\uÕU€çŸðŸÿùŸØ·oæÍ›‡™3g"33§OŸÆªU«°cÇŽKÆûÐCãñx<˜6mAÀúõë±eËÜwß}1b.\¸€?þñ8xð`þ„µá÷ûqûí·+•?þñÑÜÜ ‹Å¢ØW„îf³‹/Æ”)Sàv»ÑÐÐñ˜ëÖ­ƒ×ëÅ-·Ü‚'Ÿ|2âw\QQ¼¼<<ôÐCÁßÁý÷ßo¼<òöíÛ×å?BHïÀO8À‰J;ø¥FDb!ºŽ\ØÅeÈ;‹ÎÃÚÖ›¥›ÁìIŠ!~œêSꉺñ”è<PCξIâÀ)'Pš%Íò픨ÔÑU_ÿ™Ám9)ܘæ‹|OEô–~DZ‰'ÂívãèÑ£ÁdÉøñãûÜu×]˜>}:êêêPUU…!C†\ÖcÚív,Y²v»_|ñ¾ùæx½^477c÷îÝÁý¾ùæ|ðÁ—õX½Éõ×_ Àív£´´^¯“'OFUU¶nÝ ApË-·à¶ÛnSW\\Œ«®º gΜAZZæÏŸÉ“'²³³ñ›ßü999ذa¶mÛ†––466bÓ¦MÁsìܹ«V­ÂÙ³g±dÉ,\¸~¿»víBAA–.]ŠÑ£G_2Þðx¦NŠªª*¤§§cáÂ…xóÍ7a6›áp80xð`<öØc0zÿ=Ž?þcÇŽ þìFÑ£Gãý÷ߨ7šŸû/~ñ £¶¶ååå>|ø%¿­ßñW_}@ùw`„ ¨««£—„K⥪K¿TÀlÔ&3&µ@h8¥“­´ì­;1u·ïFpŽÞë!¥(†Zöݧ©gDó|;@åšuC¨+“ÃV0)­P»€H·êýÙÊÉÉÁ€°sçNH’„€sŽñãÇcõêÕàœ#;;ãÆCmm-–.] I’pë­·bÖ¬Y—õ¸¢(âøñãøûßÿI’‚_Û½{7vìØI“&aýúõ¨¨ ¥áÂg¹6I€ÜÜ\¬\¹'NÄÊ•+Ç-Z´>Ÿ·Ýv.\ˆ1cÆ`ûöíÈË˃Á`Àðæ›oÂïÕDúâ‹/0zôhÌ™3«V­BII 233qà 7àÔ©S¸ÿþûá÷ûQ\\Œ|sçΘ©ŽWÏwÞ‰Ûo¿Û¶mÓO> xýõ×1pà@ 0@óÝíoûŠ‹‹qÛm·áW¿ún½õVÔÔÔ`Ó¦MX¸pap¿h~îýû÷ÇÔ©Sqþüy<ðÀðûý¸ï¾ûpÓM7µûømý޳³³1oÞ<Œ?o¿ý6úõë‡~ýúaÆ 1•„ „ôA§\€O 5ØP;ø!šM¢¢³rj¨üˆ”^J5wV`W¨j½’ø&§ ¡æ„à<03™ô]¥5BXr"xV ݀Р.Ap‡d’¬E0ÔìÑ0(Ò]hFeœj]ö=qâDÜ{ï½X°`cHOOÖÈËÍÍ>|8˜PpòäÉ6÷///ÇÎ;1qâD,[¶ ¥¥¥˜:u*|>ÞyçËüŽú®åË—ã“O>Á¡C‡Úüz4?÷²²2øàX,Lš4 GŽÁOúÓàŒ>»ššlß¾íîÍÏýw¿û¶mÛ†ŒŒ äææâw¿ûŽÎ½ñi½–Ûü;A!íáeªÙ$´ìMWDWI`òE\L 4 !]'Õ–™¬ŠX.J⚺>¥è: j:Hø$«U+¤èyPW"êTªg‘^¡»*utÞ¶¾ÎÂÆ[ÿÚØßG;®u»õC¼ø¯áâç­ÿ¦]sÍ5Ûêëë£þfìv;8çàœÙèEBB^yå8üò—¿Ô:œËRVVƘâƒô~  D«Ê¤I“°téR|úé§xöÙg5‰áÂ… Qïët:ƒKÞIÏzö™ÿŠ?½†ÒÒK—`ŒaÖÌÙøìóOz(2¢V”67¬„ˆÄ!?» ðv~FÞõ×ãÓO?î‚èH4ZÆþrr¨Ñ¡±ò3O}¨aD7eòU8|ø ê¢]ÞÝØøþ`ß­6B‹òs›™Z~Ç“‘#F£¾¡••Ê/0îIKÁ ¡2U 'VÃpn{GHâUzñ8ÔOÌ Ôµ@~i«v‘˜p!îÉ¿„ÐâàÄ’7 :º¿ÄQJJ FƒýU·?V«´´4ìÞ½û*u$þ°募Ëa<ì£uaÛSoó°ÏÃuôØåO4£²—6lAhw¹0!D¦M›øê«ž{’$„ô¼Ì¡L¸ˆ dÕ. 3Á©¬µ§ž=F.ËW.ûƉJRꈜ2H‘¤8D'5Ò!!‰•ªURi&0{’6Á˜1Ù ¡^yžê5÷>”¨ìÅÌf3î¸ãx½Þ6»BôÇ`0`Ú´iðz½Ø½{·ÖáBôÆ+Ê1´ü[_"–½%õ7¦jM/#0`ˆ2qOõ)õE°šÎ‚yë4ІÄ#ƒÓƒ[¹Š€çÛÚٛģˆçAj¨ÓëP¢²óx<8þ<^zé¥`3Bˆ¾Mš4 ÉÉÉØ³g<ÖáBt("ñ¢žAFâšP_øÃk¬1z“ÖU¤¦°R%œêSêM ‘Nuû&8|Nù:b&5‰ku¢2ÑÙœ¥Q4¤;P×ï(H’Aät=5Ž(:²,ã¹çžÓ:Œ.A B¶mÛ†Ù³gkC,Ýë !ñ‡—:Àf·™Ýn5:‚“¸Ç ÃPw~û˜à˜d-‚x~‡†Qõ³‹Ï5^m‚!1ã†$EýV Ð!˜5Kµ®Á¡l°Ü(>z«¬é ˜Çž˜“Ò‹ ¸©{{oA3*£àóù‚[.Õù—tŸÖŸ;5Ð!D{>ŸOë!—£º>"ùB³IôEPÍ&‘Ò‹ztÙXòÿ?N³)õD²*ÿ0Ù ¡¡\»€HÜJ>ïQÖž5Š@^šv‘˜‰®£ŠmZYлP¢2 ^oàÅ¥¾ÈªÆR‚ó( û5ІÄ3Á+gêctÃN_Ôu*¥´B@0¶³7ÑJTFÁçó)f;wŽÞ¨÷ǃsçÎEŒS²’mø|¾àÍBˆŽ©ê6@¤—…zÁ¼.nåë#êþ}yXa†rVªÇTºÚ?€ÄÆ ¥W Q}Jr)꬀nØé‰è: p94 !¥Õ. Ò¥èi”šššÀc ~¿p8”°ì&‡ðûýÁŸ=!D[TþB_cHOKCfFÌf³Öá8ÂKW.{c´ìMWUí=u›ˆú”'k•KCI\““òÀʱ‚ji(!á"ee&i&m‚!±ó7Ch<­¢v½5Ó‰’$I¨««CZZàE¼ p¹\p:GÖ{1Æ ‚"II KB´SWW¿Ÿ–Pé‰ ˜2u Fމ]»vãÈ‘’Ž"}C³¼º,754–Ÿ”Óë½%ð÷»6¸-§ 7XÀüÍÚ¥WŒClŠ!~‚–}뉤ªO'¸ÏAh¡ß!¹„3õ€Û˜CË…Y¾|O•†A‘XˆÎÈ)ƒƒÛ2ݰë5(QŸÏ§Ó‰ääd 0ÆÀ9çt·µ«©““áÿBz–ÏçCcc#%)uH’$üßÿ}‚ÒÒ2­C!ñèD –¨dvðÏk‰…X_ H^@L 0rú0ˆ5{µ Lú¥I Š¡ˆÙV$®©g«gAæàe°Q9¡±|;@‰JÝGàøÝà¶lÉO´‚y覫ÞQ¢2Œ±àÌJ£ÑˆÄÄDF­ ïjê¤$%+ éY’$ÁçóÁãñPMJBz)^ê›VÏ)+HNˆèNâ”ìƒX_ªXê&¥Q¢²"jÓ]hêZ´ †ÄÎ`O¬)QI¢ÀK•‰J6Ô.0*û BÓi0_#¸198&Y‹`¨þ·†Q‘®@‰Êµ&ÊÔ vhVe×i/II!„.TY´øÓÅ—ƒ,Ðõ”ï;£m\$j‚«D™¨´ŽÀÐëÒX¨»ýÒ²o}‘Ò‡ƒ‡·^}ëi%é;áü¹l}»™hëŸ^A´ts®c2LJäô"€•ºGS;I]+±u›>.ÿ£½Ÿ1!„BºÌòZÅPDC×Ô³ÆxBdKN;{“¶0³1°ô; ?A˾õDJW6Ð\ÇÙ×ÎÞ„„ðFøùå`AFÛ;“¸$º”õ×¥ôá5ІtšQy™(‘F!l6l6JKK£šeÏÀ””„òòr´´(—fffbÈ!Ç577ãàÁƒ]7éÛx©¬(+40Ôh,B+EtApŸ‡Ðâ€l %˜eëÍg5ŒJgòí€özÞ'§i6•~°ˆF:êÄ!—Tê²Ã:Ƶ›´ ‡Ä&ðÿ=4-–‹&È)ƒ Ьj]£D%!„r²³³±lÙ2Œ3œs444àÑGÅ¿þõ¯6÷7¸ûî»q÷Ýw#)) Œ1¸ÝnüáÀÊ•+ƒû}÷»ßÅã?ŽÆÆFÅñÇŽí·ÞÚßéKJUK\-F 7%Ð •è‚Pw²éªà¶d-‚¡ªí¿?$RÄ,âr' ÉÚCbÆ“rÁÒcÕ§$18á®ÜdýRÁ- @3ÕkÖæ­‡ÐtrR¿à˜d-¢D¥ÎÑÒoB!¤“L&Þ{ï=ÔÕÕášk®Á¤I“ðá‡bùòåøÖ·¾Õæ1ãÇÇ”)SpÏ=÷`ìØ±˜ 5ÒÑõ²o¡öF‘Ý’"ë5c(ÕkÖõ ;9)ܘÒÎÞD(QI!„tÒœ9s°qãFEB‘sŽuëÖaÖ¬Y0QG–eÔÖÖ*ö§D%é1êåßýS$š‘§Lò@l(WŒ©“7¤m¬P5›ÒÑ ÔÒß]½™rв–³:aAH4¸êyfê5]êËÀ$Oh€1Héô ˆ\6JTB!”——‡ÒÒÒˆñ’’ˆ¢ˆììì¨Î“””„üü|ìß¿?8f6›‘‘‘Ù³gãÆoĸqã ŠÔÅt=~ª¶eo4›DOU÷oÉ:¢=I8V ºÎÕI{ך̓!¬å‚ì‡Pw\»€ˆnñª’– ‡fäé—"þïËô<¨kÔL‡B c6›±`Á‚v¿~æÌ|øá‡E™™™¨­­ØÇá¼ÙÍÎÎFeee‡yï½÷âìÙ³øøãqØívÜsÏ=HNNÆ Aƒpúôi<üðÊ„&!—MâàeÊî߬ |?uŽÖ ÑYß ï·¹)Ü”ÖBõÛe2Ò•cTŸRWšÍÊÙ”B}˜L PH'8ÝàŽf0»%8Ä ìàg©±œ^ˆÎ#l£ƒÛRúðÀ¬XÎ5ŒŠt%* !„0 ¸æškÚýú‘#Gðá‡B–eø|>$%%µy¨¯ïøîرcqçwâþûï‡ßïŽ?üðÃàa/®ú÷ï—^z Ë–-ÃìÙ³áv»;<·(Šøîw¿ƒúúÅøö®.¸ÍƒÁ`@Vft3@IïÓRíCcØjaV˜‰¬ì@îø¾A¤kG{~THÄäàˆ%oR\»5Œ©c‰‰&Øm0™Ì=þØž‚44¡¥Ì/ÃÞh£kY’,ÉhNÈWŒ¥û*J¿?Ò´Ôt$Y’"ž·šÎ¸áKT& ÏEZ •‚Ð ŸpUaÛܘ‚ôW ¡å\—=†ÅbAb‚)ê×<ç/tÝc÷5”¨$„BÂÔÕÕaþüùîÇ9Guu5rrr"¾–™™ 8{öÒ3Òúõë‡+Vàå—_Æ_|qþpUUUxê©§°víZŒ=;wîì0FƟϧ¯¨¨B‚*1`0‰)Ò'ùÝ"Žqº à‰"’‡€¥ÖwÉã@4èÚ‰ Ò98•’u²«.q„öM°ÚíHJéù%–g†§*¶“jüȶgµ³7‰7Rr.¼~åÂæ:˜èo¹´ää$&&F¨üÂQÂäkñb¡Ä}¼ä|ÇH:Ç?$èúÛ~Ö›ŽÚ.|}’’’‚Ä„zÍÓ¨™!„ÒI«V­Baa!n¸á†àXÿþý1gά\¹R16vìØà¶ÕjÅÛo¿Ý»wã‰'žhóÜm-)Ÿ;w.Ün78Ðuß!ñãÛ¬0S£HHgˆÎE-..$@NªaDñ‹õK’•7|"ši¸V—0P±-8¶³'!QòIÀi—bˆdh é ÑU¢Ø–S‡†ž/-B.ͨ$„B:içÎXµjžyæ\}õÕp8˜3göìÙƒ¿ÿýïÁýþüç?£  S§N…ßïÇÛo¿ÜÜ\üýïÇwÜ¡8çûï¿ÄÄDlݺ_ý5Ž;¯×‹ñãÇcÒ¤Ixä‘G¢ª}IH¬ø‰°iaÍ)²S€”D Á£]P$jÌß¡±rJ(#¥ApÓ0ª8¥N>Ô4ÎŽëþ’8a° É ¼‘¢NPÒ¼Ô6ÄÚj»ÄÞ$Þˆõ'ÙF‡)­¢ƒšPê %* !„ËðÛßþ»wïÆ´iÓ0`À,_¾kÖ¬$IÁ}þ÷ÿLJÓéDaa!êêêPWW‡Y³fEœïŸÿü'\.n¹å|ÿûßÇ!CÀÃðøã£¢‚–&’nRY´øÓÅ—‡ìb÷ïoâ»Î! ]%ŠD¥?½F¬×0¢øÄ •‰J~œfSê‰d-_(û B.׉àºÂà&K7ƒÛ-€ƒšêè‚ä…ØpRڰеˆ•:D‰JB!ä2mذ6lh÷ëï¼óNðócÇŽEÕ¬§¤¤%%4C„ô ™fUމg…”¨ÔÑU_Þìà6OÊOHóÒ,ì ¤ WÕ¼§Ô¡M,¤Süé#ÛbÝq@òj éMøùF°ú Õc…™àŽSFEb!:(•ª¿D¨F%!„B P'l†Ø‘i ‰«/üáK˜$ëH­Â‰K¬ `a×´W?U«]@$6ŒA¶)†ÄÚÃCz#~Bù<¨žMâ›à<¢Øæ‰Vð¤~EC:‹•„B!ÀÅ%°a Yh˳j‰ ƒÙL€•Jvåv™xÛû’¸#'å•3b'%*IR7ÖhDmb!1š«!x”7Ÿüô<¨;´ô;Ff³&“ ýèH×óûýhiiÛ}yÝé:%]©«®KBˆ4{³ @¿Ôà+Ì/§gzap†”ñ­à¶d- û5Œ*N ,ŸêSê™dS&ÚJJr9x™L’ñâœ.‘ µƒ—œ×605¡öäÜéÁmÉ:ÆÊÏ4ŒˆÄŠfTFIEX­V$''Sò‡tƒÁ€äädX­Vˆbìwîè:%Ýár¯KBˆ¾D$nÔ3ÐH\œG³b¹)e¨†Å‘i¡fQÀÝî‰~HéÊD¥H³)IWóJÀi—rŒ–늨Zþ-§ 7X4Іt%*£”ššJ‰Òc RSS;ÞQ…®SÒ:{]Bô…¿ ÈLÒLmïLâó5Bh:­“m£4Š&¾°ÂLåÀ¹ Á£M0$fܘ 99O1¦NHÒø1åó +̨\³nD4Øb¤ô¢ö q‡•Q0›Í”ü!=Î`0Àl6G½?]§¤'Äz]BtèlШì ‘à!qM¬=¤ØöS¢2@5;8")Oâšl©h„$r/„ú2 #"½•:Q‰ä ‡nÖë†ìƒX\9DσºB‰Ê(˜L4‹€h#–k®SÒSèZÓAPTT„ ®DNv¶Öá½à¼T¹–ºžê‹z9,7e€›ûx²9Õ–¥lÂUw_ßüÖŠm‹»à’6ÁÞÍéw4+†•AÑõ ;É:`”þÒ úMEf©­ÄríÑuJz ]kúb6%"ÉbÁH¿7ƒRUg°0RZ½«À¼uŠ1ÉÚ·g“°Â åÒÍ?xU]»û“8ÃÈéÃC÷I‚!}‚ª~-ÖÇoöèLà†]X½fƒrÊ í"1¡D%!„ÒKɲŒoöîÃ[¶¢²²Jëpˆž”:9ôFlU»xHŒxĬJ¿ud;ûöêÙP'j”×8‰kRÊU3 Ž$JT’n±ü»_j` 8Ñæq5UŒI}ýyPG(QI!„B¸Û^©ìzÊ hù·ž¨•rZ>`è£5†E6D]Ÿ’º}ë‰lS&,þZ¤&¢!}Âig x+ÆÀòéyPO ªçÁ¾¾²@O(QI!„B"©—SJ]œGÙ`"üi…Ú¤¥AV !¬tçàeTŸROüéÊú”i¾ÓíìIH‘Úø;A7ìt%â†]R?ðDZ¢”¨ì£ -Z„Õ«WcõêÕX´h‘¢îœÑhÄ}÷݇µk×bíÚµ¸÷Þ{a45Œ˜B!=‰SÍ8³šÁìIÚCbÆd/ÄúRŘÜGg“DÌ®ªš¼mïLâOHOÊUŒ¥û*4Іô)ª™×,߬I¼ÊÁüʦH’ª)‰O”¨ì£æÏŸyóæÁn·Ãn·cÞ¼y˜?~ðë .ÄM7Ý„¤¤$$%%áæ›oÆÂ… {$¶¬¬,deeõÈc‘®³qãFlܸ±ÓÛ}]Û„]9ßÔ·(Ǩ멮mu=E|“­š Ì_hgGõUC×-ó7Ãâ§ß!é~üø…ð~,€Éä¥k‰—!ºJCT§R(QÙGÍž=ðàƒ⡇RŒÀ¬Y³K–,Á’%K3gÎìð¼f³ ,Àk¯½†>øï¿ÿ>žyæŒ?°nÝ:¼ûî»—<þ7ÞÀo¼³9TGiΜ9xë­·°fÍ,^¼‰‰‰HJJc}ðÅvóꫯbãÆøÕ¯~ñµßÿþ÷ظq#¬ÖøœÂ~½·wmBHÜâWw=¥åߺ":•‰Jž 9y€FÑh¤­™À'hÙ·žÈ6å (Ñy Ô‰ô€F/xu½bH îߺ¢¾a'§Z)ï ïBz#Q Ôéijj &û!2oÍ‹:(žzê)Œ7.— ‡BVVÆŒƒ5kÖDuǃòòòàç0uêT,Y²øê«¯PYY‰Ÿÿüç¸öÚk±xñb”••EunÒ½fÏž3fs¿ÿýï±yófÅ×ÕûÇâÚk¯ÅG}„½{÷^v¬ZhëÚ&„¸wÂŒKlµÖú o0@â–ÐâsŸ7‡fóKÖ‘ûβYV¨L*ðFODâÄ1Á9m˜rÈy {&¤§¯rSCÛÀ§Ç´‹‡ÄDt¸ °@®ƒ Ró#fZ’øB‰Ê>jóæÍ¸ùæ›ñꫯ*ÆZ}þùç¸å–[ðÊ+¯(Æ.¥°°ãÆÃ¾}ûð裂óÀN“ɯ7º:@²,ãPŒ;ðâ‹/âÀ€1cÆDu>ÒsñðÃ#11ððÃc×®]hllì’ósÎqÿý÷cñâÅðûÍô4£¶­k›Bâ/s€I/þ½°¡vð’óÚF¢&:Þ¨´‚±â #êaªr서&ã醔š.&†¸ ÑYd Ñ.(Ò§ðã5`× d&éfÀåÖ.(5æo†ÐP95ô;”¬#)Qç(QÙG½ùæ›HLLDqq1à£>Â_þò—à×W®\ Qñƒü°víZ¼õÖ[—Ÿ[·nÔÔÔ`ÅŠÁÄc{Ž= ǃáÇãÍ7ßÄ]wÝ…AƒEì—’’‚«¯¾gΜAzz:,X€É“'·yÎM›6?ß¹s'V­Z…-[¶ǶmÛ†¿þõ¯1}ï¤{äääΞ=‹“'Oˆ¬¬,<øàƒ°Ùl°Ùlxøá‡‘œœ x饗ðYýdè IDAT /Duþ7Þxuuu˜?~0)®žQ¹dÉ,\¸~¿»víBAA–.]ŠÑ£G+ö»þúë±`Á¸Ýn”–†:¢cêÔ©¨ªªBzz:.\ˆ7ß|f³‡ƒÆc=ƒÁ¯×‹É“'£ªª [·n… ¸å–[pÛm·Eõý”––bÍš5X³f Ö® æÎ‹ýèGزe –-[†ºººà¾wÝu<,X€ `̘1ؾ}{Ä9¿øâ Œ=sæÌÁªU«PR˜¢}ÅWàÚk¯ÅÛo¿M5*ãDvvàý¹sçpæÌÀ Aƒàóù ¾üòKØl¶àL˪ª*Œ1.—+ªó744àõ×_ÇÏþsÜsÏ=xúé§_ÏÌÌÄ 7Ü€S§Náþûï‡ßïGqq1|ðAÌ;TìÿÐCEŒÀ¢E‹àóùpçwâöÛoǶmÛðä“O^ýu 8 @yy9,X<.77+W®Äĉ±råÊ¿ŸC‡áСÀ“æ¼yóÿøÇ?pðàA :“&Mž={‚m2™0}útôë×UUUQýÌ!¤+ðcÀ¾3<4”ôKªêÚ?ˆÄ.At…ß>68$ÙFÁp~Ç%ê"š^”;¿6Á˜É–\È&åÒ}±6òµ!Ýîx 0¶_p“ ±S½fݚ΀µÔ‚›B3ìeÛ(U´R-^Q¢’´«¦¦Ÿ~ú©bYvGöîÝ‹ûî»&LÀ¬Y³0mÚ4\{íµàœã¿þ뿵µµÁÙ›GŽ€à ;¢_­‰Êêêjœ>}0dȤ¥¥vïÞ‚‚Œ9„Åb?~<êÇØ¸q#¾óï`ÆŒøøã_2dAÀ®]»‚5,7oÞŒ|TìëñxÚLRÖÕÕg·&Åkkkƒ_/))ÁÀ‘š(¨=|øpÜ|óÍ5jRRRÀ ~-ZƒÆwÜŠŠŠ`ù…ÖxÇq!%%%¦ó“¾M|kÜX èߥee¨¬¤$7駸ШËu‘0,2%*uC¨=„%*åôáÞ‹ßd3^`GøÜ_ù•,ÐIµì›yœ`Mg4Іôe¼Ô&s@ÕkÆ` Zq@â—XW¿éªà¶ß:†ªi¹JT±w`¾Î9vî܉;wbܸqxæ™gpÅW´¹¯$õâÈ}Lk¢òüùó8vì|>FŽ ð{Þ¹s'ŒF#€ÀLK«Õ ¶D%ç/¿ü2–/_Ž%K–(fcšL&¡ŽöÎyDTõv[Úº6ÃÇrrrðÜsÏáܹsxþùçqúôé`Çóh‰¢ˆGy‚ à™gž &ðëëÝH¿ùæ¼üòËŠc¨F%‰çN— ç/\€»™Š¾“ÎãÇ/€…%*1,ØtB»€HL]OypÉ>MS‡B¨‹þ9Xwú§‚%'*ÇNвo=Q/û¦Ù”D3?øiØ`kpH– ™•º!Ö‚?;”¨äiCƒðÓëãxD5*û(£Ñˆûî»/¸}ï½÷“He00lذˆÇ§ÓyYçVk1G³ËâGøŒÊÆÆF<ûì³p8¨­­Åþðœ?^1Ó²¨¨@l‰J8yò$Ö®]‹¼¼Ÿï¼óN'¿«öÕÔ^¬Ã`0ö„Ϻ¬¯¯Gvv6.\ˆ÷Þ{Oqü!Cpûí·@°Ãwë÷ñ¯ý }ô¾ÿýïãü#6mÚ»Ýޤ¤¤ˆÚœ„Òx¥ ¬ÙXÂnjØ]•ÚEb":CN•B‘m£€òuFÔ͆)›]pu²Ä5Ù:`¡›½LöB¬/½Ä„t/~ìØu…¡TXV ø¹í‚"Ñ“}ëN@²†šÉù­#!ÖìÕ0(ÒšQÙGÍš5 @ Kò’%K3gμ¬sVVVbíÚµhhh@aa!rssQRR‚¥K—â“O>¹ì˜Ã­_¿Ÿþ9rrrP\\ÜfwqÒ³Nž<‰C‡¡¡¡ý'ëð™–‡Ï=÷œ¢ÉR´Ün7–/_1þôÓOãƒ>€ÅbÁ¤I“päÈüô§?Eee׿‘Þ·oV¯^ ¿ßë®»¥¥¥ŠŽôðÚk¯¡¶¶7ÜpC0ißêŠ+®€Á¸WôƒüóæÍüyópõÕW–/_Ž•+WB–eÌ;EEEp»ÝÔõ›¢ ™ƒ—ª=êF%$®‰ªnɲ9 ÜÔK;צ™À²U«nŽS¢ROüªú”‚³D1ŠWÓ¸TË„ {éßÐ^JtQlËé#‚%QH|é®ßJGçmëë,l¼õ_¡íð}„°ãZ·[?Ä‹ÿ.~ÞúoÚ5×\³­µ\423{ß ñwß}6› K–,c ¯¼ò n½õV­C#*.DWûDëë´µéKk½ÓX·‰¾D{]Ò—[Z‚tγÏüVüé5”–^ºüc ³fÎÆgŸwíM%Ò»°QÙ`?ðËŸÝŒë¯O?ý¸ýI|` î O'„š¾ËÖÂxvË%ê^S&_…Ç¢¾!ú×åÑ`òÀ¾WhöAþÀ̻ôqH7a"Ü“ŸMÁ¡„ãï(:Õ1õ u¨¬¬hë „´«ÿ<¤¥¥áðáØWu±ïMÊ nó ø_vvex¤É&;Z®üµbÌ´ÿE åQŸ’’‚Ñ£Æàß_Õ Ñµ--- »wï¾ @ €?ì_ùâçrØûhÝFØ6ÂÆÔÛ<ìóp=yvù“+ͨì£>ÿüsÀ+¯¼lÖÑ:F!„¢ÆO8)쵨Aj×. Î!ºJC²}´FÁt³áÊ›·üøJRꈔV HR®Ý#í@HO9®¼QϤE6í"qKhq@h>«“l½ôyPç¨FeµråJˆ¢¨˜ÝöÖ[oiÑ3õÌÈX· !„Ä9ü´lˆ-46,hÑ.$±öüY“‚ÛRj~ïëzjÁY•cTŸRWÔݾ…ÆS`^ªH´ÇOÖ‚µøÓÅ4 czÍ{Ïh‰šX{²%7¸-ÙFÁxêC #"m¡Deåóù°bÅ ¬X±BëP!„¢Ç.a‰J6,|¿†ñ˜ˆ®£€äÄ„À!YG@¼°GÛÀºË·†°Ec2?éÐ. 3õL_êöMâ†ÌÁË`#³CcÃ2)Q©#bí!ø\Ü–-¹à¦ °º¡Ohé7!„B‰ ?¦ªO›”€†dZR«’býqåjöšÞ1u“§SN Å¯M0$f²%r¢M1fpR¢’ÄÕó Ë·FQ£`H¬3´•u‘ÕÍ»ˆö(QI!„B¢ãtŽfÅÐ+%*õD=;Ío °^ò&›1ðeÝTùèy‚!!©Ìãk¢Ùj$~ðcªš·Flmÿ_8‡è<¬êm7ìzJTB!„è©f“8(Q©+bíA(tÌÓò5‹§KõOllq‚–}뉺±Eàz%$Ž´ø —bHž¥Q0¤3Ô7ìxz`°h i %*£à÷Ór¢X®=ºNIO¡k¾M>ªLT6$q°t³FÑX1o=„† ÅXo™M 3”Úæ¶w&q‡“!'TŒQ¢’Ä£ˆ2(Ã2¦M,$v¢«$P¯ù"þô" #"j”¨ŒBK µ³$ÚˆåÚ£ë”ôºÖôCE\{í üð‡7£°°@ëpHoQéÜ>ÅÏ··³3‰G¢S™ü‘ìWhISÕ§äÔí[WdëH€…Þž2Ù ±¾TÈi/Q•”HNë—¦M0$v²b²^³º‰Ñ%*£àv»iéq~¿n·;êýé:%=!Öë’hK–e””Å®]{pîÕi#]Dæàªå´‚º ‰kêYjr¢ ²%W£hºHš ,+E9¦žõD⚺>¥è,dzmKâÓ Ô4)ÇèyPWÔ7ìüé#zO½æ^€•Qª¯¯§$é1~¿õõõï¨B×)éN½.‰v8種®Æ©S§èwGºÖqUh°•ºžêˆÐt‚§V1¦® ¨7L½ôÒí¯ªÓ,#&BR-½hÙ7‰c\U…Q¢RWÄÚƒï¥õš{JTFI’$8N466R"ˆt¿ßÆÆF8NH’óñt’îp¹×%!¤÷á'j"ºž²¡6í"1ªåß6שTÕ§ŒèÌKâš”V.†5Bâ¢ëˆvÒõŒíìd€ê5ëó6@hRÕkÖù »ÞÄ uzãv»iÙ#‰{tBéV-~ðÓN°ÁaÉÉÂLà(-µÕ Ñyþ~×·åäAà ©`^ξ6ŠP\‹p‚êSê‰:A 4žó6h !ãUu`Í^À’cÃ2ÀwT\â(ODÇAE/¿u4ŒX«aD¤ͨ$„B!±S5* ,½¥¶§z!Öüa75ƒd©]@—åÛCØÛ™ƒ—:Ú?€ÄY]Ÿ²öF‘%™ÇÕσYC:àªSÉM½ ^s/A‰JB!„3~´®§¨ë©np ¢«D1¤ÛeoÃUµáN9*£rR?ȉʱ'%*IüS×©Ä +`¢E«zÁza½æÞ‚•„B!$vN7ø9åÒLVD³IôDÝý[Jˆ íì§V¨LTò’óíìLâ‘d£Ø<µ`Mg4ІèñRà—C"ËÏhÿw"žõ^¯¹— D%!„BéÕòm$®œ‡Ö$M0BJ+Ô. N`ƒ¬€ÅàmÌr"qM²]¡Øjöi !1òIà'•3ò@Ý¿uEÝX®µ^3Ñ%* !„BHç¨g®Ù,@f’6±ØùÝêËC’U_ËÞØpå,^~¶¨oÑ(+n²ANê§kh !±ãªî߬0¨^³^ˆõ¥mÔk¦Y•Z£D%!„Bé^]“W9¦N‘øfP5-‘l£õÕi˜r™eDíT×ü¶+„®7æo‚ØP®Y<„ÄìØ€‡m› `Ó5 ‡Ä¨ÍzÍ”¨Ô%* !„BHçp á|9Éhù·®ªÙkÂÛ¤§Q¢2 &“IëH˵G×)é)t­BÚ¢N±Â @¤øz!ÖüÍa#,~›ê Ë„°kË×F¢œÄ/&@²ŽT ‰ZöMtŽsàXbˆ•ú"8ö+¶yB:ääEÓ·Q¢2 4Kh%–k®SÒSèZ 1 xä‘GðÑGaûöíX¶lòòò.yÌí·ßŽãÇG|¬_¿þ²ÏMˆ–ø±ó7j­ `ƒmšÅCbÄ%œÊ¥·RF|.{cÃU³uO8ÉJ¢ RÊp£²#²ºóÃ]wÝY–±hÑ¢v³X,p¹\())Q|œ¢!±âIý ›”3bÅÚýíìMˆ•¨nØ µ…fX’¸'4V€y\Š1êþÝóèNHOÓŽŠ„ÄÀ`0à®»î»ヒիWcÑ¢EmÖ2Œv?Bâ]AAöîÝ1¾k×.$%%!##£Íã, š››‘––†ììl09ݬ³ç&DkÜÑÔ(— ³ÙEC:CTu=•¬EàB‚FѨ—Q†£nߺâW5h<µšÎh !]¿Hrh@ÍåˆNðÈçAJTö8JTÆçŸ6›²Ø¼Á`ÀÆ5ŠˆØÝyç˜;w.l6ìv;æÍ›‡;Óû¢ƒÁ€±cǶû‘ŸŸ PC2''Gdí½ ošsssÛ| ‹Å‚3f`×®]øòË/±ÿ~<ýôÓÁçË97!ñ€QÖ d#hÉ”žj<¬1`„d-Ò. 0l °„%M9(Q©3’}¬b›šè^Ç+eªš«´ü[W ªD¥œœž@“ËzMcŠyyyxöÙgñÈ# ¶6ðGÍï÷cöìÙ>§ÙlÆ~ô#\sÍ5ÈÉÉÛíFyy9Þ}÷]ìÙ³§«Bï”ÄÄD 477ƒ‡u]·nÜn7æÍ›§at¤³®».Ptøg?ûcxá…0oÞ¼vŸáû]ýõxóÍ7;|ŒY³faæÌ™:t(, Ξ=‹Í›7ãÝwßí’k“ôéééøÛßþÖî×·oߎùóçC„à‡š$Þàûýþ6Ïñꫯâ•W^Auu5’““qõÕWã¿ø†Šùóç@§ÏݓɄ¤¤$ŘÛí†,ËíAÈåá%çÁ¦ Ø,`Ù)àç´ ŠDÏß ±î¤ôáÁ!Ù>pÄÁòÜ‘Ê7ûül=¸ëÒ¥4Hüm“ú+Æ„šÈÕ„è/9¯˜EÉ 3À à§×^z Ôó7Z_?³@°Fú{ÕS(Q'òòòðßÿýßxôÑGár¹`0ðÑGu*Y)žzê)Œ7.— ‡BVVÆŒƒ5kÖtCô±ùùÏŽk¯½‹/FYY™Öá.ÖÖ2ÖŽöë()(Š"~ó›ß`Ê”)hnnFYYcÈÏÏÇàÁƒ/'\º6IMM ;ÜO’$œ?YY‘wÈ[—eŸ={¶ÍcKKKƒŸ·´´`ݺu¨¯¯ÇŸÿüg >‡îô¹ÕðàÏþÿˆñ7£¦F9c3993¿}}Tç%$\’%)âÚÙîÜæÐöàâ)rª‡#vJòá@ؤJdŽÅ·û_C×¾ÉNJJÆäÉ©Á›0—Âüû À6–ïIÅ@ú»¥'¤|”„ýªáÁuW€!?æs™MfH²„a…ñ1Û—èGBBDQDNv÷­Nñmà­owDŒ3 vjn¯{%'*¥Ðþ”ü˜bJ‚ÙdŽúõò¿6}Ú]áõz”¨Œ#ƒÆ3Ï<LVÎ;·Sç),,ĸqã°oß><úè£Á$Éd‚×ëíàhB:çÓO?żyóð /ÇV¯^¿üå/Šý-Z±ß§Ÿ^úøøCL™2Û·oÇ3Ï<ƒ††À¬Æ»ð» $zååå?~|Äø˜1càr¹‚3ä£qð``é[NN>ÜeçöûýøÇ?×ãܹsŠñ#GJÐÔª#È왳éé”ë¯/ޏv˜aØÔAÁíSæFœÜôïžtOH&Œ.ÞTôÈϾ)‡è:Ú¥3eòU8|ø êê;Ü— ´‚MŸ ;ñÑW8áhîÒ˜H÷isÚ–ªwaSiçJ]1õ u¨¬¬è¢èH_Ñ¿ÒÒÒpøp÷–r'ƒ¬Áíý¾3à›uëc’®#Ùªÿ_pÛ!Û°m×7ST€ý•†‘õ ”¨Œ#åååŠdåûï¿ï}ï{1-ñB3nL& |¾@'Ä–––à>ëÖ­ÃæÍ›áñx0mÚ4ÿ½;ª>ûÇÿþœ9“}_H!„ v%ˆâ†R\ª¶Ôª´\Ô^íWÛGñ§¶>­«^m­-VŸj}´Ô,hk[EEÅV"KØÂB62$CB¶I2gÎç÷ǘɜIB’93“÷뺼ì¹sÎÉô˜dîù|î[Q°aÃlÙ²÷Üs&Nœˆšš<÷ÜsžЊ¢àöÛoÇUW]…ÔÔT”••aíڵعs§ç¾½óßÿýßX°`àOú\.-Zä¹Þjµâ‡?ü!æÏŸ‹Å‚÷Þ{k×®õ|<""Ë—/Çœ9sýû÷ã…^ð¼ïøºZ[[1oÞ½N¥­‘ÏS‘a ÐcGbª}ŸIÙ =Y|«P)òR!èl/ ,õÅz{ç09¡ =~€þÕfh`8L'€<üðÃ:WVîÕ0iiiøõ¯ 6à׿þ5ÒÒÎ?=óÈ‘#hkkC^^V¯^»ï¾cÆŒérÞ¢E‹0gÎTVV"!!Ë–-ÃêÕ« »ÝŽììlüìg?óLd¾÷Þ{±lÙ2hš†ÂÂBäææâÉ'ŸÄäÉÓûz;gëÖ­žs·mÛ†×^{ÍSll,æÍ›‡ªª*$$$`éÒ¥˜={¶çã?ÿùÏqÓM7áĉؾ};fÍš…•+W¶/Z´sçÎEUUâããq×]wîá/}-ò„J1HÓ4CŸÉ¿üå/Ð4 ³gÏÆºuë°nÝ:Ìš5«Çóz’‘‘ˆˆ;v çÎëñ¼ }6Î÷löåÞ×^{-–.] ‡ÃaØÚh†Ûs9”Þÿ}ìß¿þóŸqóÍ7ã²Ë.Ë/¾UU ß»W_}Ÿ}öbbb×_wß}7.¿ür\z饸çž{ðÄ mô. IDATOà•W^Auuu¿îM°*Ï ­†˜ÄéßÁÄâÓ“Ò•4ųÂÒTcÌgh6-eÜÿGº ­¢þ¸y  1yøŒ»gE‡H+D² Ý KÝaC¨5n¢IÉ ?\Q@êëë=ÿÛ»ïÞ<€3ffΜ‰+Và§?ýi÷©­­Å£>Šüà7n–,Y‚o|ãزe þøÇ?Š=Ë—/‡ÓéÄw¿û]ÜyçØ¶mV®\ xå•W••…ÌÌL477cñâÅ8uê~ô£AÓ4,Z´+V¬À’%KpàÀ¤¦¦özÎÖ­[±yóf,X°kÖ¬é¶àÝwß¶¶6Ïʯ©S§bÇŽÈÉÉAAAvïÞíÉ1""óçÏGFF*++»|]wÜq–-[湇¿uzZÁ6ŠA÷ÝwŸg•ïý÷ß;ï¼³_×gddÀy‹”ƒñlôôlöçÞ<ð€gr ãs984MÃÒ¥KñÈ#à¾ûîCDDvìØ%K–x¦s@uu5ÒÒÒàt:!„ÀÆqã7â‡?ü!„())Á/~ñ ¼ýöÛý¾7QÀ’€,®(è\A%&Œ€ÜzÒĤ¨?T{œÙ7yŽeX,ôرPü¿B[dÄC$DƒÅ,T½›i߃Ýó”( 4´BV7@ŒŒó„Ä„4ÈÒ:“¢þPìE€×Ï®öØ\¸ôÃ繂 •&KLLìõœ)S¦pXV¯^í9>Ÿ½{÷âž{îÁ%—\‚«¯¾—]v,X)%~õ«_p~:¶…€¡ïYqq1²²²‡#F@QzV¿mÞ¼+V¬@VV`ìØ±½žÓ›³gÏz¶G>ìþ!ž{Ìœ9›6ûÙÄÆv6¼ñþº:îß§Ï?Ö®]‹ööv|ï{ßëg1¨wv»{àÇÈ‘=7¼Êg£¯÷nkk Š"e>—ƒÃápà±Ç;ï9?ùÉO ÇkÖ¬éS;оܛ( Û¯B%FÆ ‘§4ÑZ Ñ\á‰iISfB¡|†‹Ù[ Ï4ù?WìXCÌÂiß4׸÷u˜ |Xl\iIK­;„vé„ … »º!LÔ‰…J%%%y¶xŸ:Õ9 ³£We‡Ž­×Ü}ûBJ‰]»va×®]˜>}:ž~ú鋜ÝM[ôŽEDDp÷ ìÖ¥G`oçô‡oN îFë{öìÁóÏ?oø˜ï ˆžîa–7Þxø w‘òá‡ö¬HÌÌtÿ‡Ð± ¬/TUÅE]dˆu7ëê¶Ô¼¬¬ 0{öl„…¹_px¶-öõž¯Í{5Z_sÐu¹¹¹¨¯¯GEE…çŸþ|ÌòÆox A¡X RUwß}·çxùòåPU»víÂwÜ;ï¼»víêñ¼ž´µµaÆ P<òˆg+x‹Å2hÏFwÏf°?w½ õç’ˆL¤KÈ#Æí¹b"ûTßa'2" zÌèÎ"i1@R”1Ã,TÍgÛ·ZwÐ9‚†Úf Æ¸ú›ýšƒ‹Åç÷ ]Œì°CC†+*MÔÞÞŽƒâ¿ø…gÕÖÃ?ŒúúzaæÌ™ž¡#û÷ïïó}/¹äüò—¿„ÝnGEE¢¢¢0nœûœ 6 (×ÒÒRìÚµ ³fÍÂÿøGœ8qsæÌÓéĺuëú|OÑò‡?ü!¾øâ ¬_¿ííí½æP[[‹7â†nÀsÏ=‡O>ùÉÉÉˆŽŽÆSO=5 ¯ËßB¹ôÝï~K–,ñwLõöœÓŸó¼½ú꫘.¼âÿVº9ö>Gñº®ã¸ãËWÿV¿úßÿŽ¿üòË·y{“š8PàþûïGuu5xà³Ó!ÉÉÉž/C¡¯~Í~Nׯ_äädOñqÕªUç=ßû¼ÚÚZÜqÇCžãp(Ï%àn9Ñ×Þº4¸~ûô¯ð§—^Ɖç~!„ÀÕW-Ä¿ÿ3ð7³høºöÚEøè£÷{ü¸¸9bZgÛYZ¹¦Ð©Ñ ÑpLØ‹Ø÷{(ƒ°ªòÒÙsqèÐ44öðwyr”{çBúŸw•ìï,Ú&ý®Ä‰žcKí„ù¿ ¾ï¤‰“ÑÐxå|/^Føøx:ä¿!˜Êÿ› ¤F{Žå§ 7±Ok°ÐÒç¡}Ü7=ÇÂÕ†È?ô¡o/¿ür.€s\4¯ë_ýoÝëéõOÇ1¼Žáó=–èþ­ÀÞÞô·¹õ;@©ªŠ7báÂ…†øÎ;YС€ôÑGáöÛo7(ׯ_¿üå/†ó–/_Þå¼>úÈoy‘ŸŸ¼ •bLÙÔfbRÔWîíßg Gv®lôÛöoß^nm@‹”AC„+ÁØ7ŸÛ%i8roÿÎñsûwp±œ-rn„{´„Ã;–CÁ†·~(MÓº)‰Ùš5kðúë¯Ãn·£¶¶ëׯï¶÷a_Ï#"¢Ð OØvWg@È‹RÌKˆúÍbßk8ÖS¦ÃÛ¿ŸáKò0·}-1–΀î„Rwȼ„ˆÌâ;,.Èàöï`!Ú¡œ3nÿ’Á†WTÑ Ð4 «W¯>ïPœþœGDNUU|ûöoÁápà“ÍŸb÷î=f§DѦC­˜Ü9ELN‡Ü]ibRÔjí^83;ß@×ÃÝÓ¿cûwODrkˆÉÃgz8›‘+e†áØRÂÅ•Ô4üÈ3MµÍ@Jçöo1) ’m,‚Fxé[hŸø=èተT}¥á¤Ù)…4*‰ˆˆB”¦iXÿú½ö¨$r‡l€w¡2+‘Û¿ƒHwÛ¿])Ó‡´P)'¥Ölʦ6 ¼~È> 25®„§ä/|Öˆh äjñÄG˜” õWÇöoo®äéCó¹¦f ­ìå,¤ ÝwÚw-{$ùöÙ“Óý1—Œ(è°PÙ­­­f§@ÃTž=>§ä/|Öˆh@NØÛ¿ &r5I0Qjý³ý[L4¶m€ä¶ï`¡%Oƒô~™éj‡rö y ŠC]§ Nÿ&ê‚…Ê>p8\AD~§i޾o‘ásJþÐßç’ˆÈC—@±Ïj’|*ƒ‰jïfûwÌ oÿN5LÆÐõÅ=4WªÏ´ïºƒz»IÙikì-†·uÅBe544°D~£iú}ŸSJ}.‰ˆ:ȃÆíßȈçöï ¢4WAønÿNÜíß"ßgˆN½²ŠÛ¾ƒ… ‹ƒ7γpÛ7Q'Ÿ7^äÄÜþM䃅Ê>r¹\¨««CSS A4d4MCSSêêêàr¹ú}=ŸS ú\u'Ï-Î΀è¦0EÍâ³ý[K™A{•-º®.roûœÛÓÐs%ODçKLájƒZwØÄŒˆ‹ìfú·hR6DI5;`ãp8¸í‘ jjjz?ÉÏøœR >—DDÐ%äaÄÅ™žÈOƒÜVj^NÔ/jÍ—ÐF/ôËðD¸âÆÂÒPrá7$FB¾C˜(°¹ ×,ö"@wöp6Ñð#m5M@jLg0? («3/)¢Ã•DDDDä?¾ýGÆA$G™“ õ›â°A4Wb®Ô‹åÞb²qu­´7¶ÆA¹7 =–=v¬!ÆmßD]é>oÀˆü4@áþo¢,T‘ßÈÒ: Ég°Æ$nÿ&jínñ+e: ,vS`‚qÚ7rˆN0q?^ÅÍKýó" Tª--¢Â r’MK‡(аPIDDDDþ#ÝÛ¿ &èþ\ HîBeç«l©FÕwA÷£!|¶}³PT´Ô™†cÕ^Hö¶&ê¢ÎœöP™ÏéßDX¨$"" Qªªâ–¯ß„þàû˜:uŠÙéyøNÿi±@J´IÙP‰Ö³PJ 1—OoÂ~ó-V×4¹ÿ¡  ‡'AmˆY|VÞQ'¹ÿ´áXLX/pe:Qˆ`¡’ˆˆ(Diš†½µzéeí7;¢Nåç€Æ6CHLiR24ªÝØ{Е<P¬»™" |¶ÿsˆNpqùLZ3”úcæ%Dàä! {íÿW!rSÌKˆ(€°PIDDDDþ%e×U•“Ó½ëà,µ{  {Ž¥%®¤É»Yv"fŒ:sÙ‘¿i>•,ö}†çƒˆ|4¶Až2NúSد™`¡’ˆˆˆˆL ÷û¬˜KŒFÅ›“ õ›hoì²bNK™ÙÃÙ½ÜËg5­¬jpOü¦  £3 £3 1Ë™/Mʆ(ˆø¼a‡Ü B5'¢ÂB%ùßé†.=¹ý;¸XjŒÅ(WÒ$H5ª_÷‘çÓŸÒ§w6-õñh«ƒ¥±Ä¤lˆ‚‡V«ªªB¾Ø£ '¥„¦ip:½ŸLDÔb5° ·³7eT0.8Vkj^Ô7ÂÕ µî´äiž˜+õb¨¶}¾‡6Ñ8]ë²Z–O_Rnû*¾Ct”æJˆæ*“²! >òH Ðîê (bRšy ¾â죸¸8(ÉoTUE\\ßþÈ÷Î% !ÂÃÃÍNƒˆBoa*/ëÿ›udµî„«µ3 ´äé}ºÖžn,^·8]Åœö4«a5-ðÕ¶o"ê;§Ë]¬ô–Ïíß4¼±PÙ‘‘‘,R’ß©ªŠÈÈÈ>ŸÏU”ä«+‰ˆ‹4y´ë0äs˜@ЪÏP-u z~©!|VÍÊ>-( 9“§Š×êºêÙýæ%Dää>ã*‘ ŒN4)"s±PIDD¢TUÅ¢ëbé]w`âÄ f§CÔ3§ ò°q5 ·½Ë™†cWüønÏ£âdcÿ5ßmØtŸ>¤–³ÍaR6D! ºÒÖh‰iü=Hà •DDD!JÓ4üë­ øÓK/£¨ˆ+](°É"ŸBÕÈ8ˆ´Xs’¡~SZª¡4•b®ÝŸìûâûl PÉÞ†ÁBF¤À7Öã¶o¢AàÛeR`µ˜” ‘yX¨ 1Ï>û,6mÚ„M›6aÕªUf§CDDDÔ7¥uÀ¹VcŒ«I‚Šo±JKšiñé5jùÆA;r_À]ßACQïæyÂÙKÝaó" rÿic Œp"/Õ¼„ˆLÂ)1ALUU,[¶ ×\s ’’’º|}ºáœÔÔTLš4 RJ|ñÅ}¾·¢(¸òÊ+1oÞ<Œ1¨««Cll,û6eoΜ9øÖ·¾…„„„~}]DDÔ³-åÆ7œ„Oa‹›åÌ.ñ?zøW…­ØpˆœdÃÇ­ký• WÚlñÒ\¥¹Ò¤lˆBБ Õk¤" ¦° /\QÄ’“Ýè:tpðàAäççÎéXÖqNÇ5çsÛm·áÒK/ÅŽ;ðôÓO£±Ñ=}Lððð^®Zº®ãÇ?þ±©9åää ´´[·nH)‘““ƒÝ»wp¯hœ7o„8pàjkûþ‚gâĉÈÌÌDEE¶mÛæ)~ !`±°q5‘)ö²¼Þ,Ÿ DY§y9QŸ©g©5CªÑ_E\©—@©Øäžä®tö6´h–ãgÍI”úMZ" y­–‹«)‰•ÓY|bº×›tSGÛO™—‘Ÿ±PBV¬XqÁ÷°X,¸ë®»ÐÒÒ‚gžyÆS¤Ü¢ÖVw“{EQpûí·ãª«®Bjj*ÊÊʰvíZìÜÙùÇÊÛo¿Í›7£­­ —]vEÁ† °eËÜsÏ=˜8q"jjjðÜs϶ØFDDà±ÇÃÅ_ŒÚÚZüãÿÀÆ ÷mooÇ7¿ùMÃçimmżyó`µZñÞ{ïaÍš5†{._¾sæÌAtt4öïß^x6›í‚¿gä_RJÑù"GÓ4¼õÖ[ý¾¢(˜:u*œN§¡HÙñ94MCdd$¾ño ¶¶ï¿ÿ>à’K.Áĉ±yófdgg{Vßpà Râµ×^»°/ˆh˜“‡l×çuN:µ¸W“Èe翃tÁR»Zúež–VkÅG]VÇ&Ukphºï(@¹Rg–°Î€t¹ûSÑ ’ûª …J‘ ŒŒƒ<Ý`bVDþÃB%ddd ""ûöíùsçz<ïÞ{ïÅ7Þˆ’’bîܹxòÉ'ñÀŠŽ‹-‚ÍfCee%¦L™‚eË–aÙ²e8xð ìv;²³³ñ³Ÿý K—.õ ù‰GFF 1gÎÜÿý8{öìy·ôv|žªª*L:wÝuŽ9‚;v~þóŸã’K.Á_|ææf\yå•X¹r%î¹çö p%%%†•Â…Ážú˜z«©©Á|ÐíÇbcc¡ª*l6Û€Û”••yò)//ÇÙ³\BDtÁÚ4÷j¯­nbZ •ADµí4*eD ôÜ©PR¢ ç¥T¹PîïähÀ´Ôñzö „ÖlR6D!¬¬¨w ‘±™£€÷X¨¤á=*É #ÃýÎÍùŠ”©©©X¼x1N:…ýèGxâ‰'ðÜsÏ@·Ã}–/_އzëׯlÛ¶ +V¬ÀÝwß²²2$''#33Ópͽ÷Þ‹'žxÏ>û,ছnê5÷åË—ãá‡ö¬¤œ:u*÷Öá‚‚ìÝ»+W®Äoû[lß¾ãÆó|½¸öîÝ‹ƒ"--­ß=RÏW„ŽÏ*á8uêJKKûöíCQQÑ€ïEDDäÞ*c =H‹1'ê7¥© J‹qJ­kô<ñ´· ¶ž“¢ƒ…Œ=.Û³œÙaN2D¡Nvý=(òÓ;w…8®¨$»Ý9²ç†½cÇŽ…¢((,,ô¬‚ܼy3V¬X¬¬,ùç΃Óéî)U\\ †UgÅÅÅÈÊÊB\\œ'f³Ùàr¹ÿpݲe |ðAŒ=ú¼y{žÃ‡p¯ÌàÉiæÌ™Ø´i“Ẏb.]×±{÷nOOÊÈËËC]]6nÜØe xoZZZð " H¥g»¬&Ó2 751)êÕöÚÇ~ÝsìÔræ,…°~Õk´¨ ,´:[ïˆöFXêŠÍKˆ(ÄɽU—çtöõP!&¥Aî«:ÿ…D!€…J2(//‡®ë7nÆŒƒS§º6툈ð‘°°0CËît{‹yëÞÓQí ß{64¸—ÈïÙ³Ï?ÿ¼ácìQœÒÓÓ‘——]×ñùçŸ÷»H ¸Ÿ )%‘€úúúÏõî‰IDD~ ¹¿bþXOHL ùŸc€‹-[‚åÌN`Ì €òÕË ]fkf) %ä¾ÓÀD*ƒ‚ÐR/1„,5»É±DC¦¡²Ä‘›â ‰,TÒ°À­ßdÐÖÖ† 6@Q<òÈ#]¶F[,”•¹{DÍž=aaî†ÚB ¤¤ä‚sHKKó(/¾øbè¶`ÚWeeeÐu¹¹¹¨¯¯GEE…矎U˜<¬V+æÎ À½µ»c…oiš†£GBË.»¬ËÊJEQ<ÏG||¼§0Ÿ`8¯£HÚñÌ!â㑚’‚ÈÈÈÞ/ r_à]“Œ ƒ˜0´|¨„ÖËÙý†˜³ê«V?'Ï o½Bþ¥'N„ 7þý£žÙeR6DÇÜ]i ŒN„HŽîþd¢Â•ÔÅ«¯¾ŠÉ“'#77/¿ü2JJJÐÐЀœœìܹ«V­Â®]»0kÖ,üñĉ'0gÎ8N¬[·nPrxñÅqôèQ\z饀7ß|sÀ÷ª­­ÅÆqà 7à¹çžÃ'Ÿ|‚äädDGGã©§ž”|ɦOŸŽèèhOoÈŽA;¾[ÃûbÏž=1bqÓM7¡®®mmmHLLDee%¶oߎ³gÏ")) ‹-B[[ÒÓÓ ÷¨««àž^QQýû÷÷ºR˜È_EÁôÓ‘=6EEûqìØq³S"껳-§ÎBd'uÆfŒr7D°Pm_À•2Ãs¬7ÆÃÕeïþó\EÆ™6Çp¬4–Ai9mR6DÃÈÑ ¹ˆv/‚0=øÏ1SÓ"j\QI]´´´àÇ?þ1V¯^£GbôèÑÈË˃Ífóô™|ê©§ðÎ;ï ** 8|ø0î»ï>TTT\ðç÷ÝwQUU…Ù³g£ºº¤N¦m IDAT+W®4Lˆ^x¯¾ú*t]Ç’%K0aÂ8né B9998yò$¶nÝŠ­[·âäÉ“7nÜ€îåt:±qãFìÙ³v»qqqHIIASSjkkŸþ9ìv;bcc!„è2}þÈ‘#8yò$bbb››ÛeÅ%‘™\.6oþÿøÇ¿X¤¤ ä»šDŒM†HŽ2)ê/˹£¢ÑÓÊGA>cRFÔ_ÒWâ$CL=³Ý¤lˆ†]vÙê-¦etö­$ Q\QÄìv;’““1iÒ$:tè¼çv¬:ë(¾ôÆåráõ×_Ç믿ÞíÇ[ZZðüóÏwéùèíæ›o6báÂ…†ØªU«°jÕª¯éË}}‹ŠŠº|MÓ°nݺA[ñIæq¹\†³â¼Ó½{£ë:8Ðc1¼¾¾7n4ÄŽë|Óårá³Ï>ðç'"¢ó8lZò€(ïÕ$£¸š$X(€uT%Ú+&xBÎÓ°BÐn^^ÔgZú@tö¥z;,5ýßÅBD#÷TBÌÉîœe1>òßð¡ÐÅBeûè£pûí·ãÙgŸí×5DÁ¬¤¤ÄSx€ììì ^qKDDÊåº"æŒñ„Ä´ ÈOŽ:‡ê:1! Ö1•h¯ÌdÇ«ìp¸’§Á‡Oh#fB–3…®6“"†ì-õ£;wm‰,TRHãÖï ¶fͼþúë°Ûí½ž[[[‹õë×cíÚµ~ÈŒhèìÝ»DZZÒÒÒpàÀìÛ·Ïì´ˆˆhˆÈÝÆ¡:1ayªfd@D´BM2îèÑÒ.5)!ê=q"dD’!¦Ú¶™” ÑðÕe¨Nn ËAžº¸¢2ˆiš†Õ«WcõêÕf§Bä7º®c÷îÝžC4T’’’PPP€ääd|ùå—ž~¾Ý™?>¦OŸÞãÇ_ýuÔÔÔ`òäɸòÊ+»|¼¦¦¦Ç¶D!ÉÞ”Õc=!qq&äaÕ hIQc“jF94{ªçC®¸è‘,6º.CtšÊ 4]x?z"ê§C6àú< ü«ò" fŒ‚ÜRbn^DC„…J""¢ 0wî\¼ð ¨­­EKK V®\‰ÿýßÿÅoûÛnÏÏÈÈÀ”)SºÄçÌ™UUñ׿þpñÅãûßÿ~—¨±±±ƒÿE8ýË (^…JŒM#:‡yIÑy‰™£<=ÕÔ„µ ÒÙ±HÀ5ò2Õf¥G½añГò 1ÕÆ!:D¦pº TC\œé ‰‹3!?;É6(’X¨$"" ÔÔT¼üòËxùå—=ý‚/^ŒU«V¡¸¸ï¼óN—kÞxã ¼ñÆ]âëÖ­Cee%Ξ= ˆŽŽFYYî¹çž¡ý"ˆ‚Áá3@K»×P1}”»W%‹pO¦í èPqNÌô„œ©³àÂû&$G}¡¥] éÕ%ŒCtˆÌ% Ë …JĆy©îßD!†=*‰ˆˆè®»î‚ÝnÇþðOì½÷ÞçŸ~ŠeË–õù>&LÀ¬Y³ }„###áppµÀ¥C6ÆfdŠèþ|2•˜0ˆ3ÄÔ#ÿ¤îˆDµ’åç̨O8D‡(ðØš Ëë !Cá’(„°PÙš¦™ Sýyö¤ä²ò>k,X€>ú¨Ë÷äƒ>ÀÔ©SÙ§û|ç;ßAQQŠŠŠ<±¨¨(´´´ j¾DÁÌw˜€ˆ wÄ(ðÌe8”¥u§+a©?lˆWŠ\fE}Ä!:DªÐØ#VŒM’£LJ†hè°PÙ­­­f§@ÃTž=ÔÉ_ø¬uÊÈÈ@EE×Áeee€‘#GözøøxÜxãX³f!…üü|<úè£xê©§ðƒü™™|眆±Úf Ìg5IÁh“’¡¥D{†èt»Ý?'ÕÓŸâM"Îh®ª 4íi—Ž9D‡(0ÈC6w”—ð÷ …ö¨ì‡Ãˆˆ¨*¿]ä?š¦õkÛ§Ó鄪ª‚ÛàhèH)át:ÍNcHÅÇÇã÷¿ÿ}?räž~úi¨ªŠ„„466v9§®®€{xIÉù'2.Y²ÍÍÍØ¸q£!^^^Ž-[¶ ­­ V«·Ývî¿ÿ~<úè£xóÍ7ð•?¹«"+¡3•‘ iëúß!™CÌí¢hn÷ôP³Ô†Òj‡ÑYÈlI*€¨>àç,©'2"zâDCL­æ¢€àÒ!÷TAÌËö„Ä´‘œ.óò"d¬¼õQCCâââX¬$¿Ð4 ý¾®­­ ááá,VÒR¢­-ôûSµ··cïÞ½=~¼²Ò½ýTÓ4455!!!¡Ë9qqq€3gÎßà\QÜyçxã7º€_xá….ç>ùä“X¹r%>þøcÏÐó±X,¸å–¯£¹©Ùÿì³m¨«ë\™&„€ÕjEæ(¾+OýgUýøì4ØZ4¸¢:ÿ‹¹bâ?çôè@ ­ lÓFÁ«%b5"6½s+xã j".÷·&NÆØ¬<¨.¶º5IWÂáõw¤¢·"+¬J€ý~ˆ‹ƒÕªìFCý”””Œ¨¨¨ ý›G«ÐP#ÙñŸi„Ió'!êHýy¯£ ‰ÈˆÈ>?;•åCœQèbÕ­\.êêêÉÕ•4d4MCkkë€h躇ëÕÊÕ•4h¤”Ð4-äWRvp8xþùçûtîéÓ§‘•ÕuÛbFF¤”¨®>ñäꫯFzz:Ö­[×ëçÒu/½ô¾ùÍobÊ”)øôÓO{½F©)p&ÄâñññhowÎSÑÑѽޓȗ¢¿>; %ͰOî|¦ãã‘~¨J»~ž«Èêób¡‡yu–Ò%RÊÚ¡z=®°Ë¹Ð…ûoi ޤ™HoÙãïtɇ.T4Äæb©­Åˆ nNR= ƒ.uþÞ¢~‹ˆˆ@XXXð>;h>ÝŠæŒOÈ19©Ããït3…‡‡CUÕà}v‚«mýäp88…•žÓé6E%"3mß¾_ûÚ×ðøãÃåêÜrsÍ5×à‹/¾@{{ûy®–.]Š?ü6›­OŸÏjµêëûö®¹¦ixé_Á‰çß~.„@ffŽ-îÓ}‰¼eë×gGT…CLœXÜoÆéã±ÍÛOù-ꆔkçB²ø Nìíº­[ŒÏFxޫՋpîØÆ©àäwZú<¸R¼ ’RâÜ¡ hlë}¿¿Y,*Ï¡¢‚+–¨Føøø þ›GÈZˆoÏð·%Xq¤å4PqÎĬB_ll,¢£c‚úÙ ¦CDD4@kÖ¬ARRzè!OlÞ¼y¸îºëðꫯzbW_}5î¾ûnõ¹¹¹˜3gÖ®]Ûí½çÎkX½‡zååå8|øp·× ²© 8l,î‹KFÜE`*‘Óuú¬ÜÕ}Ézú3ãyá‰p%N²Ü¨/´‘ó KÝA(X¤$îäq;Pg\<%fq0…®¨$"" S§NaÅŠxæ™gpíµ×Ân·cêÔ©Xµj>þøcÏy?ü0rrrðÖ[o¡¶¶ðï|ÅÅÅ(,,ìrß„„üîw¿CXXNž<‰ööväååÁn·ãž{îéu¥&Q¨“»Ê!&§w#ÜdàX­yI s¢Àø"YÚSuÝžëž"]=¦óçÈËa9Ë¡:fÑãs¡G¥bêé­&eCDç%%ä—׌÷„Ĥ4ÈC¿Ÿ<…>*‰ˆˆ.ÀƱwï^ ""?ýéO»Lú~øá‡1jÔ(O‘ÊÊÊðî»ïv{ÏúúzÌŸ?sæÌÁرc!„À‹/¾ˆmÛ¶¶˜ W²¼¢ºHõÄDA$ •æè({+¬8ï%ÖÓŸ¡müžc=á"èÑPš«†"Cê…Óg5¥â8KýQ“²!¢ÞÈÝWäV‹;`³F»'€9*‰ˆˆ.PUUÞzë­?¾oß>ìÛ·Ï{å•WÎ{OMÓ°uëVlÝÊ-DÝ‘;Ë nêü!r’!Sc€š&³žDA–aë½t8!‹NŸ÷Kín„¿mèáÌX€ðc½£Á¥‡'Á•4Ùs¯¦äHm¢€ÕªAî; qI¦'$.΄ÜzpòMm nìQIDDDDAG´-^m æŒ1/¡á* 1c”1¶·ª÷ʺ†Qºqå+e&¤5n¤Þ¸F-DçËBáj…åÌNó"¢>‘;NÒë …H+0u¤y  *‰ˆˆˆ(ø8]>Û‹Å”t &̤„†'qñ( ÌÒÐ%äβ>]›!O@H­3 ¨Ð2.ä é¼Ô(hi—B–êm.ö¹# xöà¸Ý—fq¸=*‰ˆˆˆ((É]寕{ 'Ÿúâî‰fpÈœkíÓåa² ‘gm1´ôË ‹ÍþâLŸ ©t~¿tX9D‡(hÈÆ7†Dr4„oÏ`¢ ÃB%§ævÈýÕÆØ¬ÑÃhH‰)#¸CLÿâT¿îeÿÞ½¥-õ’ÁHz#,ÐFW°Zjö@´u?­ˆ,±6cofq)Û Ppc¡’ˆˆˆˆ‚–»G—W B…˜Æ]þàûbX–ÖU ýº‡ÚZ K]±!¦e\€[‡š+õbȰCL­úĤlˆh ô>oe'A¤Åš“ Ñ `¡’ˆˆˆˆ‚WM3äñZcl6{t ¹±I@ZŒ!$û¹š²ƒZµÙp¬G¦Á•”ßí¹4XÚ3"ʹcPš*º?ˆ×þj Ég¸Ü¼lÓÒ!ºP,T…(EQ0cú4\qù|dfŽêý¢`åS ÉÑy©&%3…±Ù+•V'ð¥±uƒ˜žnRBDÇB%¿C6H{‹!¤ÌkR2!,%bÂCH~q Ðô º­€µòcCÌ•=fôÝ—ºjÏ\h8íõPkv™”  }{©ñg±ª¸{6*‰ˆˆˆ(øéØ^jŒI„ÈJ4#›å^M鵜²Uƒürp°¨gv@8SÃ}·(Ó…Ñ£GAOšhˆ©:Ûƒ½¦®«ÛÅ%™@„Õ¤„ˆ†…J"""" r_ÐÐj ^–mJ.!)1"?Ý’;Ë€ÖA*réÔÊO !Wò4è‘iƒs‚6z!¼÷í g#¬g¾0/!"Tr[©û»᪻XIDX¨$"""¢Ðà’з•B"7gN>!FÌ˯Քí.÷¶ïA¤Vh¯O* erUå`Уҡ%M5ÄÔªOW»IÑ «s@2ö%—ŽÂ,&%DÔ,TQèØS4 /ìU9â" ¦2„daùà­¦üŠpµÂZý™!æq d䈮 ¾Ò2¯1nÛ×Z žþ¬ç ˆ((ÉÏOgcEY!Ø«’‚ •DDDD:œÝ¬òˤŚ“Oˆó²‹W‘«»ïó Q+7CèÅf ÎÑ× Éç.dd*\©3 1ëé-®Ö® ¢ ek‚; ˆ`¯Ê>S„µÍ§êÌÉg˜àJDD¢,s.‹ÆGñ‘#8y²´Ûó"""’’ŒÉ“'wûq MÍÍÍ8}ú4Z[Cw˜†,,‡˜3ˆ ï .¼Zh^RAD¤ÅBäûBʧº¬T2šjåf8Ç|­3”<jl”Æ2ÿääœcû™šp6A=ýiÏQH‘Ÿ–@LLë|Ã)\…¸l,ä¿™›XSGÉQ†˜þÉq@—=\Aƒ…J""¢¥ë'KO¡¢¢uuÝ¿ó{ñÅcñâÅHˆOÀÔi,T7­­­x÷Ýw±{÷n³Sš}K ”Å=!‘•ä¦@¯51± ±`œa˰t8!·û·@¨žþÚ¨jÇ EgöÍßÿ¼_óFz|.\ y†˜µâß®6“2""¿«m†_Qkvw ãÌZi‰èáŠáË™qôð$C,¬t M*4‘ùNÈÏJ !16 b|Š9ù²ä(à’Lcì`5,§›ÌÉgb¡’ˆˆˆˆBž,­ƒ7«ÊÕÜúæq™q•©Cˆˆh˜“òýbÀ»›G¸ÊÁ:p·>AJ´!&?=´±Ÿ»¿±PIDDD!åí·ßÆ®]»ðè£BQŒêÜ{ï½hmmÅ‹/¾èלâãã1räH„‡÷oÅÂ÷¿ÿ}¼÷Þ{(++ëýd/½ôæÏŸ & $ÍáÁá>5n}#b€ÙÃxë›" ù<3­äÇÙ“K-ÛÑn\ä{+ X{¸"ôiis¡ÇŸakùíçLʈˆVÅ9`_•!$¦Œ„Èêß›©!%>âòCHVžƒÜ]iRBà •DDDrüqäååá¶ÛnóÄ233ñï|¿ùÍoàp8Îsõà[»v-æÎ‹êêê>_“˜˜ˆ«®º ÿüç?û|MII öîÝkøº©+YXÑeë›rÅ8 nxÖén‰þï£@‹³‡+Ì%\m°–ëèÉpf^cRFæ’Ö´Ylˆ)-ÕP«¶˜”:ý?Ç€Vãî,ʶ» Äuy€Õ«õ‰.÷‹iö ¹á‰…J""" 9ÅÅÅøë_ÿŠ|111€‡~EEExçwLήofÏž EQ°sçÎ~]·}ûvÌŸ?ˆ² º„|ï°ñH˜¥koªá 1⊮«H°§ª‡ ƒZó%, Æ–ÎÌk £3LÊÈ<Μ[5Ê+"a=ñw@ºLˉˆ\s;äfãÏP‘ 1/Ûœ|L$òR!&Œ0Ääî Ȫ†® ¡¦š ‹Å‚믿 (,ü‡÷é:gÖõp¥Ï…4y¥:D{=¬'߆RßÿÏ>û,/^Œ{ï½›6mÂu×]‡[n¹å¼×|øá‡7n\ÏÍÍí6‰+V`áÂ…HIIAii)6oÞŒgžypë­·båÊ•˜:uªçøÛßþ66n܈o¼¹¹¹())ÁÓO?mÛ¶¦N ›Í†öövÏñßþö7<øàƒx÷ÝwIIIظq#^{í5üÏÿü ¼¼ãÆCTTZZZúñfª wWB\œé ‰ #€ü4ȃ6ó#ˆó«H¤>8«H$ÂJÞ„cÚÿˆ¯ò´åÞŽˆ¢g©ŸÿòáJš -e¦!¦Ö솥áDW¹ÉÂrˆi#‘qž˜¸<²ø PÓlbf~au÷©öÖÜÞu::ù •DDD!J×u|±ý ”••£©¹opê yв qf}#ñÕ–Æ Ë±ãçý.<444à·¿ý-žxâ \}õÕøÛßþ†C‡÷šxýßþûØcaêÔ©øõ¯S§N!++ Nçù·ÍΘ1¥¥¥xî¹çÐÔÔ„ï}ï{x饗pÝuסªª #FŒ@EEç´Þ¢¢"üîw¿Ãã?Ž]»vÁf³áW¿úŠ‹‹ñ /xÎ+//‡©©©8uêT¿¿–aåããÀ„@t˜'$M€[¾[5èïžç ùWT‘‡pµ!bßï ÇfJXï %é‚h?á¨ñÛ§hÊ7ß|~ø!®¿þz\yå•xã7°k×.Ü}÷Ýp¹ú^ø‘^Å–ÆÆFLž<¹Ë9«¥ºëA™‘á^ÐÐÀ&ð}%ß/†ÈN¢:û²ŠÅ!+Î ¡WðsÆc}Šà{*!Kì&eta”†¨ÕŸAÙ9DJ môBXË?01³¡!ÃâÐ>þÛpéýŠæ@Øñ¿™–1§ 62 IDATòÝÃß¹_ý\±Z Ü:ú+;Wèõü7L⌭~äGGÆ6“2"o,T‘‘tAi8iv¦hJÀ]@üûßÿŽ¿ÿýï˜={6þú׿b„ ÞN^RR‚Ûn» BCsåʕعs'Ž;†?üá¸ùæ› Ë‘#G¢±±55þ+ð½ævw±ò¶)±H+”[&C_û% ‡PŸ®‘qWúÜZ!ÿÝÿUÄZú\  #S=1-k!,õÅPKÍKlÐ ´¿ÒjlíVº¢½Þ¤œˆ(誃ÜQqé˜ÎXZ,”«r¡Ü¿|‰é]wM”Ø!÷ÖŽ¢áŒ…J"""¢¯ ´¨øƒü§OŸÆñãÇa±Xðõ¯‡••ÿ£wïÞ½ Cff&ÊËËßüæ7qÝu×añâŰÛíxë­·ðøãz]Ž?ûöí37©wò`50!"?½38&â²±[JÌKl0Y-PnX¼VâI ý_€Vͼ¼ÐÛ~l-Z§Üç™.¡ í¢»±÷Wh¬ŒÕ2®€+a‚!f±ï‡jÛnRFD*äŽc“ Ò¼Þ¹4 8^ œ<Ûó…Á$9 b‘ñg(NèotOq¤€º[ˆˆˆˆü$,, ßÿþ÷±nÝ:¼öÚkÈÎÎÆòåËQ_?ðNûöíCUU-rOaŸ8q"~ñ‹_à±ÇCUUÚÚÚ°bÅ ,^¼_ÿú×=y\uÕUxï½÷åënä{‡z‡!&.ϲLÊhp‰ÿ¿½;ª¼ß?~Ÿ33Ù7‚ ›„M6ÛâbUD)â‚ Ô¢b«ÖõËOk«¸´¶h…¢bTTŠÅ]ÄbYD#Ù!,IX²Îœß1qf2“LÖs&y¿®k®9óœe>3 Üó,?í)µNh³>É‘¾k¼ù[›’yd»<Û‡z[qmTrÊÕ &¥|IUÒ墀6£¤ |ŽN¨/¯Ozu£Tæ7ÔÛ0d^Þ§Ê0é¨äqɼ¾ä’KdYAe]•É÷ï/d^?H2¿¶LCÆØ,Ys>‹ê_dŒÁedulÜ] ë£-öÔH<»Þ“¯UOySºU¶y[÷Qi§såÙù®•ÕåIVqÏI’é¿’¥Øìù2ÊŽ…?jÁÚwDz/[ÆÈî?4&ÄÈüY–|Ï®’¼ÑÛíÐøiO©}à´Öš²6ï·©"„CJ‡š;w®âââ*{LVÇ4MM:U3gÎ ¹È"´3¿Jxg$Åʼ¢ŸäŽÎέdŒ85°ñûP¶YÍ¿)I–O1ß̫ޕv¾PÞÔSÜäl–L•ô¸^VL`Ï^Ïî÷eæ5¯¹ãØÏúßvY_…wSeŒìú„(` ñe]îQYËø7Ô‰¢ó§-€àøñãºñÆõöÛo×x¬ÏçÓ´iÓ4oÞ¼&¨¬y³>É‘õíÀÆÌ”òÞÑ&%NÛ燢’dIÖ6J‡šg mVÌæI–ÿðES%=®“ׯ¾Âꨬۥò¦œÐfæ}#w=§4‚ïÿ°þaœÞIÐѦ¢êÎ8±•Œóƒ¾¨*.“ï¥õR©×–šP=‚JÛ°aƒŽ=ѱ«V­RYYt/Šâ–%-þ²ê/i}3eüèD{jª‹8Œ«úËHŠ lÿd[ÕÞ2ÍŒ+ÿy¶¿Ðf¹UÔûFYž$›ªª½ÒÌ3UÚax@›QtH±_ÿK†|a΀z**“^ÙP%È3/ì)ã”(ú§m¢Œqý‚¾¬³d½ú¥t°y~Y×TA¬ÂRY/­“JI3Î9Eê›iSUµà2eŒë+##0”³¾= ߇Ík^Êp<;ß“ëàmV\÷ü¹dzlª*rÞ6ýUzbд¾RÅ~=—y)4:kßY¯o \ Û4d\žUe®GGJŽ•yÕ).piëãm²¾Îµ©(D‚ €fÊívkÌ¥—èÆ)7(+«ÝåÑ'÷Xy¯ Ëï·4C2/î%9¹G‰aȸ´·Œ[¶8&-z=Íš¥˜oæÉ<º3 Õ—|¢Š»_+®0çÙÏ—z²ŠO¹Z2üW+·óí‹2î°­.-‹õÅ^YË·6Ƹd^5@FëD{ŠŠÄ÷# ”¸Z¹µy¿¬·†9 NAP @3UVV¦Å¯¾¦Y³çhÆ/j>@ÖæýU'Û7 ™c³¤®éöUÓ1º·ŒÞíÛËz~­¬ÂR{겉á+Qì¦Ê(:ÐîMî×92¬ô¦œ¤â^¿\á[’ç»7äÎ]cSUZ*ë£-²ÖïlLŠ‘qí@)=Áž¢ªç‘yuí‚VøÞ‘'«E}Y½*€jXŸm—µ"'°Ñã’yegõ¬4 £O«º²iq™|ϯ••WhO]63J ûÕ?¥²ÀùÈÊZg©Äa=+}©§¨¤÷YfL@»{Ïryv¾kSUZ4K²^ß$k[à>JŽ•yí@©U¼=u…ç–1a€Ô15°ýàqY/®cñœ(AP ÔÀz?[ZÔ£ÄmÊ×Oê‘aOQþ\¦Œ1§ÉèÔ“²ÌW¾²é¾#öÔåæñ½Šûê)¾’€ö²Ö}UÜcb•`ÐÞ´*êyCÕòàzÅl[lSU ÉkÉzy½´» °=%Næõƒ¤v˜³2)Fæu§ËèØ~¤XÖ‚Ï¥6¢ šT5±$ßë›d}¹7°Ýõý0ðÁ'ØS—$Źe^3 êpï2Ÿ¬…ë¤à^0-”Y°U1gU +½é§©¸Ï-²bRÂœÙøÊÚ SIï_H®àrƒb¾~N²Xá€ÍŠÊä›ÿ¹¬à°29VæÄA2N¶q„AÛ$™“‡T L Šd=·¦ÅŽ(ˆV•@$|Vùâ:Ásu™†Ì zȸ°§ä2BŸÛHŒŒ$“K]‚Î)õÊ÷âZY[6i=Nç*ت˜³«„•¾¤Î*ês›|‰›¶ Ã¥’®—ªää+dýjæ:°N1_ÿK²ªÀ!ŠJ¥ŸK{‚ÂÊ—ŒñýdØñ¥Ý)mdNTeáåÉ÷¯Õ²kúšP/•ÔS»víô§?ýI›7oVLLõÃÝn·~ûÛßêÍ7ßÔgŸ}¦'žxB'œPõ‡ºHÐÄ|–|¯m’>ßUe—qz'7Ý|]}3eL\uåÕ¯¬…륭ô¤ ÅU°E±gÉš³ÒŠKWQÖm*kÿ£&©ÃŠMSQŸ_ª,ó¬*ûܹ«¿ïIIH ÀY¬ÂRYó?—•s8p‡iȸ ‡Œ±YR¬;ôÉ É4džªÌñý¥¸ ç;\(ß³«¤Ãô¤ŒF•ÔQjjª¦M›¦÷Þ{OW\q…\®êd0 C³gÏÖ…^¨Y³fiúôéjÛ¶­.\¨Ž;Öú8´LW_}µzôèQãq†aè–[nQÛ¶m› ªƲä{c“¬¾•‚52SdNVÞ«Äh¤Þ•ɱ2®è'stoÉôïNA‘|sÿ'k+=)«clU܆ÇdÚáQÉI?SQÏ_ÈŠk¬UÝ •µ¦Â~wÊ—|b•½îËóÍb¸7g² KËç} žE’ѫ̇ÉhÌÅæÚ'ËüùiX)ø¿Úùò=ó?)¿¨ñžŠ €:š1c†úöí«n¸A“'O®ñø3ÏŸO“&Mªõqí‚ .Ђ Ô©S§*û\.—üqMœ8цÊê/33SÓ§OWJJÍséY–¥aÆé–[ni‚ÊZ K²–o“õï/ª®"ã’qA™“ÉèÜ*ôùuá6¥a]dÞ4LF÷ª´µ+_¾§ÿ'í;ÚpÏÙŒ…û·þ¯2 ¶VÙçK異þw©´Óy ºÐŽ/©‹ŠúüR%']!¹ƒzÞúJ“ý¼b¶¿©* 88×'ßâ/d-ßZõŸ¬Ô8Wö/ï]™žÐpÏ™#ã‚îå!eû ø|¹W¾çVKÇJªîCÔ ¨ Žn¿ýv]}õÕúïÿ+˪ù—Ê«®ºJË—/WNNNe[AA^}õU]~ùå2M³VÇ!´?üP:uÒ]wÝUe߸qãtÖYgéí·ß¶¡²ú›2eŠÖ¯_¯ÿýïÿøãküøñÊÈpÀªÔÍ”µq¯¬gVIBÌÕ1UÆõ§Ë¸ª¿Œn­«öúˆT¬[ÆÐ.2§þHæù§Jqžªu¬Þ!ëÙÕÒ‘â:>IËd”SÜ—OȽëÿ¦m™1*ír‘ŠNÿ*ëx¶ä®û/ÛÞ”“TÜs²ŠúÞ&_J·ªuP܆¿É½?²¿Ûà–d}°E¾׆\UÛèÕNæÍgȸ¸—ŒŒ¤º?OJœŒsO‘ù«ËÜY2ƒþCõúd-Ý,ß¿¿ÊèíøM€:*,¬Ý¼7'Ÿ|²Ö­[W¥}õêÕJLLT›6mjuB+**Òý÷߯ .¸@ƒ®lOLLÔ­·ÞªÙ³gk÷îÝÕ\Á™bbbtÑEiáÂ…Ÿ³råJíÙ³GcÆŒiÄÊ`í;"ßœÏd­Ù²#œqr× yódœu’Œ)UÉ >'Þ#£G†Œ1}dÞ>\ƈS«. IGKä{i½¬77K^~9«Ë«˜œÿ(î«92J ªîö¤¨äÄÑ:~ú}*9u‚¼múÕZ¦|‰UzÂõ¿SÅ}~)ozUM«-¹÷ÿOñë•ylgƒ½$hRÙäûçÊÐs#›†ŒþeÜ8¬üË»!e´Žà‹ŸäX©_¦Ì+û—”?:QŠ©:Í’µïˆ|Ϭ’µjGý_¡ f8 º¸ÝnõîÝ;ìþ£GjË–-µº¦ajß¾½¬:o\nn®$©C‡ÊÍÍè¸ýû÷×êù[šeË–iùòåºçž{4zôhù|>ÝtÓM*..Öœ9sì.¯N¬ÔÔT½ÿþûŸcY–Þ{ï=1B³gÏnÄê R¯¬7¾’õå^™õ’BýÖ:AÆðnÒðn2J½åC´ó eU Qó˜2’ãʇɥ'TßÓ²dmØ#kÙ7!{± öÌC›_ð€Jº\¤²vgTcÔ£²¶UÖv $KFá™EûeÈðÊrÅIî8ùbZÉJ̔劭þùŠʳå%¹ò¾n¼M%¿H¾k¤¬L™#»W]àF*Ÿ¥s+idwÇKeí;"•oû,‰1²’ce´M”RB|9ç¯Ì'kùVY+r$Óe4'•IKKÓ+¯¼vÿgŸ}¦k®¹¦V×4M³òÌë-Ÿß®¬¬,âã"a†ÒRSÕ6¨f^~¾JKÃFfŠÔ§ƒŒàE:ššeÉ*(’Vï”U‡ æøƒÞ|óM7N}ô‘&Nœ¨;î¸CEEá'Wøá‡•™™vÿÕW_vŸiš;v¬¬””mÞ¼Y ,о}û$•Ï9~üx 0@111Z»v­æÏŸ¯’’æQ:çœs4räHµiÓF999Z³fÞ|óMIR¿~ýtøða”÷øêÓ§îºë.ÝÿýÚ´i“¤òýÑGÕºuë4wî\IRNNŽ®¼òJy<žjÿÜÑ@¾;,߬Oe è$ã'ݤ¤0óz\R§T©Sj­G„[ÛIïfËÚSµ÷ꩬP1[^–{ï§*éüSùÒ{…9ÐßVÞøÚ/Ve”—gÇ2¹÷,gUoÍ‹%iýnù¾Î•ñ£Ë– ÷ód‚GF×-3‚îÃòYÒ†=ò}¸E*`Áœæˆ € Ð)§œÒ ×ôz½Ú¿ȹ+†rïÙ³'âã"áñxtÓMSª´/[ö¡8¨N袽{÷(99E¦éRrrЬVq*º¶¯,W#­V\K†$WÏŠ}áËZŸ{àÀAÍŸ?_wÜq‡FŽ©õë7hÅŠO•œ~!šM›¾ªvXx¸s].—ž|òÊÌÌÔÒ¥o)7÷€úõë¯>úXÇ*&&FO=õ”’““ôÖ[o+11A·Ür‹~ö³Ÿi„kU\\¬‰¯×ĉõÆojÕªUêÔ©“zôè©åË?‘$uíÚM»víª¬!'ç;8pP=ö˜®¼ò*•””hêÔ©êÛ·Ÿ|pFåqTLLŒºu;)äkóxbÔ¾}söù¿·þë|nsç]/ík'íÊ”ŽÕs-Ã’Ú”NØ%¥¤K=†H5/þîh‰‰I2$¥òKçÙ¦<ßamó¨Ý¾²ê9kV‚q\]]Ût‚g‡ÜÝ=R÷s¨Î–'>.^^ŸW§žå Ðäbbbär¹Ô¾]»Kiþ|RÉšòÿ÷´—Jê¹.™Ë+µß'uÚm(¾0Sþ‹åÆàr¹ñÏ<ïðN#WÔ|TÐDrrr4`À€*íYYYÊËËÓ¡C‡ju\MJKKõ‹ µ{w`°™“ó Õ±S{IÒ‘#JIIÑ‘#2NN–鲂·C’Ž“Jjfüå/ѨQ£tÆgèâ‹/Ö‘#Õ÷@›;÷™:ÕxÝuשK—.1b„Ž­ºâòM7ݤ֭Ó5räÈʹMçΫ7ÞxCcÇ^®Y³féüóÏ׋/¾¨3f„|Žøø8íØ±#à5üßÿÝ­%K–èÆ§è­·ÞÒÕW_¥ñãÇkÏžÉììo$I.—òõ—––hÇŽïêüõùçâ‡ñ'¤IÝÛJÝ3"››K*N¾3_Ú¼_ÖWûµïh±ö5n™Mjè3´iÓ—*¨áï¥Äy’åmÝGÞÖYò¦œ$™U4 Å(Ì•;ï+¹¬“ŽlÓ6ËÒ¶F®µ%èÕó4É×ÎÌI‡ÚéØñ¥¦¦jÓ¦ÚŠzpR·Ö2z¶“qr›ð£ ‚•–"øj¿J¿ÉÕŽ¯ìú[Ÿœœ¬Ózgé¿+WØTAËAP @#1 C111*.._…÷å—_Ö#<¢SO=Uß|SÅÅÅi̘1zá…*Ï‹ô¸šX–¥œœï´eËÖÈ‹Þ~¸|µD·ƒÖÛÛ™_§R*_ðèÝwßÕÀ+ßËÆpöÙgëwÞ RJÒO~ò½þúë 0mß¾]Ë–-Ó Aƒ4kÖ,­\¹R&LP||¼>þøc-_¾<`¨¶ÏçS|||Àu;¦Ûo¿]‹-Òĉuï½÷jãÆÇ$&&J’ƒ{­µ ÖŽ«^½zéì³ÏÖÑ£GµtéR]wÝuzúé§õÈ#èàÁƒšúè#3F=ô,ËÒÓO?­Y³fI’Ž9¢nݺU¹Æúõë+·ßzë­*û;tèPy>âx‰¬oHßÚ]êÂOƱ]Ò±]²ù_IˆNùEåa$A%dïÞ½j×®]e¯¸²²2M˜0Awß}·n½õVÅÅÅé³Ï>Ó¸qã*Wô®ÍqÅÚ] í.h‘_`¯]»VÛ¶Õ~`æîÝ»«])>''G¬ÒÞ»wo}ýuùŠ¿>ŸOŸ|ò‰>ù䙦© &èž{îÑ;ï¼£-[¶h×®]ºð «\ãºë®Óž={tèÐ!=ôÐCºá†ÂÙÌÌL•””4Ég¨‚JÀòåË«,ÀsçwV9®°°P÷Þ{o׋ô84¬çŸ¾Nç½úê«zøá‡5nÜ8½üòË’¤“N*_¼æøñãš?¾žyæÝtÓMzúé§åóù4a 8P÷Üs$ièСںu«öïß/I•«“WL°aÃ%&&*--Myyy’¤¾}ûjÚ´iºþúëµcǽñÆš8q¢žy懹6;w¾úŠ¿àx•õ´xñbuéÒEøÃôÿ÷òù|2 C“&MÒÚµkõñÇëw¿ûîºë.ÝvÛmòù|ÊÍÍÕ 7Ü œœIÒ¤I“töÙgëØ±c2 C¦iêÐÎåCßW­Z¥£GêÜsÏÕ¢E‹”––¦™3gjîܹZµj•$iúôézì±Ç´jÕ*}ñÅ2 CgŸ}¶.\h×[DŒ 4kÏ>û¬-ZÔèÏóØciöìÙêÖ­›JJJ´}ûöÊÞ’´`Á½ôÒK:餓tìØ1íܹ3`ˆö/~ñ ¥¥¥)33S†a(''GÇŽ«Ü_XX¨%K–hìØ±Z´h‘bccõ›ßüFŸþyå1o½õ–ƯãÇK’† ¦öíÛ7Éëê‹ 4kß}÷]“=Waaa•U·ý•––jóæÍa÷çååUëeÖ¬YZ¶l™†ª•+Wjß¾}UŽY·n]åö/ùK½øâ‹!œ†  JìÚµK÷ÝwŸ j<Ö4M}úé§¾R<ÐP*¢HÅb=5ñù|š9sf#W4Ó€íú @3åv»uåø+TXX¨>üHŸ¾Öî’ ,‚J𩲲2½ðâBmÙ²5ä~˲dFW'²,Ëî†~ÐRåçç+55Õî2`³´´4åååÙ]@P @KµmÛ6uèÐA§žzªÝ¥À&Ý»wWûöí•““cw)C¿h©6nܨ͛7ëúë¯×áǵwï^y½^»ËBp¹\JOOW»víôÕW_iãÆv—TÐRY–¥ùóç«wïÞ:ÿü‘òù|ÌYÙBø|>mݺUï½÷!%ƒ €̲,mܸQíÛuÔ»ï½mw9Z0樠…‹W«V­är¹ì.QÆír©U«4ÅÇÅÙ] ¢PëÖ­””œdwˆBééi,‡:IMMUzzšÝe %'%©uët»Ëh*háN>é$y–’“ P;©iiqþ™êÚ­«Ý¥ ]tÑ8 ¿Ýe qžÎ<óÇv—(tæðë‚‘çÙ]¢Ð€ýuÑE#í.£E ¨`;‚Jà(‰ êÑ£»ÝeTÊìÐAíÛ·³»ŒJ={öP||¼Ýe8ÖõÐKINÖ)§œlw•:uꤌŒ »Ëp,'}vLÃpT=i©©êFÏé°²²úÈívÎòNúì¸].õí›ewŽÕµkW¥¥9g(zÿþýdšÎ‰‰œôYFÓqÎ'@Rrr²úœÖÛî2*uî|‚:Ÿp‚ÝeTêÛ7K‰‰ v—áXgœ1Ôî*¥¦¥ªW¯žv—Q©[·Õ¡C{»Ëp,'}vd:tˆÝUTjݦµ£¾@ršA§”Çã±»ŒJNú,»= tºÝe8VM›Öv—QièÁ2 Ãî2*9鳌¦ãœ¯}@ƒr»\êØ1³Æã*‚‹.'vQë£G»¬µNOWZZšN:©›Ý¥H’2ÚeÈòùSOjjª:wî숅$*jÈÌì ââb›«)—˜˜à˜?«ŒŒ µjÕÊ1õ´mÛVññ :ꀿç’d†ÒÓóþ8é³cš¦SOÇŽ™JOOwL=11G½?ÉÉIêÚõDþ !&&FÉÉIŽ©'1)QžcêiÝ:]Ç 3eY–Ý¥H*ºuë*¯Ïgw)’œõYNOo%Ã0"®'//_l䪚§ÆŠÊkºn¨ý†_{Žâ±ÿ1¦ßy+n®ïïÝßoWܧ>üÓ‚‚‚Z¼@]>|ØQ½ Z’'žø›Š‹Šåõz«=Î4 ¹Ý•––:âeÃ0dšfu7•Š!P>‡üÐîr¹äóùógåñ8ç³#In·[eeev—!‰ÏrM<|^¯c~!vÒgGrV=åŸeC^¯sþ¬,ËrÌß-·Ë¥2‡Ô"9ë³#9«—Ë%Ã0T)ŸÏâÿÐ0œTišr¹\*--èø>^®×_³^Ï™ššª5kÖœ!)_’WR™ß½ïûmŸßÍò»U<–ßcùµ?¶ü¶ýÕôálð/=*h¦¦N½Õî bÌQ Àv•lGP Àv•lGP Àv•lGP Àv•lGP Àv•´` ÐSO=¥Õ«WëÕW_Õĉí. QàôÓO×ìÙ³õñÇkÍš5š7ož `wYˆB&LPvv¶úöíkw)ˆñññºóÎ;µhÑ"mذA|ðî½÷^%%%Ù],%%EÓ§O×|  6è7ÞÐUW]ewYp¨¬¬,=÷Üszùå—«ìkÛ¶­}ôQ-_¾\ï¿ÿ¾î»ï>ÅÅÅÙPeóå¶»`¡C‡jΜ9Z´h‘žyæõë×OwÞy§ÒÓÓõè£Úv ß&lIDAT]jÈ!š9s¦æÍ›§çŸ^ úùÏ®gŸ}V—\r‰rrrì.Q¢k×®ºûî»í.Q$##CO?ý´ÊÊÊôÒK/)''GíÛ·×ðáÃUXXhwyp°™3g*==]O>ù¤²³³õ“ŸüD¿ûÝïäv»õÜsÏÙ]¢k×®úõ¯­óÏ?_.—KëÖ­ Øß¶m[½ôÒKÚ¾}»î¹çµnÝZwÜq‡ºwï®k®¹F^¯×¦Ê›‚JZ¨iÓ¦iéÒ¥ºï¾û$IŸ~ú©JJJôë_ÿZÏ=÷œrssí-Ž´víZwÞy*((¨l[±b…>úè#]tÑEzüñÇm¬ÑÂår顇Òœ9stóÍ7Û]¢Ä­·Þª£Gjâĉ***ªl_¼x±UÁé:vì¨3Î8C—]v™¾øâ Iåÿ—eddèâ‹/&¨„$ÉãñhÁ‚Z¾|¹.¸à;VC† 8fÒ¤I*--Õ”)S*ÿ ÊÎÎÖ¢E‹tî¹çjÙ²ev”Þì0ô€è´ÓNSŸ>}4þü€ö… ʲ,=Ú¦Êàt%%%!¥$(''GmÛ¶µ©*D›)S¦¨¸¸X ,°»D‰ŒŒ 3FO<ñD@H ÔÄårI’RSSÚ uôèQ;J‚•––êÜsÏÕwÞrtˆËåÒ¸qãôÒK/ü´aí[·N?ûÙÏš°Úæ €èä“O–×ëÕ—_~Ð~äÈ}ýõ×:ñÄí) QÉ4Mxâ‰úöÛoí.Q W¯^š4i’îºë.Y–ew9ˆó˜®X±BRùœƒ‰‰‰v–„(±}ûv}þùçúÓŸþ¤~ýúI’Î;ï<]vÙeš5k–ÍÕÁIª›B"##C)))U†ƒKÒêÕ«ùÙ¹TÐuèÐA‡’Ï竲/77W:t°¡*D«Ë.»L’´dÉ›+ÓÅÄÄèá‡Öc=¦;wÚ]¢Hff¦öï߯¬¬,ýç?ÿÑš5k´víZ-\¸Pݺu³»<8Ü”)SôÉ'Ÿèå—_Vvv¶þò—¿hÊ”)úì³Ïì. Q¢âgãƒVÙ—››«öíÛ7uIÍA%-Çã‘i†þ1 ¬¬LeeeM\¢U›6mtÇwèñÇW^^žÝåÀán¿ývåååUù6 ÃæŠ-222”””¤{ï½Wüã•••¥K.¹D.—KO>ù¤<Ý%ÂÁÎ9çsÎ9úøãõÖ[oÉãñhâĉêÔ©“Ý¥!JTüêçç²²2Òi@•´@»wïV«V­*çmò×¶m[íٳdžªmbcc5kÖ,­^½ZÏ<óŒÝåÀáN?ýt]yå• ùF]:uÒÀm¬ÑbïÞ½*..Ö€ªìËÊÊâgçä¶»ÐôÖ¬Y£mÛ¶éÚk¯ øÁýâ‹/–išúÏþccup:Ó4õðëcÇŽºþúë«|¨pÓM7UéÅݾ}{-X°@wÜq‡Ö­[§ÜÜ\›ªƒÓ-_¾\ùùùºæškô׿þµ²½OŸ>2MS›7o¶±:8Yaa¡:tè ¤¤¤«|?~܆ªmJKKõꫯjìØ±š;wnåç¦k×®:t¨&Mšds…ÍA%-eYzä‘Gô÷¿ÿ]÷ß¿^{í5uïÞ]Ó¦MÓßÿþwåççÛ]"Ê4M͘1Cgžy¦n¾ùfeff*33³rvv6ó4!¤ŠqþŠ‹‹%•÷ŠÛ¾}{S—„(rüøq=ñĺû?üPmÛ¶ÕwÜ¡^x¡rX&ì•W^ÑøñãõüóÏkΜ9Ú±c‡233uË-·híÚµZ¿~½Ý%"JüóŸÿÔyç§§žzJÿüç?¯ßüæ7Z¾|yåÔA%-Ô²eË4eÊÝpà zòÉ'µuëVýþ÷¿×Ë/¿lwip°~ýúéÒK/•$ÍŸ?¿ÊþaÆéÀM]€`îܹÊËËÓUW]¥«®ºJ»víÒ‚ 4wî\»KƒƒmÙ²EãÇ×Ô©S5mÚ4¥¥¥iÏž=zûí·5gÎDĶoß®+®¸BwÞy§f̘¡¼¼<-[¶L>ú¨Ý¥5+µÌ^M× µßðk¯¸7C<ö?Æô;¯âqÅÍõý½ûûíŠûÔáÇZPPP‹—¨«Ã‡³'ÔBjjªÖ¬Ys†¤|I^Ie~÷¾ï·}~7ËïVñX~å×üØòÛöWÓ$ä >I9‹é°A%ÛT°A%ÛT°A%ÛT°A%ÛT°A%ÛT@ùðÃ5yòd»Ë ÁT@~ýë_kãÆêÚµk•}sçÎÕ’%Käv»ÚÝn·V¯^­x ä5 ÃЊ+4uêÔF©€hBP xüñǵcÇýáh¿ä’K4lØ0Ýu×]*++ ØWVV¦¥K—êüóÏ—ËåªrÍ*##Co¼ñF£Ö@4 ¨€”””èî»ïÖàÁƒ5fÌIRZZš¦OŸ®Ù³gkãÆ!Ï[²d‰RSS5lذ*ûF¥ 6(''§1K *T@„Ö®]«yóæéî»ïVZZšî¾ûnªcÇŽiÑ¢E=z´îºë.•––†=Þ²,½þúë1bDÀðïªuëÖzóÍ7%IIIIºí¶Ûôúë¯kÆ Z±b…f̘¡Ö­[×XSvv¶FŽÐ6sæLÍœ9³ò±ÛíÖÍ7߬¥K—jýúõzå•Wtæ™gÖöåÐh*  õÇ?þQ;wÖÊ•+µaÆÏY²d‰ÒÒÒ4dÈʶ /¼P+W®Tnn®¤òù,“““5oÞûì3Íš5K§Ÿ~zƒ\€úr×|ÀßСC%I]ºtQ||¼ «=~Ó¦MÚºu«F¥O?ýT¦ijäÈ‘zôÑG+)**ÒÿøÇ€ó ÃÐC=$—Ë%¯×[çz»uë¦Ñ£GkÔ¨QúöÛo%IkÖ¬QçÎ5zôh­^½ºÎ× ¡Ð£j¡ÿþºöÚk5uêTÅÆÆjÚ´i÷Úk¯Uÿ4hRSSµlÙ²€c:vì¨[n¹Eÿú׿´dÉýõ¯•Çã ¹bxmôìÙS’´téReggWÞ.¸à%$$ÔëÚ4zT@„bbbôàƒjñâÅZ¶l™,ËÒO<¡·ß~[+W®¬öÜ×_]·Ýv› ¤Q£FéÃ?Ô‘#G*÷wêÔI‹/ÖâÅ‹õÈ#è»ï¾Ó!Côü#¢Ú ûïСC’¤#Fhûöíû,ËŠèú46zT@„~õ«_)55U>ø $éwÞÑ[o½¥|°Æž‰ß}÷6lØ Ÿþô§9rd•Õ¾üã+&&F3fÌÐ_|¡‚‚‚°× %óóóÕ¡C‡€¶¸¸¸ÊíÍ›7«¸¸X—^z©¼^oÀÍçóEüúhLõ?^ø¯òÂï7üÚ«»Þw3ýîýoq]ºt™\\\\‹—¨«¢¢¢zWÀ N;í4=øàƒš>}º¾øâ‹ÊöU«ViÒ¤IÊÈÈЇ~Xí5âããuóÍ7Ë0 MŸ>=`ÞÉääd7N©©©ÊÏÏWVV–þö·¿I’þñT;|øpeffêóÏ?¯ì‘Ù£G]zé¥Ú¹s§uÑEéšk®Ñ·ß~«¥K—ª¨¨H’4uêT†¡Ã‡+))Içž{®8 ãÇ7ä[¨§¸¸8íÙ³çiIÅ’,I¾ ûà›¿Ú>v ‚J@£"¨4n·[sæÌѦM›À‘¤ãÇ+77W·ß~»Ö¬Y£;v„½ÎîÝ»5yòd­X±B‹/Ø·sçNé²Ë.Óøñãu 'èoû›Î=÷\=ùä“•Aå4aÂ3F‹/VQQ‘V®\©nݺiÒ¤I:çœstìØ1­^½ZIIIZºt©¤ò@u×®]ºä’Ktã7êòË/WZZšV®\©¼¼¼~ÇõÑRƒÊšÅƺn¤A¥â±ÿ1¦ª†“7×÷÷îï·+îS‡þiAAA-^ ®>,Çcw5RSSµfÍš3$åKòJ*ó»÷}¿íó»ù‡–å÷X~mÁC… ÓV›ýµÆ•lGP ÀvT:v¬;€zi”ì/Ú{Tˆå¢:+³+¨Œê7 hÆlÉG%'™¨ÊÒœTÖåÍŒª? š]næô @ @P Àv•lç´ ²¡ÆÉW{ŸÏç3 £ž h¦i*--­¦Ãš$CkjN *#üZ5쳂¶½^¯·Àår5Ry@ݘ¦©ŒŒŒRI^…ζüÕ”‹E§•V5÷ÁÛán>¿ûŠ›$•–””lt»ÝY?PkG©©©»%•~ßäŸmùg^ÕÝb;Ô½£ØTFú†Ôõ •(û$•¼äñxêxY qx<åççÏ—T¦:ÞU×s2RÅÕ›S{Tú õæT÷†Õ”({³³³W–””ìŒmèZ€:‰UVVÖñ^xá5ý®®çd(µÍÓÁIAeMoVuûý»¼*̶ÿ­øÐ¡CÄÆÆŠ¹*`7—Ë¥¸¸8=&©X‘é®N}2·&Õ˜Ae}»¡†;¿6ƒú˜þãøË²³³Wäçç/‰+€À.¦i*!!Aƒ^ÿâ‹/.Öþƒç¤¬M YS¶ÖØCÈk­±»Ö”ï7ÂÜWl?öoµß¿ÍüþVÑæÛ·oßÊ6mÚôJLL<Áëõʲ @³QTTDïuÃår)11QƒÞ>kÖ¬ë$*pŸ~¼N…šˉŠÐËî 2ø˜pAepè®=Ôu ýPŸãÛ³gÏ­Zµj—œœÜ]’¼^o%"EP ¡ÅÆÆ*!!AC† Y?kÖ¬ëURzU5 ´¸ò·:°TˆÇµak -Ae¸}5õ¢ôïMi)°GeÅþ²}ûöý×ãñlJHH8-!!!Å4ËGÄÓÃê Ê™¦)—ËUP0àxjjê#Ï>ûìÃ’Žë‡p2ToJÿÐRªXú«©‡¥#5öäŒu *ý·ýÃÆàvÿ¶à›éwï ºwû=®hóHŠ=ù䓇¦¤¤Œíår¹RÌŠÔP'ùùùr»Ýv—¶KKKSFFFiJJÊžüüü/¾øâ•/œSªBÉŠ ²LÁeÅ}¨!àþaep¯ËŠ6…h¯n;œF =›b™†š§2ToÉPmþ¥ôÃÜ”Áa¥+ľŠ³â|-VÝ@mˆ!dÅÍ¿çdðvð½/ĵB 7<¼¾sY6jÏL'tq±YXqœÿ½‚Úüõé‡!ß¾žÃ¼™Â¡@¤Â‰þacðPïPCÀCõ˜ ÷Ámµ©Ó6N*ém€Y±]PV<®P‘8*ÿƒ®ØïRà‡ÄÐÁf¨…x€Hù†¡†lW7¥/Ä9‚˨ $ÃqbPªwdÅcÿ^’Á=)ƒ·+TWñ‡+ WÐ~ÿp²"Ôdè7ê"Ô<‘Á¡ep¯Êàž”Õ­ôj;ø9ƒ õØvMTFÚ3²>×—ª†”eE¸éï®t\pJÿaæþÏT'TÈš†€‡Úö?_ V6vðØèÁfS…n ¹ú·Tó àþmÁ«†› \$§ºïék ծnåîà°R ìnUïHzS:rµï Nú-Õ­f¸áàÒ½$+zTZ BîbÒ£ ¡º•ûƒ{L‡‘ÁCƃ¯]—Ñqþ%gõ¨ >®.½*ƒWèµr·´?øqðqÁÛÁuÁ‚Ã@_ˆíàà2xNÊPÇU7gecõ¦¬ÍquÖT=*sžJÿž”B-ªSÁ´ß¿WeÅñ¦~X<ÜuüŸÂçH¾j×´hN¸EtB…”¡Iz`:uè·zEoÿ¶Š¡Ü¡Î ^PG!‡"^qŒ¯šÇ5!¼hjàU·N¨áÝ5…–áž¿6½)¥)Cµ†þ¼<‚Ó @úo×&¤ &Ö·7e“õÀlê®.½*ý×Ô«2\{$‹ñ„Û6DP €ú 7d»º€Ò¿­¦^“5õ¦ Õ›RrfÊPÇÕ&÷z¬®geÅvð›iK Rá >Fª9̬kHìè)ØXa¥TsÏÊpç†ê5î9ª«-[]†`GÒÛ²>!¥ã{SJÎ*CéB;µ 2Ã-®®ŽÚ"Јnõ íªëE¼?Ò ². æÔv¥ò&cW€Öн*Cí«Kj¨c€Ú¨®e¨cj "# #£¢7¥äü 2Ô±u +k»¿ºã€ÚL*D[$!dc‡”µ=¶AØÀ5EXYñ8’óÃ…”‘´Á" &ýÛjP†;&’}5±ež¦^õ;Xc…•‘¶EºHN]‡ª y«ëPêÚÎ)YÓjÞQRJökõ *ƒÛj³¿ºcéE €†iOÊPÇ×'¤ ×N‹ *¥ú‡•Áíõ ,ý÷9áý@ón®Jÿý5mGº¿ºöúÛàœÄÕ¶†º†•5SShÉq@…H‚ÄPûj@6DHY—ã”SB·† +ý÷5Dðؽ=м5T¯ÅÚ›µ ?kbkH)9+\kŒ°2ÒëÖn:é}@ô©©×c$Aa]{hÖæº¶qZW—zcÈ6óS ±Ô4Oe¨ãCmWw\]®m+§…qu­§!zM6Ö¹h¹jÓc²>çÖ5p$¨¬Fc†•þÇ6äkwâû€¦Ó_}z\Ööyé[}êªË¹f=ž¨/_ΩOÐè¨RrnP)5}X|®“ßD¯ú ¾FSŸÛhœÆÕ·¾†x}N" ¬ï5RJÑÂ95lŒ†÷M¯1Â@'„œ*šÂ¶†ª5š^3Z®† PVˆ¶ÐŽ•ºÐÜ5ô âQ!Ã:†q ¹qêpñ&Í]cÖÍï œ¯1CĨ (+4‡@®)_Csx¿Ðtš24ŒÊ€²Bs Þœø:œXêω kª•æ¦5·×T'êÊ Í9Økί -W³ 'ýµ„0¯%¼F4Í2 ¬ÐÒB¼–özÝšu8鯥w-ýõÀYZL0Œ .ïšR‹ &ƒÌE†÷ õA Y¸†Ç{ Ð2>МüÎ7¬íûû¥¯IEND®B`‚Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/se.sjoerd.Graphs.desktop.in000066400000000000000000000011361520337127000267710ustar00rootroot00000000000000[Desktop Entry] Name=Graphs Exec=graphs %U Icon=@APPLICATION_ID@ Terminal=false Type=Application Categories=Education;Science StartupNotify=true DBusActivatable=true MimeType=application/graphs;text/mplstyle;text/plain;text/xy;text/dat;text/csv;text/xrdml;text/xry;text/txt Keywords=Plotting;Graph;Graphing;Science;Mathematics;Math;Equations;Data;Plot;Visualization;Fitting;xrdml; X-Purism-FormFactor=Workstation;Mobile; Actions=new-window;style-editor; [Desktop Action new-window] Name=New Window Exec=graphs --new-window %U [Desktop Action style-editor] Name=Style Editor Exec=graphs --style-editor %U Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/se.sjoerd.Graphs.gschema.xml000066400000000000000000000220501520337127000271170ustar00rootroot00000000000000 "middle-x" "savgol" "linear" "trf" "1std" "a*x+b" false 10 3 4 "X Value" "Linear" "Adwaita" "Y Value" "Linear" true "Best" "Y Value 2" "Linear" "" "X Value 2" "Linear" false false "X" "X" "0" "10" 100 "Linear" "png" true false 800 600 [(0,1,2,3,false,false,false,"n")] "whitespace" "" "period" 0 [(0,1,2,3,false,false,false,"n")] 0 false false Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/se.sjoerd.Graphs.metainfo.xml.in000066400000000000000000001120761520337127000277270ustar00rootroot00000000000000 @APPLICATION_ID@ CC0-1.0 GPL-3.0-or-later Graphs The Graphs Developers @APPLICATION_ID@.desktop @GETTEXT_PACKAGE@ @ISSUE_URL@ @HELP_URL@ @HOMEPAGE_URL@ @VCS_URL@ @TRANSLATION_URL@ @CONTRIBUTE_URL@ keyboard pointing touch tablet 360 #99c1f1 #09356d Plot and manipulate any data https://gitlab.gnome.org/World/Graphs/-/raw/main/data/screenshots/sin_cos.png Full support for light and dark mode https://gitlab.gnome.org/World/Graphs/-/raw/main/data/screenshots/sin_cos_dark.png Generate data from an equation https://gitlab.gnome.org/World/Graphs/-/raw/main/data/screenshots/add_equation.png Manage plot stylesheets https://gitlab.gnome.org/World/Graphs/-/raw/main/data/screenshots/previews.png Manipulate imported data https://gitlab.gnome.org/World/Graphs/-/raw/main/data/screenshots/curve_fitting.png Plotting Plot Graph Graphing Science Mathematics Math Equations Data Visualization Fitting xrdml Plot and manipulate data

Graphs is a simple, yet powerful tool that allows you to plot and manipulate your data with ease. New data can be imported from a wide variety of filetypes, or generated by equation. All data can be manipulated using a variety of operations such as the ability to select, cut, translate, multiply, center and smoothen data, as well as apply any custom transformations on the data.

Moreover, Graphs supports curve fitting on imported data and offers extensive customization options for the style of the plots. You can fine-tune and personalize stylesheets to your liking.

Graphs is an excellent fit for both plotting and data manipulation. The plots created with Graphs can be saved in a variety of formats suitable for sharing and presenting to a wide audience, such as in a scientific publication or presentations. Additionally, the option to save plots as vector images allows for easy editing in software like Inkscape for further refinement. Graphs is written with the GNOME environment in mind, but should be suitable for any other desktop environment as well.

For any feedback, questions or general issues, please file an issue on the GitLab page.

Fixes a bug where changing the style would break when error bars are present on the canvas

Fixes a bug where the canvas was not refreshed when setting the minimum value on the left-axis

Version 2.0 of Graphs is a major update, introducing several new features such as proper equation support and a completely redesigned style editor.

Different data types:

  • Graphs now differentiates between imported data from files, generated data and equations
  • Equations now span an infinite range
  • Equations can now be edited afterwards, as well as simplified using the item editor
  • Equations with undefined values (e.g. 1/x at x=0) are now properly rendered as well
  • Operations on equations are now performed analytically, meaning the name of the equation will also change accordingly when performing operations
  • Generated data can now be changed afterwards with regard to step size and rendered span

New Style Editor:

  • Graphs has a completely redesigned style editor with a live preview of the edited styles
  • Styles can now be exported
  • New styles can now be imported from matplotlib-style files
  • Added the ability to draw tick labels (values) on all axes
  • The style editor now contains options to style the error bars

Reworked Curve fitting:

  • The confidence band in the curve fitting dialog is now correctly calculated using the delta-method
  • The curve fitting dialog now has the option to show residuals
  • The parameter values themselves in the curve fitting dialog are no longer rounded (e.g. 421302 used to be rounded to 421000)
  • The results in the curve fitting dialog now also show the root mean squared error as a second goodness-of-fit figure
  • The curve fitting dialog now shows more useful error messages when things go wrong
  • Custom equations in the curve fitting dialog now have an apply button, greatly improving the smoothness when entering new equations

Improved data import:

  • Revamped the import dialog, where the import settings can now be set independently for multiple files
  • Added support for sqlite database files
  • Added support for spreadsheets files (both .xlsx and .ods)
  • Added proper support for single-column imports, x-data can be generated using your own equation
  • Multiple items can now easily be imported from the same file at once
  • Imported data now supports error bars, with styling configurable per item or globally via the style editor

Quality of life changes:

  • It is now possible to have multiple instances of Graphs open at the same time
  • Data can now be imported by drag-and-drop into Graphs
  • The subtitle now also shows the full file path for Flatpaks
  • Limits can now easily be clicking on the numbers near the axes
  • The custom transformation has gained the following extra variables: x_mean, y_mean, x_median, y_median, x_std, y_std and counts
  • Settings that affect the canvas (item or figure settings) are now displayed in the sidebar, so you can immediately see the changes on your graph
  • Graphs now properly supports mobile screen sizes
  • Legend labels are now truncated dynamically to the window width, instead of to the previously fixed 40 character limit
  • Graphs now inhibits the session when unsaved data is still open
  • The resolution (image size) for exported figures can now be set manually
  • Added support for base-2 logarithmic scaling
  • Warnings are now displayed when trying to open a project from a beta version
  • Translation updates

Bug fixes and tweaks:

  • Graphical fixes for the drag-drop animations
  • Limit entries can now be properly set even for many significant digits
  • Panning and zooming are now done consistently on all axes when using multiple axes
  • Fixed a bug where the text size was set incorrectly after exporting a figure
  • Implemented a custom math parser, which is more performant and robust
  • Overall tweaks and refactors under the hood

Minor update:

  • Translation updates
  • Update to the GNOME 50 runtime

Minor update:

  • Translation updates
  • Fix compatibility with Python 3.14 for non-Flatpak builds

Minor update, offering some language updates.

Minor update

  • Update to the GNOME 48 runtime
  • Update runtime dependencies to the latest versions
  • Slightly tweak the system styles to match GNOME 48
  • Updated translations

Minor update with the new GNOME 47 runtime.

  • Update to the GNOME 47 runtime with support for accent colours
  • Update runtime dependencies to the latest versions
  • Improve the canvas rubberband drawing
  • Improved equation parsing

Minor update, offering some language updates.

Minor update, offering some language updates.

Minor update focusing on some bug fixes and language updates.

  • Updates to the translations, and added support for Hungarian
  • The minimum height of the window has been reduced significantly
  • Style previews are bundled with the build, resulting in a about 600% faster start-up times
  • Pressing "Set as default" in the Figure settings now properly shows a toast again
  • Fixed a bunch of issues with regard to equation generations
  • Custom equations in the curve fitting dialog are now stored properly
  • Parameters in the curve fitting dialog are now displayed, even when no proper initial fit could be made

A smaller release focusing on mostly background changes.

  • Help has been ported to Yelp and can be accessed from whithin the app
  • Numerical entries now show the validity of user input
  • Improve equation handling
  • Added some new goniometric functions such as the hyperbolic sinoids and their inverses
  • Graphs now fully supports touch screen devices
  • There is now a warning, when editing a style with poor contrast between labels and background colors
  • Curve fitting now supports duplicate variables, and has gotten some bug fixes with regards to equation naming
  • Many improvements to localization
  • Many updates to translations
  • Update to GNOME 46
  • Lots of background changes to improve performance

Graphs is now part of GNOME Circle, the codebase has been moved to the GNOME GitLab. This patch changes updates the metadata to reflect this, and adds some small quality-of-life changes.

Full changelist:

  • The label and title size can now be set within finer increments
  • Data that has been hidden is no longer used when setting the limits automatically
  • Slight performance increasements with regard to preview generation
  • Updated the metadata to reflect the move to GNOME GitLab

Minor patch with a few tweaks.

  • Some strings were updated to use Title Case
  • Local translations have been updated to the latest version at Weblate
  • The highlighted area now deactivates after performing an operation
  • The subtitle now just shows the location without the filename

Version 1.7 marks our biggest release yet. With a migration to GNOME 45 and a new UI overhaul with a revamped style editor. Other major highlights include a new curve fitting functionality, the ability to open projects directly and support for gestures in the canvas. A full changelog can be found below:

New in Graphs:

  • The style editor has been revamped completely and now shows previews for each style
  • Curve fitting functionality has been added to Graphs
  • Graphs can now open data as well as Graphs project files directly from the file manager
  • When closing the application while unsaved changes are present, a dialog is now shown allowing you to save the data
  • The active project and its directory are now shown in the headerbar, including an indicator for unsaved changes
  • Graphs now includes forwards/backwards buttons to quickly navigate to the next and previous view
  • The smoothening action can now be configured with a choice of two different filters, a rolling average and a LOESS Savitzky-Gotsky filter
  • A new Yaru style has been added, which is set as the default system style for the Snap package when Yaru is used in the system, offering a more consistent experience
  • The default matplotlib style has been added to Graphs
  • The title font size can now be changed with respect to the overall font size
  • New scaling options are available for the axes, allowing for radian, square root and inverse scaling
  • Transparent colours for the curves are now supported
  • Superscript characters are now supported when entering equations
  • Support has been added for cotangents, secants and cosecants for equations and transformations
  • Headers are now written to exported files if present in the originally imported data
  • Style sheets now allow you to choose whether a frame should be drawn around the axes
  • The size of the title and labels can now be set seperately in the style editor
  • Importing column data is now more robust, supporting expressions as data points
  • Pinch and ctrl+scroll to zoom gestures are now supported on the canvas
  • The canvas can now be panned using two fingers on a touch screen, as well as with the middle mouse button
  • Toasts now show an "Open Location" button when saving data, bringing you to the saved file location
  • Translate/multiply entries now get a red CSS when input value is invalid, while the corresponding button is disabled

Changed behaviour:

  • Several linguistic changes were made, to get a clearer and more consistent description
  • The syntax for equations has been simplified
  • Delimiters can now be specified from a dropdown menu instead of having to rely on regex
  • The used axes limits are now saved when saving/loading a project
  • Settings related to specific axes are now only displayed when the axis is in use
  • The preferences have been redesigned and simplified, leaving only a single dialog for the figure settings
  • The drag and drop animation when moving items has been improved
  • The headerbar now follows the color of the used stylesheet, giving a more unified look
  • The shortcuts have been modified to follow the rest of the GNOME ecosystem
  • The logic for placing the legend has been changed, so that it now properly moves away when it intersects with a curve
  • The behaviour of the "Shift" action has been revamped to be more consistent when only part of the data span is selected

Bugfixes and changes under the hood:

  • Graphs has been migrated to GNOME 45, and uses the new Libadwaita 1.4 widgets
  • Number inputs are now handled safely without calling the Python eval function
  • The clipboard implementation has been rewritten from scratch
  • The scale buttons in the view menu are now properly changed when the scale has been changed from the figure settings
  • Automatic scaling is now handled properly even when the dataset contains infinite values
  • Graphs now uses unit tests, reducing the risk of regression bugs
  • Part of the code-base has been migrated to Vala
  • Fixed a bug where "Skip rows" did not work properly with single-column data
  • Fixed a bug where rows would change width when selected in case they are adjecent to other entry rows.
  • Graphs translations are now hosted on Weblate
  • More smaller changes and fixes throughout the code-base

Minor patch with some bug fixes:

  • Fixed a bug where "Export Figure" and "Preferences" could not be loaded
  • The "Add data from file" dialog now has filters to make it easier to find the required files.
  • Fixes a bug where the first data point would not be loaded
  • Fixed a bug all styles in the style manager had a check-mark if the system preferred style was used.
  • Fixed a bug where the legend would not be removed from the graph when toggled off, until it was completely reloaded.
  • Automatic axes limits are no longer rounded, which used to lead to problems with the scaling when using data span with a large amount of significant digits.
  • Removed some shortcuts that were overlapping with typing a capital character, making it difficult to write a capital for the respective characters in titles and labels.

New in Graphs:

  • Data can now be opened directly from project files.
  • Adds Dutch translation for Graphs.
  • Adds Turkish translation for Graphs.
  • Adds Swedish translation for Graphs.

Changes:

  • Graphs now always follows the preset system style, unless custom style is set
  • Action dialogs have been changed to follow the GNOME HIG.
  • Regular and advanced import have been merged, offering a single method to import data
  • Labels are now set as an item attribute when loading a new data set with headers, data will be plotted on a new axis when different data types are added.
  • Axis limits are now persistent when saving and opening projects.
  • The axis limits are now reset more intelligently, resulting in fewer unneeded resets
  • Graphs now uses GFile when handling data and figures
  • Multiple refactors under the hood

Bugfixes:

  • Fixed an upstream bug in Matplotlib where part of the Graph would be cut off at scaled resolutions.
  • Fixed a bug where the styles could not be deleted
  • Fixed a bug where the styles could not be reset to defaults
  • Fixed a bug where the legend would remain when all data is removed
  • Fixed a bug where Graphs would crash when the name of an item is changed and a new item is selected from the dropdown.

Changes:

  • Add support for .xry file types from Leybold X-Ray apparatus.
  • Add support for single-column files
  • Changed the behaviour of the canvas so that the limits are not reset unnecessarily
  • Started work to add localization support
  • Refactors under-the-hood

Bug fixes:

  • Fixed a bug where data was not saved when multiple files were exported simultaneously

Hotfix update with bug fixes:

  • Fixes a bug that prevents "Add Equation" from generating new data
  • Fixes a bug where a change of item properties was not included in the clipboard when loading a new style
  • Fixes a bug where the "Restore View" did not properly find the correct limits in specific situations

Major Highlights

  • Massive UI overhaul
  • Save and Load functionality
  • Customizable Plot Styles
  • Loads of optimizations and refactors in the background

Detailed Changelist

  • Removed PIP mode
  • Removed Toolbar
  • Sidebar is now responsive
  • Rearranged button layouts
  • Dialogs now save automatically
  • Graph now has three different interaction modes: pan, zoom and select
  • Operation Buttons are now enabled only when items are selected
  • Operations can now be be performed for just a selected span of data
  • Added combine operation
  • Added custom Adwaita stylesheets for the graph
  • Added a function to quickly change axis scale in the view menu
  • Added a notice when no data is loaded
  • Added functionality to save and load a project
  • Graph ornaments like the zoom rectangle and selector overlay now follow the system colors
  • Follow GNOME HIG in regards to keyboard shortcuts
  • Add a warning dialog, when opening a project while data is loaded
  • Separate Item related options into own dialog
  • Added Toasts on some occasions
  • Removed some options in Preferences, Plot Settings and the Item menu
  • Added a Plot Style editor
  • Plot limits can now be set in Plot Settings
  • Added reordering of items via drag and drop
  • Added an option to hide unselected items from the graph
  • Added a dialog before exporting the figure
  • Support for Panalytical .xdrml files
  • Improved clipboard behaviour

Background Changes

  • Loads of optimizations and refactors
  • Migrate to GNOME 44
  • Blueprint is now used for the UI
  • Introduce linting and follow PEP8
  • Many fixed bugs and edge cases

Minor update with updated AppID.

  • The sidebar is now retractable
  • Graphs now uses symbolic GNOME icons in the toolbar wherever possible
  • The legend is now accomponied with a frame for all styles in order to improve readability
  • Some code clean-up has been performed
  • The new app-id for Graphs is now se.sjoerd.Graphs

Major update with a significant UI overhaul.

New in Graphs:

  • The data list has been completely redesigned, with a selection mode toggle to select/deselect data sets
  • The action grid on the left has been replaced by Expander Rows, sorting the actions by category
  • Checkboxes in settings have been replaced by switches
  • Old entry rows have been replaced by AdwEntryRows
  • The save data button has been moved to the header bar
  • There's no longer an error shown when a new config file is loaded (such as on initial setup)
  • There's now multiple options to choose from on how to handle data with the same name
  • The translation and multiplication transforms now also accept basic expressions (such as 1/2 instead of 0.5)

Bugfixes and other changes:

  • "Shift vertically" option now works properly on linear scale as well
  • Fixed a bug where the last graph to be deleted was still shown
  • Fixed a bug where the text in the dropdown menu of plot-settings didn't update when changing the name of a data set
  • Fourier transforms are now sorted so that the x-data is continiously increasing
  • Added new screenshots for Flathub
  • Some code clean-up has been performed

Minor update with some bugfixes, plus a new logo!

New in Graphs:

  • Graphs has a new icon that is more in-line with the GNOME guidelines!

Bugfixes:

  • Fixed a bug where the graph lines was drawn on top of the legend in certain cases
  • Fixed a bug where the legend wasn't shown for the picture-in-picture graph

Slightly bigger update than usual, with new features and some bug fixes.

New in Graphs:

  • Added the ability to get the derivative of the data
  • Added the ability to get the indefinite integral of the data
  • Added the ability to get the Fast Fourier Transform of the data
  • Added the ability to get the Inverse Fast Fourier Transform of the data
  • Added preference options for the default settings in the "Add equation" window
  • Added tooltips for all buttons on the main window

Other Changes:

  • Default graph limits have been improved, most prominently the y-axis scaling on a linear scale now shows a small margin in both directions if the y-data has a constant value
  • Changed the "reset view" button to use Graph's own canvas limits function, as the built-in version of the toolbar didn't always work properly
  • Gave the "Save Data" option a blue "Suggested action" colour
  • Update Screenshots on Flathub

Bugfixes:

  • Fixed a bug where the x-axis limits were not applied properly if the y-axis was on the right-hand side
  • Fixed a bug where equations would not function without having an X variable. (e.g. Y = 5 is now an accepted equation)
  • Fixed a bug where the initial values for data generated by equation were not added to the clipboard, making it possible to "undo" to the initial state

Minor update mostly focused on the color picker, plus minor quality of life stuff.

  • Changed the color picker to a pop-over window
  • Data set no longer deselects when changing the color
  • Removed the file extensions in the label used for each data set
  • When saving multiple files, files that already exists are saved with a (copy) suffix instead of overwriting the existing file
  • Minor code cleanup

Minor update:

  • Made all pop-up windows modal
  • Added the ability to change axes labels and the title of the plot by double clicking

Brings some minor quality of life features.

  • Ctrl+S now opens the Save Data dialog
  • Fixed a bug where custom settings for tick positions no longer worked properly

Probably last update of the year, most noteworthy is the ability to plot data on right and bottom axis independently. Operations on cutting data still work seamlessly, even when using different axes! Next few updates will probably mainly focus on polish and code clean-up.

  • Added the option to plot data on the right-hand axis
  • Added the option to plot data on the top axis
  • Added the ability to use different labels for right and top axis
  • Scaling of top-bottom and right-left is now handled independently
  • Added a series of toast pop-ups for common actions and errors
  • Made some linguistic changes

Hot-fix update, fixes some bugs with the new "plot settings" window

  • Fixed a bug where the axes labels and title would go back to default when plot settings was opened twice
  • Fixed a bug where the new font wouldn't properly display in plot settings menu
  • Fixed a bug where shortcut would stop working after opening plot settings menu
  • Added a shortcut to open plot settings menu (ctrl+shift+p)
  • Reordered Flathub screenshots

With the ability to edit axes properties without changing the default settings, all essential features are in and it's time to declare v1.2.0. Also added some QoL features. Still many ideas are yet to be implemented. See current changelog below:

  • The "Plot Settings" button now also contains a tab to edit the axes properties
  • The pop-up graph now follows the same scaling as the regular graph
  • Added a shortcut to select all data sets
  • Added a shortcut to deselect all data sets
  • Pressing delete now deletes all selected data sets
  • Changed the wording in "Transform Data" ui to be less confusing
  • Tweaked the save icon a bit
  • Updated Flathub description
  • Made new screenshots for Flathub
  • Changed the webpage to direct to the landing page of Graphs (under construction)

Minor update:

  • Added a "Plot settings" option to control the individual line settings
  • Added a pop-up button to show the graph in a separate window
  • Gave certain buttons a blue "Suggested action" colour
  • Fixed a bug where the advanced column choice didn't work for column indices higher than 1'
  • Some minor bug fixes

Minor update, next update will add an option to control individual line settings (e.g. thickness and style):

  • Cleaned up preferences, making it easier to find the correct setting
  • Linguistic chances
  • Minor UI tweaks in the pop up windows
  • Groundwork for the individual line settings in the code

Major update:

  • Improved the UI for the "Add equation" and "Transform data" windows
  • Added import settings
  • Added an advanced import setting
  • Changed the "general" tab in settings to be the default view
  • Changed screenshots for Flathub
  • Changed capitalization to be more in line with the GNOME HIG
  • Other minor linguistic changes

Minor update with some bug fixes, next update will focus on adding more options for file imports:

  • Fixed a bug where files with a special character in the name didn't save
  • Fixed a bug where minor ticks would show anyway when ticks were turned off
  • Configuration now resets when new options are detected (instead of crashing the application)
  • Added an option to allow for duplicate filenames when importing

Name change and more bugfixes

  • Changed the name of the application to be more in line with the GNOME HIG
  • Transformation window can be closed with the escape button
  • Fixed a bug where graph would not plot if any of the values where infinite (e.g. if equation Y = 1/X was plotted)
  • Step-size, X-start and X-stop in add-equation window now also handle numpy notation

Minor update with some bugfixes

  • Add equation window can now be closed with the escape button
  • File chooser dialog and preference dialogs are modal (stick to parent window)
  • Remove arrow from hamburger menu
  • Add a placeholder hint to Add equation window name
  • Changed saving behaviour to allow saving files without file system access for flatpak
  • Fixed a bug in the add equation window where powers were not working
  • Fixed a bug in add equation window where duplicate filenames were not detected properly

Initial release

Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/se.sjoerd.Graphs.mime.xml000066400000000000000000000011341520337127000264370ustar00rootroot00000000000000 Graphs Project File Graphs Graphs Project File matplotlib Style File mplstyle matplotlib style Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/se.sjoerd.Graphs.service.in000066400000000000000000000001221520337127000267520ustar00rootroot00000000000000[D-BUS Service] Name=@APPLICATION_ID@ Exec=@BINDIR@/graphs --gapplication-service Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/style.css000066400000000000000000000025621520337127000235300ustar00rootroot00000000000000.style-grid { background: none; } .style-grid child { margin: 6px 6px 6px 6px; } .style-grid child:selected { background: none; } .style-grid child:hover { background: none; } .style-grid child picture { border-radius: 12px; box-shadow: 0 0 0 1px @borders; } .style-grid child:selected picture { box-shadow: 0 0 0 3px @theme_selected_bg_color; } .style-grid child:focus { outline-style: none; } .style-grid child:focus picture { outline: 0 solid transparent; outline-color: alpha(@theme_selected_bg_color, .5); outline-width: 2px; outline-offset: 2px; transition: outline-color 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-width 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94), outline-offset 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); } .style-grid child image#indicator { opacity: 0; } .style-grid child:selected image#indicator { color: @theme_selected_bg_color; opacity: 1; } .drag-overlay-status-page { background-color: color-mix(in srgb, var(--accent-bg-color), transparent); color: var(--accent-fg-color); padding: 32px; } .blurred { filter: blur(6px); } .drag-overlay { box-shadow: none; } .import-mode { background: color-mix(in srgb, currentColor 10%, transparent); color: inherit; border-radius: 99px; padding-top: 3px; padding-bottom: 3px; padding-left: 6px; padding-right: 6px; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/000077500000000000000000000000001520337127000231745ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/adwaita-dark.mplstyle000066400000000000000000000045731520337127000273310ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Adwaita Dark #~graphs ticklabels: False #~graphs errorbar.capthick: 1.2 #~graphs errorbar.capsize: 3.0 #~graphs errorbar.linewidth: 1.2 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: FFFFFF # font font.family: sans-serif font.sans-serif: Adwaita Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 3 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: False axes.spines.left: False axes.spines.top: False axes.spines.right: False # ticks xtick.direction: in xtick.minor.visible: True xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: in ytick.minor.visible: True ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: False ytick.right: False # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.6 grid.alpha: 0.6 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: FFFFFF axes.labelcolor: FFFFFF xtick.labelcolor: FFFFFF ytick.labelcolor: FFFFFF xtick.color: C0BFBC ytick.color: C0BFBC axes.edgecolor: C0BFBC grid.color: 77767B axes.facecolor: 222226 figure.facecolor: 222226 figure.edgecolor: 222226 axes.prop_cycle: cycler('color', ['1A5FB4', '26A269', 'E5A50A', 'C64600', 'A51D2D', '613583', '63452C', '9A9996']) patch.facecolor: 1A5FB4 # other axes.linewidth: 0.8 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.linewidth: 1 image.cmap: Greys legend.numpoints: 1 legend.scatterpoints: 1 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/adwaita.mplstyle000066400000000000000000000045671520337127000264150ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Adwaita #~graphs ticklabels: False #~graphs errorbar.capthick: 1.2 #~graphs errorbar.capsize: 3.0 #~graphs errorbar.linewidth: 1.2 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 000000 # font font.family: sans-serif font.sans-serif: Adwaita Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 3 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: False axes.spines.left: False axes.spines.top: False axes.spines.right: False # ticks xtick.direction: in xtick.minor.visible: True xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: in ytick.minor.visible: True ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: False ytick.right: False # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.6 grid.alpha: 0.6 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 000000 axes.labelcolor: 000000 xtick.labelcolor: 000000 ytick.labelcolor: 000000 xtick.color: 5E5C64 ytick.color: 5E5C64 axes.edgecolor: 5E5C64 grid.color: 9A9996 axes.facecolor: FAFAFB figure.facecolor: FAFAFB figure.edgecolor: FAFAFB axes.prop_cycle: cycler('color', ['1A5FB4', '26A269', 'E5A50A', 'C64600', 'A51D2D', '613583', '63452C', '9A9996']) patch.facecolor: 1A5FB4 # other axes.linewidth: 0.8 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.linewidth: .3 image.cmap: Greys legend.numpoints: 1 legend.scatterpoints: 1 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/bmh.mplstyle000066400000000000000000000046411520337127000255420ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: BMH #~graphs ticklabels: False #~graphs errorbar.capthick: 2 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 2 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 262626 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 legend.fontsize: 12 figure.labelsize: 12 figure.titlesize: 16 axes.titlesize: 16 # lines lines.linewidth: 2 lines.linestyle: solid lines.marker: none lines.markersize: 6 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0.5 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: projecting lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: in xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment : center ytick.direction: in ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: True ytick.right: True # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.5 grid.alpha: 1.0 grid.linestyle: -- # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 262626 axes.labelcolor: 262626 xtick.labelcolor: 262626 ytick.labelcolor: 262626 xtick.color: 262626 ytick.color: 262626 axes.edgecolor: BCBCBC grid.color: B2B2B2 axes.facecolor: EEEEEE figure.facecolor: FFFFFF figure.edgecolor: FFFFFF axes.prop_cycle: cycler('color', ['348ABD', 'A60628', '7A68A6', '467821', 'D55E00', 'CC79A7', '56B4E9', '009E73', 'F0E442', '0072B2']) patch.facecolor: 348ABD # other axes.linewidth: 1 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.linewidth: 0.5 patch.edgecolor: eeeeee patch.antialiased: True text.hinting_factor: 8 mathtext.fontset: cmGraphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/classic.mplstyle000066400000000000000000000146741520337127000264240ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Classic #~graphs ticklabels: False #~graphs errorbar.capthick: 1 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 1 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 000000 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 1.0 lines.linestyle: solid lines.marker: none lines.markersize: 6 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0.5 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: projecting lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: in xtick.minor.visible: False xtick.major.width: 0.5 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: in ytick.minor.visible: False ytick.major.width: 0.5 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: True ytick.right: True # grid axes.grid: False axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.5 grid.alpha: 1.0 grid.linestyle: : # padding xtick.major.pad: 4 xtick.minor.pad: 4 ytick.major.pad: 4 ytick.minor.pad: 4 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 000000 axes.labelcolor: 000000 xtick.labelcolor: 000000 ytick.labelcolor: 000000 xtick.color: 000000 ytick.color: 000000 axes.edgecolor: 000000 grid.color: 000000 axes.facecolor: FFFFFF figure.facecolor: BFBFBF figure.edgecolor: BFBFBF axes.prop_cycle: cycler('color', ['0000FF', '008000', 'FF0000', '00BFBF', 'BF00BF', 'BFBF00', '000000']) patch.facecolor: 0000FF # other axes.linewidth: 1.0 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.linewidth: 1.0 patch.force_edgecolor: True patch.edgecolor: k patch.antialiased: True hatch.color: k hatch.linewidth: 1.0 hist.bins: 10 font.stretch: normal font.serif: DejaVu Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif font.cursive: Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, cursive font.fantasy: Comic Sans MS, Chicago, Charcoal, ImpactWestern, Humor Sans, fantasy font.monospace: DejaVu Sans Mono, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace text.usetex: False text.hinting_factor: 8 text.antialiased: True mathtext.cal: cursive mathtext.rm: serif mathtext.tt: monospace mathtext.it: serif:italic mathtext.bf: serif:bold mathtext.sf: sans\-serif mathtext.fontset: cm mathtext.fallback: cm axes.titley: 1.0 axes.formatter.limits: -7, 7 axes.formatter.use_locale: False axes.formatter.use_mathtext: False axes.formatter.useoffset: True axes.formatter.offset_threshold: 2 axes.unicode_minus: True axes.autolimit_mode: round_numbers axes.xmargin: 0 axes.ymargin: 0 polaraxes.grid: True axes3d.grid: True date.autoformatter.year: %Y date.autoformatter.month: %b %Y date.autoformatter.day: %b %d %Y date.autoformatter.hour: %H:%M:%S date.autoformatter.minute: %H:%M:%S.%f date.autoformatter.second: %H:%M:%S.%f date.autoformatter.microsecond: %H:%M:%S.%f date.converter: auto legend.numpoints: 2 legend.borderpad: 0.4 legend.markerscale: 1.0 legend.labelspacing: 0.5 legend.handlelength: 2. legend.handleheight: 0.7 legend.handletextpad: 0.8 legend.borderaxespad: 0.5 legend.columnspacing: 2. legend.shadow: False legend.framealpha: None legend.scatterpoints: 3 legend.facecolor: inherit legend.edgecolor: inherit figure.dpi: 80 figure.autolayout: False figure.frameon: True figure.subplot.left: 0.125 figure.subplot.right: 0.9 figure.subplot.bottom: 0.1 figure.subplot.top: 0.9 figure.subplot.wspace: 0.2 figure.subplot.hspace: 0.2 image.aspect: equal image.interpolation: bilinear image.cmap: jet image.lut: 256 image.origin: upper image.resample: False image.composite_image: True contour.negative_linestyle: dashed contour.corner_mask: True errorbar.capsize: 3 scatter.marker: o boxplot.bootstrap: None boxplot.boxprops.color: b boxplot.boxprops.linestyle: - boxplot.boxprops.linewidth: 1.0 boxplot.capprops.color: k boxplot.capprops.linestyle: - boxplot.capprops.linewidth: 1.0 boxplot.flierprops.color: b boxplot.flierprops.linestyle: none boxplot.flierprops.linewidth: 1.0 boxplot.flierprops.marker: + boxplot.flierprops.markeredgecolor: k boxplot.flierprops.markerfacecolor: auto boxplot.flierprops.markersize: 6.0 boxplot.meanline: False boxplot.meanprops.color: r boxplot.meanprops.linestyle: - boxplot.meanprops.linewidth: 1.0 boxplot.medianprops.color: r boxplot.meanprops.marker: s boxplot.meanprops.markerfacecolor: r boxplot.meanprops.markeredgecolor: k boxplot.meanprops.markersize: 6.0 boxplot.medianprops.linestyle: - boxplot.medianprops.linewidth: 1.0 boxplot.notch: False boxplot.patchartist: False boxplot.showbox: True boxplot.showcaps: True boxplot.showfliers: True boxplot.showmeans: False boxplot.vertical: True boxplot.whiskerprops.color: b boxplot.whiskerprops.linestyle: -- boxplot.whiskerprops.linewidth: 1.0 boxplot.whiskers: 1.5 agg.path.chunksize: 0 path.simplify: True path.simplify_threshold: 0.1111111111111111 path.snap: True path.sketch: None ps.papersize: letter ps.useafm: False ps.usedistiller: False ps.distiller.res: 6000 ps.fonttype: 3 pdf.compression: 6 pdf.fonttype: 3 pdf.inheritcolor: False pdf.use14corefonts: False pgf.texsystem: xelatex pgf.rcfonts: True pgf.preamble: svg.image_inline: True svg.fonttype: path keymap.fullscreen: f, ctrl+f keymap.home: h, r, home keymap.back: left, c, backspace keymap.forward: right, v keymap.pan: p keymap.zoom: o keymap.save: s, ctrl+s keymap.quit: ctrl+w, cmd+w keymap.grid: g keymap.yscale: l keymap.xscale: k, L animation.writer : ffmpeg animation.codec : mpeg4 animation.bitrate: -1 animation.frame_format: png animation.ffmpeg_path: ffmpeg animation.ffmpeg_args: animation.convert_path: convert animation.convert_args: animation.html: none _internal.classic_mode: TrueGraphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/dark-background.mplstyle000066400000000000000000000047741520337127000300410ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Dark Background #~graphs ticklabels: False #~graphs errorbar.capthick: 1 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 1 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: FFFFFF # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 1 lines.linestyle: solid lines.marker: none lines.markersize: 6 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0.5 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: projecting lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: True ytick.right: True # grid axes.grid: False axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.5 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: FFFFFF axes.labelcolor: FFFFFF xtick.labelcolor: FFFFFF ytick.labelcolor: FFFFFF xtick.color: FFFFFF ytick.color: FFFFFF axes.edgecolor: FFFFFF grid.color: FFFFFF axes.facecolor: 000000 figure.facecolor: 000000 figure.edgecolor: 000000 axes.prop_cycle: cycler('color', ['8DD3C7', 'FEFFB3', 'BFBBD9', 'FA8174', '81B1D2', 'FBD462', 'B3DE69', 'BC82BD', 'CCEBC4', 'FFED6F']) patch.facecolor: 8DD3C7 # other axes.linewidth: 1 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.edgecolor: white boxplot.boxprops.color: white boxplot.capprops.color: white boxplot.flierprops.color: white boxplot.flierprops.markeredgecolor: white boxplot.whiskerprops.color: whiteGraphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/fivethirtyeight.mplstyle000066400000000000000000000047071520337127000302150ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: FiveThirtyEight #~graphs ticklabels: False #~graphs errorbar.capthick: 2 #~graphs errorbar.capsize: 4 #~graphs errorbar.linewidth: 2 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 008FD5, FC4F30, E5AE38, 6D904F, 8B8B8B, 810F7C # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 14 axes.labelsize: 14 xtick.labelsize: 14 ytick.labelsize: 14 axes.titlesize: 14 legend.fontsize: 14 figure.titlesize: 14 figure.labelsize: 14 # lines lines.linewidth: 4 lines.linestyle: solid lines.marker: none lines.markersize: 6 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0.5 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: butt lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 0 xtick.minor.width: 0 xtick.major.size: 0 xtick.minor.size: 0 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 0 ytick.minor.width: 0 ytick.major.size: 0 ytick.minor.size: 0 ytick.alignment: center xtick.bottom: False ytick.left: False xtick.top: False ytick.right: False # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 1.0 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 262626 axes.labelcolor: 262626 xtick.labelcolor: 262626 ytick.labelcolor: 262626 xtick.color: 262626 ytick.color: 262626 axes.edgecolor: F0F0F0 grid.color: CBCBCB axes.facecolor: F0F0F0 figure.facecolor: F0F0F0 figure.edgecolor: F0F0F0 axes.prop_cycle: cycler('color', ['008FD5', 'FC4F30', 'E5AE38', '6D904F', '8B8B8B', '810F7C']) patch.facecolor: 008FD5 # other axes.linewidth: 3 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.edgecolor: f0f0f0 patch.linewidth: 0.5 svg.fonttype: path figure.subplot.left: 0.08 figure.subplot.right: 0.95 figure.subplot.bottom: 0.07Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/ggplot.mplstyle000066400000000000000000000045341520337127000262710ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: ggplot #~graphs ticklabels: False #~graphs errorbar.capthick: 1 #~graphs errorbar.capsize: 3 #~graphs errorbar.linewidth: 1 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 000000 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 10 axes.labelsize: 10 xtick.labelsize: 10 ytick.labelsize: 10 axes.titlesize: 10 legend.fontsize: 10 figure.titlesize: 10 figure.labelsize: 10 # lines lines.linewidth: 1.0 lines.linestyle: solid lines.marker: none lines.markersize: 6 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0.5 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: projecting lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: True ytick.right: True # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.5 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 555555 axes.labelcolor: 555555 xtick.labelcolor: 555555 ytick.labelcolor: 555555 xtick.color: 555555 ytick.color: 555555 axes.edgecolor: FFFFFF grid.color: FFFFFF axes.facecolor: E5E5E5 figure.facecolor: FFFFFF figure.edgecolor: FFFFFF axes.prop_cycle: cycler('color', ['E24A33', '348ABD', '988ED5', '777777', 'FBC15E', '8EBA42', 'FFB5B8']) patch.facecolor: E24A33 # other axes.linewidth: 1 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.linewidth: 0.5 patch.edgecolor: EEEEEE patch.antialiased: TrueGraphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/grayscale.mplstyle000066400000000000000000000044461520337127000267510ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Grayscale #~graphs ticklabels: False #~graphs errorbar.capthick: 1 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 1 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 000000 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 1.0 lines.linestyle: solid lines.marker: none lines.markersize: 6 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0.5 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: projecting lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: True ytick.right: True # grid axes.grid: False axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.5 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 000000 axes.labelcolor: 000000 xtick.labelcolor: 000000 ytick.labelcolor: 000000 xtick.color: 000000 ytick.color: 000000 axes.edgecolor: 000000 grid.color: 000000 axes.facecolor: FFFFFF figure.facecolor: BFBFBF figure.edgecolor: BFBFBF axes.prop_cycle: cycler('color', ['000000', '666666', '999999', 'B3B3B3']) patch.facecolor: 000000 # other axes.linewidth: 1 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.edgecolor: black image.cmap: grayGraphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/matplotlib.mplstyle000066400000000000000000000047471520337127000271520ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Matplotlib #~graphs ticklabels: False #~graphs errorbar.capthick: 1.5 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 1.5 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 1F77B4, FF7F0E, 2CA02C, D62728', 9467BD, 8C564B, E377C2, 7F7F7F, BCBD22, 17BECF # font font.family: sans-serif font.sans-serif: DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 10 axes.labelsize: 10 xtick.labelsize: 10 ytick.labelsize: 10 axes.titlesize: 10 legend.fontsize: 10 figure.titlesize: 10 figure.labelsize: 10 # lines lines.linewidth: 1.5 lines.linestyle: solid lines.marker: none lines.markersize: 6.0 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 1.0 lines.antialiased: True lines.scale_dashes: True markers.fillstyle: full #axes axes.spines.bottom: True axes.spines.left: True axes.spines.right: True axes.spines.top: True #ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 0.8 xtick.minor.width: 0.6 xtick.major.size: 3.5 xtick.minor.size: 2.0 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 0.8 ytick.minor.width: 0.6 ytick.major.size: 3.5 ytick.minor.size: 2.0 ytick.alignment: center_baseline xtick.bottom: True ytick.left: True xtick.top: False ytick.right: False # grid axes.grid: False axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.8 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 3.5 xtick.minor.pad: 3.5 ytick.major.pad: 3.5 ytick.minor.pad: 3.5 axes.labelpad: 4.0 axes.titlepad: 6.0 # colors text.color: 000000 axes.labelcolor: 000000 xtick.labelcolor: 000000 ytick.labelcolor: 000000 xtick.color: 000000 ytick.color: 000000 axes.edgecolor: 000000 grid.color: b0b0b0 axes.facecolor: FFFFFF figure.facecolor: FFFFFF figure.edgecolor: FFFFFF axes.prop_cycle: cycler('color', ['1F77B4', 'FF7F0E', '2CA02C', 'D62728', '9467BD', '8C564B', 'E377C2', '7F7F7F', 'BCBD22', '17BECF']) patch.facecolor: 1f77b4 # other axes.linewidth: 0.8 patch.antialiased: True patch.edgecolor: 000000 mathtext.default: regular axes.axisbelow: line legend.fancybox: True legend.frameon: True # custom patch.linewidth: 1.0 image.cmap: viridis legend.numpoints: 1 legend.scatterpoints: 1 Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/seaborn-white.mplstyle000066400000000000000000000045331520337127000275430ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Seaborn White #~graphs ticklabels: False #~graphs errorbar.capthick: 1.75 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 1.75 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 262626 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 1.75 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 6 xtick.minor.size: 3 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 6 ytick.minor.size: 3 ytick.alignment: center xtick.bottom: False ytick.left: False xtick.top: False ytick.right: False # grid axes.grid: False axes.grid.which: major axes.grid.axis: both grid.linewidth: 1.0 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 262626 axes.labelcolor: 262626 xtick.labelcolor: 262626 ytick.labelcolor: 262626 xtick.color: 262626 ytick.color: 262626 axes.edgecolor: 262626 grid.color: CCCCCC axes.facecolor: FFFFFF figure.facecolor: FFFFFF figure.edgecolor: FFFFFF axes.prop_cycle: cycler('color', ['4C72B0', '55A868', 'C44E52', '8172B2', 'CCB974', '64B5CD']) patch.facecolor: 4C72B0 # other axes.linewidth: 1.25 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom legend.numpoints: 1 legend.scatterpoints: 1 image.cmap: Greys Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/seaborn-whitegrid.mplstyle000066400000000000000000000045331520337127000304110ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Seaborn Whitegrid #~graphs ticklabels: False #~graphs errorbar.capthick: 1.75 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 1.75 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 262626 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 1.75 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 6 xtick.minor.size: 3 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 6 ytick.minor.size: 3 ytick.alignment: center xtick.bottom: False ytick.left: False xtick.top: False ytick.right: False # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 1.0 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 262626 axes.labelcolor: 262626 xtick.labelcolor: 262626 ytick.labelcolor: 262626 xtick.color: 262626 ytick.color: 262626 axes.edgecolor: CCCCCC grid.color: CCCCCC axes.facecolor: FFFFFF figure.facecolor: FFFFFF figure.edgecolor: FFFFFF axes.prop_cycle: cycler('color', ['4C72B0', '55A868', 'C44E52', '8172B2', 'CCB974', '64B5CD']) patch.facecolor: 4C72B0 # other axes.linewidth: 1 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom legend.numpoints: 1 legend.scatterpoints: 1 image.cmap: Greys Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/seaborn.mplstyle000066400000000000000000000045451520337127000264300ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Seaborn #~graphs ticklabels: False #~graphs errorbar.capthick: 1.75 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 1.75 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 262626 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 1.75 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 6 xtick.minor.size: 3 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 6 ytick.minor.size: 3 ytick.alignment: center xtick.bottom: False ytick.left: False xtick.top: False ytick.right: False # grid axes.grid: False axes.grid.which: major axes.grid.axis: both grid.linewidth: 1.0 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 262626 axes.labelcolor: 262626 xtick.labelcolor: 262626 ytick.labelcolor: 262626 xtick.color: 262626 ytick.color: 262626 axes.edgecolor: FFFFFF grid.color: FFFFFF axes.facecolor: EAEAF2 figure.facecolor: FFFFFF figure.edgecolor: FFFFFF axes.prop_cycle: cycler('color', ['4C72B0', '55A868', 'C44E52', '8172B2', 'CCB974', '64B5CD']) patch.facecolor: 4C72B0 # other axes.linewidth: 0 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom image.cmap: Greys legend.numpoints: 1 legend.scatterpoints: 1 patch.linewidth: .3Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/solarized-light.mplstyle000066400000000000000000000044701520337127000300750ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Solarized Light #~graphs ticklabels: False #~graphs errorbar.capthick: 2 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 2 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 657B83 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 legend.fontsize: 12 figure.labelsize: 12 axes.titlesize: 16 figure.titlesize: 16 # lines lines.linewidth: 2 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: butt lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: True ytick.right: True # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 1.0 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 657B83 axes.labelcolor: 657B83 xtick.labelcolor: 657B83 ytick.labelcolor: 657B83 xtick.color: 657B83 ytick.color: 657B83 axes.edgecolor: EEE8D5 grid.color: FDF6E3 axes.facecolor: EEE8D5 figure.facecolor: FDF6E3 figure.edgecolor: FDF6E3 axes.prop_cycle: cycler('color', ['268BD2', '2AA198', '859900', 'B58900', 'CB4B16', 'DC322F', 'D33682', '6C71C4']) patch.facecolor: 268BD2 # other axes.linewidth: 1 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.antialiased: TrueGraphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/tableau-colorblind10.mplstyle000066400000000000000000000044721520337127000307010ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Tableau Colorblind10 #~graphs ticklabels: False #~graphs errorbar.capthick: 1.75 #~graphs errorbar.capsize: 0 #~graphs errorbar.linewidth: 1.75 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 657B83 # font font.family: sans-serif font.sans-serif: DejaVu Sans font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 1.75 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: out xtick.minor.visible: False xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: out ytick.minor.visible: False ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: True ytick.right: True # grid axes.grid: False axes.grid.which: major axes.grid.axis: both grid.linewidth: 1.0 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 262626 axes.labelcolor: 262626 xtick.labelcolor: 262626 ytick.labelcolor: 262626 xtick.color: 262626 ytick.color: 262626 axes.edgecolor: FFFFFF grid.color: FFFFFF axes.facecolor: EAEAF2 figure.facecolor: FFFFFF figure.edgecolor: FFFFFF axes.prop_cycle: cycler('color', ['006BA4', 'FF800E', 'ABABAB', '595959', '5F9ED1', 'C85200', '898989', 'A2C8EC', 'FFBC79', 'CFCFCF']) patch.facecolor: 006BA4 # other axes.linewidth: 1 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: TrueGraphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/thesis.mplstyle000066400000000000000000000045541520337127000262760ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Thesis #~graphs ticklabels: False #~graphs errorbar.capthick: 1.2 #~graphs errorbar.capsize: 4.0 #~graphs errorbar.linewidth: 1.2 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 000000 # font font.family: sans-serif font.sans-serif: Cantarell font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 3 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: True axes.spines.left: True axes.spines.top: True axes.spines.right: True # ticks xtick.direction: in xtick.minor.visible: True xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 8 xtick.minor.size: 4 xtick.alignment: center ytick.direction: in ytick.minor.visible: True ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 8 ytick.minor.size: 4 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: True ytick.right: True # grid axes.grid: False axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.6 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 000000 axes.labelcolor: 000000 xtick.labelcolor: 000000 ytick.labelcolor: 000000 xtick.color: 000000 ytick.color: 000000 axes.edgecolor: 000000 grid.color: 646464 axes.facecolor: FFFFFF figure.facecolor: FFFFFF figure.edgecolor: FFFFFF axes.prop_cycle: cycler('color', ['BF1926', '1970D7', '33A02C', 'FF7F00', 'A6CEE3', 'B2DF8A', 'FB9A99', 'FDBF6F', 'CAB2D6']) patch.facecolor: E24A33 # other axes.linewidth: 1 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.linewidth: 0.5 patch.edgecolor: EEEEEE patch.antialiased: True Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/yaru-dark.mplstyle000066400000000000000000000045641520337127000266770ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Yaru Dark #~graphs ticklabels: False #~graphs errorbar.capthick: 1.2 #~graphs errorbar.capsize: 3.0 #~graphs errorbar.linewidth: 1.2 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: FFFFFF # font font.family: sans-serif font.sans-serif: Cantarell font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 3 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: False axes.spines.left: False axes.spines.top: False axes.spines.right: False # ticks xtick.direction: in xtick.minor.visible: True xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: in ytick.minor.visible: True ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: False ytick.right: False # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.6 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: FFFFFF axes.labelcolor: FFFFFF xtick.labelcolor: FFFFFF ytick.labelcolor: FFFFFF xtick.color: C0BFBC ytick.color: C0BFBC axes.edgecolor: C0BFBC grid.color: 77767B axes.facecolor: 2C2C2C figure.facecolor: 2C2C2C figure.edgecolor: 2C2C2C axes.prop_cycle: cycler('color', ['335280', '0E8420', 'F99B11', 'E95420', 'A91224', '2C001E', '72441D', '878787']) patch.facecolor: 1A5FB4 # other axes.linewidth: 0.8 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.linewidth: 1 image.cmap: Greys legend.numpoints: 1 legend.scatterpoints: 1Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/styles/yaru.mplstyle000066400000000000000000000045601520337127000257540ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later #~graphs name: Yaru #~graphs ticklabels: False #~graphs errorbar.capthick: 1.2 #~graphs errorbar.capsize: 3.0 #~graphs errorbar.linewidth: 1.2 #~graphs errorbar.barsabove: False #~graphs errorbar.color_cycle: 000000 # font font.family: sans-serif font.sans-serif: Cantarell font.style: normal font.weight: 400 axes.titleweight: 400 axes.labelweight: 400 figure.titleweight: 400 figure.labelweight: 400 font.variant: normal font.size: 12 axes.labelsize: 12 xtick.labelsize: 12 ytick.labelsize: 12 axes.titlesize: 12 legend.fontsize: 12 figure.titlesize: 12 figure.labelsize: 12 # lines lines.linewidth: 3 lines.linestyle: solid lines.marker: none lines.markersize: 7 lines.markerfacecolor: auto lines.markeredgecolor: auto lines.markeredgewidth: 0 lines.dash_joinstyle: round lines.dash_capstyle: butt lines.solid_joinstyle: round lines.solid_capstyle: round lines.antialiased: True lines.dashed_pattern: 6, 6 lines.dashdot_pattern: 3, 5, 1, 5 lines.dotted_pattern: 1, 3 lines.scale_dashes: False markers.fillstyle: full # axes axes.spines.bottom: False axes.spines.left: False axes.spines.top: False axes.spines.right: False # ticks xtick.direction: in xtick.minor.visible: True xtick.major.width: 1 xtick.minor.width: 0.5 xtick.major.size: 4 xtick.minor.size: 2 xtick.alignment: center ytick.direction: in ytick.minor.visible: True ytick.major.width: 1 ytick.minor.width: 0.5 ytick.major.size: 4 ytick.minor.size: 2 ytick.alignment: center xtick.bottom: True ytick.left: True xtick.top: False ytick.right: False # grid axes.grid: True axes.grid.which: major axes.grid.axis: both grid.linewidth: 0.6 grid.alpha: 1.0 grid.linestyle: - # padding xtick.major.pad: 7 xtick.minor.pad: 7 ytick.major.pad: 7 ytick.minor.pad: 7 axes.labelpad: 5 axes.titlepad: 15 # colors text.color: 000000 axes.labelcolor: 000000 xtick.labelcolor: 000000 ytick.labelcolor: 000000 xtick.color: 5E5C64 ytick.color: 5E5C64 axes.edgecolor: 5E5C64 grid.color: 9A9996 axes.facecolor: FAFAFA figure.facecolor: FAFAFA figure.edgecolor: FAFAFA axes.prop_cycle: cycler('color', ['335280', '0E8420', 'F99B11', 'E95420', 'A91224', '2C001E', '72441D', '878787']) patch.facecolor: 1A5FB4 # other axes.linewidth: 0.8 mathtext.default: regular axes.axisbelow: True legend.fancybox: True legend.frameon: True # custom patch.linewidth: .3 image.cmap: Greys legend.numpoints: 1 legend.scatterpoints: 1Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/000077500000000000000000000000001520337127000222665ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/add-equation.blp000066400000000000000000000026201520337127000253400ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsAddEquationDialog: Adw.Dialog { content-width: 450; title: _("Add Equation"); default-widget: confirm_button; focus-widget: confirm_button; child: Adw.ToolbarView { [top] Adw.HeaderBar { show-end-title-buttons: false; [start] Button { label: _("Cancel"); action-name: "window.close"; } [end] Button confirm_button { label: _("Add"); clicked => $on_accept(); styles [ "suggested-action", ] } } content: ScrolledWindow { propagate-natural-height: true; child: Viewport { child: Adw.Clamp { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; Adw.PreferencesGroup { separate-rows: true; description: _("Enter a mathematical expression"); Adw.EntryRow equation { max-width-chars: 25; title: _("Y ="); activates-default: true; notify::text => $on_equation_change(); styles [ "preferencesgroup", ] } Adw.EntryRow item_name { max-width-chars: 25; title: _("Name (optional)"); activates-default: true; } } }; }; }; }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/curve-fitting.blp000066400000000000000000000143431520337127000255600ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsCurveFittingDialog: Adw.Dialog { content-width: 1000; content-height: 600; width-request: 360; height-request: 100; focus-widget: confirm_button; ShortcutController { Shortcut { trigger: "F9"; action: "action(win.toggle_sidebar)"; } } Adw.Breakpoint { condition ("max-width: 675sp") setters { split_view.collapsed: true; } } Adw.Breakpoint { condition ("max-height: 500sp") setters { residuals_container.height-request: 150; } } child: Adw.ToolbarView { top-bar-style: flat; content: Adw.OverlaySplitView split_view { enable-show-gesture: bind split_view.collapsed; enable-hide-gesture: bind split_view.collapsed; sidebar: Adw.ToolbarView { [top] Adw.HeaderBar { title-widget: Adw.WindowTitle { title: _("Curve Fitting"); }; [end] MenuButton { icon-name: "view-more-symbolic"; tooltip-text: _("Open Curve Fitting Menu"); primary: true; menu-model: fitting_menu; } } content: Box { orientation: vertical; ScrolledWindow { vexpand: true; width-request: 280; hscrollbar-policy: never; Box { orientation: vertical; margin-start: 12; margin-end: 12; margin-bottom: 12; margin-top: 12; spacing: 12; Adw.PreferencesGroup { Adw.ComboRow equation { title: _("Equation"); model: StringList { strings [ C_("regression-type", "Linear"), C_("regression-type", "Quadratic"), C_("regression-type", "Exponential"), C_("regression-type", "Power Law"), C_("regression-type", "Logarithmic"), C_("regression-type", "Sigmoid Logistic"), C_("regression-type", "Gaussian"), C_("regression-type", "Custom"), ] }; } Adw.EntryRow custom_equation { visible: false; title: _("Y ="); } } Box fitting_params_box { hexpand: true; spacing: 12; orientation: vertical; } ScrolledWindow { hexpand: true; hscrollbar-policy: automatic; vscrollbar-policy: never; propagate-natural-height: true; TextView text_view { left-margin: 12; right-margin: 12; top-margin: 12; bottom-margin: 12; halign: fill; editable: false; styles [ "card", ] } } } } }; [bottom] Adw.Clamp { maximum-size: 400; child: Box { margin-start: 12; margin-end: 12; margin-top: 6; margin-bottom: 12; Button confirm_button { hexpand: true; label: _("Add Fit to Data"); clicked => $on_accept(); styles [ "pill", "suggested-action", ] } }; } }; content: Adw.ToolbarView { styles [ "system-canvas-view", ] [top] Adw.HeaderBar { show-title: false; ToggleButton show_sidebar_button { icon-name: "sidebar-show-symbolic"; tooltip-text: _("Toggle Sidebar"); active: bind split_view.show-sidebar bidirectional; visible: bind split_view.collapsed; } } content: Adw.ToastOverlay toast_overlay { focusable: true; hexpand: true; child: Box { orientation: vertical; hexpand: true; vexpand: true; Adw.Bin canvas_container { hexpand: true; vexpand: true; Adw.StatusPage { visible: false; icon-name: "dialog-error-symbolic"; title: _("Canvas Failed to Load"); } } Adw.Bin residuals_container { hexpand: true; vexpand: false; height-request: 200; visible: false; } }; }; }; }; }; } menu fitting_menu { section { label: _("Optimization Method"); item { // Translators: see https://help.gnome.org/graphs/curve_fitting.html#algorithms label: C_("optimization", "Levenberg-Marquardt"); action: "win.optimization"; target: "lm"; } item { // Translators: see https://help.gnome.org/graphs/curve_fitting.html#algorithms, NOTE: This is a reflective version of the Trust-region algorithm. label: C_("optimization", "Trust Region Reflective"); action: "win.optimization"; target: "trf"; } item { // Translators: see https://help.gnome.org/graphs/curve_fitting.html#algorithms label: C_("optimization", "Dogbox"); action: "win.optimization"; target: "dogbox"; } } section { label: _("Confidence Bounds"); item { label: C_("confidence", "None"); action: "win.confidence"; target: "none"; } item { /* xgettext: no-c-format */ label: C_("confidence", "1σ: 68% Confidence"); action: "win.confidence"; target: "1std"; } item { /* xgettext: no-c-format */ label: C_("confidence", "2σ: 95% Confidence"); action: "win.confidence"; target: "2std"; } item { /* xgettext: no-c-format */ label: C_("confidence", "3σ: 99.7% Confidence"); action: "win.confidence"; target: "3std"; } } section { item { label: _("Show Residuals"); action: "win.show-residuals"; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/dialogs/000077500000000000000000000000001520337127000237105ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/dialogs/beta-disallowed.blp000066400000000000000000000005301520337127000274450ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; Adw.AlertDialog beta_disallowed_dialog { heading: _("Beta Project"); body: _("The project you are trying to import is from a beta version of Graphs. It may contain invalid data."); responses [ continue: _("Continue"), close: _("Abort"), ] close-response: "close"; default-response: "close"; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/dialogs/delete-style.blp000066400000000000000000000003601520337127000270060ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; Adw.AlertDialog delete_style_dialog { heading: _("Delete Style?"); responses [ cancel: _("Cancel"), delete: _("Delete") destructive, ] close-response: "cancel"; default-response: "delete"; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/dialogs/invalid-project.blp000066400000000000000000000003141520337127000274770ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; Adw.AlertDialog invalid_project_dialog { heading: _("Invalid Project"); responses [ close: _("Close"), ] close-response: "close"; default-response: "close"; } legacy-migration-disallowed.blp000066400000000000000000000007101520337127000317060ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/dialogsusing Gtk 4.0; using Adw 1; Adw.AlertDialog legacy_migration_disallowed_dialog { heading: _("Legacy Project"); body: _("You are trying to open a legacy project.\n\nThe legacy project format may contain dangerous code and may cause harm to your system.\n\nOnly proceed if you trust the author of this file."); responses [ continue: _("Continue") destructive, close: _("Abort"), ] close-response: "close"; default-response: "close"; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/dialogs/reset-import-settings.blp000066400000000000000000000004751520337127000307050ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; Adw.AlertDialog reset_import_settings_dialog { heading: _("Reset to Defaults?"); body: _("Are you sure you want to reset the import settings?"); responses [ cancel: _("Cancel"), reset: _("Reset") destructive, ] close-response: "cancel"; default-response: "reset"; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/dialogs/save-project-changes.blp000066400000000000000000000006071520337127000304220ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; Adw.AlertDialog save_project_changes_dialog { heading: _("Save Changes?"); body: _("Current project contains unsaved changes, changes that are not saved will be permanently lost."); responses [ cancel: _("Cancel"), discard: _("Discard") destructive, save: _("Save") suggested, ] close-response: "cancel"; default-response: "discard"; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/dialogs/save-style-changes.blp000066400000000000000000000006031520337127000301100ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; Adw.AlertDialog save_style_changes_dialog { heading: _("Save Changes?"); body: _("Current style contains unsaved changes, changes that are not saved will be permanently lost."); responses [ cancel: _("Cancel"), discard: _("Discard") destructive, save: _("Save") suggested, ] close-response: "cancel"; default-response: "discard"; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/export-figure.blp000066400000000000000000000040761520337127000255740ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsExportFigureDialog: Adw.Dialog { content-width: 450; title: _("Export Figure"); focus-widget: confirm_button; child: Adw.ToolbarView { [top] Adw.HeaderBar { show-end-title-buttons: false; [start] Button { label: _("Cancel"); action-name: "window.close"; } [end] Button confirm_button { label: _("Export"); clicked => $on_accept(); styles [ "suggested-action", ] } } content: Adw.Clamp { maximum-size: 800; margin-bottom: 12; margin-top: 12; margin-start: 12; margin-end: 12; child: Box { orientation: vertical; spacing: 10; Adw.PreferencesGroup { title: _("Export Settings"); Adw.ComboRow file_format { title: _("File Format"); model: StringList { strings [ C_("file-format", "Encapsulated PostScript"), C_("file-format", "JPEG"), C_("file-format", "PDF"), C_("file-format", "PNG"), C_("file-format", "PostScript"), C_("file-format", "SVG"), C_("file-format", "WebP"), ] }; } Adw.SwitchRow transparent { title: _("Transparent Background"); } } Adw.PreferencesGroup { title: _("Export Size"); Adw.SpinRow width { title: _("Width (pixels)"); adjustment: Adjustment { step-increment: 10; lower: 100; upper: 7680; }; } Adw.SpinRow height { title: _("Height (pixels)"); adjustment: Adjustment { step-increment: 10; lower: 100; upper: 4320; }; } Adw.ButtonRow { title: _("Use Same Size as App"); activated => $on_use_window_size(); } } }; }; }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/fitting-parameters.blp000066400000000000000000000021241520337127000265710ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsFittingParameterBox: Box { orientation: vertical; Grid { column-homogeneous: true; margin-bottom: 3; margin-top: 3; column-spacing: 4; row-spacing: 4; Label label { justify: left; use-markup: true; margin-bottom: 4; hexpand: false; halign: start; layout { column: 0; row: 0; column-span: 2; } } Adw.PreferencesGroup { Adw.EntryRow initial { title: _("Initial Guess"); text: "1"; } layout { column: 0; row: 1; column-span: 2; } } Adw.PreferencesGroup { visible: bind lower_bound.visible; Adw.EntryRow lower_bound { title: _("Minimum"); text: "-inf"; } layout { column: 0; row: 2; } } Adw.PreferencesGroup { visible: bind upper_bound.visible; Adw.EntryRow upper_bound { title: _("Maximum"); text: "inf"; } layout { column: 1; row: 2; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/generate-data.blp000066400000000000000000000057051520337127000254750ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsGenerateDataDialog: Adw.Dialog { content-width: 450; title: _("Generate Data"); default-widget: confirm_button; focus-widget: confirm_button; child: Adw.ToolbarView { [top] Adw.HeaderBar { show-end-title-buttons: false; [start] Button { label: _("Cancel"); action-name: "window.close"; } [end] Button confirm_button { label: _("Generate"); clicked => $on_accept(); styles [ "suggested-action", ] } } content: ScrolledWindow { propagate-natural-height: true; child: Viewport { child: Adw.Clamp { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; Box { spacing: 20; orientation: vertical; Adw.PreferencesGroup { separate-rows: true; description: _("Enter a mathematical expression"); Adw.EntryRow equation { max-width-chars: 25; title: _("Y ="); activates-default: true; notify::text => $on_equation_change(); } Adw.EntryRow item_name { max-width-chars: 25; title: _("Name (optional)"); activates-default: true; } } Adw.PreferencesGroup { Box { spacing: 12; orientation: horizontal; homogeneous: true; Adw.PreferencesGroup { Adw.EntryRow xstart { title: _("X Start"); notify::text => $on_entry_change(); } } Adw.PreferencesGroup { Adw.EntryRow xstop { title: _("X Stop"); notify::text => $on_entry_change(); } } } } Adw.PreferencesGroup { Adw.SpinRow steps { title: _("Steps"); input => $on_steps_input(); adjustment: Adjustment { step-increment: 1; page-increment: 100; lower: 2; upper: 1000000000; }; } Adw.ComboRow scale { title: _("Scale"); subtitle: _("How points are spaced"); model: StringList { strings [ C_("scale", "Linear"), C_("scale", "Logarithmic (Base 10)"), C_("scale", "Logarithmic (Base 2)"), C_("scale", "Radians"), C_("scale", "Square Root"), C_("scale", "Inverse"), ] }; } } } }; }; }; }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/000077500000000000000000000000001520337127000236005ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/columns/000077500000000000000000000000001520337127000252605ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/columns/box.blp000066400000000000000000000004561520337127000265540ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsColumnsBox: Box { orientation: vertical; spacing: 10; Box items_box { orientation: vertical; spacing: 10; hexpand: true; } Adw.PreferencesGroup { Adw.ButtonRow { title: _("Add Item"); activated => $add(); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/columns/item-group.blp000066400000000000000000000053451520337127000300560ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsColumnsItemGroup: Adw.PreferencesGroup { margin-top: 10; header-suffix: Button remove_button { icon-name: "user-trash-symbolic"; tooltip-text: _("Remove"); clicked => $on_remove(); styles [ "flat", "destructive-action", ] }; Adw.PreferencesRow { activatable: false; Box { orientation: horizontal; homogeneous: true; Adw.SpinRow column_x { title: _("X Column"); sensitive: bind single_column.active inverted; adjustment: Adjustment { lower: 0; upper: 100; step-increment: 1; value: 0; }; } Adw.SpinRow column_y { title: _("Y Column"); adjustment: Adjustment { lower: 0; upper: 100; step-increment: 1; value: 1; }; } } } Adw.SwitchRow single_column { title: _("Y Values Only"); subtitle: _("Import only Y values, X values will be generated"); } Adw.EntryRow equation { sensitive: bind single_column.active; title: _("Equation"); text: "n"; [suffix] MenuButton { valign: center; icon-name: "info-symbolic"; tooltip-text: _("More info"); styles [ "flat", ] popover: Popover { Label { label: _("X Value Calculation\n\nEnter an equation to calculate X values.\nUse 'n' for the row index (starting from 0).\n\nExamples:\n• n → 0, 1, 2, 3, 4...\n• n*0.5 → 0, 0.5, 1.0, 1.5, 2.0...\n• n^2 → 0, 1, 4, 9, 16...\n• 2^n → 1, 2, 4, 8, 16...\n• n*10+100 → 100, 110, 120, 130..."); use-markup: true; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; } }; } } Adw.PreferencesRow { activatable: false; Box { orientation: horizontal; homogeneous: true; Adw.SwitchRow use_xerr { title: _("X Error Bars"); } Adw.SwitchRow use_yerr { title: _("Y Error Bars"); } } } Adw.PreferencesRow { activatable: false; Box { orientation: horizontal; homogeneous: true; Adw.SpinRow column_xerr { title: _("X Error Column"); sensitive: bind use_xerr.active; adjustment: Adjustment { lower: 0; upper: 100; step-increment: 1; value: 0; }; } Adw.SpinRow column_yerr { title: _("Y Error Column"); sensitive: bind use_yerr.active; adjustment: Adjustment { lower: 0; upper: 100; step-increment: 1; value: 1; }; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/columns/main-group.blp000066400000000000000000000036241520337127000300420ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsColumnsGroup: Adw.PreferencesGroup { title: _("Format"); Adw.ComboRow delimiter { title: _("Delimiter"); subtitle: _("Character used to separate columns"); model: StringList { strings [ C_("delimiter", "Whitespace"), C_("delimiter", "Tab"), C_("delimiter", "Colon (:)"), C_("delimiter", "Semicolon (;)"), C_("delimiter", "Comma (,)"), C_("delimiter", "Period (.)"), C_("delimiter", "Custom"), ] }; } Adw.EntryRow custom_delimiter { sensitive: false; title: _("Custom Delimiter"); [suffix] MenuButton { valign: center; icon-name: "info-symbolic"; tooltip-text: _("More info"); styles [ "flat", ] popover: Popover { position: bottom; Label { label: "Uses regex pattern matching\n\nThese characters have special meanings in regex syntax:\n. * + ? [ ] ^ $ | \\ ( ) { }\n\nTo match these characters literally, escape them with \\\n\nExamples:\n• \\. matches a period\n• \\* matches an asterisk\n• \\| matches a pipe character\n\nLearn more about regex syntax..."; use-markup: true; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; } }; } } Adw.ComboRow separator { title: _("Decimal Separator"); model: StringList { strings [ C_("separator", "Decimal comma (,)"), C_("separator", "Decimal point (.)"), ] }; } Adw.SpinRow skip_rows { title: _("Skip Rows"); subtitle: _("Number of rows to skip at the beginning"); adjustment: Adjustment { lower: 0; upper: 9999; step-increment: 1; value: 0; }; } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/dialog.blp000066400000000000000000000067301520337127000255440ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsImportDialog: Adw.Dialog { content-width: 900; content-height: 576; width-request: 360; height-request: 200; focus-widget: confirm_button; Adw.Breakpoint { condition ("max-width: 500sp") setters { navigation_view.collapsed: true; } } child: Adw.NavigationSplitView navigation_view { sidebar: Adw.NavigationPage file_list_page { title: _("Import Parameters"); width-request: 260; child: Adw.ToolbarView { [top] Adw.HeaderBar { [start] Button { icon-name: "list-add-symbolic"; tooltip-text: _("Add File"); clicked => $on_add(); } } content: ScrolledWindow { propagate-natural-height: true; child: Viewport { child: Adw.Clamp { child: Box { orientation: vertical; ListBox file_list { selection-mode: single; vexpand: true; valign: start; row-activated => $on_row_activated(); row-selected => $on_row_selected(); styles [ "navigation-sidebar", ] } Button confirm_button { label: _("Import"); margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; clicked => $on_accept(); styles [ "suggested-action", "pill", ] } }; }; }; }; }; }; content: Adw.NavigationPage file_settings_page { title: "tmp"; child: Adw.ToolbarView { [top] Adw.HeaderBar { [end] Button { icon-name: "history-undo-symbolic"; tooltip-text: _("Reset to guessed values"); clicked => $on_reset(); } } content: Adw.ToastOverlay toast_overlay { child: ScrolledWindow { propagate-natural-height: true; child: Viewport { child: Adw.Clamp { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; Box { orientation: vertical; spacing: 10; Adw.PreferencesGroup { Adw.ComboRow mode { title: _("Import Mode"); notify::selected => $on_mode(); } } Box file_settings_box { orientation: vertical; spacing: 10; } Adw.PreferencesGroup default_group { Adw.ButtonRow { title: _("Set as Default"); activated => $set_as_default(); } } Adw.PreferencesGroup remove_group { Adw.ButtonRow { title: _("Remove"); activated => $remove(); styles [ "destructive-action", ] } } } }; }; }; }; }; }; }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/file-row.blp000066400000000000000000000005301520337127000260210ustar00rootroot00000000000000using Gtk 4.0; template $GraphsImportFileRow: ListBoxRow { activatable: true; child: Box { margin-start: 3; margin-top: 9; margin-bottom: 9; spacing: 3; Label filename { hexpand: true; halign: start; ellipsize: end; } Label mode { styles [ "import-mode", ] } }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/spreadsheet/000077500000000000000000000000001520337127000261075ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/spreadsheet/box.blp000066400000000000000000000004621520337127000274000ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsSpreadsheetBox: Box { orientation: vertical; spacing: 10; Box items_box { orientation: vertical; spacing: 10; hexpand: true; } Adw.PreferencesGroup { Adw.ButtonRow { title: _("Add Item"); activated => $add(); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/spreadsheet/item-group.blp000066400000000000000000000053711520337127000307040ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsSpreadsheetItemGroup: Adw.PreferencesGroup { margin-top: 10; header-suffix: Button remove_button { icon-name: "user-trash-symbolic"; tooltip-text: _("Remove"); clicked => $on_remove(); styles [ "flat", "destructive-action", ] }; Adw.PreferencesRow { activatable: false; Box { orientation: horizontal; homogeneous: true; Adw.SpinRow column_x { title: _("X Column"); sensitive: bind single_column.active inverted; adjustment: Adjustment { lower: 0; upper: 16383; step-increment: 1; value: 0; }; } Adw.SpinRow column_y { title: _("Y Column"); adjustment: Adjustment { lower: 0; upper: 16383; step-increment: 1; value: 1; }; } } } Adw.SwitchRow single_column { title: _("Single Column"); subtitle: _("Import only Y values, X values will be generated"); } Adw.EntryRow equation { sensitive: bind single_column.active; title: _("X Value Equation"); text: "n"; [suffix] MenuButton { valign: center; icon-name: "info-symbolic"; tooltip-text: _("More info"); styles [ "flat", ] popover: Popover { Label { label: _("X Value Calculation\n\nEnter an equation to calculate X values.\nUse 'n' for the row index (starting from 0).\n\nExamples:\n• n → 0, 1, 2, 3, 4...\n• n*0.5 → 0, 0.5, 1.0, 1.5, 2.0...\n• n^2 → 0, 1, 4, 9, 16...\n• 2^n → 1, 2, 4, 8, 16...\n• n*10+100 → 100, 110, 120, 130..."); use-markup: true; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; } }; } } Adw.PreferencesRow { activatable: false; Box { orientation: horizontal; homogeneous: true; Adw.SwitchRow use_xerr { title: _("X Error Bars"); } Adw.SwitchRow use_yerr { title: _("Y Error Bars"); } } } Adw.PreferencesRow { activatable: false; Box { orientation: horizontal; homogeneous: true; Adw.SpinRow column_xerr { title: _("X Error Column"); sensitive: bind use_xerr.active; adjustment: Adjustment { lower: 0; upper: 16383; step-increment: 1; value: 0; }; } Adw.SpinRow column_yerr { title: _("Y Error Column"); sensitive: bind use_yerr.active; adjustment: Adjustment { lower: 0; upper: 16383; step-increment: 1; value: 1; }; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/spreadsheet/main-group.blp000066400000000000000000000003401520337127000306610ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsSpreadsheetGroup: Adw.PreferencesGroup { title: _("Spreadsheet"); Adw.ComboRow sheet_selector { title: _("Sheet"); subtitle: _("Select which sheet to import"); } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/sql/000077500000000000000000000000001520337127000243775ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/import/sql/main-group.blp000066400000000000000000000022731520337127000271600ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsSqlGroup: Adw.PreferencesGroup { Adw.ComboRow table_row { title: _("Database Table"); notify::selected => $on_table_changed(); } Adw.ComboRow column_x { title: _("Column X"); notify::selected => $on_columns_changed(); } Adw.ComboRow column_y { title: _("Column Y"); notify::selected => $on_columns_changed(); } Adw.PreferencesRow { activatable: false; Box { orientation: horizontal; homogeneous: true; Adw.SwitchRow use_xerr { title: _("X Error Bars"); notify::active => $on_err_toggled(); } Adw.SwitchRow use_yerr { title: _("Y Error Bars"); notify::active => $on_err_toggled(); } } } Adw.ComboRow column_xerr { title: _("X Error Column"); sensitive: bind use_xerr.active; notify::selected => $on_columns_changed(); } Adw.ComboRow column_yerr { title: _("Y Error Column"); sensitive: bind use_yerr.active; notify::selected => $on_columns_changed(); } Label no_numeric_warning { margin-top: 12; margin-bottom: 2; label: _("This table contains no numeric columns"); visible: false; } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/item-box.blp000066400000000000000000000022711520337127000245130ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsItemBox: Adw.ActionRow { title-lines: 1; activatable: true; [prefix] CheckButton check_button { halign: start; notify::active => $on_toggle(); styles [ "selection-mode", ] } [suffix] Button color_button { tooltip-text: _("Pick Color"); vexpand: false; valign: center; clicked => $choose_color(); styles [ "flat", ] Image { icon-name: "color-picker-symbolic"; pixel-size: 20; } } [suffix] MenuButton { icon-name: "view-more-symbolic"; vexpand: false; valign: center; styles [ "flat", ] popover: PopoverMenu { has-arrow: false; menu-model: item_menu; }; } } menu item_menu { section { label: _("Move Item"); display-hint: "inline-buttons"; item { verb-icon: "down-symbolic"; action: "item_box.move_down"; } item { verb-icon: "up-symbolic"; action: "item_box.move_up"; } } section { item { label: _("Curve Fitting"); action: "item_box.curve_fitting"; } item { label: _("Remove Item"); action: "item_box.delete"; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/000077500000000000000000000000001520337127000236775ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/edit-item/000077500000000000000000000000001520337127000255605ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/edit-item/base.blp000066400000000000000000000011021520337127000271630ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsEditItemBaseBox: Box { Adw.PreferencesGroup { title: _("Name and Position"); Adw.EntryRow name_entry { title: _("Name"); max-width-chars: 25; } Adw.ComboRow xposition { title: _("X-Axis Position"); model: StringList { strings [ _("Bottom"), _("Top"), ] }; } Adw.ComboRow yposition { title: _("Y-Axis Position"); model: StringList { strings [ _("Left"), _("Right"), ] }; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/edit-item/data.blp000066400000000000000000000042711520337127000271740ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsEditItemDataItemBox: Box { orientation: vertical; spacing: 20; Adw.PreferencesGroup { title: _("Line and Markers"); Adw.ComboRow linestyle { title: _("Linestyle"); notify::selected => $on_linestyle(); model: StringList { strings [ C_("linestyle", "None"), C_("linestyle", "Solid"), C_("linestyle", "Dotted"), C_("linestyle", "Dashed"), C_("linestyle", "Dashdot"), ] }; } Adw.ActionRow { title: _("Linewidth"); Scale linewidth { sensitive: false; draw-value: true; width-request: 200; adjustment: Adjustment { lower: 0; upper: 10; }; } } Adw.ComboRow markerstyle { title: _("Markers"); notify::selected => $on_markers(); model: StringList { strings [ C_("markerstyle", "None"), C_("markerstyle", "Point"), C_("markerstyle", "Pixel"), C_("markerstyle", "Circle"), C_("markerstyle", "Triangle Down"), C_("markerstyle", "Triangle Up"), C_("markerstyle", "Triangle Left"), C_("markerstyle", "Triangle Right"), C_("markerstyle", "Octagon"), C_("markerstyle", "Square"), C_("markerstyle", "Pentagon"), C_("markerstyle", "Star"), C_("markerstyle", "Hexagon 1"), C_("markerstyle", "Hexagon 2"), C_("markerstyle", "Plus"), C_("markerstyle", "X"), // Translators: Diamond as in Cards Symbol C_("markerstyle", "Diamond"), // Translators: Diamond as in Cards Symbol C_("markerstyle", "Thin Diamond"), C_("markerstyle", "Vertical Line"), C_("markerstyle", "Horizontal Line"), C_("markerstyle", "Filled Plus"), C_("markerstyle", "Filled X"), ] }; } Adw.ActionRow { title: _("Marker Size"); Scale markersize { draw-value: true; width-request: 200; sensitive: false; adjustment: Adjustment { lower: 0; upper: 20; }; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/edit-item/equation-group.blp000066400000000000000000000005531520337127000312410ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsEditItemEquationGroup: Adw.PreferencesGroup { title: _("Equation"); Adw.EntryRow equation { max-width-chars: 25; title: _("Y ="); notify::text => $on_equation_change(); apply => $on_equation_apply(); } Adw.ButtonRow simplify { title: _("Simplify"); activated => $on_simplify(); } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/edit-item/equation.blp000066400000000000000000000013261520337127000301060ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsEditItemEquationItemBox: Box { orientation: vertical; spacing: 20; $GraphsEditItemEquationGroup equation_group {} Adw.PreferencesGroup { title: _("Line"); Adw.ComboRow linestyle { title: _("Linestyle"); model: StringList { strings [ C_("linestyle", "Solid"), C_("linestyle", "Dotted"), C_("linestyle", "Dashed"), C_("linestyle", "Dashdot"), ] }; } Adw.ActionRow { title: _("Linewidth"); Scale linewidth { draw-value: true; width-request: 200; adjustment: Adjustment { lower: 0; upper: 10; }; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/edit-item/errorbar-group.blp000066400000000000000000000022641520337127000312330ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsEditItemErrorBarGroup: Box { orientation: vertical; spacing: 20; Adw.PreferencesGroup { title: _("Error Bars"); Adw.SwitchRow use_xerr { title: _("Show Horizontal"); visible: false; } Adw.SwitchRow use_yerr { title: _("Show Vertical"); visible: false; } Adw.SwitchRow errbarsabove { title: _("Draw Above Data"); } $GraphsStyleColorRow errcolor_row { title: _("Color"); } Adw.ActionRow { title: _("Cap Length"); Scale errcapsize { draw-value: true; width-request: 200; adjustment: Adjustment { lower: 0; upper: 12; }; } } Adw.ActionRow { title: _("Cap Thickness"); Scale errcapthick { draw-value: true; width-request: 200; adjustment: Adjustment { lower: 0; upper: 10; }; } } Adw.ActionRow { title: _("Line Width"); Scale errlinewidth { draw-value: true; width-request: 200; adjustment: Adjustment { lower: 0; upper: 10; }; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/edit-item/generated-data.blp000066400000000000000000000024721520337127000311310ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsEditItemGeneratedDataItemBox: Box { orientation: vertical; spacing: 12; $GraphsEditItemEquationGroup equation_group {} Adw.PreferencesGroup { Box { spacing: 12; orientation: horizontal; homogeneous: true; Adw.PreferencesGroup { Adw.EntryRow xstart { title: _("X Start"); notify::text => $on_entry_change(); apply => $on_entry_apply(); } } Adw.PreferencesGroup { Adw.EntryRow xstop { title: _("X Stop"); notify::text => $on_entry_change(); apply => $on_entry_apply(); } } } } Adw.PreferencesGroup { Adw.SpinRow steps { title: _("Steps"); input => $on_steps_input(); adjustment: Adjustment { step-increment: 1; page-increment: 100; lower: 2; upper: 1000000000; }; } Adw.ComboRow scale { title: _("Scale"); subtitle: _("How points are spaced"); model: StringList { strings [ C_("scale", "Linear"), C_("scale", "Logarithmic (Base 10)"), C_("scale", "Logarithmic (Base 2)"), C_("scale", "Radians"), C_("scale", "Square Root"), C_("scale", "Inverse"), ] }; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/edit-item/page.blp000066400000000000000000000007321520337127000271750ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsEditItemPage: Adw.NavigationPage { title: _("Edit Item"); child: Adw.ToolbarView { [top] Adw.HeaderBar {} ScrolledWindow { propagate-natural-height: true; child: Viewport { Box edit_item_box { orientation: vertical; spacing: 12; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; } }; } }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/figure-settings/000077500000000000000000000000001520337127000270165ustar00rootroot00000000000000settings-page.blp000066400000000000000000000170641520337127000322200ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/figure-settingsusing Gtk 4.0; using Adw 1; template $GraphsFigureSettingsPage: Adw.NavigationPage { title: _("Figure Settings"); Adw.ToolbarView { [top] Adw.HeaderBar {} content: ScrolledWindow { hscrollbar-policy: never; propagate-natural-height: true; Adw.Clamp { margin-bottom: 12; margin-top: 12; margin-start: 12; margin-end: 12; Box settings_box { orientation: vertical; spacing: 16; Adw.PreferencesGroup { title: _("Labels"); Adw.EntryRow title_entry { title: _("Title"); } Adw.EntryRow bottom_label { visible: false; title: _("Bottom X Axis Label"); } Adw.EntryRow top_label { visible: false; title: _("Top X Axis Label"); } Adw.EntryRow left_label { visible: false; title: _("Left Y Axis Label"); } Adw.EntryRow right_label { visible: false; title: _("Right Y Axis Label"); } } Adw.PreferencesGroup { title: _("Axis Limits"); Box { orientation: vertical; spacing: 12; Box bottom_limits { visible: false; orientation: horizontal; homogeneous: true; spacing: 6; Adw.PreferencesGroup { Adw.EntryRow min_bottom { title: _("Bottom X Axis Minimum"); notify::text => $on_limit_entry_change(); } } Adw.PreferencesGroup { Adw.EntryRow max_bottom { title: _("Bottom X Axis Maximum"); notify::text => $on_limit_entry_change(); } } } Box top_limits { visible: false; spacing: 6; homogeneous: true; orientation: horizontal; Adw.PreferencesGroup { Adw.EntryRow min_top { title: _("Top X Axis Minimum"); notify::text => $on_limit_entry_change(); } } Adw.PreferencesGroup { Adw.EntryRow max_top { title: _("Top X Axis Maximum"); notify::text => $on_limit_entry_change(); } } } Box left_limits { visible: false; orientation: horizontal; homogeneous: true; spacing: 6; Adw.PreferencesGroup { Adw.EntryRow min_left { title: _("Left Y Axis Minimum"); notify::text => $on_limit_entry_change(); } } Adw.PreferencesGroup { Adw.EntryRow max_left { title: _("Left Y Axis Maximum"); notify::text => $on_limit_entry_change(); } } } Box right_limits { visible: false; homogeneous: true; orientation: horizontal; spacing: 6; Adw.PreferencesGroup { Adw.EntryRow min_right { title: _("Right Y Axis Minimum"); notify::text => $on_limit_entry_change(); } } Adw.PreferencesGroup { Adw.EntryRow max_right { title: _("Right Y Axis Maximum"); notify::text => $on_limit_entry_change(); } } } } } Adw.PreferencesGroup { title: _("Scaling"); Adw.ComboRow bottom_scale { visible: false; title: _("Bottom X Axis Scale"); model: StringList { strings [ C_("scale", "Linear"), C_("scale", "Logarithmic (Base 10)"), C_("scale", "Logarithmic (Base 2)"), C_("scale", "Radians"), C_("scale", "Square Root"), C_("scale", "Inverse"), ] }; } Adw.ComboRow top_scale { visible: false; title: _("Top X Axis Scale"); model: StringList { strings [ C_("scale", "Linear"), C_("scale", "Logarithmic (Base 10)"), C_("scale", "Logarithmic (Base 2)"), C_("scale", "Radians"), C_("scale", "Square Root"), C_("scale", "Inverse"), ] }; } Adw.ComboRow left_scale { visible: false; title: _("Left Y Axis Scale"); model: StringList { strings [ C_("scale", "Linear"), C_("scale", "Logarithmic (Base 10)"), C_("scale", "Logarithmic (Base 2)"), C_("scale", "Radians"), C_("scale", "Square Root"), C_("scale", "Inverse"), ] }; } Adw.ComboRow right_scale { visible: false; title: _("Right Y Axis Scale"); model: StringList { strings [ C_("scale", "Linear"), C_("scale", "Logarithmic (Base 10)"), C_("scale", "Logarithmic (Base 2)"), C_("scale", "Radians"), C_("scale", "Square Root"), C_("scale", "Inverse"), ] }; } } Adw.PreferencesGroup { title: _("Appearance"); Adw.SwitchRow legend { title: _("Show Legend"); } Adw.ComboRow legend_position { title: _("Legend Position"); sensitive: bind legend.active; model: StringList { strings [ C_("legend-position", "Auto"), C_("legend-position", "Upper Right"), C_("legend-position", "Upper Left"), C_("legend-position", "Lower Left"), C_("legend-position", "Lower Right"), C_("legend-position", "Center Left"), C_("legend-position", "Center Right"), C_("legend-position", "Lower Center"), C_("legend-position", "Upper Center"), C_("legend-position", "Center"), ] }; } Adw.SwitchRow hide_unselected { title: _("Hide Unselected Items"); } Adw.ActionRow { title: _("Style"); activatable: true; activated => $open_style_page(); [suffix] Label style_name {} [suffix] Image { icon-name: "go-next-symbolic"; } } } Adw.PreferencesGroup { margin-top: 12; margin-bottom: 12; Adw.ButtonRow { title: _("Set as Default"); activated => $set_as_default(); } } } } }; } } style-page.blp000066400000000000000000000013401520337127000315060ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/figure-settingsusing Gtk 4.0; using Adw 1; template $GraphsStylePage: Adw.NavigationPage { title: _("Style"); Adw.ToolbarView { [top] Adw.HeaderBar { [end] Button { label: _("Manage"); action-name: "app.style-editor"; } } content: ScrolledWindow { hscrollbar-policy: never; child: Viewport { child: Adw.Clamp { margin-bottom: 6; margin-top: 6; margin-start: 6; margin-end: 6; halign: center; hexpand: true; child: GridView style_grid { min-columns: 2; max-columns: 2; styles [ "style-grid", ] }; }; }; }; } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/main.blp000066400000000000000000000075331520337127000253320ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsMainSidebarPage: Adw.NavigationPage { title: _("Graphs"); child: Adw.ToolbarView { [top] Adw.HeaderBar { [start] MenuButton add_button { icon-name: "list-add-symbolic"; tooltip-text: _("Add New Data"); always-show-arrow: true; menu-model: add_data_menu; } [end] MenuButton { icon-name: "open-menu-symbolic"; menu-model: primary_menu; tooltip-text: _("Open Application Menu"); primary: true; } [end] Button figure_settings_button { action-name: "win.figure-settings"; icon-name: "settings-symbolic"; tooltip-text: _("Figure Settings"); } } ScrolledWindow { child: Viewport { child: Box { orientation: vertical; Stack itemlist_stack { StackPage { child: Adw.StatusPage { icon-name: "list-compact"; title: _("No Data"); description: _("Add data from a file or manually as an equation"); styles [ "compact", ] }; } StackPage { child: ScrolledWindow scrollwindow_itemlist { vexpand: true; hexpand: true; hscrollbar-policy: never; Viewport { ListBox item_list { margin-bottom: 12; margin-top: 6; margin-start: 12; margin-end: 12; vexpand: false; hexpand: true; valign: start; selection-mode: none; styles [ "boxed-list", ] } } }; } } Separator { orientation: horizontal; } Box { spacing: 10; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; ToggleButton pan_button { icon-name: "move-tool-symbolic"; action-name: "win.mode-pan"; hexpand: true; tooltip-text: _("Pan Mode. Click and drag to pan"); } ToggleButton zoom_button { icon-name: "loupe-symbolic"; action-name: "win.mode-zoom"; hexpand: true; tooltip-text: _("Zoom Mode. Select an area on the figure to zoom in"); } ToggleButton select_button { icon-name: "edit-select-all-symbolic"; action-name: "win.mode-select"; hexpand: true; tooltip-text: _("Select Mode. Click and drag to make a selection of data"); } } Separator { orientation: horizontal; } Adw.Bin operations_bin {} }; }; } }; } menu primary_menu { section { item (_("New Project"), "app.new-window") } section { item (_("Save Project…"), "win.save-project") item (_("Save Project as…"), "win.save-project-as") item (_("Open Project…"), "win.open-project") item (_("Close Project"), "win.close-project") } section { item (_("Export Data…"), "win.export-data") item (_("Export Figure…"), "win.export-figure") } section { item (_("Style Editor"), "app.style-editor") } section { item (_("Keyboard Shortcuts"), "win.show-shortcuts") item (_("Help"), "app.help") item (_("About Graphs"), "app.about") } } menu add_data_menu { section { item (_("Add Data from File…"), "win.add-data") item (_("Add Equation…"), "win.add-equation") item (_("Generate Data…"), "win.generate-data") } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/sidebar/operations.blp000066400000000000000000000215251520337127000265660ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsOperations: Box { orientation: vertical; hexpand: false; spacing: 18; margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; Adw.InlineViewSwitcher { stack: stack; homogeneous: true; } Adw.ViewStack stack { Adw.ViewStackPage { title: _("Adjust"); child: Adw.PreferencesGroup { Grid { column-homogeneous: true; column-spacing: 10; row-spacing: 10; Button combine_button { sensitive: bind shift_button.sensitive; tooltip-text: _("Combine all selected data"); clicked => $perform_operation(); layout { column: 0; row: 0; } Adw.ButtonContent { halign: center; icon-name: "edit-paste-symbolic"; label: _("Combine"); } } Button cut_button { tooltip-text: _("Cut selected data"); clicked => $perform_operation(); layout { column: 1; row: 0; } Adw.ButtonContent { halign: center; icon-name: "edit-cut-symbolic"; label: _("Cut"); } } Button shift_button { tooltip-text: _("Shift all data vertically with respect to each other"); clicked => $perform_operation(); layout { column: 0; row: 1; } Adw.ButtonContent { halign: center; icon-name: "shift-symbolic"; label: _("Shift"); } } Button normalize_button { sensitive: bind shift_button.sensitive; tooltip-text: _("Normalize data"); clicked => $perform_operation(); layout { column: 1; row: 1; } Adw.ButtonContent { halign: center; icon-name: "normalize-symbolic"; label: _("Normalize"); } } Adw.SplitButton smoothen_button { can-shrink: true; tooltip-text: _("Smoothen data"); menu-model: smoothen_menu; clicked => $perform_operation(); layout { column: 0; row: 2; column-span: 2; } Adw.ButtonContent { halign: center; can-shrink: true; icon-name: "smoothen-symbolic"; label: _("Smoothen"); } } Adw.SplitButton center_button { sensitive: bind shift_button.sensitive; tooltip-text: _("Center data"); menu-model: center_menu; clicked => $perform_operation(); layout { column: 0; row: 3; column-span: 2; } Adw.ButtonContent { halign: center; icon-name: "center-symbolic"; label: _("Center"); } } } }; } Adw.ViewStackPage { title: _("Transform"); child: Adw.PreferencesGroup { Grid { column-homogeneous: true; column-spacing: 12; row-spacing: 12; Button derivative_button { sensitive: bind shift_button.sensitive; tooltip-text: _("Get the derivative of the data"); clicked => $perform_operation(); layout { column: 0; row: 0; } Adw.ButtonContent { halign: center; icon-name: "derivative2-symbolic"; label: _("Derivative"); } } Button integral_button { sensitive: bind shift_button.sensitive; tooltip-text: _("Get the indefinite integral of the data"); clicked => $perform_operation(); layout { column: 1; row: 0; } Adw.ButtonContent { halign: center; icon-name: "integral-symbolic"; label: _("Integral"); } } Button fft_button { sensitive: bind shift_button.sensitive; tooltip-text: _("Get the Fast Fourier Transform of the data"); clicked => $perform_operation(); layout { column: 0; row: 1; column-span: 2; } Adw.ButtonContent { halign: center; icon-name: "fast-fourier-transform-symbolic"; label: _("FFT"); } } Button inverse_fft_button { sensitive: bind shift_button.sensitive; tooltip-text: _("Get the Inverse Fast Fourier Transform of the data"); clicked => $perform_operation(); layout { column: 0; row: 2; column-span: 2; } Adw.ButtonContent { halign: center; icon-name: "inverse-fast-fourier-transform-symbolic"; label: _("Inverse FFT"); } } Button custom_transformation_button { sensitive: bind shift_button.sensitive; tooltip-text: _("Perform custom transformations on the data"); clicked => $perform_operation(); layout { column: 0; row: 3; column-span: 2; } Adw.ButtonContent { halign: center; icon-name: "transform-symbolic"; label: _("Custom Transformation"); } } } }; } Adw.ViewStackPage { title: _("Modify"); child: Adw.PreferencesGroup { Grid { column-spacing: 10; row-spacing: 10; Entry translate_x_entry { max-width-chars: 6; hexpand: true; text: "10"; layout { column: 0; row: 0; } } Button translate_x_button { valign: center; clicked => $perform_operation(); width-request: 120; layout { column: 1; row: 0; } Adw.ButtonContent { icon-name: "horizontal-arrows-symbolic"; label: _("Translate X"); } } Entry translate_y_entry { max-width-chars: 6; hexpand: true; text: "10"; layout { column: 0; row: 1; } } Button translate_y_button { valign: center; clicked => $perform_operation(); width-request: 120; layout { column: 1; row: 1; } Adw.ButtonContent { icon-name: "vertical-arrows-symbolic"; label: _("Translate Y"); } } Entry multiply_x_entry { max-width-chars: 6; hexpand: true; text: "10"; layout { column: 0; row: 2; } } Button multiply_x_button { valign: center; clicked => $perform_operation(); width-request: 120; layout { column: 1; row: 2; } Adw.ButtonContent { icon-name: "horizontal-arrows-symbolic"; label: _("Multiply X"); } } Entry multiply_y_entry { max-width-chars: 6; hexpand: true; text: "10"; layout { column: 0; row: 3; } } Button multiply_y_button { valign: center; clicked => $perform_operation(); width-request: 120; layout { column: 1; row: 3; } Adw.ButtonContent { icon-name: "vertical-arrows-symbolic"; label: _("Multiply Y"); } } } }; } } } menu center_menu { item { label: _("At Maximum Y Value"); action: "win.center"; target: "max-y"; } item { label: _("At Middle X Value"); action: "win.center"; target: "middle-x"; } } menu smoothen_menu { section { item { label: _("Savitzky–Golay Filter"); action: "win.smoothen"; target: "savgol"; } item { label: _("Moving Average"); action: "win.smoothen"; target: "moving-average"; } } section { item { label: _("Advanced Settings"); action: "win.smoothen-settings"; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/smoothen-settings.blp000066400000000000000000000034131520337127000264600ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsSmoothenDialog: Adw.Dialog { content-width: 640; content-height: 576; title: _("Smoothen Settings"); focus-widget: reset_button; child: Adw.ToolbarView { [top] Adw.HeaderBar { [start] Button reset_button { icon-name: "history-undo-symbolic"; clicked => $on_reset(); } } content: ScrolledWindow { propagate-natural-height: true; child: Viewport { child: Adw.Clamp { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; Box { orientation: vertical; spacing: 10; Adw.PreferencesGroup { title: _("Savitzky–Golay Filter"); Adw.SpinRow savgol_window { title: _("Span percentage"); subtitle: _("What percentage of the data span to use for the filter window"); adjustment: Adjustment { step-increment: 1; upper: 99; }; } Adw.SpinRow savgol_polynomial { title: _("Polynomial degree"); adjustment: Adjustment { step-increment: 1; upper: 20; }; } } Adw.PreferencesGroup { title: _("Moving Average"); Adw.SpinRow moving_average_box { title: _("Box points"); subtitle: _("Amount of points to use when calculating a moving average"); adjustment: Adjustment { step-increment: 1; upper: 9999; }; } } } }; }; }; }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/style-editor/000077500000000000000000000000001520337127000247125ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/style-editor/add-style.blp000066400000000000000000000016561520337127000273070ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsAddStyleDialog: Adw.Dialog { content-width: 450; title: _("Add New Style"); focus-widget: confirm_button; child: Adw.ToolbarView { [top] Adw.HeaderBar { show-end-title-buttons: false; [start] Button { label: _("Cancel"); action-name: "window.close"; } [end] Button confirm_button { label: _("Add"); clicked => $on_accept(); styles [ "suggested-action", ] } } content: Adw.Clamp { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; Adw.PreferencesGroup { Adw.ComboRow style_templates { title: _("Template"); enable-search: true; notify::selected => $on_template_changed(); } Adw.EntryRow new_style_name { title: _("Name"); } } }; }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/style-editor/color-row.blp000066400000000000000000000004051520337127000273330ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsStyleColorRow: Adw.ActionRow { tooltip-text: _("Change Color"); activatable: true; activated => $on_color_choose(); [suffix] Image image { icon-name: "color-picker-symbolic"; pixel-size: 20; } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/style-editor/editor-box.blp000066400000000000000000000250541520337127000274730ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsStyleEditorBox: Box { orientation: vertical; spacing: 20; Adw.PreferencesGroup { Adw.EntryRow style_name { title: _("Style Name"); } Adw.ActionRow { title: _("Font"); activatable-widget: font_chooser; FontDialogButton font_chooser { valign: center; use-font: true; dialog: FontDialog {}; } } Adw.ActionRow { title: _("Title Size"); subtitle: _("Title size in relation to text size"); Scale titlesize { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 1; upper: 4; }; } } Adw.ActionRow { title: _("Label Size"); subtitle: _("Label size in relation to text size"); Scale labelsize { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 1; upper: 4; }; } } } Adw.PreferencesGroup { title: _("Lines"); Adw.ComboRow linestyle { title: _("Linestyle"); notify::selected => $on_linestyle(); model: StringList { strings [ C_("linestyle", "None"), C_("linestyle", "Solid"), C_("linestyle", "Dotted"), C_("linestyle", "Dashed"), C_("linestyle", "Dashdot"), ] }; } Adw.ActionRow { title: _("Line width"); sensitive: bind linewidth.sensitive; Scale linewidth { sensitive: false; draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 10; }; } } Adw.ComboRow markers { title: _("Markers"); notify::selected => $on_markers(); model: StringList { strings [ C_("markerstyle", "None"), C_("markerstyle", "Point"), C_("markerstyle", "Pixel"), C_("markerstyle", "Circle"), C_("markerstyle", "Triangle Down"), C_("markerstyle", "Triangle Up"), C_("markerstyle", "Triangle Left"), C_("markerstyle", "Triangle Right"), C_("markerstyle", "Octagon"), C_("markerstyle", "Square"), C_("markerstyle", "Pentagon"), C_("markerstyle", "Star"), C_("markerstyle", "Hexagon 1"), C_("markerstyle", "Hexagon 2"), C_("markerstyle", "Plus"), C_("markerstyle", "X"), // Translators: Diamond as in Cards Symbol C_("markerstyle", "Diamond"), // Translators: Diamond as in Cards Symbol C_("markerstyle", "Thin Diamond"), C_("markerstyle", "Vertical Line"), C_("markerstyle", "Horizontal Line"), C_("markerstyle", "Filled Plus"), C_("markerstyle", "Filled X"), ] }; } Adw.ActionRow { title: _("Marker Size"); sensitive: bind markersize.sensitive; Scale markersize { sensitive: false; draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 20; }; } } } Adw.PreferencesGroup { title: _("Error Bars"); Adw.ActionRow { title: _("Cap Length"); Scale errorbar_capsize { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 12; }; } } Adw.ActionRow { title: _("Cap Thickness"); Scale errorbar_capthick { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 6; }; } } Adw.ActionRow { title: _("Line Width"); Scale errorbar_linewidth { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 8; }; } } Adw.SwitchRow errorbar_barsabove { title: _("Draw Above Data"); } } Adw.PreferencesGroup { title: _("Axes"); Adw.ActionRow { title: _("Axis Width"); Scale axis_width { draw-value: true; width-request: 200; adjustment: Adjustment { lower: 0; upper: 4; }; } } Adw.SwitchRow draw_frame { title: _("Draw Frame"); } } Adw.PreferencesGroup { title: _("Ticks"); Adw.ComboRow tick_direction { title: _("Tick Directions"); model: StringList { strings [ _("Inwards"), _("Outwards"), ] }; } Adw.SwitchRow minor_ticks { title: _("Minor Ticks"); } Adw.ActionRow { title: _("Major Tick Width"); Scale major_tick_width { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 4; }; } } Adw.ActionRow { title: _("Minor Tick Width"); sensitive: bind minor_ticks.active; Scale minor_tick_width { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 4; }; } } Adw.ActionRow { title: _("Major Tick Length"); Scale major_tick_length { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 20; }; } } Adw.ActionRow { title: _("Minor Tick Length"); sensitive: bind minor_ticks.active; Scale minor_tick_length { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 20; }; } } Adw.SwitchRow tick_labels { title: _("Show Tick Labels on all Axes"); } Adw.SwitchRow tick_bottom { title: _("Ticks on Bottom Axis"); } Adw.SwitchRow tick_left { title: _("Ticks on Left Axis"); } Adw.SwitchRow tick_right { title: _("Ticks on Right Axis"); } Adw.SwitchRow tick_top { title: _("Ticks on Top Axis"); } } Adw.PreferencesGroup { title: _("Grid"); Adw.SwitchRow show_grid { title: _("Show Grid"); } Adw.ActionRow { title: _("Grid Width"); sensitive: bind show_grid.active; Scale grid_linewidth { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 4; }; } } Adw.ActionRow { title: _("Grid Opacity"); sensitive: bind show_grid.active; Scale grid_opacity { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 1; }; } } } Adw.PreferencesGroup { title: _("Padding"); description: _("Padding for different parts of the figure"); Adw.ActionRow { title: _("Value Padding"); subtitle: _("Padding between axes and values"); Scale value_padding { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 40; }; } } Adw.ActionRow { title: _("Label Padding"); subtitle: _("Padding between axes and labels"); Scale label_padding { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 40; }; } } Adw.ActionRow { title: _("Title Padding"); subtitle: _("Padding between axes and the title"); Scale title_padding { draw-value: true; width-request: 200; valign: center; adjustment: Adjustment { lower: 0; upper: 40; }; } } } Adw.PreferencesGroup { title: _("Colors"); header-suffix: Box poor_contrast_warning { spacing: 6; tooltip-text: _("Label text might be hard to read"); styles [ "warning", "flat", ] Image { icon-name: "dialog-warning-symbolic"; } Label { label: _("Poor Contrast"); } }; Grid { row-spacing: 20; column-spacing: 20; column-homogeneous: true; Adw.PreferencesGroup { layout { column: 0; row: 0; } $GraphsStyleColorRow text_color { title: _("Text Color"); } } Adw.PreferencesGroup { layout { column: 1; row: 0; } $GraphsStyleColorRow tick_color { title: _("Tick Color"); } } Adw.PreferencesGroup { layout { column: 0; row: 1; } $GraphsStyleColorRow axis_color { title: _("Axis Color"); } } Adw.PreferencesGroup { layout { column: 1; row: 1; } $GraphsStyleColorRow grid_color { title: _("Grid Color"); } } Adw.PreferencesGroup { layout { column: 0; row: 2; } $GraphsStyleColorRow background_color { title: _("Background Color"); } } Adw.PreferencesGroup { layout { column: 1; row: 2; } $GraphsStyleColorRow outline_color { title: _("Outline Color"); } } } } Adw.PreferencesGroup { title: _("Line Colors"); header-suffix: Button { clicked => $add_color(); styles [ "flat", ] Adw.ButtonContent { halign: center; icon-name: "list-add-symbolic"; label: _("Add Color"); } }; ListBox line_colors_box { vexpand: false; valign: start; hexpand: true; selection-mode: none; styles [ "boxed-list", ] } } Adw.PreferencesGroup { title: _("Error Bar Colors"); header-suffix: Button { clicked => $add_errbar_color(); styles [ "flat", ] Adw.ButtonContent { halign: center; icon-name: "list-add-symbolic"; label: _("Add Color"); } }; ListBox errbar_line_colors_box { vexpand: false; valign: start; hexpand: true; selection-mode: none; styles [ "boxed-list", ] } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/style-editor/item-color-row.blp000066400000000000000000000013671520337127000302770ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsStyleItemColorRow: Adw.ActionRow { title-lines: 1; [prefix] Image { icon-name: "list-drag-handle-symbolic"; styles [ "drag-handle", ] } [suffix] Button color_button { tooltip-text: _("Edit"); vexpand: false; valign: center; clicked => $on_color_choose(); styles [ "flat", ] Image { hexpand: false; icon-name: "color-picker-symbolic"; pixel-size: 20; } } [suffix] Button { tooltip-text: _("Remove"); vexpand: false; valign: center; clicked => $on_delete(); styles [ "flat", ] Image { hexpand: false; icon-name: "edit-delete-symbolic"; pixel-size: 20; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/style-editor/shortcuts.blp000066400000000000000000000020251520337127000274460ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; Adw.ShortcutsDialog shortcuts { Adw.ShortcutsSection { title: C_("shortcut window", "General"); Adw.ShortcutsItem { title: C_("shortcut window", "Show Shortcuts"); action-name: "win.show-shortcuts"; } Adw.ShortcutsItem { title: C_("shortcut window", "Open Help"); action-name: "app.help"; } Adw.ShortcutsItem { title: C_("shortcut window", "Close Application"); action-name: "app.quit"; } Adw.ShortcutsItem { title: C_("shortcut window", "Close Application Window"); accelerator: "w"; } } Adw.ShortcutsSection { title: C_("shortcut window", "Save"); Adw.ShortcutsItem { title: C_("shortcut window", "Save Style"); accelerator: "S"; } Adw.ShortcutsItem { title: C_("shortcut window", "Save Style As"); accelerator: "S"; } Adw.ShortcutsItem { title: C_("shortcut window", "Open Style"); accelerator: "O"; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/style-editor/window.blp000066400000000000000000000161721520337127000267270ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsStyleEditor: Adw.ApplicationWindow { title: _("Graphs Style Editor"); default-width: 1200; default-height: 700; width-request: 360; height-request: 200; ShortcutController { Shortcut { trigger: "w"; action: "action(window.close)"; } Shortcut { trigger: "question"; action: "action(win.show-shortcuts)"; } Shortcut { trigger: "S"; action: "action(win.save-style)"; } Shortcut { trigger: "S"; action: "action(win.save-style-as)"; } Shortcut { trigger: "O"; action: "action(win.open-style)"; } } Adw.Breakpoint { condition ("max-width: 720sp and min-height: 530sp") setters { multi_layout_view.layout: bottom_sheet_layout; editor_headerbar.show-end-title-buttons: true; style_grid.max-columns: 2; style_menu_button.visible: true; } } Adw.Breakpoint { condition ("max-width: 720sp and max-height: 530sp") setters { multi_layout_view.layout: bottom_sheet_layout; editor_headerbar.show-end-title-buttons: true; style_grid.max-columns: 2; style_menu_button.visible: true; sheet_box.height-request: 200; } } content: Stack stack { StackPage { child: Adw.ToolbarView { [top] Adw.HeaderBar { title-widget: Adw.WindowTitle { title: _("Graphs Style Editor"); }; [end] MenuButton { icon-name: "open-menu-symbolic"; menu-model: empty_menu; tooltip-text: _("Open Application Menu"); primary: true; } } [bottom] Adw.Clamp { child: Box { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; spacing: 24; homogeneous: true; MenuButton style_menu_button { icon-name: "list-add-symbolic"; tooltip-text: _("Add New Style"); always-show-arrow: true; visible: false; popover: PopoverMenu { menu-model: style_menu; }; styles [ "pill", ] } Button { label: _("Import File…"); halign: center; action-name: "win.import-style"; visible: bind style_menu_button.visible inverted; styles [ "pill", ] } Button { label: _("Create Style…"); halign: center; action-name: "win.create-style"; visible: bind style_menu_button.visible inverted; styles [ "pill", "suggested-action", ] } Button { label: _("Open File…"); halign: center; action-name: "win.open-style"; visible: bind style_menu_button.visible inverted; styles [ "pill", ] } }; } content: Adw.Clamp { child: ScrolledWindow { child: Viewport { child: GridView style_grid { min-columns: bind style_grid.max-columns; max-columns: 3; styles [ "style-grid", ] }; }; }; }; }; } StackPage { child: Adw.MultiLayoutView multi_layout_view { Adw.Layout side_by_side_layout { name: "side-by-side"; content: Box { orientation: horizontal; homogeneous: true; Box { orientation: horizontal; Adw.LayoutSlot { id: "editor"; } Separator {} } Adw.ToolbarView content_view { styles [ "canvas-view", ] [top] Adw.HeaderBar { name: "preview-headerbar"; show-start-title-buttons: false; show-title: false; } content: Adw.LayoutSlot { id: "canvas"; }; } }; } Adw.Layout bottom_sheet_layout { name: "bottom-sheet"; content: Adw.BottomSheet bottom_sheet { content: Adw.Bin { margin-bottom: bind bottom_sheet.bottom-bar-height; child: Adw.LayoutSlot { id: "editor"; }; }; bottom-bar: CenterBox { height-request: 46; center-widget: Label { label: _("Open Preview"); }; }; sheet: Box sheet_box { orientation: vertical; height-request: 500; Separator { margin-top: 36; orientation: horizontal; } Adw.LayoutSlot { id: "canvas"; } }; }; } [editor] Adw.ToolbarView { [top] Adw.HeaderBar editor_headerbar { show-end-title-buttons: false; title-widget: Adw.WindowTitle { title: _("Graphs Style Editor"); }; [end] MenuButton { icon-name: "open-menu-symbolic"; menu-model: primary_menu; tooltip-text: _("Open Application Menu"); primary: true; } } content: ScrolledWindow { hscrollbar-policy: never; child: Viewport { child: Adw.Clamp { margin-bottom: 12; margin-top: 12; margin-start: 12; margin-end: 12; child: Adw.Bin editor_bin {}; }; }; }; } [canvas] Adw.Bin canvas_bin { child: Adw.StatusPage { icon-name: "dialog-error-symbolic"; title: _("Canvas Failed to Load"); }; } }; } }; } menu primary_menu { section { item (_("Open Style…"), "win.open-style") item (_("Save Style…"), "win.save-style") item (_("Save Style as…"), "win.save-style-as") item (_("Close Style…"), "win.close-style") } section { item (_("New Window"), "app.style-editor") } section { item (_("Keyboard Shortcuts"), "win.show-shortcuts") item (_("Help"), "app.help") item (_("About Graphs"), "app.about") } } menu empty_menu { section { item (_("New Window"), "app.style-editor") } section { item (_("Keyboard Shortcuts"), "win.show-shortcuts") item (_("Help"), "app.help") item (_("About Graphs"), "app.about") } } menu style_menu { section { item (_("Create Style…"), "win.create-style") item (_("Import File…"), "win.import-style") item (_("Open File…"), "win.open-style") } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/style-preview.blp000066400000000000000000000022061520337127000256040ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsStylePreview: Adw.Bin { child: AspectFrame { child: Box { orientation: vertical; Overlay { height-request: 93; width-request: 155; [overlay] Image { halign: end; valign: end; margin-end: 6; margin-bottom: 6; icon-name: "check-round-outline-whole-symbolic"; name: "indicator"; } [overlay] MenuButton menu_button { visible: false; icon-name: "view-more-symbolic"; halign: end; valign: start; margin-end: 4; margin-top: 4; menu-model: style_menu; styles [ "flat", ] } child: Picture picture {}; } Label label { margin-top: 8; ellipsize: end; } }; }; } menu style_menu { section { item { label: _("Open"); action: "style.open"; } item { label: _("Open With…"); action: "style.open_with"; } item { label: _("Delete…"); action: "style.delete"; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/transform.blp000066400000000000000000000040451520337127000250030ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsTransformDialog: Adw.Dialog { content-width: 450; title: _("Transform Data"); default-widget: confirm_button; focus-widget: confirm_button; child: Adw.ToolbarView { [top] Adw.HeaderBar { show-end-title-buttons: false; [start] Button { label: _("Cancel"); action-name: "window.close"; } [end] Button confirm_button { label: _("Transform"); clicked => $on_accept(); styles [ "suggested-action", ] } [end] MenuButton { halign: end; icon-name: "info-symbolic"; tooltip-text: _("More info"); popover: Popover { position: bottom; Label { label: _("Available variables\nGeneral:\n counts - number of data points\n\nX-Axis:\n x_min, x_max - minimum and maximum values,\n x_mean, x_median - average and median,\n x_std, x_sum — standard deviation and sum\n\nY-Axis:\n y_min, y_max - minimum and maximum,\n y_mean, y_median — average and median,\n y_std, y_sum - standard deviation and sum\n\nTrigonometric functions use radians by default.\nAppend d to use degrees, e.g. sind(x) or cosd(x)."); use-markup: true; margin-top: 12; margin-bottom: 12; margin-start: 12; margin-end: 12; } }; } } content: ScrolledWindow { propagate-natural-height: true; child: Viewport { child: Adw.Clamp { margin-start: 12; margin-end: 12; margin-top: 12; margin-bottom: 12; Adw.PreferencesGroup { Adw.EntryRow transform_x { title: _("X ="); activates-default: true; } Adw.EntryRow transform_y { title: _("Y ="); activates-default: true; } Adw.SwitchRow discard { title: _("Discard Unselected Data"); } } }; }; }; }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/window-shortcuts.blp000066400000000000000000000076071520337127000263420ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; Adw.ShortcutsDialog shortcuts { Adw.ShortcutsSection { title: C_("shortcut window", "General"); Adw.ShortcutsItem { title: C_("shortcut window", "Show Shortcuts"); accelerator: "question"; } Adw.ShortcutsItem { title: C_("shortcut window", "Open Help"); action-name: "app.help"; } Adw.ShortcutsItem { title: C_("shortcut window", "Open Figure Settings"); accelerator: "comma"; } Adw.ShortcutsItem { title: C_("shortcut window", "Close Application"); action-name: "app.quit"; } Adw.ShortcutsItem { title: C_("shortcut window", "Close Application Window"); accelerator: "w"; } } Adw.ShortcutsSection { title: C_("shortcut window", "Mode Switching"); Adw.ShortcutsItem { title: C_("shortcut window", "Pan Mode"); accelerator: "1"; } Adw.ShortcutsItem { title: C_("shortcut window", "Zoom Mode"); accelerator: "2"; } Adw.ShortcutsItem { title: C_("shortcut window", "Select Mode"); accelerator: "3"; } } Adw.ShortcutsSection { title: C_("shortcut window", "New Data"); Adw.ShortcutsItem { title: C_("shortcut window", "Add Data from File"); accelerator: "N"; } Adw.ShortcutsItem { title: C_("shortcut window", "Add Data from Equation"); accelerator: "N"; } Adw.ShortcutsItem { title: C_("shortcut window", "Generate Data"); accelerator: "N"; } Adw.ShortcutsItem { title: C_("shortcut window", "New Project"); accelerator: "N"; } Adw.ShortcutsItem { title: C_("shortcut window", "Open Project"); accelerator: "O"; } Adw.ShortcutsItem { title: C_("shortcut window", "Delete Selected Data"); accelerator: "Delete"; } } Adw.ShortcutsSection { title: C_("shortcut window", "Save and Export"); Adw.ShortcutsItem { title: C_("shortcut window", "Export Data"); accelerator: "E"; } Adw.ShortcutsItem { title: C_("shortcut window", "Export Figure"); accelerator: "E"; } Adw.ShortcutsItem { title: C_("shortcut window", "Save Project"); accelerator: "S"; } Adw.ShortcutsItem { title: C_("shortcut window", "Save Project As"); accelerator: "S"; } } Adw.ShortcutsSection { title: C_("shortcut window", "View"); Adw.ShortcutsItem { title: C_("shortcut window", "Previous View"); accelerator: "Z"; } Adw.ShortcutsItem { title: C_("shortcut window", "Next View"); accelerator: "Z"; } Adw.ShortcutsItem { title: C_("shortcut window", "Optimize limits"); accelerator: "0"; } Adw.ShortcutsItem { title: C_("shortcut window", "Zoom in"); accelerator: "plus"; } Adw.ShortcutsItem { title: C_("shortcut window", "Zoom out"); accelerator: "minus"; } Adw.ShortcutsItem { title: C_("shortcut window", "Select None"); accelerator: "A"; } Adw.ShortcutsItem { title: C_("shortcut window", "Toggle Sidebar"); accelerator: "F9"; } } Adw.ShortcutsSection { title: C_("shortcut window", "Actions"); Adw.ShortcutsItem { title: C_("shortcut window", "Select All"); accelerator: "A"; } Adw.ShortcutsItem { title: C_("shortcut window", "Select None"); accelerator: "A"; } Adw.ShortcutsItem { title: C_("shortcut window", "Undo Action"); accelerator: "Z"; } Adw.ShortcutsItem { title: C_("shortcut window", "Redo Action"); accelerator: "Z"; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/ui/window.blp000066400000000000000000000202371520337127000243000ustar00rootroot00000000000000using Gtk 4.0; using Adw 1; template $GraphsWindow: Adw.ApplicationWindow { default-width: 1200; default-height: 700; width-request: 360; height-request: 200; ShortcutController { Shortcut { trigger: "w"; action: "action(window.close)"; } Shortcut { trigger: "question"; action: "action(win.show-shortcuts)"; } Shortcut { trigger: "comma"; action: "action(win.figure-settings)"; } Shortcut { trigger: "N"; action: "action(win.add-data)"; } Shortcut { trigger: "N"; action: "action(win.add-equation)"; } Shortcut { trigger: "N"; action: "action(win.generate-data)"; } Shortcut { trigger: "A"; action: "action(win.select-all)"; } Shortcut { trigger: "A"; action: "action(win.select-none)"; } Shortcut { trigger: "Z"; action: "action(win.undo)"; } Shortcut { trigger: "Z"; action: "action(win.redo)"; } Shortcut { trigger: "KP_0"; action: "action(win.optimize-limits)"; } Shortcut { trigger: "0"; action: "action(win.optimize-limits)"; } Shortcut { trigger: "Z"; action: "action(win.view-back)"; } Shortcut { trigger: "Z"; action: "action(win.view-forward)"; } Shortcut { trigger: "E"; action: "action(win.export-data)"; } Shortcut { trigger: "E"; action: "action(win.export-figure)"; } Shortcut { trigger: "period"; action: "action(win.styles)"; } Shortcut { trigger: "S"; action: "action(win.save-project)"; } Shortcut { trigger: "O"; action: "action(win.open-project)"; } Shortcut { trigger: "Delete"; action: "action(win.delete-selected)"; } Shortcut { trigger: "plus|KP_Add|equal|ZoomIn"; action: "action(win.zoom-in)"; } Shortcut { trigger: "minus|KP_Subtract|ZoomOut"; action: "action(win.zoom-out)"; } Shortcut { trigger: "S"; action: "action(win.save-project-as)"; } Shortcut { trigger: "N"; action: "action(app.new-window)"; } Shortcut { trigger: "F9"; action: "action(win.toggle-sidebar)"; } Shortcut { trigger: "1"; action: "action(win.mode-pan)"; } Shortcut { trigger: "2"; action: "action(win.mode-zoom)"; } Shortcut { trigger: "3"; action: "action(win.mode-select)"; } } // If both width and height are limited Adw.Breakpoint { condition ("max-width: 700sp and max-height: 410sp") setters { overlay_split_view.collapsed: true; undo_button.visible: false; content_footerbar.visible: true; main_page.height_limited: true; } } // If only height is limited Adw.Breakpoint { condition ("min-width: 700sp and max-height: 410sp") setters { main_page.height_limited: true; } } // If only width is limited Adw.Breakpoint { condition ("max-width: 700sp and min-height: 410sp") setters { overlay_split_view.collapsed: true; undo_button.visible: false; content_footerbar.visible: true; } } // If width is very limited (below 380 pixels) Adw.Breakpoint { condition ("max-width: 380sp and min-height: 410sp") setters { sidebar_navigation_view.width-request: 340; overlay_split_view.collapsed: true; undo_button.visible: false; content_footerbar.visible: true; } } // If width is very limited (below 380 pixels), and height is limited Adw.Breakpoint { condition ("max-width: 380sp and max-height: 410sp") setters { sidebar_navigation_view.width-request: 340; overlay_split_view.collapsed: true; undo_button.visible: false; content_footerbar.visible: true; main_page.height_limited: true; } } content: Overlay drag_overlay { styles [ "drag-overlay", ] [overlay] Revealer drag_revealer { can-target: false; transition-type: crossfade; Adw.StatusPage { title: _("Drop Here to Import"); icon-name: "list-add-symbolic"; styles [ "drag-overlay-status-page", ] } } child: Adw.OverlaySplitView overlay_split_view { enable-show-gesture: bind overlay_split_view.collapsed; enable-hide-gesture: bind overlay_split_view.collapsed; sidebar: Adw.NavigationView sidebar_navigation_view { width-request: 360; $GraphsMainSidebarPage main_page {} $GraphsEditItemPage edit_page {} }; content: Adw.ToolbarView content_view { styles [ "canvas-view", ] [top] Adw.HeaderBar { title-widget: Adw.WindowTitle content_title {}; [start] ToggleButton { icon-name: "sidebar-show-symbolic"; tooltip-text: _("Show Sidebar"); active: bind overlay_split_view.show-sidebar bidirectional; visible: bind overlay_split_view.collapsed; } [start] Button undo_button { action-name: "win.undo"; icon-name: "edit-undo-symbolic"; tooltip-text: _("Undo"); } [start] Button redo_button { action-name: "win.redo"; icon-name: "edit-redo-symbolic"; tooltip-text: _("Redo"); visible: bind undo_button.visible; } [end] Button optimize_limits_button { action-name: "win.optimize-limits"; icon-name: "view-reveal-symbolic"; tooltip-text: _("Optimize View Limits"); visible: bind undo_button.visible; } [end] Button view_forward_button { action-name: "win.view-forward"; icon-name: "go-next-symbolic"; tooltip-text: _("Next View"); visible: bind undo_button.visible; } [end] Button view_back_button { action-name: "win.view-back"; icon-name: "go-previous-symbolic"; tooltip-text: _("Previous View"); visible: bind undo_button.visible; } } [bottom] Adw.HeaderBar content_footerbar { show-title: false; show-end-title-buttons: false; visible: false; [start] Button sidebar_undo_button { action-name: "win.undo"; icon-name: "edit-undo-symbolic"; tooltip-text: _("Undo"); sensitive: bind undo_button.sensitive; } [start] Button sidebar_redo_button { action-name: "win.redo"; icon-name: "edit-redo-symbolic"; tooltip-text: _("Redo"); sensitive: bind redo_button.sensitive; } [end] Button sidebar_optimize_limits_button { action-name: "win.optimize-limits"; icon-name: "view-reveal-symbolic"; tooltip-text: _("Optimize View Limits"); } [end] Button sidebar_view_forward_button { action-name: "win.view-forward"; icon-name: "go-next-symbolic"; tooltip-text: _("Next View"); sensitive: bind view_forward_button.sensitive; } [end] Button sidebar_view_back_button { action-name: "win.view-back"; icon-name: "go-previous-symbolic"; tooltip-text: _("Previous View"); sensitive: bind view_back_button.sensitive; } } content: Adw.ToastOverlay toast_overlay { focusable: true; child: Adw.StatusPage { icon-name: "dialog-error-symbolic"; title: _("Canvas Failed to Load"); }; }; }; }; }; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/data/whats_new000066400000000000000000000100501520337127000235670ustar00rootroot00000000000000

Version 2.0 of Graphs is a major update, introducing several new features such as proper equation support and a completely redesigned style editor.

Different data types:

  • Graphs now differentiates between imported data from files, generated data and equations
  • Equations now span an infinite range
  • Equations can now be edited afterwards, as well as simplified using the item editor
  • Equations with undefined values (e.g. 1/x at x=0) are now properly rendered as well
  • Operations on equations are now performed analytically, meaning the name of the equation will also change accordingly when performing operations
  • Generated data can now be changed afterwards with regard to step size and rendered span

New Style Editor:

  • Graphs has a completely redesigned style editor with a live preview of the edited styles
  • Styles can now be exported
  • New styles can now be imported from matplotlib-style files
  • Added the ability to draw tick labels (values) on all axes
  • The style editor now contains options to style the error bars

Reworked Curve fitting:

  • The confidence band in the curve fitting dialog is now correctly calculated using the delta-method
  • The curve fitting dialog now has the option to show residuals
  • The parameter values themselves in the curve fitting dialog are no longer rounded (e.g. 421302 used to be rounded to 421000)
  • The results in the curve fitting dialog now also show the root mean squared error as a second goodness-of-fit figure
  • The curve fitting dialog now shows more useful error messages when things go wrong
  • Custom equations in the curve fitting dialog now have an apply button, greatly improving the smoothness when entering new equations

Improved data import:

  • Revamped the import dialog, where the import settings can now be set independently for multiple files
  • Added support for sqlite database files
  • Added support for spreadsheets files (both .xlsx and .ods)
  • Added proper support for single-column imports, x-data can be generated using your own equation
  • Multiple items can now easily be imported from the same file at once
  • Imported data now supports error bars, with styling configurable per item or globally via the style editor

Quality of life changes:

  • It is now possible to have multiple instances of Graphs open at the same time
  • Data can now be imported by drag-and-drop into Graphs
  • The subtitle now also shows the full file path for Flatpaks
  • Limits can now easily be clicking on the numbers near the axes
  • The custom transformation has gained the following extra variables: x_mean, y_mean, x_median, y_median, x_std, y_std and counts
  • Settings that affect the canvas (item or figure settings) are now displayed in the sidebar, so you can immediately see the changes on your graph
  • Graphs now properly supports mobile screen sizes
  • Legend labels are now truncated dynamically to the window width, instead of to the previously fixed 40 character limit
  • Graphs now inhibits the session when unsaved data is still open
  • The resolution (image size) for exported figures can now be set manually
  • Added support for base-2 logarithmic scaling
  • Warnings are now displayed when trying to open a project from a beta version
  • Translation updates

Bug fixes and tweaks:

  • Graphical fixes for the drag-drop animations
  • Limit entries can now be properly set even for many significant digits
  • Panning and zooming are now done consistently on all axes when using multiple axes
  • Fixed a bug where the text size was set incorrectly after exporting a figure
  • Implemented a custom math parser, which is more performant and robust
  • Overall tweaks and refactors under the hood
Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/000077500000000000000000000000001520337127000222245ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/actions.vala000066400000000000000000000317371520337127000245440ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gee; using Gtk; namespace Graphs { namespace Actions { public void setup_global () { var application = (Application) GLib.Application.get_default (); var quit_action = new SimpleAction ("quit", null); quit_action.activate.connect (application.quit_action); application.add_action (quit_action); application.set_accels_for_action ("app.quit", {"q"}); var about_action = new SimpleAction ("about", null); about_action.activate.connect (() => { var file = File.new_for_uri ("resource:///se/sjoerd/Graphs/whats_new"); string release_notes; try { release_notes = (string) file.load_bytes ().get_data (); } catch { release_notes = ""; } var dialog = new Adw.AboutDialog () { application_name = _("Graphs"), application_icon = application.application_id, website = Config.HOMEPAGE_URL, developer_name = _("The Graphs Developers"), issue_url = Config.ISSUE_URL, version = application.version, developers = { "Sjoerd Stendahl ", "Christoph Matthias Kohnen " }, designers = { "Sjoerd Stendahl ", "Christoph Matthias Kohnen ", "Tobias Bernard " }, copyright = "© " + Config.COPYRIGHT, license_type = License.GPL_3_0, translator_credits = _("translator-credits"), release_notes = release_notes }; dialog.present (application.active_window); }); application.add_action (about_action); var help_action = new SimpleAction ("help", null); help_action.activate.connect (() => { try { AppInfo.launch_default_for_uri ( "help:graphs", application.active_window.get_display ().get_app_launch_context () ); } catch { assert_not_reached (); } }); application.add_action (help_action); application.set_accels_for_action ("app.help", {"F1"}); var new_window_action = new SimpleAction ("new-window", null); new_window_action.activate.connect (() => { var window = application.create_main_window (); window.present (); }); application.add_action (new_window_action); var style_editor_action = new SimpleAction ("style-editor", null); style_editor_action.activate.connect (() => { var style_editor = application.create_style_editor (); style_editor.present (); }); application.add_action (style_editor_action); } public void setup_local (Window window) { var data = window.data; var toggle_sidebar_action = new SimpleAction ("toggle-sidebar", null); toggle_sidebar_action.activate.connect (() => { OverlaySplitView split_view = window.overlay_split_view; split_view.show_sidebar = !split_view.show_sidebar; }); window.overlay_split_view.bind_property ( "collapsed", toggle_sidebar_action, "enabled", BindingFlags.SYNC_CREATE ); window.add_action (toggle_sidebar_action); var modes = new ArrayList.wrap ({"pan", "zoom", "select"}); foreach (string mode in modes) { string current_mode = mode; var action = new SimpleAction (@"mode-$current_mode", null); action.activate.connect (() => { window.canvas.mode = (Mode) modes.index_of (current_mode); window.on_selection_changed (); }); window.add_action (action); } string[] settings_actions = {"center", "smoothen"}; GLib.Settings actions_settings = Application.get_settings_child ("actions"); foreach (string settings_action in settings_actions) { window.add_action (actions_settings.create_action (settings_action)); } var operation_action = new SimpleAction ( "perform_operation", new VariantType ("s") ); operation_action.activate.connect ((a, target) => { PythonHelper.perform_operation (window, target.get_string ()); }); window.add_action (operation_action); var optimize_limits_action = new SimpleAction ("optimize-limits", null); optimize_limits_action.activate.connect (() => { data.optimize_limits (); }); window.add_action (optimize_limits_action); var smoothen_settings_action = new SimpleAction ("smoothen-settings", null); smoothen_settings_action.activate.connect (() => { new SmoothenDialog (window); }); window.add_action (smoothen_settings_action); var select_all_action = new SimpleAction ("select-all", null); select_all_action.activate.connect (() => { data.select_all (); data.add_history_state (); }); window.bind_property ("is_main_view", select_all_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (select_all_action); var select_none_action = new SimpleAction ("select-none", null); select_none_action.activate.connect (() => { data.unselect_all (); data.add_history_state (); }); window.bind_property ("is_main_view", select_none_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (select_none_action); var undo_action = new SimpleAction ("undo", null); undo_action.activate.connect (() => { data.undo (); }); window.add_action (undo_action); var redo_action = new SimpleAction ("redo", null); redo_action.activate.connect (() => { data.redo (); }); window.add_action (redo_action); var view_back_action = new SimpleAction ("view-back", null); view_back_action.activate.connect (() => { data.view_back (); }); data.bind_property ("can_view_back", view_back_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (view_back_action); var view_forward_action = new SimpleAction ("view-forward", null); view_forward_action.activate.connect (() => { data.view_forward (); }); data.bind_property ("can_view_forward", view_forward_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (view_forward_action); var delete_selected_action = new SimpleAction ("delete-selected", null); delete_selected_action.activate.connect (() => { Item[] items = {}; var name_builder = new StringBuilder (); foreach (Item item in data) { if (item.selected) { items += item; name_builder.append (item.name); name_builder.append (", "); } } data.delete_items (items); string names = name_builder.free_and_steal ()[:-2]; window.add_undo_toast (_("Deleted %s").printf (names)); }); window.bind_property ("is_main_view", delete_selected_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (delete_selected_action); var save_project_action = new SimpleAction ("save-project", null); save_project_action.activate.connect (() => { Project.save.begin (window, false); }); save_project_action.set_enabled (false); window.add_action (save_project_action); var save_project_as_action = new SimpleAction ("save-project-as", null); save_project_as_action.activate.connect (() => { Project.save.begin (window, true); }); save_project_as_action.set_enabled (false); window.add_action (save_project_as_action); var open_project_action = new SimpleAction ("open-project", null); open_project_action.activate.connect (() => { Project.open.begin (window); }); window.bind_property ("is_main_view", open_project_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (open_project_action); var close_project_action = new SimpleAction ("close-project", null); close_project_action.activate.connect (() => { Project.close (window); }); window.add_action (close_project_action); var add_data_action = new SimpleAction ("add-data", null); add_data_action.activate.connect (() => { var dialog = new FileDialog (); dialog.set_filters (DataImporter.file_filters); dialog.open_multiple.begin (window, null, (d, response) => { try { var files_list_model = dialog.open_multiple.end (response); var settings_list = new GLib.ListStore (typeof (ImportSettings)); for (uint i = 0; i < files_list_model.get_n_items (); i++) { var file = (File) files_list_model.get_item (i); var settings = DataImporter.get_settings_for_file (file); settings_list.append (settings); } new ImportDialog (window, settings_list); } catch {} }); }); window.bind_property ("is_main_view", add_data_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (add_data_action); var export_data_action = new SimpleAction ("export-data", null); export_data_action.activate.connect (() => { Export.export_items (window); }); window.bind_property ("is_main_view", export_data_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (export_data_action); var figure_settings_action = new SimpleAction ("figure-settings", null); figure_settings_action.activate.connect (() => { window.open_figure_settings (); }); window.bind_property ("is_main_view", figure_settings_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (figure_settings_action); var add_equation_action = new SimpleAction ("add-equation", null); add_equation_action.activate.connect (() => { new AddEquationDialog (window); }); window.bind_property ("is_main_view", add_equation_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (add_equation_action); var generate_data_action = new SimpleAction ("generate-data", null); generate_data_action.activate.connect (() => { new GenerateDataDialog (window); }); window.bind_property ("is_main_view", generate_data_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (generate_data_action); var export_figure_action = new SimpleAction ("export-figure", null); export_figure_action.activate.connect (() => { new ExportFigureDialog (window); }); window.bind_property ("is_main_view", export_figure_action, "enabled", BindingFlags.SYNC_CREATE); window.add_action (export_figure_action); window.add_action (new SimpleAction ("zoom-in", null)); window.add_action (new SimpleAction ("zoom-out", null)); var show_shortcuts_action = new SimpleAction ("show-shortcuts", null); show_shortcuts_action.activate.connect (() => { string path = "/se/sjoerd/Graphs/ui/window-shortcuts.ui"; var builder = new Builder.from_resource (path); var shortcuts_dialog = (Adw.ShortcutsDialog) builder.get_object ("shortcuts"); shortcuts_dialog.present (window); }); window.add_action (show_shortcuts_action); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/add_equation.vala000066400000000000000000000034131520337127000255270ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { /** * Add Equation dialog. */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/add-equation.ui")] public class AddEquationDialog : Adw.Dialog { [GtkChild] private unowned Adw.EntryRow equation { get; } [GtkChild] private unowned Button confirm_button { get; } [GtkChild] private unowned Adw.EntryRow item_name { get; } private Window window; private GLib.Settings settings; public AddEquationDialog (Window window) { Object (); this.window = window; this.settings = Application.get_settings_child ("add-equation"); this.equation.set_text (settings.get_string ("equation")); present (window); } [GtkCallback] private void on_accept () { string equation_str = this.equation.get_text (); this.settings.set_string ("equation", equation_str); string name = item_name.get_text (); if (name == "") name = "Y = " + equation_str; Item item = ItemFactory.new_equation_item (window.data, equation_str); item.name = name; Item[] items = {item}; window.data.add_items (items); window.data.optimize_limits (); close (); } [GtkCallback] private void on_equation_change () { if (PythonHelper.validate_equation (equation.get_text ())) { equation.remove_css_class ("error"); confirm_button.set_sensitive (true); } else { equation.add_css_class ("error"); confirm_button.set_sensitive (false); } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/application.vala000066400000000000000000000150721520337127000254010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gdk; using Gee; using Gtk; namespace Graphs { /** * Graphs application */ public class Application : Adw.Application { public static GLib.Settings settings { get; private set; } private Gee.List main_windows; private Gee.List style_editors; private static uint _css_counter = 0; private const OptionEntry[] OPTION_ENTRIES = { { "new-window", 'n', 0, OptionArg.NONE, null, N_("New window"), null }, { "style-editor", 's', 0, OptionArg.NONE, null, N_("Style Editor"), null }, { OPTION_REMAINING, 0, 0, OptionArg.STRING_ARRAY, null, null, N_("[FILE…]") }, { null }, }; public Application () { Object ( application_id: Config.APPLICATION_ID, version: Config.VERSION, flags: ApplicationFlags.HANDLES_COMMAND_LINE | ApplicationFlags.HANDLES_OPEN ); add_main_option_entries (OPTION_ENTRIES); } /** * Setup the application. */ public override void startup () { base.startup (); Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); Intl.textdomain (Config.GETTEXT_PACKAGE); Intl.setlocale (LocaleCategory.NUMERIC, "C"); settings = new GLib.Settings (application_id); this.main_windows = new Gee.LinkedList (); this.style_editors = new Gee.LinkedList (); Gtk.Window.set_default_icon_name (application_id); Actions.setup_global (); } /** * Activate the application. */ public override void activate () { base.activate (); var window = main_windows.is_empty ? create_main_window () : main_windows[0]; window.present (); } /** * Handle File Opening. */ public override void open (File[] files, string hint) { base.open (files, hint); if (files.length == 1) { File file = files[0]; string uri = file.get_uri (); if (uri.has_suffix (".graphs")) { var window = create_main_window (); window.present (); Project.load.begin (window, window.data, file); return; } else if (uri.has_suffix (".mplstyle")) { var style_editor = create_style_editor (); style_editor.load (file); style_editor.present (); return; } } // Import // try using a "clean" window Window? window = null; foreach (Window pot_window in main_windows) { if (!pot_window.data.unsaved && pot_window.data.file == null) { window = pot_window; break; } } if (window == null) { window = create_main_window (); } window.present (); var settings_list = new GLib.ListStore (typeof (ImportSettings)); for (uint i = 0; i < files.length; i++) { settings_list.append (DataImporter.get_settings_for_file (files[i])); } new ImportDialog (window, settings_list); } /* * Handle command line */ public override int command_line (ApplicationCommandLine command_line) { VariantDict options = command_line.get_options_dict (); bool new_window, new_style_editor; options.lookup ("new-window", "b", out new_window); options.lookup ("style-editor", "b", out new_style_editor); var val = options.lookup_value (OPTION_REMAINING, VariantType.STRING_ARRAY); if (val != null) { string[] remaining = val.get_strv (); File[] files = new File[remaining.length]; for (int i = 0; i < remaining.length; i++) { files[i] = command_line.create_file_for_arg (remaining[i]); } open (files, ""); } else if (new_window) { var window = create_main_window (); window.present (); } else if (new_style_editor) { var style_editor = create_style_editor (); style_editor.present (); } else { activate (); } return 0; } public Window create_main_window () { Window window = PythonHelper.create_window (); main_windows.add (window); add_window (window); return window; } public StyleEditor create_style_editor () { var style_editor = PythonHelper.create_style_editor (); style_editors.add (style_editor); add_window (style_editor); return style_editor; } public static string get_next_css_name () { _css_counter++; return "view" + _css_counter.to_string (); } /** * Retrieve a child of the applications settings. * * @param path a slash-separated path */ public static GLib.Settings get_settings_child (string path) { GLib.Settings settings_child = settings; foreach (string child_name in path.split ("/")) { settings_child = settings_child.get_child (child_name); } return settings_child; } public void on_main_window_closed (Window window) { main_windows.remove (window); try_quit (); } public void on_style_editor_closed (StyleEditor style_editor) { style_editors.remove (style_editor); try_quit (); } private void try_quit () { if (main_windows.size == 0 && style_editors.size == 0) { quit (); } } public void quit_action () { // We need to cast to array here as the list size might change // during iteration foreach (Window window in main_windows.to_array ()) { window.close (); } foreach (StyleEditor style_editor in style_editors.to_array ()) { style_editor.close (); } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/artist.py000066400000000000000000000502641520337127000241130ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """ Wrapper classes for mpl artists. Provides GObject based wrappers for mpl artists. """ from gi.repository import GObject, Graphs from graphs import misc, utilities from matplotlib import artist, pyplot from matplotlib.figure import Figure import numpy from scipy.stats import median_abs_deviation import sympy from sympy.calculus.singularities import singularities as find_singularities def new_for_item(fig: Figure, item: Graphs.Item) -> GObject.Object: """ Create a new artist for an item. Creates bindings between item and artist properties so changes are handled automatically. """ if isinstance(item, Graphs.DataItem): cls = DataItemArtistWrapper elif isinstance(item, Graphs.EquationItem): cls = EquationItemArtistWrapper elif isinstance(item, Graphs.TextItem): cls = TextItemArtistWrapper elif isinstance(item, Graphs.FillItem): cls = FillItemArtistWrapper artist_wrapper = cls( fig.axes[item.get_yposition() * 2 + item.get_xposition()], item, ) for prop in dir(artist_wrapper.props): if not (prop == "label" and artist_wrapper.legend): item.bind_property(prop, artist_wrapper, prop, 0) artist_wrapper.connect("notify", lambda _x, _y: fig.update_legend()) return artist_wrapper class ItemArtistWrapper(GObject.Object): """Wrapper for base Item.""" __gtype_name__ = "GraphsItemArtistWrapper" legend = False def get_artist(self) -> artist: """Get underlying mpl artist.""" return self._artist @GObject.Property(type=str, default="") def name(self) -> str: """Get name/label property.""" return self._artist.get_label() @name.setter def name(self, name: str) -> None: """Set name/label property.""" self._artist.set_label(name) @GObject.Property(type=str, default="000000") def color(self) -> str: """Get color property.""" return self._color_artist.get_color() @color.setter def color(self, color: str) -> None: """Set color property.""" self._color_artist.set_color(color) @GObject.Property(type=float, default=1) def alpha(self) -> float: """Get alpha property.""" return self._color_artist.get_alpha() @alpha.setter def alpha(self, alpha: float) -> None: """Set alpha property.""" self._artist.set_alpha(alpha) class DataItemArtistWrapper(ItemArtistWrapper): """Wrapper for DataItem.""" __gtype_name__ = "GraphsDataItemArtistWrapper" selected = GObject.Property(type=bool, default=True) linewidth = GObject.Property(type=float, default=3) markersize = GObject.Property(type=float, default=7) legend = True @GObject.Property(type=Graphs.DataHolder) def data(self) -> Graphs.DataHolder: """Get data property.""" raise NotImplementedError @data.setter def data(self, data: Graphs.DataHolder) -> None: """Set data property.""" xdata, ydata, xerr, yerr = self._handle_singularities(data) self._data.set_data((xdata, ydata)) if xerr is not None: start = numpy.column_stack((xdata - xerr, ydata)) end = numpy.column_stack((xdata + xerr, ydata)) self._xbar.set_segments(numpy.stack((start, end), axis=1)) self._xcaps[0].set_data(xdata - xerr, ydata) self._xcaps[1].set_data(xdata + xerr, ydata) if yerr is not None: start = numpy.column_stack((xdata, ydata - yerr)) end = numpy.column_stack((xdata, ydata + yerr)) self._ybar.set_segments(numpy.stack((start, end), axis=1)) self._ycaps[0].set_data(xdata, ydata - yerr) self._ycaps[1].set_data(xdata, ydata + yerr) @GObject.Property(type=bool, default=True) def showxerr(self) -> bool: """Get showxerr property.""" raise NotImplementedError @showxerr.setter def showxerr(self, showxerr: bool) -> None: """Set showxerr property.""" self._xbar.set_visible(showxerr) for cap in self._xcaps: cap.set_visible(showxerr) @GObject.Property(type=bool, default=True) def showyerr(self) -> bool: """Get showyerr property.""" raise NotImplementedError @showyerr.setter def showyerr(self, showyerr: bool) -> None: """Set showyerr property.""" self._ybar.set_visible(showyerr) for cap in self._ycaps: cap.set_visible(showyerr) @GObject.Property(type=int, default=1) def linestyle(self) -> int: """Get linestyle property.""" return misc.LINESTYLES.index(self._data.get_linestyle()) @linestyle.setter def linestyle(self, linestyle: int) -> None: """Set linestyle property.""" self._data.set_linestyle(misc.LINESTYLES[linestyle]) @GObject.Property(type=int, default=1) def markerstyle(self) -> int: """Get markerstyle property.""" return misc.MARKERSTYLES.index(self._data.get_marker()) @markerstyle.setter def markerstyle(self, markerstyle: int) -> None: """Set markerstyle property.""" self._data.set_marker(misc.MARKERSTYLES[markerstyle]) @GObject.Property(type=float, default=0) def errcapsize(self) -> float: """Get errcapsize property.""" raise NotImplementedError @errcapsize.setter def errcapsize(self, errcapsize: float) -> None: """Set errcapsize property.""" for cap in self._caps: cap.set_markersize(errcapsize * 2) @GObject.Property(type=float, default=1) def errcapthick(self) -> float: """Get errcapthick property.""" raise NotImplementedError @errcapthick.setter def errcapthick(self, errcapthick: float) -> None: """Set errcapthick property.""" for cap in self._caps: cap.set_markeredgewidth(errcapthick) @GObject.Property(type=float, default=1) def errlinewidth(self) -> float: """Get errlinewidth property.""" raise NotImplementedError @errlinewidth.setter def errlinewidth(self, errlinewidth: float) -> None: """Set errlinewidth property.""" for bar in self._bars: bar.set_linewidth(errlinewidth) @GObject.Property(type=bool, default=False) def errbarsabove(self) -> bool: """Get errbarsabove property.""" raise NotImplementedError @errbarsabove.setter def errbarsabove(self, errbarsabove: bool) -> None: """Set errbarsabove property.""" zorder = self._data.get_zorder() offset = 1 if errbarsabove else -1 for bar in self._bars: bar.set_zorder(zorder + offset) @GObject.Property(type=str, default="") def errcolor(self) -> str: """Get errcolor property.""" raise NotImplementedError @errcolor.setter def errcolor(self, errcolor: str) -> None: """Set errcolor property.""" if not errcolor: return for bar in self._bars: bar.set_color(errcolor) for cap in self._caps: cap.set_color(errcolor) cap.set_markerfacecolor(errcolor) cap.set_markeredgecolor(errcolor) def _set_properties(self, *_args) -> None: linewidth, markersize = self.props.linewidth, self.props.markersize if not self.props.selected: linewidth *= 0.35 markersize *= 0.35 self._data.set_linewidth(linewidth) self._data.set_markersize(markersize) @staticmethod def _handle_singularities(data: Graphs.DataHolder) -> tuple: """Adjust data to handle singularity jumps.""" xdata = utilities.bytes_to_ndarray(data.get_xdata_b()) ydata = utilities.bytes_to_ndarray(data.get_ydata_b()) xerr = utilities.bytes_to_ndarray(data.get_xerr_b()) yerr = utilities.bytes_to_ndarray(data.get_yerr_b()) if len(xdata) < 2: return xdata, ydata, xerr, yerr # Detect singularities using Median Absolute Deviation grad = numpy.abs(numpy.gradient(ydata, xdata)) median = numpy.median(grad) mad = median_abs_deviation(grad, scale="normal") if mad == 0: mad = (xdata[1] - xdata[0]) * 0.01 threshold = median + 6 * mad sign_change = numpy.sign(ydata[:-1]) != numpy.sign(ydata[1:]) mask = (grad[:-1] > threshold) & sign_change if not numpy.any(mask): return xdata, ydata, xerr, yerr edges = numpy.diff(mask.astype(int)) starts = numpy.where(edges == 1)[0] + 1 ends = numpy.where(edges == -1)[0] + 1 if mask[0]: starts = numpy.r_[0, starts] if mask[-1]: ends = numpy.r_[ends, len(mask)] mask = numpy.zeros_like(mask, dtype=bool) mask[(starts + ends) // 2] = True bad_points = numpy.zeros(len(xdata), dtype=bool) left = numpy.abs(ydata[:-1]) > numpy.abs(ydata[1:]) bad_points[:-1] |= mask & left bad_points[1:] |= mask & ~left xdata = xdata.copy() ydata = ydata.copy() xdata[bad_points] = numpy.nan ydata[bad_points] = numpy.nan if xerr is not None: xerr = xerr.copy() xerr[bad_points] = numpy.nan if yerr is not None: yerr = yerr.copy() yerr[bad_points] = numpy.nan return xdata, ydata, xerr, yerr def __init__(self, axis: pyplot.axis, item: Graphs.Item) -> None: super().__init__() xdata, ydata, xerr, yerr = self._handle_singularities(item.props.data) self._artist = axis.errorbar( xdata, ydata, xerr=xerr, yerr=yerr, label=item.get_name(), color=item.get_color(), alpha=item.get_alpha(), linestyle=misc.LINESTYLES[item.get_linestyle()], marker=misc.MARKERSTYLES[item.get_markerstyle()], capsize=item.get_errcapsize(), capthick=item.get_errcapthick(), elinewidth=item.get_errlinewidth(), barsabove=item.get_errbarsabove(), ecolor=item.get_errcolor(), ) self._data, self._caps, self._bars = self._artist self._color_artist = self._data # We iterate over bar and caps in assignments to handle all # combinations with error bars on either or both axes. bar_iter = iter(self._bars) cap_iter = iter(self._caps) if xerr is not None: self._xbar = next(bar_iter) self._xcaps = tuple(cap_iter) if not item.get_showxerr(): self._xbar.set_visible(False) for cap in self._xcaps: cap.set_visible(False) if yerr is not None: self._ybar = next(bar_iter) self._ycaps = tuple(cap_iter) if not item.get_showyerr(): self._ybar.set_visible(False) for cap in self._ycaps: cap.set_visible(False) for prop in ("selected", "linewidth", "markersize"): self.set_property(prop, item.get_property(prop)) self.connect(f"notify::{prop}", self._set_properties) self._set_properties() class EquationItemArtistWrapper(ItemArtistWrapper): """Wrapper for EquationItem.""" __gtype_name__ = "GraphsEquationItemArtistWrapper" selected = GObject.Property(type=bool, default=True) linewidth = GObject.Property(type=float, default=3) legend = True _singularities_cache = {} def __init__(self, axis: pyplot.axis, item: Graphs.Item): super().__init__() equation = item.get_preprocessed_equation() self._equation = equation self._expr = sympy.sympify(equation) self._axis = axis self._view_change_timeout_id = None axis.callbacks.connect("xlim_changed", self._on_view_change) self._artist = axis.plot( [], [], label=item.get_name(), color=item.get_color(), alpha=item.get_alpha(), linestyle=misc.LINESTYLES[item.get_linestyle() + 1], marker="none", )[0] self._color_artist = self._artist for prop in ("selected", "linewidth"): self.set_property(prop, item.get_property(prop)) self.connect(f"notify::{prop}", self._set_properties) self._set_properties(None, None) self._generate_data() def _timeout_callback(self) -> bool: self._view_change_timeout_id = None self._generate_data() return False def _on_view_change(self, *_args) -> None: """Debounced view change handler that generates data after delay.""" if self._view_change_timeout_id is not None: GObject.source_remove(self._view_change_timeout_id) self._view_change_timeout_id = \ GObject.timeout_add(100, self._timeout_callback) @GObject.Property(type=str, flags=2) def equation(self) -> None: """Write-only property, ignored.""" @equation.setter def equation(self, equation: str) -> None: self._singularities_cache.clear() self._equation = Graphs.preprocess_equation(equation) self._expr = sympy.sympify(self._equation) self._generate_data() @GObject.Property(type=int, default=1) def linestyle(self) -> int: """Get linestyle property.""" return misc.LINESTYLES.index(self._artist.get_linestyle()) - 1 @linestyle.setter def linestyle(self, linestyle: int) -> None: """Set linestyle property.""" self._artist.set_linestyle(misc.LINESTYLES[linestyle + 1]) def _set_properties(self, _x, _y) -> None: linewidth = self.props.linewidth if not self.props.selected: linewidth *= 0.35 self._artist.set_linewidth(linewidth) def _generate_data(self): """Generate new data for the artist.""" x_start, x_stop = self._axis.get_xlim() scale = Graphs.scale_from_string(self._axis.get_xscale()) lower = Graphs.get_value_at_fraction(-1, x_start, x_stop, scale) upper = Graphs.get_value_at_fraction(2, x_start, x_stop, scale) limits = (lower, upper) data = utilities.equation_to_data(self._equation, limits, scale=scale) singularities = self._find_singularities(limits) if singularities: data = self._insert_singularity_points(data, singularities) self._artist.set_data(*data) if self._axis.figure.parent is not None: self._axis.figure.parent.queue_draw() def _find_singularities(self, limits): lower, upper = limits cached = self._singularities_cache.get(self._equation) if cached: cached_min, cached_max = cached["limits"] if lower >= cached_min and upper <= cached_max: return { s for s in cached["singularities"] if lower <= s <= upper } x_min, x_max = min(lower, cached_min), max(upper, cached_max) else: x_min, x_max = lower, upper domain = sympy.Interval(x_min, x_max) all_singularities = find_singularities(self._expr, misc.X, domain) self._singularities_cache[self._equation] = { "limits": (x_min, x_max), "singularities": all_singularities, } return {s for s in all_singularities if lower <= s <= upper} def _insert_singularity_points(self, data, singularities) -> tuple: """Insert NaN and infinite value points at singularities.""" xdata, ydata = data singularities_arr = numpy.fromiter(sorted(singularities), dtype=float) indices = numpy.searchsorted(xdata, singularities_arr) n = len(xdata) triple_mask = (indices > 1) & (indices < n - 1) new_size = n + len(indices) + 2 * triple_mask.sum() ylim = self._axis.get_ylim() ylim_range = abs(ylim[1] - ylim[0]) ydata_range = numpy.nanmax(ydata) - numpy.nanmin(ydata) inf_value = max(ylim_range * 1.5, ydata_range * 1.5) * 2 epsilon = (xdata[1] - xdata[0]) * 0.01 # shift indices due to previous insertions shifts = numpy.cumsum(1 + 2 * triple_mask) - (1 + 2 * triple_mask) target_indices = indices + shifts triple_idxs = indices[triple_mask] triple_targets = target_indices[triple_mask] triple_values = singularities_arr[triple_mask] data_mask = numpy.ones(new_size, dtype=bool) data_mask[target_indices] = False data_mask[triple_targets + 1] = False data_mask[triple_targets + 2] = False x_new = numpy.empty(new_size, dtype=float) y_new = numpy.empty(new_size, dtype=float) x_new[data_mask] = xdata y_new[data_mask] = ydata left = numpy.sign(ydata[triple_idxs - 1] - ydata[triple_idxs - 2]) right = -numpy.sign(ydata[triple_idxs + 1] - ydata[triple_idxs]) inf_values = inf_value + ydata[triple_idxs] x_new[triple_targets] = triple_values - epsilon x_new[triple_targets + 1] = numpy.nan x_new[triple_targets + 2] = triple_values + epsilon y_new[triple_targets] = left * inf_values y_new[triple_targets + 1] = numpy.nan y_new[triple_targets + 2] = right * inf_values single_targets = target_indices[~triple_mask] x_new[single_targets] = numpy.nan y_new[single_targets] = numpy.nan return x_new, y_new class TextItemArtistWrapper(ItemArtistWrapper): """Wrapper for TextItem.""" __gtype_name__ = "GraphsTextItemArtistWrapper" @GObject.Property(type=float, default=12) def size(self) -> float: """Get size property.""" return self._artist.get_fontsize() @size.setter def size(self, size: float) -> None: """Set size property.""" self._artist.set_fontsize(size) @GObject.Property(type=int, default=0, minimum=0, maximum=360) def rotation(self) -> int: """Get rotation property.""" return self._artist.get_rotation() @rotation.setter def rotation(self, rotation: int) -> None: """Set rotation property.""" self._artist.set_rotation(rotation) @GObject.Property(type=str, default="") def text(self) -> str: """Get text property.""" return self._artist.get_text() @text.setter def text(self, text: str) -> None: """Set text property.""" self._artist.set_text(text) @GObject.Property(type=float, default=0) def xanchor(self) -> float: """Get xanchor property.""" return self._artist.get_position()[0] @xanchor.setter def xanchor(self, xanchor: float) -> None: """Set xanchor property.""" self._artist.set_position((xanchor, self.props.yanchor)) @GObject.Property(type=float, default=0) def yanchor(self) -> float: """Get yanchor property.""" return self._artist.get_position()[1] @yanchor.setter def yanchor(self, yanchor: float) -> None: """Set yanchor property.""" self._artist.set_position((self.props.xanchor, yanchor)) def __init__(self, axis: pyplot.axis, item: Graphs.Item): super().__init__() self._artist = axis.text( item.get_xanchor(), item.get_yanchor(), item.get_text(), label=item.get_name(), color=item.get_color(), alpha=item.get_alpha(), fontsize=item.get_size(), rotation=item.get_rotation(), clip_on=True, ) self._color_artist = self._artist class FillItemArtistWrapper(ItemArtistWrapper): """Wrapper for FillItem.""" __gtype_name__ = "GraphsFillItemArtistWrapper" @GObject.Property(type=object, flags=2) def data(self) -> None: """Write-only property, ignored.""" @data.setter def data(self, data) -> None: dummy = Figure().add_subplot().fill_between(*data) self._artist.set_paths([dummy.get_paths()[0].vertices]) def __init__(self, axis: pyplot.axis, item: Graphs.Item): super().__init__() self._artist = axis.fill_between( *item.get_data_tuple(), label=item.get_name(), color=item.get_color(), alpha=item.get_alpha(), ) self._color_artist = self._artist Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/canvas.py000066400000000000000000000513351520337127000240600ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """ Custom canvas implementation. Acts as an interface between matplotlib and GObject and contains a custom implementation of a `SpanSelector` as well as a dummy toolbar used for interactive navigation in conjunction with graphs-specific structures. """ import math from gi.repository import Adw, Gdk, Gio, Graphs, Gtk from graphs.figure import Figure from matplotlib import RcParams, backend_tools as tools from matplotlib.backend_bases import ( FigureCanvasBase, MouseEvent, NavigationToolbar2, ) from matplotlib.backends.backend_gtk4cairo import FigureCanvas from matplotlib.widgets import SpanSelector _SCROLL_SCALE = 1.08 class Canvas(Graphs.Canvas, FigureCanvas): """Custom Canvas.""" __gtype_name__ = "GraphsPythonCanvas" def __init__( self, style_params: tuple[RcParams, dict], items: Gio.ListModel, interactive: bool = True, figure_settings: Graphs.FigureSettings = None, ): """ Create the canvas. Create figure, axes and define rubberband_colors based on the current style context. Bind `items` to `data.items` and all figure settings attributes to their respective values. """ Graphs.Canvas.__init__( self, hexpand=True, vexpand=True, ) self._idle_draw_id = 0 self.set_draw_func(self._draw_func) FigureCanvasBase.__init__( self, figure=Figure(style_params, items, self, figure_settings), ) self._rubberband_rect = None self.connect("notify::scale-factor", self._update_device_pixel_ratio) self.connect("resize", self._on_resize) # Handle stuff only used if the canvas is interactive if interactive: self._setup_interactive() def _setup_interactive(self): self._ctrl_held, self._shift_held = False, False self._xfrac, self._yfrac = None, None self.mpl_connect("pick_event", self._on_pick) self.mpl_connect("motion_notify_event", self._set_mouse_fraction) self._make_ticklabels_pickable() # Reference is created by the toolbar itself _DummyToolbar(self) click = Gtk.GestureClick() click.set_button(0) # All buttons. click.connect("pressed", self.button_press_event) click.connect("update", self.handle_touch_update) click.connect("released", self.button_release_event) self.add_controller(click) motion = Gtk.EventControllerMotion() motion.connect("motion", self.motion_notify_event) motion.connect("enter", self.enter_notify_event) motion.connect("leave", self.leave_notify_event) self.add_controller(motion) scroll = Gtk.EventControllerScroll.new( Gtk.EventControllerScrollFlags.BOTH_AXES, ) scroll.connect("scroll", self.scroll_event) scroll.connect("scroll-end", self.toolbar.push_current) self.add_controller(scroll) zoom = Gtk.GestureZoom.new() zoom.connect("scale-changed", self.zoom_event) zoom.connect("end", self.end_zoom_event) self.add_controller(zoom) def rgba_to_tuple(rgba): return (rgba.red, rgba.green, rgba.blue, rgba.alpha) style_manager = Adw.StyleManager() rgba = style_manager.get_accent_color_rgba() self.rubberband_edge_color = rgba_to_tuple(rgba) rgba.alpha = 0.2 self.rubberband_fill_color = rgba_to_tuple(rgba) self.highlight = _Highlight(self) self.connect("notify::mode", self._on_mode_change) self._on_mode_change() for item in ("min", "max"): self.connect( f"notify::{item}-selected", lambda _a, _b: self.highlight.load(self), ) def _make_ticklabels_pickable(self) -> None: """Make all tick labels pickable.""" for ax in self.figure.axes: for label in (ax.get_xticklabels() + ax.get_yticklabels()): label.set_picker(True) def handle_touch_update(self, controller: Gtk.GestureClick, _data) -> None: """ Handle an update event for GtkGestureClick motion. This is needed for touch screen devices to handle gestures properly. """ if not controller.get_point()[0]: # If touch event coords = controller.get_bounding_box_center() x, y = coords.x, coords.y MouseEvent( "motion_notify_event", self, *self._mpl_coords((x, y)), )._process() def key_press_event( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> None: """Handle key press event.""" if keyval in {65507, 65508}: # Control_L or Control_R self._ctrl_held = True elif keyval in {65505, 65506}: # Left or right Shift self._shift_held = True else: # Prevent keys from being true with key combos self._ctrl_held = False super().key_press_event(controller, keyval, keycode, state) def key_release_event( self, controller: Gtk.EventControllerKey, keyval: int, keycode: int, state: Gdk.ModifierType, ) -> None: """Handle key release event.""" self._ctrl_held = False self._shift_held = False super().key_release_event(controller, keyval, keycode, state) def scroll_event( self, controller: Gtk.EventControllerScroll, dx: float, dy: float, ) -> None: """ Handle scroll event. Updates only axes with independent coordinate systems to prevent uneven scaling: - X-limits: _axis and _top_left_axis (independent x ax.) - Y-limits: _axis, _right_axis, and _top_right_axis (independent y ax.) """ if self._ctrl_held: self.zoom(1 / _SCROLL_SCALE if dy > 0 else _SCROLL_SCALE) else: if self._shift_held: dx, dy = dy, dx if controller.get_unit() == Gdk.ScrollUnit.WHEEL: dx *= 10 dy *= 10 for ax in [self.figure.axis, self.figure.top_left_axis]: xmin, xmax = ax.get_xlim() scale = Graphs.scale_from_string(ax.get_xscale()) xmin, xmax = self._calculate_pan_values(xmin, xmax, scale, dx) ax.set_xlim(xmin, xmax) for ax in [ self.figure.axis, self.figure.right_axis, self.figure.top_right_axis, ]: ymin, ymax = ax.get_ylim() scale = Graphs.scale_from_string(ax.get_yscale()) ymin, ymax = self._calculate_pan_values(ymin, ymax, scale, -dy) ax.set_ylim(ymin, ymax) self.toolbar.push_current() super().scroll_event(controller, dx, dy) def zoom_event( self, controller: Gtk.GestureZoom, scale: float, ) -> None: """Handle zoom event.""" coords = controller.get_bounding_box_center() x, y = coords.x, coords.y event = MouseEvent( "motion_notify_event", self, *self._mpl_coords((x, y)), ) self._set_mouse_fraction(event) scale = 1 + 0.015 * (scale - 1) if scale > 5 or scale < 0.2: # Don't scale if ridiculous values are registered return self.zoom(scale) def end_zoom_event(self, controller: Gtk.GestureZoom, _sequence) -> None: """ End the zoom event. Pushes the canvas to the stack, and emits a `release` signal cancel out registered touches from touchscreen devices. """ coords = controller.get_bounding_box_center() x, y = coords.x, coords.y MouseEvent( "button_release_event", self, *self._mpl_coords((x, y)), 1, )._process() self.toolbar.push_current() def enter_notify_event( self, controller: Gtk.EventControllerMotion, x: float, y: float, ) -> None: """Process pointer entry.""" self.grab_focus() super().enter_notify_event(controller, x, y) def _set_mouse_fraction(self, event) -> None: """Set the mouse coordinate in terms of fraction of the canvas.""" if event.inaxes is not None: xlim = self.figure.top_right_axis.get_xlim() ylim = self.figure.top_right_axis.get_ylim() self._xfrac = Graphs.get_fraction_at_value( event.xdata, xlim[0], xlim[1], self.figure.props.top_scale, ) self._yfrac = Graphs.get_fraction_at_value( event.ydata, ylim[0], ylim[1], self.figure.props.right_scale, ) else: self._xfrac, self._yfrac = None, None def zoom(self, scaling: float = 1.25, respect_mouse: bool = True) -> None: """ Zoom with given scaling. Update all axes' limits in respect to the current mouse position, updates only axes with independent coordinate systems to prevent uneven scaling: - X-limits: _axis and _top_left_axis (independent x-ax.) - Y-limits: _axis, _right_axis, and _top_right_axis (independent y-ax.) """ if not respect_mouse: self._xfrac, self._yfrac = 0.5, 0.5 if self._xfrac is None or self._yfrac is None: return for ax in [self.figure.axis, self.figure.top_left_axis]: ax.set_xlim( self._calculate_zoomed_values( self._xfrac, Graphs.scale_from_string(ax.get_xscale()), ax.get_xlim(), scaling, ), ) for ax in [ self.figure.axis, self.figure.right_axis, self.figure.top_right_axis, ]: ax.set_ylim( self._calculate_zoomed_values( self._yfrac, Graphs.scale_from_string(ax.get_yscale()), ax.get_ylim(), scaling, ), ) self.queue_draw() @staticmethod def _calculate_pan_values( current_min: float, current_max: float, scale: Graphs.Scale, panspeed: float, ) -> tuple[float, float]: """Calculate axis values required for panning.""" pan_scale = 0.003 value1 = Graphs.get_value_at_fraction( panspeed * pan_scale, current_min, current_max, scale, ) value2 = Graphs.get_value_at_fraction( 1 + panspeed * pan_scale, current_min, current_max, scale, ) if scale == Graphs.Scale.INVERSE: value1, value2 = value2, value1 return value1, value2 @staticmethod def _calculate_zoomed_values( fraction: float, scale: Graphs.Scale, limit: float, zoom_factor: float, ) -> tuple[float, float]: """ Calculate zoomed values. Calculates the coordinates of the canvas after a zoom gesture has been ezoomed. """ min_, max_ = limit[0], limit[1] value1 = Graphs.get_value_at_fraction( fraction - fraction / zoom_factor, min_, max_, scale, ) value2 = Graphs.get_value_at_fraction( fraction + (1 - fraction) / zoom_factor, min_, max_, scale, ) if scale == Graphs.Scale.INVERSE: value1, value2 = value2, value1 return value1, value2 def _on_resize(self, widget, width, height) -> None: """Handle the legend update on window resizes.""" self.resize_event(widget, width, height) self.figure.update_legend() def _on_pick(self, event) -> None: """Emit edit-request signal for picked label, tick or title.""" artist = event.artist if not hasattr(artist, "id"): artist.id = self._determine_figure_setting(artist) self.emit("edit_request", artist.id) def _determine_figure_setting(self, artist) -> str: """ Determine the figure settings to be used on the tick after pick event. Determines the artist's position to generate an artist id that matches with the appropriate limits-widget figure_settings. The artist position is a tuple where one element is an integer (0 or 1) indicating the axis side, and the other is a numpy float indicating the value of the clicked tick. The position of the integer determines the axis: - Integer at index 0: X-axis (0=left, 1=right) - Integer at index 1: Y-axis (0=bottom, 1=top) """ artist_position = artist.get_position() # X axis if isinstance(artist_position[0], int): position, label_value = artist_position side = "left" if position == 0 else "right" # Y-axis elif isinstance(artist_position[1], int): label_value, position = artist_position side = "bottom" if position == 0 else "top" min_val = self.figure.get_property(f"min_{side}") max_val = self.figure.get_property(f"max_{side}") midpoint = (min_val + max_val) / 2 position_type = "max" if label_value > midpoint else "min" return f"{position_type}_{side}" # Overwritten function - do not change name def _post_draw(self, _widget, context) -> None: """Allow custom rendering extensions.""" if self._rubberband_rect is not None: self._draw_rubberband(context) def _draw_rubberband(self, ctx) -> None: """ Implement custom rubberband. Draw a rubberband matching libadwaitas style, where `_rubberband_rect` is set. """ radius = 6 x0, y0, width, height = ( dim / self.device_pixel_ratio for dim in self._rubberband_rect ) x1 = x0 + width y1 = y0 + height if x1 < x0: x0, x1 = x1, x0 if y1 < y0: y0, y1 = y1, y0 degrees = math.pi / 180 ctx.new_sub_path() ctx.arc(x1 - radius, y0 + radius, radius, -90 * degrees, 0 * degrees) ctx.arc(x1 - radius, y1 - radius, radius, 0 * degrees, 90 * degrees) ctx.arc(x0 + radius, y1 - radius, radius, 90 * degrees, 180 * degrees) ctx.arc(x0 + radius, y0 + radius, radius, 180 * degrees, 270 * degrees) ctx.close_path() ctx.set_line_width(1) ctx.set_source_rgba(*self.rubberband_fill_color) ctx.fill_preserve() ctx.set_source_rgba(*self.rubberband_edge_color) ctx.stroke() def _on_mode_change(self, *_args) -> None: highlight_enabled = self.props.mode == Graphs.Mode.SELECT self.highlight.set_active(highlight_enabled) self.highlight.set_visible(highlight_enabled) self.queue_draw() class _DummyToolbar(NavigationToolbar2): """Custom Toolbar implementation.""" # Overwritten function - do not change name def _zoom_pan_handler(self, event) -> None: mode = self.canvas.props.mode if event.button == 2: event.button = 1 mode = Graphs.Mode.PAN elif event.button != 1: return if mode == Graphs.Mode.PAN: if event.name == "button_press_event": self.press_pan(event) elif event.name == "button_release_event": self.release_pan(event) elif mode == Graphs.Mode.ZOOM: if event.name == "button_press_event": self.press_zoom(event) elif event.name == "button_release_event": self.release_zoom(event) # Overwritten function - do not change name def _update_cursor(self, event) -> None: mode = self.canvas.props.mode if event.inaxes and event.inaxes.get_navigate(): if mode == Graphs.Mode.PAN and \ self._last_cursor != tools.Cursors.MOVE: self.canvas.set_cursor(tools.Cursors.MOVE) self._last_cursor = tools.Cursors.MOVE elif mode == Graphs.Mode.ZOOM and \ self._last_cursor != tools.Cursors.SELECT_REGION: self.canvas.set_cursor(tools.Cursors.SELECT_REGION) self._last_cursor = tools.Cursors.SELECT_REGION elif self._last_cursor != tools.Cursors.POINTER: self.canvas.set_cursor(tools.Cursors.POINTER) self._last_cursor = tools.Cursors.POINTER # Overwritten function - do not change name def drag_pan(self, event) -> None: """Handle dragging in pan/zoom mode.""" for ax in self._pan_info.axes: # Using the recorded button at the press is safer than the current # button, as multiple buttons can get pressed during motion. # Use custom drag_pan that maxes sure limits are set in right order # even on inverted scale self.ax_drag_pan( ax, self._pan_info.button, event.key, event.x, event.y, ) self.canvas.draw_idle() @staticmethod def ax_drag_pan(self, button, key: str, x: float, y: float) -> None: """ Handle mouse events during a pan operation. Notes ----- This is intended to be overridden by new projection types. """ points = self._get_pan_points(button, key, x, y) if points is not None: # Max and min needs to be defined at correct position for this to # work with inverted scaling ylim = points[:, 1] xlim = points[:, 0] self.set_xlim(min(xlim), max(xlim)) self.set_ylim(min(ylim), max(ylim)) # Overwritten function - do not change name def draw_rubberband(self, _event, x0, y0, x1, y1) -> None: self.canvas._rubberband_rect = [ int(val) for val in (x0, self.canvas.figure.bbox.height - y0, x1 - x0, y0 - y1) ] self.canvas.queue_draw() # Overwritten function - do not change name def remove_rubberband(self) -> None: self.canvas._rubberband_rect = None self.canvas.queue_draw() # Overwritten function - do not change name def push_current(self, *_args) -> None: """Use custom functionality for the view clipboard.""" self.canvas.highlight.load(self.canvas) for direction in ("bottom", "left", "top", "right"): self.canvas.figure.notify(f"min-{direction}") self.canvas.figure.notify(f"max-{direction}") self.canvas.emit("view_changed") # Overwritten function - do not change name def save_figure(self) -> None: pass class _Highlight(SpanSelector): def __init__(self, canvas: Canvas): super().__init__( canvas.figure.top_right_axis, lambda _x, _y: self.apply(canvas), "horizontal", useblit=True, props={ "facecolor": canvas.rubberband_fill_color, "edgecolor": canvas.rubberband_edge_color, "linewidth": 1, }, handle_props={"linewidth": 0}, interactive=True, drag_from_anywhere=True, ) canvas.figure.top_right_axis.callbacks.connect( "xlim_changed", lambda _x: self.load(canvas), ) self.load(canvas) def load(self, canvas: Canvas) -> None: xmin, xmax = canvas.figure.top_left_axis.get_xlim() scale = canvas.figure.props.top_scale self.extents = ( Graphs.get_value_at_fraction( canvas.get_min_selected(), xmin, xmax, scale, ), Graphs.get_value_at_fraction( canvas.get_max_selected(), xmin, xmax, scale, ), ) def apply(self, canvas: Canvas) -> None: xmin, xmax = canvas.figure.top_left_axis.get_xlim() low, high = self.extents self.extents = max(xmin, low), min(xmax, high) for prefix, value in zip(["min_", "max_"], self.extents): canvas.set_property( prefix + "selected", Graphs.get_fraction_at_value( value, xmin, xmax, canvas.figure.props.top_scale, ), ) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/canvas.vala000066400000000000000000000007131520337127000243450ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gtk; namespace Graphs { /** * Custom Canvas implementation. */ public class Canvas : DrawingArea { public Mode mode { get; set; default = Mode.PAN; } public double min_selected { get; set; default = 0; } public double max_selected { get; set; default = 0; } public signal void edit_request (string id); public signal void view_changed (); } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/config.vapi000066400000000000000000000006241520337127000243540ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] namespace Config { public const string GETTEXT_PACKAGE; public const string LOCALEDIR; public const string APPLICATION_ID; public const string VERSION; public const string HOMEPAGE_URL; public const string ISSUE_URL; public const string COPYRIGHT; } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/curve_fitting.py000066400000000000000000000171371520337127000254570ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Curve fitting module.""" from gettext import gettext as _ from gi.repository import Gio, Graphs from graphs import canvas from graphs.item import DataItem, FillItem import numexpr import numpy from scipy.optimize import _minpack, curve_fit import sympy DATA_COLOR = "#1A5FB4" FIT_COLOR = "#A51D2D" FILL_COLOR = "#62A0EA" FILL_ALPHA = 0.25 MARKER_STYLE = 1 MARKER_SIZE = 13 LINE_STYLE = 0 class CurveFittingDialog(Graphs.CurveFittingDialog): """Class for displaying the Curve Fitting dialog.""" __gtype_name__ = "GraphsPythonCurveFittingDialog" def __init__(self, window: Graphs.Window, item: Graphs.Item): """Initialize the curve fitting dialog.""" xdata, ydata = item.get_xydata() self._data = xdata, ydata x_min, x_max = min(xdata), max(xdata) padding = (x_max - x_min) * 0.025 self._xlim = (x_min - padding, x_max + padding) self._x_fit = numpy.linspace(*self._xlim, 5000) style = Graphs.StyleManager.get_instance().get_system_style_params() self.data_curve = DataItem.new( style, xdata=xdata, ydata=ydata, name=item.get_name(), color=DATA_COLOR, linestyle=LINE_STYLE, markerstyle=MARKER_STYLE, markersize=MARKER_SIZE, ) self.fitted_curve = DataItem.new( style, xdata=[], ydata=[], color=FIT_COLOR, ) self.fill = FillItem.new( style, ([], [], []), color=FILL_COLOR, alpha=FILL_ALPHA, ) self.residuals_item = DataItem.new( style, xdata=[], ydata=[], color=DATA_COLOR, linestyle=LINE_STYLE, markerstyle=MARKER_STYLE, markersize=MARKER_SIZE, ) super().__init__(window=window) self.present(window) def _load_canvas(self) -> None: """Initialize and set main canvas.""" settings = self.props.window.get_data().get_figure_settings() style = Graphs.StyleManager.get_instance().get_system_style_params() listmodel = Gio.ListStore.new(Graphs.Item) listmodel.append(self.fitted_curve) listmodel.append(self.fill) listmodel.append(self.data_curve) cv = canvas.Canvas(style, listmodel, interactive=False) ax = cv.figure.axis ax.set( xlabel=settings.get_bottom_label(), ylabel=settings.get_left_label(), xlim=self._xlim, ) self.set_canvas(cv) listmodel = Gio.ListStore.new(Graphs.Item) listmodel.append(self.residuals_item) cv = canvas.Canvas(style, listmodel, interactive=False) ax = cv.figure.axis ax.set_ylabel(_("Residuals")) ax.set_xlabel(settings.get_bottom_label()) ax.axhline(y=0, color="black", linestyle="--", linewidth=0.5) ax.set_xlim(*self._xlim) ax.set_ylim(-1, 1) cv.figure.props.legend = False self.set_residuals_canvas(cv) def _fit_curve(self) -> None: """Handle fit curve request.""" free_vars = self.get_free_vars() variables = ["x"] + free_vars sym_params_map = dict(zip(variables, sympy.symbols(variables))) x_data, y_data = self._data equation = self.get_equation_string() settings = self.get_settings() def func(*params) -> numpy.ndarray: return numexpr.evaluate(equation, dict(zip(variables, params))) try: symbolic = sympy.sympify(equation, locals=sym_params_map) params, param_cov = curve_fit( func, x_data, y_data, p0=self.get_p0(), bounds=self.get_bounds(), nan_policy="omit", method=settings.get_string("optimization"), ) except (sympy.SympifyError, TypeError, SyntaxError): self.set_results(Graphs.CurveFittingError.EQUATION) return except (RuntimeError, _minpack.error): self.set_results(Graphs.CurveFittingError.CONVERGENCE) return except (ValueError, ZeroDivisionError, OverflowError): self.set_results(Graphs.CurveFittingError.DOMAIN) return if numpy.any(numpy.isinf(param_cov)): self.set_results(Graphs.CurveFittingError.SINGULAR) return # Calculate statistics residuals = y_data - func(x_data, *params) ss_res = numpy.sum(residuals**2) ss_tot = numpy.sum((y_data - numpy.mean(y_data))**2) d_cov = numpy.sqrt(numpy.diagonal(param_cov)) r2 = 1 - (ss_res / ss_tot) rmse = numpy.sqrt(ss_res / y_data.size) self.props.fit_result = Graphs.FitResult.new(params, d_cov, r2, rmse) self.residuals_item.set_xydata((x_data, residuals)) # Substitute each free variables with the calculated value. values = dict(zip(free_vars, params)) fitted_eq = str(sympy.simplify(symbolic.subs(values))) fitted_eq = Graphs.prettify_equation(fitted_eq) self.props.fitted_equation_string = fitted_eq x_fit = self._x_fit y_fit = func(x_fit, *params) if numpy.ndim(y_fit) == 0: y_fit = numpy.full(x_fit.size, y_fit.item()) self.fitted_curve.set_xydata((x_fit, y_fit)) self.fitted_curve.set_name(f"Y = {fitted_eq}") # Calculate and update confidence band for error propagation. local_dict = {"x": x_fit} | values jacobian = numpy.column_stack([ numpy.full(x_fit.size, g) if numpy.ndim( g := numexpr.evaluate( str(sympy.diff(symbolic, sym_params_map[name])), local_dict, ), ) == 0 else g for name in free_vars ]) variance = numpy.sum(jacobian * (jacobian @ param_cov), axis=1) std_dev_y = numpy.sqrt(numpy.abs(variance)) confidence_band = std_dev_y * settings.get_enum("confidence") y_upper = y_fit + confidence_band y_lower = y_fit - confidence_band self.fill.set_data_tuple((x_fit, y_lower, y_upper)) # Show fill and fit again after successful fit cv = self.get_canvas() ax = cv.figure.axis for line in ax.lines[1:]: line.set_visible(True) for collection in ax.collections: collection.set_visible(True) all_y = numpy.concatenate((y_lower, y_upper, y_data)) all_y = all_y[numpy.isfinite(all_y)] y_min, y_max = all_y.min(), all_y.max() padding = (y_max - y_min) * 0.025 ax.set_ylim(y_min - padding, y_max + padding) cv.queue_draw() cv = self.get_residuals_canvas() ax = cv.figure.axis ax.lines[0].set_visible(True) max_val = abs(residuals).max() if max_val > 0: y_lim = max_val * 1.1 ax.set_ylim(-y_lim, y_lim) else: ax.set_ylim(-1, 1) cv.queue_draw() self.set_results(Graphs.CurveFittingError.NONE) def _clear_fit(self) -> None: """Clear all fit-related data by hiding curves.""" cv = self.get_residuals_canvas() ax = cv.figure.axis ax.lines[0].set_visible(False) ax.set_ylim(-1, 1) # Hide all lines except the first one (data curve) cv = self.get_canvas() ax = cv.figure.axis for line in ax.lines[1:]: line.set_visible(False) # Hide all collections (fill) for collection in ax.collections: collection.set_visible(False) cv.queue_draw() Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/curve_fitting.vala000066400000000000000000000404771520337127000257550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gee; using Gtk; namespace Graphs { public class FittingParameter : Object { public string name { get; construct set; } public double initial { get; construct set; } // properties cannot assume infinite values private double lower_bound = -double.INFINITY; private double upper_bound = double.INFINITY; public FittingParameter (string name) { Object (name: name, initial: 1d); } public double get_lower_bound () { return lower_bound; } public void set_lower_bound (double lower_bound) { this.lower_bound = lower_bound; } public double get_upper_bound () { return upper_bound; } public void set_upper_bound (double upper_bound) { this.upper_bound = upper_bound; } } public class FitResult : Object { private double[] parameters; private double[] diag_covars; private double r2; private double rmse; public FitResult (double[] parameters, double[] diag_covars, double r2, double rmse) { this.parameters = parameters; this.diag_covars = diag_covars; this.r2 = r2; this.rmse = rmse; } public double[] get_parameters () { return parameters; } public double[] get_diag_covars () { return diag_covars; } public void get_r2_rmse (out double r2, out double rmse) { r2 = this.r2; rmse = this.rmse; } } public enum CurveFittingError { NONE, VALUE, BOUNDS, SINGULAR, CONVERGENCE, DOMAIN, EQUATION, CONFIDENCE; public string to_text () { switch (this) { case VALUE: return _("Please enter valid \nnumeric parameters."); case BOUNDS: return _("Constraint error: ensure \nLower < Initial < Upper."); case SINGULAR: return _("Matrix error: Data is \ninsufficient for this model."); case CONVERGENCE: return _("Fit failed: Max iterations \nreached without converging."); case DOMAIN: return _("Domain error: Equation not \nvalid for this data range."); case EQUATION: return _("Invalid equation: Check \nsyntax and variables."); case CONFIDENCE: return _("Confidence band error: \nCovariance matrix is unstable."); default: assert_not_reached (); } } } private const string[] EQUATIONS = { "a*x+b", // linear "a*x²+b*x+c", // quadratic "a*exp(b*x)", // exponential "a*x^b", // power "a*log(x)+b", // log "L/(1+exp(-k*(x-b)))", // sigmoid "a*exp(-(x-mu)²/(2*s²))" // gaussian }; /** * Curve fitting dialog. */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/curve-fitting.ui")] public class CurveFittingDialog : Adw.Dialog { [GtkChild] private unowned Adw.ComboRow equation { get; } [GtkChild] private unowned Button confirm_button { get; } [GtkChild] private unowned Adw.EntryRow custom_equation { get; } [GtkChild] private unowned Box fitting_params_box { get; } [GtkChild] private unowned TextView text_view { get; } [GtkChild] private unowned Adw.ToastOverlay toast_overlay { get; } [GtkChild] private unowned Adw.OverlaySplitView split_view { get; } [GtkChild] private unowned Adw.Bin canvas_container { get; } [GtkChild] private unowned Adw.Bin residuals_container { get; } public Window window { get; construct set; } protected GLib.Settings settings { get; protected set; } protected string equation_string { get; private set; } protected string fitted_equation_string { get; protected set; } protected FitResult? fit_result { get; protected set; } private Map fitting_parameters; private string[] free_vars = {}; protected Canvas? canvas { get { return canvas_container.get_child () as Canvas; } set { canvas_container.set_child (value); } } protected Canvas? residuals_canvas { get { return residuals_container.get_child () as Canvas; } set { residuals_container.set_child (value); } } construct { fitting_parameters = new HashMap (); fit_result = null; settings = Application.get_settings_child ("curve-fitting"); var action_map = new SimpleActionGroup (); Action confidence_action = settings.create_action ("confidence"); confidence_action.notify.connect (() => { if (fit_result == null) return; PythonHelper.run_method (this, "_fit_curve"); }); action_map.add_action (confidence_action); Action optimization_action = settings.create_action ("optimization"); optimization_action.notify.connect (() => { update_bounds_visibility (); PythonHelper.run_method (this, "_fit_curve"); }); action_map.add_action (optimization_action); Action res_action = settings.create_action ("show-residuals"); res_action.notify.connect (() => { bool show_residuals = settings.get_boolean ("show-residuals"); residuals_container.set_visible (show_residuals && residuals_canvas != null); }); action_map.add_action (res_action); bool show_residuals = settings.get_boolean ("show-residuals"); residuals_container.set_visible (show_residuals && residuals_canvas != null); var toggle_sidebar_action = new SimpleAction ("toggle_sidebar", null); toggle_sidebar_action.activate.connect (() => { split_view.show_sidebar = !split_view.show_sidebar; }); split_view.bind_property ( "collapsed", toggle_sidebar_action, "enabled", BindingFlags.SYNC_CREATE ); action_map.add_action (toggle_sidebar_action); insert_action_group ("win", action_map); custom_equation.set_text (settings.get_string ("custom-equation")); equation.set_selected (settings.get_enum ("equation")); equation.notify["selected"].connect (set_equation_from_selection); custom_equation.notify["text"].connect (on_custom_equation_text_changed); PythonHelper.run_method (this, "_load_canvas"); Adw.StyleManager.get_default ().notify.connect (() => PythonHelper.run_method (this, "_load_canvas")); set_equation_from_selection (); } protected double[] get_p0 () { double[] result = new double[fitting_parameters.size]; var iterator = fitting_parameters.map_iterator (); int idx = 0; while (iterator.has_next ()) { iterator.next (); result[idx++] = iterator.get_value ().initial; } return result; } protected void get_bounds (out double[] lower, out double[] upper) { lower = new double[fitting_parameters.size]; upper = new double[fitting_parameters.size]; var iterator = fitting_parameters.map_iterator (); int idx = 0; while (iterator.has_next ()) { iterator.next (); var param = iterator.get_value (); lower[idx] = param.get_lower_bound (); upper[idx] = param.get_upper_bound (); idx++; } } protected string[] get_free_vars () { return free_vars; } protected void set_results (CurveFittingError error) { var buffer = text_view.get_buffer (); buffer.set_text (""); var tag_table = buffer.get_tag_table (); var bold_tag = tag_table.lookup ("bold"); if (bold_tag == null) bold_tag = buffer.create_tag ("bold", "weight", 700); TextIter end_iter; buffer.get_end_iter (out end_iter); if (error != CurveFittingError.NONE) { buffer.insert (ref end_iter, error.to_text (), -1); confirm_button.set_sensitive (false); fit_result = null; PythonHelper.run_method (this, "_clear_fit"); return; } confirm_button.set_sensitive (true); if (fit_result == null) return; buffer.insert_with_tags_by_name (ref end_iter, _("Parameters") + "\n", -1, "bold"); double[] diag_covars = fit_result.get_diag_covars (); double[] parameters = fit_result.get_parameters (); int conf_level = settings.get_enum ("confidence"); int n = free_vars.length; for (int i = 0; i < n; i++) { buffer.insert (ref end_iter, "%s: %.3g".printf (free_vars[i], parameters[i]), -1); if (conf_level > 0) { double err = diag_covars[i] * conf_level; buffer.insert (ref end_iter, " (± %.3g)".printf (err), -1); } buffer.insert (ref end_iter, "\n", -1); } buffer.insert_with_tags_by_name (ref end_iter, "\n" + _("Statistics") + "\n", -1, "bold"); double r2, rmse; fit_result.get_r2_rmse (out r2, out rmse); string r2_rmse = "%s: %.3g\n%s: %.3g".printf (_("R²"), r2, _("RMSE"), rmse); buffer.insert (ref end_iter, r2_rmse, -1); } private void on_entry_change (Object object, ParamSpec p) { var entry = (Adw.EntryRow) object; var row = (FittingParameterBox) entry.get_ancestor (typeof (FittingParameterBox)); double init, low, high; bool value_error = false; var widget = row.initial; if (try_evaluate_string (widget.get_text (), out init)) { widget.remove_css_class ("error"); } else { widget.add_css_class ("error"); value_error = true; } widget = row.lower_bound; if (try_evaluate_string (widget.get_text (), out low)) { widget.remove_css_class ("error"); } else { widget.add_css_class ("error"); value_error = true; } widget = row.upper_bound; if (try_evaluate_string (widget.get_text (), out high)) { widget.remove_css_class ("error"); } else { widget.add_css_class ("error"); value_error = true; } if (value_error) { set_results (CurveFittingError.VALUE); return; } if (low >= high) { row.lower_bound.add_css_class ("error"); row.upper_bound.add_css_class ("error"); set_results (CurveFittingError.BOUNDS); return; } if (!(low <= init <= high)) { row.initial.add_css_class ("error"); set_results (CurveFittingError.BOUNDS); return; } var param = row.param; param.initial = init; param.set_lower_bound (low); param.set_upper_bound (high); PythonHelper.run_method (this, "_fit_curve"); } private void update_bounds_visibility () { bool visible = settings.get_enum ("optimization") > 0; var entry = (FittingParameterBox) fitting_params_box.get_first_child (); while (entry != null) { entry.set_bounds_visible (visible); entry = (FittingParameterBox) entry.get_next_sibling (); } } private void on_custom_equation_text_changed () { // Only validate if custom equation is visible if (equation.get_selected () != 7) return; if (handle_new_equation (custom_equation.get_text ())) { custom_equation.remove_css_class ("error"); } else { custom_equation.add_css_class ("error"); } } private void set_equation_from_selection () { int selected = (int) equation.get_selected (); string new_equation; if (selected != 7) { // Preset equation new_equation = EQUATIONS[selected]; this.equation.set_subtitle (@"Y=$new_equation"); custom_equation.set_visible (false); } else { // Custom equation new_equation = custom_equation.get_text (); this.equation.set_subtitle (""); custom_equation.set_visible (true); } handle_new_equation (new_equation); } private bool handle_new_equation (string equation) { // clear existing widgets Widget widget; while ((widget = fitting_params_box.get_last_child ()) != null) { fitting_params_box.remove (widget); } try { equation_string = preprocess_equation (equation); free_vars = MathTools.get_free_variables (equation_string); if (free_vars.length == 0) { set_results (CurveFittingError.EQUATION); return false; } var new_map = new HashMap (); FittingParameter param; bool use_bounds = settings.get_enum ("optimization") > 0; foreach (string variable in free_vars) { if (fitting_parameters.has_key (variable)) { param = fitting_parameters.get (variable); } else { param = new FittingParameter (variable); } var p_box = new FittingParameterBox (param); p_box.set_bounds_visible (use_bounds); p_box.initial.notify["text"].connect (on_entry_change); p_box.upper_bound.notify["text"].connect (on_entry_change); p_box.lower_bound.notify["text"].connect (on_entry_change); fitting_params_box.append (p_box); new_map.set (variable, param); } fitting_parameters = new_map; PythonHelper.run_method (this, "_fit_curve"); return true; } catch (MathError e) { set_results (CurveFittingError.EQUATION); return false; } } [GtkCallback] private void on_accept () { settings.set_enum ("equation", (int) equation.get_selected ()); settings.set_string ("custom-equation", custom_equation.get_text ()); Item item = ItemFactory.new_equation_item (window.data, fitted_equation_string); item.name = "Y = " + fitted_equation_string; Item[] items = {item}; window.data.add_items (items); window.data.optimize_limits (); close (); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/fitting-parameters.ui")] public class FittingParameterBox : Box { [GtkChild] private unowned Label label { get; } [GtkChild] public unowned Adw.EntryRow initial { get; } [GtkChild] public unowned Adw.EntryRow upper_bound { get; } [GtkChild] public unowned Adw.EntryRow lower_bound { get; } public FittingParameter param { get; construct set; } public FittingParameterBox (FittingParameter param) { this.param = param; string msg = _("Fitting Parameters for %s").printf (param.name); label.set_markup (@" $msg: "); initial.set_text (param.initial.to_string ()); } public void set_bounds_visible (bool visible) { upper_bound.set_visible (visible); lower_bound.set_visible (visible); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/data.py000066400000000000000000000513261520337127000235160ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Data management module.""" import copy import logging from collections import OrderedDict from collections.abc import Iterator from gettext import gettext as _ from operator import itemgetter from gi.repository import Gio, Graphs, Gtk from graphs import misc, project, style_io, utilities from graphs.item import ItemFactory from matplotlib import RcParams import numexpr import numpy import sympy from sympy.calculus.singularities import singularities _FIGURE_SETTINGS_HISTORY_IGNORELIST = misc.LIMITS + [ "min-selected", "max-selected", ] LOG_SCALES = {1, 2} NONZERO_SCALES = {1, 2, 4} class Data(Graphs.Data): """Class for managing data.""" __gtype_name__ = "GraphsPythonData" def __init__(self): self._selected_style_params = None, {} super().__init__() self.connect("load-request", self._on_load_request) self.connect("position-changed", self._on_position_changed) self.connect("item-changed", self._on_item_changed) self.connect("item-added", self._on_item_added) self.connect("item-removed", self._on_item_removed) self.connect( "figure-settings-changed", self._on_figure_settings_changed, ) self.connect( "add-history-state-request", self._on_add_history_state_request, ) def __len__(self) -> int: """Magic alias for `get_n_items()`.""" return self.get_n_items() def __iter__(self) -> Iterator[Graphs.Item]: """Iterate over items.""" for i in range(self.get_n_items()): yield self.get_item(i) def __getitem__(self, pos: int): """Magic alias for retrieving items.""" return self.get_item(pos) def get_old_selected_style_params(self) -> tuple[RcParams, dict]: """Get the old selected style properties.""" return self._old_style_params def get_selected_style_params(self) -> tuple[RcParams, dict]: """Get the selected style properties.""" return self._selected_style_params def _update_selected_style(self) -> None: figure_settings = self.props.figure_settings style_manager = Graphs.StyleManager.get_instance() error_msg = None if figure_settings.get_use_custom_style(): stylename = figure_settings.get_custom_style() for style in self.props.style_selection_model.get_model(): if stylename == style.get_name(): try: validate = None if style.get_mutable(): validate = style_manager.get_system_style_params() self._old_style_params = self._selected_style_params style_params, graphs_params = style_io.parse( style.get_file(), validate, ) self._selected_style_params = \ style_params, graphs_params self.set_color_cycle( style_params["axes.prop_cycle"].by_key()["color"], ) self.set_errbar_color_cycle( graphs_params["errorbar.color_cycle"].by_key() ["color"], ) return except (ValueError, SyntaxError, AttributeError): error_msg = _( "Could not parse style {stylename}, loading " "system preferred style", ).format(stylename=stylename) break error_msg = _( "Style {stylename} does not exist, " "loading system preferred style", ).format(stylename=stylename) if error_msg is not None: figure_settings.set_use_custom_style(False) logging.warning(error_msg) self._old_style_params = self._selected_style_params self._selected_style_params = style_manager.get_system_style_params() color_cycle = self._selected_style_params[0]["axes.prop_cycle"] self.set_color_cycle(color_cycle.by_key()["color"]) graphs_params = self._selected_style_params[1] self.set_errbar_color_cycle( graphs_params["errorbar.color_cycle"].by_key()["color"], ) def _init_history_states(self) -> None: limits = self.props.figure_settings.get_limits().values() self._history_states = [([], limits)] self._history_pos = -1 self._set_data_copy() @staticmethod def _on_position_changed(self, index1: int, index2: int) -> None: """Change item position of index2 to that of index1.""" self._current_batch.append(( Graphs.ChangeType.ITEMS_SWAPPED, (index2, index1), )) @staticmethod def _on_item_added(self, item: Graphs.Item) -> None: self._current_batch.append(( Graphs.ChangeType.ITEM_ADDED, item.to_dict(), )) @staticmethod def _on_item_removed(self, item: Graphs.Item, index: int) -> None: self._current_batch.append(( Graphs.ChangeType.ITEM_REMOVED, (index, item.to_dict()), )) @staticmethod def _on_item_changed(self, item: Graphs.Item, prop: str) -> None: index = self.index(item) value = item.get_property(prop) if prop != "data" \ else item.get_data_tuple() self._current_batch.append(( Graphs.ChangeType.ITEM_PROPERTY_CHANGED, ( index, prop, copy.deepcopy(self._data_copy[index][prop]), value, ), )) @staticmethod def _on_figure_settings_changed(self, prop: str) -> None: if prop in _FIGURE_SETTINGS_HISTORY_IGNORELIST: return self._current_batch.append(( Graphs.ChangeType.FIGURE_SETTINGS_CHANGED, ( prop, copy.deepcopy(self._figure_settings_copy[prop]), copy.deepcopy(self.props.figure_settings.get_property(prop)), ), )) def _set_data_copy(self) -> None: """Set a deep copy for the data.""" self._current_batch: list = [] self._data_copy = copy.deepcopy([item.to_dict() for item in self]) self._figure_settings_copy = copy.deepcopy({ prop.replace("_", "-"): self.props.figure_settings.get_property(prop) for prop in dir(self.props.figure_settings.props) }) def _collapse_current_batch(self) -> None: """ Collapse transitive changes within the current history batch. This method reduces redundant "change" entries in the current history batch: - Multiple consecutive item and figure settings changes to the same property are collapsed into a single change. - If a collapsed change would be meaningless (the original old value is equal to the most recent new value), that change is dropped. - If the batch contains structural changes like items added or removed, the method aborts and leaves the batch unchanged. """ if not self._current_batch: # Nothing to collapse return collapsed = OrderedDict() for change_type, data in self._current_batch: match change_type: case Graphs.ChangeType.ITEM_PROPERTY_CHANGED: index, prop, _old_value, new_value = data key = (change_type, index, prop) if key not in collapsed: collapsed[key] = (change_type, data) else: first_old = collapsed[key][1][2] if first_old == new_value: collapsed.pop(key) else: collapsed[key] = ( Graphs.ChangeType.ITEM_PROPERTY_CHANGED, (index, prop, first_old, new_value), ) case Graphs.ChangeType.FIGURE_SETTINGS_CHANGED: prop, _old_value, new_value = data key = (change_type, prop) if key not in collapsed: collapsed[key] = (change_type, data) else: first_old = collapsed[key][1][1] if first_old == new_value: collapsed.pop(key) else: collapsed[key] = ( Graphs.ChangeType.FIGURE_SETTINGS_CHANGED, (prop, first_old, new_value), ) case _: # On any other change such as items added or removed we # abort collapsing return self._current_batch = list(collapsed.values()) @staticmethod def _on_add_history_state_request(self) -> bool: """Add a state to the clipboard.""" self._collapse_current_batch() if not self._current_batch: # Nothing to add return False if self._history_pos != -1: self._history_states = self._history_states[:self._history_pos + 1] self._history_pos = -1 limits = self.get_figure_settings().get_limits().values() self._history_states.append((self._current_batch, limits)) # Keep history states length limited to 100 spots if len(self._history_states) > 101: self._history_states = self._history_states[1:] self._set_data_copy() return True def _undo(self) -> None: """Undo the latest change that was added to the clipboard.""" if not self.props.can_undo: return batch = self._history_states[self._history_pos][0] self._history_pos -= 1 selected = Gtk.Bitset.new_empty() mask = Gtk.Bitset.new_empty() for change_type, change in reversed(batch): match change_type: case Graphs.ChangeType.ITEM_PROPERTY_CHANGED: index, prop, value = itemgetter(0, 1, 2)(change) if prop == "selected": mask.add(index) if value: selected.add(index) elif prop == "data": self[index].set_data_tuple(value) else: self[index].set_property(prop, value) case Graphs.ChangeType.ITEM_ADDED: self._remove_item(self.get_n_items() - 1) case Graphs.ChangeType.ITEM_REMOVED: self._insert_item( ItemFactory.new_from_dict(copy.deepcopy(change[1])), change[0], ) case Graphs.ChangeType.ITEMS_SWAPPED: self.change_position(change[0], change[1]) case Graphs.ChangeType.FIGURE_SETTINGS_CHANGED: self.props.figure_settings.set_property( change[0], change[1], ) self.set_selection(selected, mask) limits = Graphs.Limits.new(self._history_states[self._history_pos][1]) self.get_figure_settings().set_limits(limits) self.props.can_redo = True self.props.can_undo = \ abs(self._history_pos) < len(self._history_states) self._set_data_copy() def _redo(self) -> None: """Redo the latest change that was added to the clipboard.""" if not self.props.can_redo: return self._history_pos += 1 state = self._history_states[self._history_pos] selected = Gtk.Bitset.new_empty() mask = Gtk.Bitset.new_empty() for change_type, change in state[0]: match change_type: case Graphs.ChangeType.ITEM_PROPERTY_CHANGED: index, prop, value = itemgetter(0, 1, 3)(change) if prop == "selected": mask.add(index) if value: selected.add(index) elif prop == "data": self[index].set_data_tuple(value) else: self[index].set_property(prop, value) case Graphs.ChangeType.ITEM_ADDED: change = copy.deepcopy(change) self._add_item(ItemFactory.new_from_dict(change)) case Graphs.ChangeType.ITEM_REMOVED: self._remove_item(change[0]) case Graphs.ChangeType.ITEMS_SWAPPED: self.change_position(change[1], change[0]) case Graphs.ChangeType.FIGURE_SETTINGS_CHANGED: self.props.figure_settings.set_property( change[0], change[2], ) self.set_selection(selected, mask) self.get_figure_settings().set_limits(Graphs.Limits.new(state[1])) self.props.can_redo = self._history_pos < -1 self.props.can_undo = True self._set_data_copy() def _optimize_limits(self) -> None: """Optimize the limits of the canvas to the data class.""" figure_settings = self.get_figure_settings() axes = [[ direction, False, figure_settings.get_property(f"min_{direction}"), figure_settings.get_property(f"max_{direction}"), figure_settings.get_property(f"{direction}_scale"), None, ] for direction in ("bottom", "left", "top", "right")] equation_items = [] hide_unselected = figure_settings.get_hide_unselected() for item in self: if not isinstance(item, (Graphs.DataItem, Graphs.EquationItem)): continue if not item.get_selected() and hide_unselected: continue if isinstance(item, Graphs.EquationItem): equation_items.append(item) continue indices = (item.get_xposition() * 2, 1 + item.get_yposition() * 2) for index, xydata in zip(indices, item.get_xydata()): axis = axes[index] xydata = xydata[numpy.isfinite(xydata)] if xydata.size == 0: continue if axis[4] in NONZERO_SCALES: nonzero = xydata[xydata != 0] min_value = nonzero.min() if nonzero.size else xydata.min() else: min_value = xydata.min() max_value = xydata.max() if axis[1]: axis[2] = min(axis[2], min_value) axis[3] = max(axis[3], max_value) else: axis[2] = min_value axis[3] = max_value axis[1] = True for item in equation_items: xindex = item.get_xposition() * 2 xaxis = axes[xindex] yaxis = axes[1 + item.get_yposition() * 2] x_limits = [xaxis[2], xaxis[3]] yscale = yaxis[4] equation = item.get_preprocessed_equation() expr = sympy.sympify(equation) domain = sympy.Interval(*x_limits) has_singularities = singularities(expr, misc.X, domain) if xaxis[5] is None: xscale = xaxis[4] xaxis[5] = utilities.create_equidistant_xdata(x_limits, xscale) ydata = numexpr.evaluate(equation, local_dict={"x": xaxis[5]}) ydata = ydata[numpy.isfinite(ydata)] if has_singularities: # Don't take negative values into account for log scaling if yscale in LOG_SCALES: ydata = ydata[ydata > 0] y_min, y_max = ydata.min(), ydata.max() lower_bound = Graphs.get_value_at_fraction( 0.05, y_min, y_max, yscale, ) upper_bound = Graphs.get_value_at_fraction( 0.95, y_min, y_max, yscale, ) ydata = ydata.clip(lower_bound, upper_bound) if ydata.size == 0: continue if yscale in NONZERO_SCALES: nonzero = ydata[ydata != 0] min_value = nonzero.min() if nonzero.size else ydata.min() else: min_value = ydata.min() max_value = ydata.max() if yaxis[1]: yaxis[2] = min(yaxis[2], min_value) yaxis[3] = max(yaxis[3], max_value) else: yaxis[2] = min_value yaxis[3] = max_value yaxis[1] = True for count, (direction, used, min_all, max_all, scale, _x) in \ enumerate(axes): if not used: continue # 0.05 padding on y-axis, 0.015 padding on x-axis padding_factor = 0.05 if count % 2 else 0.015 if scale not in LOG_SCALES: # For non-logarithmic scales span = max_all - min_all max_all += padding_factor * span # For inverse scale, calculate padding using a factor if scale == 4: min_all *= 0.99 else: min_all -= padding_factor * span else: # Use different scaling type for logarithmic scale log_min = numpy.log10(min_all) if min_all > 0 else 0 log_max = numpy.log10(max_all) if max_all > 0 else 0 log_span = log_max - log_min log_min -= padding_factor * log_span log_max += padding_factor * log_span min_all = 10**log_min max_all = 10**log_max figure_settings.set_property(f"min_{direction}", min_all) figure_settings.set_property(f"max_{direction}", max_all) def get_project_dict(self) -> dict: """Convert data to dict.""" figure_settings = self.get_figure_settings() view_pos, view_states = self.get_view_history() return { "version": self.get_version(), "data": [item.to_dict() for item in self], "figure-settings": { key.replace("_", "-"): figure_settings.get_property(key) for key in dir(figure_settings.props) }, "history-states": self._history_states, "history-position": self._history_pos, "view-history-states": [lims.values() for lims in view_states], "view-history-position": view_pos, } def load_from_project_dict(self, project_dict: dict) -> None: """Load data from dict.""" # Load data self.set_figure_settings( Graphs.FigureSettings( **{ key.replace("-", "_"): value for (key, value) in project_dict["figure-settings"].items() }, ), ) items = list(map(ItemFactory.new_from_dict, project_dict["data"])) self.set_items(items) # Set clipboard self._set_data_copy() self._history_states = project_dict["history-states"] self._history_pos = project_dict["history-position"] view_states = project_dict["view-history-states"] limits = list(map(Graphs.Limits.new, view_states)) self.set_view_history(project_dict["view-history-position"], limits) # Set clipboard/view buttons self.props.can_undo = \ abs(self._history_pos) < len(self._history_states) self.props.can_redo = self._history_pos < -1 def _save(self) -> None: project.save_project_dict(self.props.file, self.get_project_dict()) @staticmethod def _on_load_request( self, file: Gio.File, parse_flags: Graphs.ProjectParseFlags, ) -> str: try: project_dict = project.read_project_file(file, parse_flags) except project.ProjectParseError as error: if error.log: logging.exception(error) return error.message current_data = self.get_project_dict() try: self.load_from_project_dict(project_dict) except Exception: self.load_from_project_dict(current_data) msg = _("Failed to load project") logging.exception(msg) return msg return "" Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/data.vala000066400000000000000000000652641520337127000240170ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gee; using Gtk; namespace Graphs { /** * Data class */ public class Data : Object, ListModel, SelectionModel, Traversable, Iterable { public bool can_undo { get; protected set; default = false; } public bool can_redo { get; protected set; default = false; } public bool can_view_back { get; private set; default = false; } public bool can_view_forward { get; private set; default = false; } public File file { get; set; } [CCode (notify = false)] public bool unsaved { get; set; default = false; } public SingleSelection style_selection_model { get; private set; } public string selected_stylename { get { return this.get_selected_style ().name; } } private FigureSettings _figure_settings; public FigureSettings figure_settings { get { return this._figure_settings; } protected set { this._figure_settings = value; value.notify["custom-style"].connect (_on_custom_style); value.notify["use-custom-style"].connect (_on_use_custom_style); value.notify.connect ((v, param) => figure_settings_changed.emit (param.name)); _update_used_positions (); handle_style_change.begin (); } } private bool[] _used_positions; private Item[] _items = new Item[8]; private int _n_items = 0; private string[] _color_cycle; private string[] _used_colors; private string[] _errbar_color_cycle; private string[] _used_errbar_colors; private GLib.Settings _settings; private bool _notify_selection_changed = true; private Gee.List _view_history_states = new ArrayList (); private int _view_history_pos = -1; public signal void style_changed (bool recolor_items); protected signal string load_request (File file, ProjectParseFlags parse_flags); protected signal bool add_history_state_request (); // Clipboard signals protected signal void position_changed (uint index1, uint index2); protected signal void item_changed (Item item, string prop_name); protected signal void item_added (Item item); protected signal void item_removed (Item item, uint index); protected signal void figure_settings_changed (string prop); construct { this._color_cycle = {}; this._errbar_color_cycle = {}; items_changed.connect (_update_used_positions); this._settings = Application.get_settings_child ("figure"); this.style_selection_model = new SingleSelection (StyleManager.style_model); this.figure_settings = new FigureSettings (_settings); var style_manager = StyleManager.instance; style_manager.style_changed.connect (stylename => { if (!figure_settings.use_custom_style) return; if (figure_settings.custom_style == stylename) { handle_style_change.begin (); } }); style_manager.style_deleted.connect (stylename => { if (!figure_settings.use_custom_style) return; if (figure_settings.custom_style == stylename) { figure_settings.use_custom_style = false; } }); style_manager.style_renamed.connect ((old_name, new_name) => { if (figure_settings.custom_style == old_name) { figure_settings.custom_style = new_name; } }); Adw.StyleManager.get_default ().notify.connect (() => { if (!figure_settings.use_custom_style) { handle_style_change.begin (); } }); style_selection_model.selection_changed.connect (() => { Style style = get_selected_style (); // Don't trigger unnecessary reloads if (style.file == null) { // System Style if (figure_settings.use_custom_style) { figure_settings.use_custom_style = false; } } else { if (style.name != figure_settings.custom_style) { figure_settings.custom_style = style.name; } if (!figure_settings.use_custom_style) { figure_settings.use_custom_style = true; } } }); _view_history_states.add (figure_settings.get_limits ()); run_python_method ("_init_history_states"); if (figure_settings.use_custom_style) { _on_custom_style.begin (); } } private void run_python_method (string method) { PythonHelper.run_method (this, method); } // Section ListModel // All required methods to implement the ListModel interface public Object? get_item (uint position) { return _items[(int) position]; } public Type get_item_type () { return typeof (Item); } public uint get_n_items () { return _n_items; } public Item last () { return _items[_n_items - 1]; } // End section ListModel // Section SelectionModel // All required methods to implement the SelectionModel interface private void clear_selection () { for (uint index = 0; index < _n_items; index++) { _items[index].selected = false; } } public Bitset get_selection_in_range (uint position, uint n_items) { var bitset = new Bitset.empty (); for (uint index = position; index < position + n_items; index++) { if (_items[index].selected) bitset.add (index); } return bitset; } public bool is_selected (uint position) { return _items[position].selected; } public bool select_all () { _notify_selection_changed = false; for (uint index = 0; index < _n_items; index++) { _items[index].selected = true; } _notify_selection_changed = true; selection_changed.emit (0, _n_items); return true; } public bool select_item (uint position, bool unselect_rest) { if (unselect_rest) { _notify_selection_changed = false; clear_selection (); _items[position].selected = true; _notify_selection_changed = true; selection_changed.emit (0, _n_items); } else { _items[position].selected = true; } return true; } public bool select_range (uint position, uint n_items, bool unselect_rest) { _notify_selection_changed = false; if (unselect_rest) { clear_selection (); for (uint index = position; index < position + n_items; index++) { _items[index].selected = true; } selection_changed.emit (0, _n_items); } else { for (uint index = position; index < position + n_items; index++) { _items[index].selected = true; } selection_changed.emit (position, n_items); } _notify_selection_changed = true; return true; } public bool set_selection (Bitset selection, Bitset mask) { if (mask.is_empty ()) return true; _notify_selection_changed = false; for (int index = 0; index < _n_items; index++) { if (!mask.contains (index)) continue; _items[index].selected = selection.contains (index); } _notify_selection_changed = true; selection_changed.emit (0, _n_items); return true; } public bool unselect_all () { _notify_selection_changed = false; clear_selection (); _notify_selection_changed = true; selection_changed.emit (0, _n_items); return true; } public bool unselect_item (uint position) { _items[position].selected = false; return true; } public bool unselect_range (uint position, uint n_items) { _notify_selection_changed = false; for (uint index = position; index < position + n_items; index++) { _items[index].selected = false; } _notify_selection_changed = true; selection_changed.emit (position, n_items); return true; } // End section SelectionModel // Section management public void clear () { uint n_items = get_n_items (); for (int index = 0; index < n_items; index++) { _items[index] = null; } _n_items = 0; items_changed.emit (0, n_items, 0); this.can_undo = false; this.can_redo = false; this.can_view_back = false; this.can_view_forward = false; this.figure_settings = new FigureSettings (_settings); _view_history_states.clear (); _view_history_states.add (figure_settings.get_limits ()); run_python_method ("_init_history_states"); this.file = null; this.unsaved = false; notify_property ("unsaved"); } private void grow_if_needed (int grow_size) { int minimum_size = _n_items + grow_size; if (minimum_size > _items.length) { // double the capacity unless we add even more items at this time _items.resize (grow_size > _items.length ? minimum_size : 2 * _items.length); } } protected void _update_used_positions () { if (_n_items == 0) { _used_positions = {true, false, true, false}; return; } bool[] used_positions = {false, false, false, false}; Item item; for (uint index = 0; index < _n_items; index++) { item = _items[index]; if (figure_settings.hide_unselected && !item.selected) continue; used_positions[item.xposition] = true; used_positions[item.yposition + 2] = true; } _used_positions = used_positions; } private void _connect_to_item (Item item) { item.notify["selected"].connect (() => { if (_notify_selection_changed) selection_changed.emit (index (item), 1); }); item.notify.connect (_on_item_change); item.notify["xposition"].connect (_on_item_position_change); item.notify["yposition"].connect (_on_item_position_change); } protected void _add_item (Item item) { _connect_to_item (item); grow_if_needed (1); _items[_n_items] = item; items_changed.emit (_n_items++, 0, 1); } protected void _insert_item (Item item, int index) { _connect_to_item (item); grow_if_needed (1); _items.move (index, index + 1, _n_items - index); _items[index] = item; _n_items++; items_changed.emit (index, 0, 1); } protected void _remove_item (uint index) { _items[index] = null; _items.move ((int) index + 1, (int) index, (int) (_n_items - index - 1)); _n_items--; items_changed.emit (index, 1, 0); } private bool is_default (string prop) { string figure_settings_value; figure_settings.get (prop, out figure_settings_value); return (figure_settings_value == _settings.get_string (prop)); } private void append_used_color (string color) { if (color in _used_colors) return; if (!(color in _color_cycle)) return; _used_colors += color; if (_used_colors.length == _color_cycle.length) _used_colors = {}; } private void append_used_errbar_color (string color) { if (color in _used_errbar_colors) return; if (!(color in _errbar_color_cycle)) return; _used_errbar_colors += color; if (_used_errbar_colors.length == _errbar_color_cycle.length) _used_errbar_colors = {}; } /** * Add items to be managed. * * Respects settings in regards to handling duplicate names. * New Items with a x- or y-label change the figures current labels if * they are still the default. If they are already modified and do not * match the items label, they get moved to another axis. */ public void add_items (Item[] items) { _used_colors = {}; _used_errbar_colors = {}; foreach (Item item in this) { if (item.color in _color_cycle) append_used_color (item.color); if (item is DataItem) { string errcolor = ((DataItem) item).errcolor; if (errcolor in _errbar_color_cycle) append_used_errbar_color (errcolor); } } string[] used_names = get_names (); uint prev_size = _n_items; grow_if_needed (items.length); foreach (Item item in items) { item.name = Tools.get_duplicate_string (item.name, used_names); used_names += item.name; if (item.color == "") { foreach (string color in _color_cycle) { if (!(color in _used_colors)) { append_used_color (color); item.color = color; break; } } } if (item is DataItem) { string errcolor = ((DataItem) item).errcolor; if (errcolor == "") { foreach (string color in _errbar_color_cycle) { if (!(color in _used_errbar_colors)) { append_used_errbar_color (color); item.set ("errcolor", color); break; } } } } if (item.xlabel != "") { var original_position = item.xposition; if (original_position == XPosition.BOTTOM) { if (is_default ("bottom-label") | is_empty ()) { figure_settings.bottom_label = item.xlabel; } else if (item.xlabel != figure_settings.bottom_label) { item.xposition = XPosition.TOP; } } if (item.xposition == XPosition.TOP) { if (is_default ("top-label")) { figure_settings.top_label = item.xlabel; } else if (item.xlabel != figure_settings.top_label) { item.xposition = original_position; } } } if (item.ylabel != "") { var original_position = item.yposition; if (original_position == YPosition.LEFT) { if (is_default ("left-label") | is_empty ()) { figure_settings.left_label = item.ylabel; } else if (item.ylabel != figure_settings.left_label) { item.yposition = YPosition.RIGHT; } } if (item.yposition == YPosition.RIGHT) { if (is_default ("right-label")) { figure_settings.right_label = item.ylabel; } else if (item.ylabel != figure_settings.right_label) { item.yposition = original_position; } } } _connect_to_item (item); _items[_n_items++] = item; item_added.emit (item); } items_changed.emit (prev_size, 0, items.length); optimize_limits (); add_history_state (); } public void set_items (Item[] items) { uint removed = _n_items; foreach (Item item in items) { _connect_to_item (item); } _items = items; _n_items = items.length; _update_used_positions (); items_changed.emit (0, removed, _n_items); } public void delete_items (Item[] items) { foreach (Item item in items) { uint index = this.index (item); item_removed.emit (item, index); _remove_item (index); string axis_label; string prop; prop = item.xposition.friendly_string () + "-label"; figure_settings.get (prop, out axis_label); if (_used_positions[item.xposition] && item.xlabel == axis_label) { figure_settings.set (prop, _settings.get_string (prop)); } prop = item.yposition.friendly_string () + "-label"; figure_settings.get (prop, out axis_label); if (_used_positions[item.yposition + 2] && item.ylabel == axis_label) { figure_settings.set (prop, _settings.get_string (prop)); } } add_history_state (); } // End section management // Section style private async void handle_style_change (bool recolor_items = false) { notify_property ("selected_stylename"); run_python_method ("_update_selected_style"); style_changed.emit (recolor_items); } protected Style get_selected_style () { return (Style) style_selection_model.get_selected_item (); } protected void set_color_cycle (string[] color_cycle) { this._color_cycle = color_cycle; } protected void set_errbar_color_cycle (string[] color_cycle) { this._errbar_color_cycle = color_cycle; } // End section style // Section Vala iterator public Iterator iterator () { return new ItemIterator (this); } private class ItemIterator : Object, Traversable, Iterator { private Data _data; private int _index = -1; public bool read_only { get; default = true; } public bool valid { get { return _index >= 0 && has_next (); } } public ItemIterator (Data data) { _data = data; } public bool @foreach (ForallFunc f) { uint n_items = _data.get_n_items (); while (_index < n_items) { if (!f ((Item) _data.get_item (_index))) return false; _index++; } _index--; return true; } public bool has_next () { return _index + 1 < _data.get_n_items (); } public bool next () { if (has_next ()) { _index++; return true; } return false; } public new Item get () { return (Item) _data.get_item (_index); } public void remove () { assert_not_reached (); } } public bool @foreach (ForallFunc f) { for (int i = 0; i < _n_items; i++) { if (!f (_items[i])) return false; } return true; } // End section Vala iterator // Section misc protected string get_version () { return Config.VERSION; } public bool is_empty () { return _n_items == 0; } public Item[] get_items () { return _items[:_n_items]; } public string[] get_names () { string[] names = new string[_n_items]; for (int index = 0; index < _n_items; index++) { names[index] = _items[index].name; } return names; } public uint index (Item item) { for (uint index = 0; index < _n_items; index++) { if (_items[index] == item) return index; } assert_not_reached (); } public bool[] get_used_positions () { return _used_positions; } public void change_position (uint index1, uint index2) { if (index1 == index2) return; Item item = _items[index2]; if (index1 < index2) { _items.move ((int) index1, (int) index1 + 1, (int) (index2 - index1)); } else { _items.move ((int) index2 + 1, (int) index2, (int) (index1 - index2)); } _items[index1] = item; uint position = uint.min (index1, index2); uint changed = uint.max (index1, index2) - position + 1; items_changed.emit (position, changed, changed); position_changed.emit (index1, index2); } public void optimize_limits () { run_python_method ("_optimize_limits"); add_view_history_state (); } // End section misc // Section history public void add_history_state () { if (!add_history_state_request.emit ()) return; this.can_undo = true; this.can_redo = false; this.unsaved = true; notify_property ("unsaved"); } public void undo () { run_python_method ("_undo"); add_view_history_state (); } public void redo () { run_python_method ("_redo"); add_view_history_state (); } public void add_view_history_state () { var limits = figure_settings.get_limits (); var last = _view_history_states.last (); if (MathTools.all_close (limits.values (), last.values ())) return; if (_view_history_pos != -1) { int new_size = _view_history_states.size + _view_history_pos + 1; while (_view_history_states.size > new_size) { _view_history_states.remove_at (_view_history_states.size - 1); } } if (_view_history_states.size > 101) { _view_history_states.remove_at (0); } _view_history_pos = -1; _view_history_states.add (limits); this.can_view_back = true; this.can_view_forward = false; this.unsaved = true; notify_property ("unsaved"); } public void view_back () { if (!can_view_back) return; int index = _view_history_states.size + --_view_history_pos; figure_settings.set_limits (_view_history_states.get (index)); this.can_view_back = _view_history_pos.abs () < _view_history_states.size; this.can_view_forward = true; } public void view_forward () { if (!can_view_forward) return; int index = _view_history_states.size + ++_view_history_pos; figure_settings.set_limits (_view_history_states.get (index)); this.can_view_back = true; this.can_view_forward = _view_history_pos < -1; } protected int get_view_history (out Limits[] history) { history = _view_history_states.to_array (); return _view_history_pos; } protected void set_view_history (int pos, Limits[] history) { _view_history_states = new ArrayList.wrap (history); _view_history_pos = pos; this.can_view_back = _view_history_pos.abs () < _view_history_states.size; this.can_view_forward = _view_history_pos < -1; } // End section history // Section save & load public void save () { run_python_method ("_save"); this.unsaved = false; notify_property ("unsaved"); } public void load (File file, ProjectParseFlags flags = ProjectParseFlags.NONE) throws ProjectParseError { string error = load_request.emit (file, flags); if (error == "") { this.file = file; this.unsaved = false; notify_property ("unsaved"); } else { switch (error) { case "LEGACY_MIGRATION_DISALLOWED": throw new ProjectParseError.LEGACY_MIGRATION_DISALLOWED (""); case "BETA_DISALLOWED": throw new ProjectParseError.BETA_DISALLOWED (""); default: throw new ProjectParseError.INVALID_PROJECT (error); } } } // End section save & load // Section listeners private void _on_item_change (Object item, ParamSpec spec) { item_changed.emit ((Item) item, spec.name); } private void _on_item_position_change () { optimize_limits (); _update_used_positions (); items_changed.emit (0, 0, 0); } private async void _on_use_custom_style () { if (figure_settings.use_custom_style) { yield _on_custom_style (); } else { style_selection_model.set_selected (0); yield handle_style_change (true); } } private async void _on_custom_style () { if (!figure_settings.use_custom_style) return; var style_model = style_selection_model.get_model (); for (uint i = 1; i < style_model.get_n_items (); i++) { Style style = (Style) style_model.get_item (i); if (style.name == figure_settings.custom_style) { style_selection_model.set_selected (i); break; } } yield handle_style_change (true); } // End section listeners } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/export_figure.vala000066400000000000000000000057031520337127000257600ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { /** * Export figure dialog */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/export-figure.ui")] public class ExportFigureDialog : Adw.Dialog { [GtkChild] private unowned Adw.SwitchRow transparent { get; } [GtkChild] private unowned Adw.ComboRow file_format { get; } [GtkChild] private unowned Adw.SpinRow width { get; } [GtkChild] private unowned Adw.SpinRow height { get; } private Window window; private GLib.Settings settings; public ExportFigureDialog (Window window) { Object (); this.window = window; this.settings = Application.get_settings_child ("export-figure"); file_format.set_selected (settings.get_enum ("file-format")); transparent.set_active (settings.get_boolean ("transparent")); width.set_value (settings.get_int ("width")); height.set_value (settings.get_int ("height")); present (window); } [GtkCallback] private void on_use_window_size () { width.set_value (window.canvas.get_width ()); height.set_value (window.canvas.get_height ()); } [GtkCallback] private void on_accept () { string filename = C_("filename", "Exported Figure"); string old_suffix = settings.get_string ("file-format"); settings.set_enum ("file-format", (int) file_format.get_selected ()); string suffix = settings.get_string ("file-format"); var dialog = new FileDialog (); dialog.set_initial_name (@"$filename.$suffix"); dialog.set_accept_label (_("Export")); GLib.ListStore filter_store = new GLib.ListStore (typeof (FileFilter)); var filter = new FileFilter (); var selected = (StringObject) file_format.get_selected_item (); filter.name = selected.get_string (); filter.add_suffix (suffix); filter_store.append (filter); dialog.set_filters (filter_store); dialog.save.begin (window, null, (d, r) => { try { File file = dialog.save.end (r); settings.set_string ("file-format", suffix); settings.set_boolean ("transparent", transparent.get_active ()); settings.set_int ("width", (int) width.get_value ()); settings.set_int ("height", (int) height.get_value ()); PythonHelper.export_figure (file, settings, window.data); window.add_toast_string_with_file ( _("Exported Figure"), file ); close (); } catch { settings.set_string ("file-format", old_suffix); } }); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/export_items.py000066400000000000000000000045371520337127000253310ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for Exporting data.""" import sys from gi.repository import Gio, Graphs from graphs import utilities def export_items( mode: str, file: Gio.File, items: list[Graphs.Item], figure_settings: Graphs.FigureSettings, ) -> None: """Export items in specified format.""" callback = getattr(sys.modules[__name__], "_export_" + mode) callback(file, items, figure_settings) def _export_columns( file: Gio.File, items: list[Graphs.Item], figure_settings: Graphs.FigureSettings, ) -> None: """Save Items in columns format.""" if len(items) > 1: for item in items: name = f"{item.get_name()}.txt" _save_item( file.get_child_for_display_name(name), item, figure_settings, ) else: _save_item(file, items[0], figure_settings) def _save_item( file: Gio.File, item: Graphs.DataItem | Graphs.EquationItem | Graphs.GeneratedDataItem, figure_settings: Graphs.FigureSettings, ) -> None: """Save Item in columns format.""" delimiter = "\t" xlabel, ylabel = item.get_xlabel(), item.get_ylabel() stream = Gio.DataOutputStream.new( file.replace(None, False, Gio.FileCreateFlags.NONE, None), ) xerr, yerr = None, None if isinstance(item, (Graphs.DataItem, Graphs.GeneratedDataItem)): xdata, ydata, xerr, yerr = item.get_data_tuple() elif isinstance(item, Graphs.EquationItem): limits = figure_settings.get_limits().values() if item.get_xposition() == Graphs.XPosition.BOTTOM: limits = [limits[0], limits[1]] else: limits = [limits[2], limits[3]] equation = item.get_preprocessed_equation() xdata, ydata = utilities.equation_to_data(equation, limits) n_cols = 2 + (xerr is not None) + (yerr is not None) fmt = delimiter.join(["%.12e"] * n_cols) if xlabel != "" and ylabel != "": headers = [xlabel, ylabel] if xerr is not None: headers.append("x_err") if yerr is not None: headers.append("y_err") stream.put_string(delimiter.join(headers) + "\n") err_cols = [e for e in (xerr, yerr) if e is not None] for values in zip(xdata, ydata, *err_cols): stream.put_string(fmt % values + "\n") stream.close() Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/export_items.vala000066400000000000000000000031561520337127000256200ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gtk; namespace Graphs { namespace Export { public void export_items (Window window) { Data data = window.data; if (data.is_empty ()) { window.add_toast_string (_("No data to export")); return; } var dialog = new FileDialog (); if (data.get_n_items () > 1) { dialog.select_folder.begin (window, null, (d, response) => { try { PythonHelper.export_items ( window, "columns", dialog.select_folder.end (response), data.get_items () ); } catch {} }); } else { Item item = (Item) data.get_item (0); dialog.set_initial_name (item.name + ".txt"); dialog.set_filters (Tools.create_file_filters ( true, Tools.create_file_filter ( C_("file-filter", "Text Files"), "txt" ) )); dialog.save.begin (window, null, (d, response) => { try { PythonHelper.export_items ( window, "columns", dialog.save.end (response), data.get_items () ); } catch {} }); } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/figure.py000066400000000000000000000362541520337127000240710ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """ Custom figure implementation. Acts as an interface between matplotlib and GObject. """ import contextlib import logging from gi.repository import GObject, Gio, Graphs, Gtk from graphs import artist, misc from matplotlib import RcParams, figure, pyplot def _ellipsize(text: str, max_chars: int) -> str: """Truncate text with an ellipsis.""" return (text[:max_chars] + "…") if len(text) > max_chars else text class Figure(GObject.Object, figure.Figure): """Custom Figure.""" __gtype_name__ = "GraphsFigure" def __init__( self, style_params: tuple[RcParams, dict], items: Gio.ListModel, parent=None, figure_settings: Graphs.FigureSettings = None, ): GObject.Object.__init__(self) self._style_params = style_params self._items = items self.parent = parent pyplot.rcParams.update(self._style_params[0]) # apply style_params figure.Figure.__init__(self, tight_layout=True) self.axis = self.add_subplot(111) self.top_left_axis = self.axis.twiny() self.right_axis = self.axis.twinx() self.top_right_axis = self.top_left_axis.twinx() self._legend_axis = self.axis self._artists = [] if figure_settings is not None: bottom_scale = \ Graphs.scale_to_string(figure_settings.get_bottom_scale()) top_scale = \ Graphs.scale_to_string(figure_settings.get_top_scale()) left_scale = \ Graphs.scale_to_string(figure_settings.get_left_scale()) right_scale = \ Graphs.scale_to_string(figure_settings.get_right_scale()) self.axis.set_xscale(bottom_scale) self.axis.set_yscale(left_scale) self.top_left_axis.set_xscale(top_scale) self.top_left_axis.set_yscale(left_scale) self.right_axis.set_xscale(bottom_scale) self.right_axis.set_yscale(right_scale) self.top_right_axis.set_xscale(top_scale) self.top_right_axis.set_yscale(right_scale) limits = figure_settings.get_limits().values() self.axis.set_xlim(limits[0], limits[1]) self.axis.set_ylim(limits[4], limits[5]) self.top_left_axis.set_xlim(limits[2], limits[3]) self.top_left_axis.set_ylim(limits[4], limits[5]) self.right_axis.set_xlim(limits[0], limits[1]) self.right_axis.set_ylim(limits[6], limits[7]) self.top_right_axis.set_xlim(limits[2], limits[3]) self.top_right_axis.set_ylim(limits[6], limits[7]) title = figure_settings.get_title() self.axis.set_title(title, picker=True).id = "title" self.axis.set_xlabel( figure_settings.get_bottom_label(), picker=True, ).id = "bottom_label" self.top_left_axis.set_xlabel( figure_settings.get_top_label(), picker=True, ).id = "top_label" self.axis.set_ylabel( figure_settings.get_left_label(), picker=True, ).id = "left_label" self.right_axis.set_ylabel( figure_settings.get_right_label(), picker=True, ).id = "right_label" self._hide_unselected = figure_settings.get_hide_unselected() self._legend = figure_settings.get_legend() pos = figure_settings.get_legend_position() self._legend_position = Graphs.legend_position_to_string(pos) else: self._hide_unselected = False self._legend = True self._legend_position = "best" items.connect("items-changed", self._redraw) if isinstance(items, Gtk.SelectionModel): items.connect("selection-changed", self._redraw) self._redraw() def _redraw(self, *_args) -> None: logging.debug("redrawing figure") # bottom, top, left, right used_axes = [False, False, False, False] visible_axes = [False, False, False, False] drawable_items = [x for x in self._items if x.get_selected()] \ if self._hide_unselected else list(self._items) for item in drawable_items: xposition = item.get_xposition() yposition = item.get_yposition() visible_axes[xposition] = True visible_axes[2 + yposition] = True used_axes[xposition + 2 * yposition] = True axes_directions = ( ("bottom", "left"), # axis ("top", "left"), # top_left_axis ("bottom", "right"), # right_axis ("top", "right"), # top_right_axis ) if not any(visible_axes): visible_axes = (True, False, True, False) # Left and bottom used_axes = (True, False, False, False) # self.axis visible self._legend_axis = self.axis params, graphs_params = self._style_params draw_frame = params["axes.spines.bottom"] ticks = "both" if params["xtick.minor.visible"] else "major" for directions, axis, used \ in zip(axes_directions, self.axes, used_axes): axis.get_xaxis().set_visible(False) axis.get_yaxis().set_visible(False) # Set tick where requested, as long as that axis is not occupied # and visible if ( params[f"xtick.{directions[0]}"] or params[f"ytick.{directions[1]}"] ): tick_params = {} for i, direction in enumerate(misc.DIRECTIONS): tick_shown = ( (draw_frame and not visible_axes[i]) or direction in directions ) and params[f"{'x' if i < 2 else 'y'}tick.{direction}"] tick_params[direction] = tick_shown if graphs_params["ticklabels"]: tick_params[f"label{direction}"] = tick_shown axis.tick_params(which=ticks, **tick_params) for handle in [*axis.collections, *axis.lines, *axis.texts]: handle.remove() axis_legend = axis.get_legend() if axis_legend is not None: axis_legend.remove() for direction in misc.DIRECTIONS: axis.spines[direction].set_visible( direction in directions and used or draw_frame, ) if used: self._legend_axis = axis self.axis.get_xaxis().set_visible(visible_axes[0]) self.top_left_axis.get_xaxis().set_visible(visible_axes[1]) self.axis.get_yaxis().set_visible(visible_axes[2]) self.right_axis.get_yaxis().set_visible(visible_axes[3]) self._artists = [ artist.new_for_item(self, item) for item in reversed(drawable_items) ] self.update_legend() def update_legend(self, *_args) -> None: """Update the legend or hide if not used.""" if self._legend and self._artists: handles = [ handle.get_artist() for handle in self._artists if handle.legend ] if handles: max_char = max(10, int(self.bbox.width / 15)) labels = [_ellipsize(h.get_label(), max_char) for h in handles] self._legend_axis.legend( handles=handles, labels=labels, loc=self._legend_position, frameon=True, reverse=True, ) self.queue_draw() return legend = self._legend_axis.get_legend() if legend is not None: legend.remove() self.queue_draw() def set_properties(*args): """Pass method on to Figure.""" figure.Figure.set_properties(*args) def set_property(*args): """Pass method on to Figure.""" figure.Figure.set_property(*args) def queue_draw(self) -> None: """Queue a draw when in a canvas.""" with contextlib.suppress(AttributeError): self.canvas.queue_draw() @GObject.Property(type=bool, default=False) def hide_unselected(self) -> bool: """Whether or not to hide unselected items.""" return self._hide_unselected @hide_unselected.setter def hide_unselected(self, hide_unselected: bool) -> None: self._hide_unselected = hide_unselected self._redraw() @GObject.Property(type=bool, default=True) def legend(self) -> bool: """Whether or not, the legend is visible.""" return self._legend @legend.setter def legend(self, legend: bool) -> None: self._legend = legend self.update_legend() @GObject.Property( type=Graphs.LegendPosition, default=Graphs.LegendPosition.BEST, ) def legend_position(self) -> int: """Legend Position.""" return Graphs.LegendPosition.from_string(self._legend_position) @legend_position.setter def legend_position(self, pos: Graphs.LegendPosition) -> None: self._legend_position = Graphs.legend_position_to_string(pos) self.update_legend() @GObject.Property(type=str) def title(self) -> str: """Figure title.""" return self.axis.get_title() @title.setter def title(self, title: str) -> None: self.axis.set_title(title, picker=True).id = "title" self.queue_draw() @GObject.Property(type=str) def bottom_label(self) -> str: """Label of the bottom axis.""" return self.axis.get_xlabel() @bottom_label.setter def bottom_label(self, label: str) -> None: self.axis.set_xlabel(label, picker=True).id = "bottom_label" self.queue_draw() @GObject.Property(type=str) def left_label(self) -> str: """Label of the left axis.""" return self.axis.get_ylabel() @left_label.setter def left_label(self, label: str) -> None: self.axis.set_ylabel(label, picker=True).id = "left_label" self.queue_draw() @GObject.Property(type=str) def top_label(self) -> str: """Label of the top axis.""" return self.top_left_axis.get_xlabel() @top_label.setter def top_label(self, label: str) -> None: self.top_left_axis.set_xlabel(label, picker=True).id = "top_label" self.queue_draw() @GObject.Property(type=str) def right_label(self) -> str: """Label of the right axis.""" return self.right_axis.get_ylabel() @right_label.setter def right_label(self, label: str) -> None: self.right_axis.set_ylabel(label, picker=True).id = "right_label" self.queue_draw() @GObject.Property(type=int) def bottom_scale(self) -> int: """Scale of the bottom axis.""" return Graphs.scale_from_string(self.axis.get_xscale()) @bottom_scale.setter def bottom_scale(self, scale: int) -> None: scale = Graphs.scale_to_string(scale) for axis in (self.axis, self.right_axis): axis.set_xscale(scale) axis.set_xlim(None, None) self.queue_draw() @GObject.Property(type=int) def left_scale(self) -> int: """Scale of the left axis.""" return Graphs.scale_from_string(self.axis.get_yscale()) @left_scale.setter def left_scale(self, scale: int) -> None: scale = Graphs.scale_to_string(scale) for axis in (self.axis, self.top_left_axis): axis.set_yscale(scale) axis.set_ylim(None, None) self.queue_draw() @GObject.Property(type=int) def top_scale(self) -> int: """Scale of the top axis.""" return Graphs.scale_from_string(self.top_left_axis.get_xscale()) @top_scale.setter def top_scale(self, scale: int) -> None: scale = Graphs.scale_to_string(scale) for axis in (self.top_right_axis, self.top_left_axis): axis.set_xscale(scale) axis.set_xlim(None, None) self.queue_draw() @GObject.Property(type=int) def right_scale(self) -> int: """Scale of the right axis.""" return Graphs.scale_from_string(self.right_axis.get_yscale()) @right_scale.setter def right_scale(self, scale: int) -> None: scale = Graphs.scale_to_string(scale) for axis in (self.top_right_axis, self.right_axis): axis.set_yscale(scale) axis.set_ylim(None, None) self.queue_draw() @GObject.Property(type=float) def min_bottom(self) -> float: """Lower limit for the bottom axis.""" return self.axis.get_xlim()[0] @min_bottom.setter def min_bottom(self, value: float) -> None: for axis in (self.axis, self.right_axis): axis.set_xlim(value, None) self.queue_draw() @GObject.Property(type=float) def max_bottom(self) -> float: """Upper limit for the bottom axis.""" return self.axis.get_xlim()[1] @max_bottom.setter def max_bottom(self, value: float) -> None: for axis in (self.axis, self.right_axis): axis.set_xlim(None, value) self.queue_draw() @GObject.Property(type=float) def min_left(self) -> float: """Lower limit for the left axis.""" return self.axis.get_ylim()[0] @min_left.setter def min_left(self, value: float) -> None: for axis in (self.axis, self.top_left_axis): axis.set_ylim(value, None) self.queue_draw() @GObject.Property(type=float) def max_left(self) -> float: """Upper limit for the left axis.""" return self.axis.get_ylim()[1] @max_left.setter def max_left(self, value: float) -> None: for axis in (self.axis, self.top_left_axis): axis.set_ylim(None, value) self.queue_draw() @GObject.Property(type=float) def min_top(self) -> float: """Lower limit for the top axis.""" return self.top_left_axis.get_xlim()[0] @min_top.setter def min_top(self, value: float) -> None: for axis in (self.top_left_axis, self.top_right_axis): axis.set_xlim(value, None) self.queue_draw() @GObject.Property(type=float) def max_top(self) -> float: """Upper limit for the top axis.""" return self.top_left_axis.get_xlim()[1] @max_top.setter def max_top(self, value: float) -> None: for axis in (self.top_left_axis, self.top_right_axis): axis.set_xlim(None, value) self.queue_draw() @GObject.Property(type=float) def min_right(self) -> float: """Lower limit for the right axis.""" return self.right_axis.get_ylim()[0] @min_right.setter def min_right(self, value: float) -> None: for axis in (self.right_axis, self.top_right_axis): axis.set_ylim(value, None) self.queue_draw() @GObject.Property(type=float) def max_right(self) -> float: """Upper limit for the right axis.""" return self.right_axis.get_ylim()[1] @max_right.setter def max_right(self, value: float) -> None: for axis in (self.right_axis, self.top_right_axis): axis.set_ylim(None, value) self.queue_draw() Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/figure_settings.vala000066400000000000000000000075711520337127000263040ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { private const string[] LIMIT_NAMES = { "min-bottom", "max-bottom", "min-top", "max-top", "min-left", "max-left", "min-right", "max-right", }; public class Limits { private double[] _values; public Limits (double[] values) requires (values.length = 8) { _values = values; } public double[] values () { return _values; } public double get (uint i) { return _values[i]; } } /** * Figure settings */ public class FigureSettings : Object { public string title { get; set; default = ""; } public string bottom_label { get; set; default = ""; } public string left_label { get; set; default = ""; } public string top_label { get; set; default = ""; } public string right_label { get; set; default = ""; } public Scale bottom_scale { get; set; default = Scale.LINEAR; } public Scale left_scale { get; set; default = Scale.LINEAR; } public Scale top_scale { get; set; default = Scale.LINEAR; } public Scale right_scale { get; set; default = Scale.LINEAR; } public bool legend { get; set; default = true; } public LegendPosition legend_position { get; set; default = LegendPosition.BEST; } public bool use_custom_style { get; set; default = false; } public string custom_style { get; set; default = "Adwaita"; } public bool hide_unselected { get; set; default = false; } public double min_bottom { get; set; default = 0; } public double max_bottom { get; set; default = 1; } public double min_left { get; set; default = 0; } public double max_left { get; set; default = 10; } public double min_top { get; set; default = 0; } public double max_top { get; set; default = 1; } public double min_right { get; set; default = 0; } public double max_right { get; set; default = 10; } public double min_selected { get; set; default = 0; } public double max_selected { get; set; default = 0; } public FigureSettings (GLib.Settings settings) { Object ( bottom_scale: settings.get_enum ("bottom-scale"), left_scale: settings.get_enum ("left-scale"), right_scale: settings.get_enum ("right-scale"), top_scale: settings.get_enum ("top-scale"), title: settings.get_string ("title"), bottom_label: settings.get_string ("bottom-label"), left_label: settings.get_string ("left-label"), top_label: settings.get_string ("top-label"), right_label: settings.get_string ("right-label"), legend: settings.get_boolean ("legend"), use_custom_style: settings.get_boolean ("use-custom-style"), legend_position: settings.get_enum ("legend-position"), custom_style: settings.get_string ("custom-style") ); } public Limits get_limits () { double[] values = new double[8]; for (uint i = 0; i < LIMIT_NAMES.length; i++) { double limit; get (LIMIT_NAMES[i], out limit); values[i] = limit; } return new Limits ((owned) values); } public void set_limits (Limits limits) { for (uint i = 0; i < LIMIT_NAMES.length; i++) { set (LIMIT_NAMES[i], limits[i]); } } public void set_selection_range (double minimum, double maximum) requires (0 <= minimum <= 1) requires (0 <= maximum <= 1) requires (minimum <= maximum) { this.min_selected = minimum; this.max_selected = maximum; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/000077500000000000000000000000001520337127000245355ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/__init__.py000066400000000000000000000065071520337127000266560ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for importing data from files.""" import logging from gettext import gettext as _ from pathlib import Path from gi.repository import Graphs, Gtk from graphs.file_import import parsers from graphs.file_import.parsers import ( columns, project, spreadsheet, sql, xrdml, xry, ) from graphs.misc import ParseError _REQUESTS = ( "guess_import_mode", "init_import_settings", "append_settings_widgets", "parse", ) class DataImporter(Graphs.DataImporter): """Class for importing data.""" __gtype_name__ = "GraphsPythonDataImporter" def __init__(self): super().__init__() for request in _REQUESTS: request = request + "-request" self.connect( request, getattr(self, "_on_" + request.replace("-", "_")), ) # Order determines UI order parsers.register_parser(columns.ColumnsParser()) parsers.register_parser(project.ProjectParser()) parsers.register_parser(sql.SqlParser()) parsers.register_parser(spreadsheet.SpreadsheetParser()) parsers.register_parser(xrdml.XrdmlParser()) parsers.register_parser(xry.XryParser()) self.setup(parsers.list_parsers()) @staticmethod def _on_guess_import_mode_request( self, settings: Graphs.ImportSettings, ) -> int: """ Guess the import mode of a file. At the moment this relies purely on the file extension. """ try: filename = Graphs.tools_get_filename(settings.get_file()) file_suffix = Path(filename).suffixes[-1][1:] except IndexError: file_suffix = None for index, mode in enumerate(parsers.list_parsers()): suffixes = mode.get_file_suffixes() if suffixes is None: continue for suffix in suffixes: if file_suffix == suffix: return index return 0 # columns @staticmethod def _on_init_import_settings_request( self, settings: Graphs.ImportSettings, ) -> None: """ Init import settings. This is intended for filetypes, where the settings are dependent on the file itself or other runtime variables. """ parser = parsers.get_parser(settings.get_mode()) try: return parser.init_settings(settings) except Exception: return False @staticmethod def _on_append_settings_widgets_request( self, settings: Graphs.ImportSettings, settings_box: Gtk.Box, ) -> Gtk.Widget: """Load the UI settings.""" parser = parsers.get_parser(settings.get_mode()) parser.init_settings_widgets(settings, settings_box) @staticmethod def _on_parse_request( self, itemlist: Graphs.ItemList, settings: Graphs.ImportSettings, data: Graphs.Data, ) -> str: parser = parsers.get_parser(settings.get_mode()) try: parser.parse(itemlist, settings, data) return "" except ParseError as error: return error.message except Exception: message = _("Import failed") logging.exception(message) return message Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/dialog.vala000066400000000000000000000151201520337127000266400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/dialog.ui")] public class ImportDialog : Adw.Dialog { [GtkChild] private unowned Adw.NavigationSplitView navigation_view { get; } [GtkChild] private unowned Adw.NavigationPage file_settings_page { get; } [GtkChild] private unowned Adw.ComboRow mode { get; } [GtkChild] private unowned Adw.ToastOverlay toast_overlay { get; } [GtkChild] private unowned ListBox file_list { get; } [GtkChild] private unowned Box file_settings_box { get; } [GtkChild] private unowned Adw.PreferencesGroup default_group { get; } [GtkChild] private unowned Adw.PreferencesGroup remove_group { get; } [GtkChild] private unowned Button confirm_button { get; } private Window window; private GLib.ListStore settings_list; private ImportSettings current_settings; public ImportDialog (Window window, GLib.ListStore settings_list) { assert (settings_list.get_item_type () == typeof (ImportSettings)); this.window = window; this.settings_list = settings_list; mode.set_model (DataImporter.get_parser_names ()); file_list.bind_model (settings_list, (item) => { ImportSettings settings = (ImportSettings) item; if (!settings.is_valid) confirm_button.set_sensitive (false); settings.notify["is-valid"].connect (on_is_valid); return new ImportFileRow (settings); }); file_list.select_row (file_list.get_row_at_index (0)); navigation_view.set_show_content (false); present (window); } private void on_is_valid () { bool is_valid = true; for (uint i = 0; i < settings_list.get_n_items (); i++) { ImportSettings settings = (ImportSettings) settings_list.get_item (i); is_valid = is_valid && settings.is_valid; if (!is_valid) break; } confirm_button.set_sensitive (is_valid); } private void load_settings (ImportSettings settings) { current_settings = null; mode.set_selected (settings.mode); current_settings = settings; load_mode_settings (); } private void load_mode_settings () { Widget widget; while ((widget = file_settings_box.get_last_child ()) != null) { file_settings_box.remove (widget); } DataImporter.append_settings_widgets (current_settings, file_settings_box); default_group.set_visible (current_settings.has_schema); remove_group.set_visible (settings_list.get_n_items () > 1); } [GtkCallback] private void on_row_activated () { if (navigation_view.get_collapsed ()) navigation_view.set_show_content (true); } [GtkCallback] private void on_row_selected (ListBoxRow? row) { if (row == null) return; var file_row = (ImportFileRow) row; file_settings_page.set_title (file_row.settings.filename); load_settings (file_row.settings); } [GtkCallback] private void on_add () { var dialog = new FileDialog (); dialog.set_filters (DataImporter.file_filters); dialog.open_multiple.begin (window, null, (d, response) => { try { var files_list_model = dialog.open_multiple.end (response); for (uint i = 0; i < files_list_model.get_n_items (); i++) { var file = (File) files_list_model.get_item (i); var settings = DataImporter.get_settings_for_file (file); if (!settings.is_valid) confirm_button.set_sensitive (false); settings_list.append (settings); } remove_group.set_visible (true); } catch {} }); } [GtkCallback] private void on_mode () { if (current_settings == null) return; current_settings.mode = mode.get_selected (); load_mode_settings (); } [GtkCallback] private void on_reset () { DataImporter.reset (current_settings); load_settings (current_settings); } [GtkCallback] private void set_as_default () { DataImporter.set_as_default (current_settings); var toast = new Adw.Toast (_("Defaults updated")); toast_overlay.add_toast (toast); } [GtkCallback] private void remove () { uint index; settings_list.find (current_settings, out index); settings_list.remove (index); int new_index = index == 0 ? 0 : (int) index - 1; file_list.select_row (file_list.get_row_at_index (new_index)); on_is_valid (); if (navigation_view.get_collapsed ()) navigation_view.set_show_content (false); } [GtkCallback] private void on_accept () { ItemList itemlist = new ItemList (); for (uint i = 0; i < settings_list.get_n_items (); i++) { var settings = (ImportSettings) settings_list.get_item (i); string message = DataImporter.parse (itemlist, settings, window.data); if (message.length != 0) { window.add_toast_string (message); } } window.data.add_items (itemlist.to_array ()); close (); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/file-row.ui")] public class ImportFileRow : ListBoxRow { [GtkChild] private unowned Label filename { get; } [GtkChild] private unowned Label mode { get; } public ImportSettings settings; public ImportFileRow (ImportSettings settings) { this.settings = settings; filename.set_label (settings.filename); settings.bind_property ("mode_name", mode, "label", BindingFlags.SYNC_CREATE); settings.notify["is-valid"].connect (on_is_valid); on_is_valid (); } private void on_is_valid () { if (settings.is_valid) { remove_css_class ("error"); } else { add_css_class ("error"); } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/file_import.vala000066400000000000000000000162201520337127000277140ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gee; using Gtk; namespace Graphs { public class Parser : Object { public string name { get; construct set; } public string ui_name { get; construct set; } public string filetype_name { get; construct set; } public string[] file_suffixes { get; construct set; } } public class DataImporter : Object { public static GLib.ListStore file_filters { get; private set; } protected signal uint guess_import_mode_request (ImportSettings settings); protected signal bool init_import_settings_request (ImportSettings settings); protected signal Widget append_settings_widgets_request (ImportSettings settings, Box settings_box); protected signal string parse_request (ItemList itemlist, ImportSettings settings, Data data); private static GLib.Settings mode_settings; private static string[] mode_settings_list; private static Parser[] parsers; private static StringList parser_names = new StringList (null); private static DataImporter instance; protected void setup (Parser[] parsers) { DataImporter.parsers = parsers; foreach (Parser parser in parsers) { parser_names.append (parser.ui_name); } mode_settings = Application.get_settings_child ("import-params"); mode_settings_list = mode_settings.settings_schema.list_children (); init_file_filters (); DataImporter.instance = this; } private static void init_file_filters () { file_filters = new GLib.ListStore (typeof (FileFilter)); var supported_filter = new FileFilter () { name = C_("file-filter", "Supported files") }; file_filters.append (supported_filter); // columns var ascii_filter = new FileFilter () { name = C_("file-filter", "ASCII files") }; string[] ascii_suffixes = {"xy", "dat", "txt", "csv"}; foreach (string suffix in ascii_suffixes) { ascii_filter.add_suffix (suffix); supported_filter.add_suffix (suffix); } file_filters.append (ascii_filter); foreach (Parser parser in parsers) { if (parser.name == "columns") continue; var filter = new FileFilter () { name = parser.filetype_name }; foreach (string suffix in parser.file_suffixes) { filter.add_suffix (suffix); supported_filter.add_suffix (suffix); } file_filters.append (filter); } file_filters.append (Tools.create_all_filter ()); } public static Widget append_settings_widgets (ImportSettings settings, Box settings_box) { return instance.append_settings_widgets_request.emit (settings, settings_box); } public static StringList get_parser_names () { return parser_names; } public static ImportSettings get_settings_for_file (File file) { var settings = new ImportSettings (file); settings.mode = instance.guess_import_mode_request.emit (settings); settings.is_valid = init_import_settings (settings); settings.notify["mode"].connect (() => { settings.is_valid = init_import_settings (settings); }); return settings; } public static void set_as_default (ImportSettings settings) { string name = parsers[settings.mode].name; if (!(name in mode_settings_list)) return; settings.set_as_default (mode_settings.get_child (name)); } public static void reset (ImportSettings settings) { uint guessed_mode = instance.guess_import_mode_request.emit (settings); if (guessed_mode == settings.mode) { init_import_settings (settings); } else { settings.mode = guessed_mode; // init happens automatically } } public static string parse (ItemList itemlist, ImportSettings settings, Data data) { return instance.parse_request.emit (itemlist, settings, data); } private static bool init_import_settings (ImportSettings settings) { settings.mode_name = parser_names.get_string (settings.mode); string name = parsers[settings.mode].name; settings.load_from_settings (name in mode_settings_list ? mode_settings.get_child (name) : null); return instance.init_import_settings_request.emit (settings); } } public class ImportSettings : Object { public File file { get; construct set; } public string filename { get; construct set; } public uint mode { get; set; } public string mode_name { get; set; } public bool has_schema { get; private set; default = false; } public bool is_valid { get; set; } public signal void value_changed (string key, Variant val); private Map settings = new Gee.HashMap (); private Map items = new Gee.HashMap (); public ImportSettings (File file) { Object ( file: file, filename: Tools.get_filename (file) ); } public void load_from_settings (GLib.Settings? default_settings) { if (default_settings == null) { has_schema = false; return; } var keys = default_settings.settings_schema.list_keys (); has_schema = keys.length > 0; foreach (string key in keys) { set_value (key, default_settings.get_value (key)); } } public void set_as_default (GLib.Settings settings) { foreach (string key in settings.settings_schema.list_keys ()) { settings.set_value (key, get_value (key)); } } public void set_item (string key, GLib.Object item) { items.@set (key, item); } public GLib.Object get_item (string key) { return items.@get (key); } public void set_value (string key, Variant val) { settings.@set (key, val); value_changed.emit (key, val); } public Variant get_value (string key) { return settings.@get (key); } public void set_string (string key, string val) { set_value (key, new Variant.string (val)); } public string get_string (string key) { return get_value (key).get_string (); } public void set_int (string key, int val) { set_value (key, new Variant.int32 (val)); } public int get_int (string key) { return get_value (key).get_int32 (); } public void set_boolean (string key, bool val) { set_value (key, new Variant.boolean (val)); } public bool get_boolean (string key) { return get_value (key).get_boolean (); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/000077500000000000000000000000001520337127000262145ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/__init__.py000066400000000000000000000027161520337127000303330ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for parsing files.""" import logging from gi.repository import Graphs _PARSERS = [] class Parser(Graphs.Parser): """Parser class.""" __gtype_name__ = "GraphsPythonParser" def __init__( self, name: str, ui_name: str, filetype_name: str, file_suffixes: list[str], ): super().__init__( name=name, ui_name=ui_name, filetype_name=filetype_name, file_suffixes=file_suffixes, ) @staticmethod def parse(_items, _settings, _data) -> None: """ Parse a file given params. Must be implemented by parsers. """ raise NotImplementedError @staticmethod def init_settings(_settings) -> bool: """Init settings.""" return True @staticmethod def init_settings_widgets(_settings, _box) -> None: """Create settings widgets and append them to box.""" def register_parser(parser: Parser) -> None: """Register an import mode.""" _PARSERS.append(parser) logging.debug("registered mode " + parser.get_name()) def list_parsers() -> list[Parser]: """List all registered parse modes.""" return _PARSERS def list_parser_names() -> list[str]: """List all localised parse names.""" return [parser[0] for parser in _PARSERS] def get_parser(index: int) -> Parser: """Get parser.""" return _PARSERS[index] Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/columns/000077500000000000000000000000001520337127000276745ustar00rootroot00000000000000__init__.py000066400000000000000000000020211520337127000317210ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/columns# SPDX-License-Identifier: GPL-3.0-or-later """Module for parsing columns files.""" from gettext import pgettext as C_ from gi.repository import GLib, Graphs from graphs.file_import.parsers import Parser from graphs.misc import ParseError class ColumnsParser(Parser): """Columns parser.""" def __init__(self): super().__init__( "columns", C_("import-mode", "Columns"), None, None, ) @staticmethod def parse( items: Graphs.ItemList, settings: Graphs.ImportSettings, data: Graphs.Data, ) -> None: """Import data from columns file.""" parser = Graphs.ColumnsParser.new(settings) try: parser.parse() parser.add_items(data, items) except GLib.Error as e: raise ParseError(e.message) from e @staticmethod def init_settings_widgets(settings, box) -> None: """Append columns specific settings.""" box.append(Graphs.ColumnsBox.new(settings)) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/columns/main.vala000066400000000000000000000065101520337127000314670ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later namespace Graphs { public errordomain ColumnsParseError { INDEX_ERROR, IMPORT_ERROR, INVALID_CONFIGURATION } enum ColumnsDelimiter { WHITESPACE, TAB, COLON, SEMICOLON, COMMA, PERIOD, CUSTOM; public string friendly_string () { return this.to_string ()[25:].down (); } public static ColumnsDelimiter parse (string delimiter) { switch (delimiter) { case "whitespace": return ColumnsDelimiter.WHITESPACE; case "tab": return ColumnsDelimiter.TAB; case "colon": return ColumnsDelimiter.COLON; case "semicolon": return ColumnsDelimiter.SEMICOLON; case "comma": return ColumnsDelimiter.COMMA; case "period": return ColumnsDelimiter.PERIOD; case "custom": return ColumnsDelimiter.CUSTOM; default: assert_not_reached (); } } public string to_regex_pattern (string custom_delimiter) throws ColumnsParseError { switch (this) { case WHITESPACE: return "\\s+"; case TAB: return "\\t"; case COLON: return ":"; case SEMICOLON: return ";"; case COMMA: return ","; case PERIOD: return "\\."; case CUSTOM: if (custom_delimiter.length == 0) { throw new ColumnsParseError.INVALID_CONFIGURATION ( _("Custom delimiter cannot be empty") ); } return custom_delimiter; default: assert_not_reached (); } } } enum ColumnsSeparator { COMMA, PERIOD; public string friendly_string () { return this.to_string ()[25:].down (); } public unichar as_unichar () { return this == ColumnsSeparator.COMMA ? ',' : '.'; } public static ColumnsSeparator parse (string separator) { switch (separator) { case "comma": return ColumnsSeparator.COMMA; case "period": return ColumnsSeparator.PERIOD; default: assert_not_reached (); } } } public struct ColumnsItemSettings { public int column_x; public int column_y; public int xerr_index; public int yerr_index; public bool single_column; public bool use_xerr; public bool use_yerr; public string equation; public void load_from_variant (Variant variant) { variant.get ("(iiiibbbs)", out column_x, out column_y, out xerr_index, out yerr_index, out single_column, out use_xerr, out use_yerr, out equation ); } public Variant to_variant () { return new Variant ("(iiiibbbs)", column_x, column_y, xerr_index, yerr_index, single_column, use_xerr, use_yerr, equation ); } } } parser.vala000066400000000000000000000174601520337127000317660ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/columns// SPDX-License-Identifier: GPL-3.0-or-later using Gee; using Gtk; namespace Graphs { [Compact] private class Column { public double[] data = new double[64]; public string header = ""; public uint requests = 0; public double[] get_data () { if (requests == 0) assert_not_reached (); // If this is the last time the data is needed, transfer ownership if (requests-- == 1) return (owned) data; return data; } } /** * Reader class for parsing column-based text files */ public class ColumnsParser : Object { private ImportSettings settings; private unichar separator; private Regex delimiter_regex; private ColumnsItemSettings[] items; private Bitset used_indices = new Bitset.empty (); private uint64 n_used_indices; private Column[] columns; private int value_size = 0; public ColumnsParser (ImportSettings settings) throws Error { this.settings = settings; var separator = ColumnsSeparator.parse (settings.get_string ("separator")); this.separator = separator.as_unichar (); var iter = settings.get_value ("items").iterator (); items = new ColumnsItemSettings[iter.n_children ()]; for (int i = 0; i < items.length; i++) { var item_settings = ColumnsItemSettings (); item_settings.load_from_variant (iter.next_value ()); items[i] = item_settings; if (!item_settings.single_column) { used_indices.add (item_settings.column_x); } used_indices.add (item_settings.column_y); if (item_settings.use_yerr) { used_indices.add (item_settings.yerr_index); } if (item_settings.use_xerr) { used_indices.add (item_settings.xerr_index); } } this.n_used_indices = used_indices.get_size (); this.columns = new Column[n_used_indices]; for (uint i = 0; i < n_used_indices; i++) { columns[i] = new Column (); } foreach (ColumnsItemSettings item_settings in items) { if (!item_settings.single_column) { columns[get_rank (item_settings.column_x)].requests++; } columns[get_rank (item_settings.column_y)].requests++; if (item_settings.use_xerr) { columns[get_rank (item_settings.xerr_index)].requests++; } if (item_settings.use_yerr) { columns[get_rank (item_settings.yerr_index)].requests++; } } var delimiter_enum = ColumnsDelimiter.parse (settings.get_string ("delimiter")); string pattern = delimiter_enum.to_regex_pattern (settings.get_string ("custom-delimiter")); try { this.delimiter_regex = new Regex (pattern); } catch (RegexError e) { throw new ColumnsParseError.INVALID_CONFIGURATION (e.message); } } public void parse () throws Error { int skip_rows = settings.get_int ("skip-rows"); int max_index = (int) used_indices.get_maximum (); var stream = new DataInputStream (settings.file.read ()); string? line; int line_number = 0; var bitset_iter = BitsetIter (); uint column_index; uint column_rank; double val; int array_size = columns[0].data.length; while ((line = stream.read_line ()) != null) { if (++line_number <= skip_rows || line.strip ().length == 0) continue; string[] str_values = delimiter_regex.split_full (line, -1, 0, 0, (int) max_index + 2); if (str_values.length < max_index + 1 && value_size > 0) { throw new ColumnsParseError.INDEX_ERROR ( _("Index error in %s, cannot access index %d on line %d, only %d columns were found") .printf (settings.filename, max_index, line_number, str_values.length) ); } // if we reach capacity, grow the arrays. if (value_size == array_size) { array_size *= 2; foreach (weak Column column in columns) { column.data.resize (array_size); } } // We assume, that we have at least one valid index bitset_iter.init_first (used_indices, out column_index); column_rank = 0; do { if (column_index >= str_values.length) break; if (try_evaluate_string (str_values[column_index], out val, separator)) { columns[column_rank++].data[value_size] = val; continue; }; // If the data cannot be parsed, treat as header. // But only if there is not already data present if (value_size > 0) { throw new ColumnsParseError.IMPORT_ERROR ( _("Cannot import from file, bad value on line %d").printf (line_number) ); } columns[column_rank++].header = str_values[column_index]; // prevent leading 0 in data value_size = -1; } while (bitset_iter.next (out column_index)); value_size++; } // shrink to actual size foreach (weak Column column in columns) { column.data.resize (value_size); } stream.close (); } public void add_items (Data data, ItemList itemlist) throws Error { foreach (var item_settings in items) { uint yrank = get_rank (item_settings.column_y); string ylabel = columns[yrank].header; double[] ydata = columns[yrank].get_data (); double[]? xerr = item_settings.use_xerr ? columns[get_rank (item_settings.xerr_index)].get_data () : null; double[]? yerr = item_settings.use_yerr ? columns[get_rank (item_settings.yerr_index)].get_data () : null; string xlabel; double[] xdata; if (item_settings.single_column) { xlabel = ""; try { string equation = preprocess_equation (item_settings.equation); xdata = PythonHelper.evaluate_expression (equation, ydata.length, "n"); } catch (MathError e) { throw new ColumnsParseError.INVALID_CONFIGURATION (e.message); } } else { uint xrank = get_rank (item_settings.column_x); xlabel = columns[xrank].header; xdata = columns[xrank].get_data (); } Item item = ItemFactory.new_data_item (data, xdata, ydata, xerr, yerr); item.xlabel = xlabel; item.ylabel = ylabel; item.name = settings.filename; itemlist.add (item); } } private uint get_rank (uint val) { uint current; uint rank = 0; var bitset_iter = BitsetIter (); bitset_iter.init_first (used_indices, out current); do { if (current == val) return rank; rank++; } while (bitset_iter.next (out current)); assert_not_reached (); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/columns/ui.vala000066400000000000000000000165641520337127000311720ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gee; using Gtk; namespace Graphs { [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/columns/box.ui")] public class ColumnsBox : Box { [GtkChild] public unowned Box items_box { get; } private ImportSettings settings; private Gee.List items; public ColumnsBox (ImportSettings settings) { this.settings = settings; prepend (new ColumnsGroup (settings)); var iter = settings.get_value ("items").iterator (); size_t n_items = iter.n_children (); ColumnsItemSettings?[] item_settings_list = new ColumnsItemSettings?[n_items]; for (int i = 0; i < n_items; i++) { item_settings_list[i] = ColumnsItemSettings (); item_settings_list[i].load_from_variant (iter.next_value ()); } items = new ArrayList.wrap (item_settings_list); reload_item_groups (); } private void reload_item_groups () { Widget widget; while ((widget = items_box.get_last_child ()) != null) { items_box.remove (widget); } for (int i = 0; i < items.size; i++) { int index = i; var item_group = new ColumnsItemGroup (items[i], i > 0); item_group.set_title (_("Item %d").printf (i + 1)); item_group.settings_changed.connect ((new_settings) => { items[index] = new_settings; update_settings (); }); item_group.remove_request.connect (() => { items.remove_at (index); update_settings (); reload_item_groups (); }); items_box.append (item_group); } } [GtkCallback] private void add () { var new_settings = ColumnsItemSettings (); new_settings.load_from_variant (items[0].to_variant ()); items.add (new_settings); update_settings (); reload_item_groups (); } private void update_settings () { var builder = new VariantBuilder (new VariantType ("a(iiiibbbs)")); foreach (var item_settings in items) { builder.add_value (item_settings.to_variant ()); } settings.set_value ("items", builder.end ()); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/columns/main-group.ui")] public class ColumnsGroup : Adw.PreferencesGroup { [GtkChild] public unowned Adw.ComboRow delimiter { get; } [GtkChild] public unowned Adw.EntryRow custom_delimiter { get; } [GtkChild] public unowned Adw.ComboRow separator { get; } [GtkChild] public unowned Adw.SpinRow skip_rows { get; } public ColumnsGroup (ImportSettings settings) { delimiter.set_selected (ColumnsDelimiter.parse (settings.get_string ("delimiter"))); delimiter.notify["selected"].connect (() => { ColumnsDelimiter selected = (ColumnsDelimiter) delimiter.get_selected (); settings.set_string ("delimiter", selected.friendly_string ()); custom_delimiter.set_sensitive (selected == ColumnsDelimiter.CUSTOM); }); custom_delimiter.set_sensitive (delimiter.get_selected () == ColumnsDelimiter.CUSTOM); custom_delimiter.set_text (settings.get_string ("custom-delimiter")); custom_delimiter.notify["text"].connect (() => { settings.set_string ("custom-delimiter", custom_delimiter.get_text ()); }); separator.set_selected (ColumnsSeparator.parse (settings.get_string ("separator"))); separator.notify["selected"].connect (() => { settings.set_string ("separator", ((ColumnsSeparator) separator.get_selected ()).friendly_string ()); }); skip_rows.set_value (settings.get_int ("skip-rows")); skip_rows.notify["value"].connect (() => { settings.set_int ("skip-rows", (int) skip_rows.get_value ()); }); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/columns/item-group.ui")] public class ColumnsItemGroup : Adw.PreferencesGroup { [GtkChild] public unowned Adw.SpinRow column_x { get; } [GtkChild] public unowned Adw.SpinRow column_y { get; } [GtkChild] public unowned Adw.SwitchRow single_column { get; } [GtkChild] public unowned Adw.EntryRow equation { get; } [GtkChild] public unowned Adw.SwitchRow use_xerr { get; } [GtkChild] public unowned Adw.SwitchRow use_yerr { get; } [GtkChild] public unowned Adw.SpinRow column_xerr { get; } [GtkChild] public unowned Adw.SpinRow column_yerr { get; } [GtkChild] public unowned Button remove_button { get; } public signal void settings_changed (ColumnsItemSettings new_settings); public signal void remove_request (); public ColumnsItemGroup (ColumnsItemSettings item_settings, bool removable) { remove_button.set_visible (removable); load_item_settings (item_settings); single_column.notify["active"].connect (on_settings_changed); column_x.notify["value"].connect (on_settings_changed); column_y.notify["value"].connect (on_settings_changed); equation.notify["text"].connect (on_settings_changed); use_xerr.notify["active"].connect (on_settings_changed); use_yerr.notify["active"].connect (on_settings_changed); column_xerr.notify["value"].connect (on_settings_changed); column_yerr.notify["value"].connect (on_settings_changed); } private void load_item_settings (ColumnsItemSettings item_settings) { column_x.set_value (item_settings.column_x); column_y.set_value (item_settings.column_y); single_column.set_active (item_settings.single_column); equation.set_text (item_settings.equation); use_xerr.set_active (item_settings.use_xerr); use_yerr.set_active (item_settings.use_yerr); column_xerr.set_value (item_settings.xerr_index); column_yerr.set_value (item_settings.yerr_index); } private ColumnsItemSettings get_item_settings () { ColumnsItemSettings item_settings = ColumnsItemSettings (); item_settings.column_x = (int) column_x.get_value (); item_settings.column_y = (int) column_y.get_value (); item_settings.single_column = single_column.get_active (); item_settings.equation = equation.get_text ().replace (";", ""); item_settings.use_xerr = use_xerr.get_active (); item_settings.use_yerr = use_yerr.get_active (); item_settings.xerr_index = (int) column_xerr.get_value (); item_settings.yerr_index = (int) column_yerr.get_value (); return item_settings; } private void on_settings_changed () { settings_changed.emit (get_item_settings ()); } [GtkCallback] private void on_remove () { remove_request.emit (); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/project/000077500000000000000000000000001520337127000276625ustar00rootroot00000000000000__init__.py000066400000000000000000000021521520337127000317140ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/project# SPDX-License-Identifier: GPL-3.0-or-later """Module for "parsing" project files.""" from gettext import pgettext as C_ from gi.repository import Graphs from graphs import project from graphs.file_import.parsers import Parser from graphs.item import ItemFactory from graphs.misc import ParseError from graphs.project import ProjectParseError class ProjectParser(Parser): """Project parser.""" __gtype_name__ = "GraphsProjectParser" def __init__(self): super().__init__( "project", C_("import-mode", "Project"), C_("file-filter", "Graphs Project File"), ["graphs"], ) @staticmethod def parse( items: Graphs.ItemList, settings: Graphs.ImportSettings, _data: Graphs.Data, ) -> None: """Import data from project file.""" try: project_dict = project.read_project_file(settings.get_file()) items = list(map(ItemFactory.new_from_dict, project_dict["data"])) items.add_all(items) except ProjectParseError as e: raise ParseError(e.message) from e Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/spreadsheet/000077500000000000000000000000001520337127000305235ustar00rootroot00000000000000__init__.py000066400000000000000000000264151520337127000325650ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/spreadsheet# SPDX-License-Identifier: GPL-3.0-or-later """Module for parsing spreadsheet files (ODS/XLSX).""" import xml.etree.ElementTree import zipfile from gettext import gettext as _ from gettext import pgettext as C_ from gi.repository import GLib, Gio, Graphs, Gtk from graphs import file_io from graphs.file_import.parsers import Parser from graphs.item import DataItem from graphs.misc import ParseError import numexpr import numpy # XML Namespaces ODS_TABLE_NAMESPACE = "urn:oasis:names:tc:opendocument:xmlns:table:1.0" XLSX_MAIN_NAMESPACE = \ "http://schemas.openxmlformats.org/spreadsheetml/2006/main" class OdsParser: """ODS file parser.""" def get_sheet_names(self, file: Gio.File) -> list[str]: """Get sheet names from ODS file.""" with file_io.open(file, "rb") as file_obj, \ zipfile.ZipFile(file_obj) as zip_file, \ zip_file.open("content.xml") as content_file: root = xml.etree.ElementTree.parse(content_file).getroot() namespaces = {"table": ODS_TABLE_NAMESPACE} sheets = root.findall(".//table:table", namespaces) attribute_name = f"{{{namespaces['table']}}}name" return [sheet.get(attribute_name) for sheet in sheets] def parse_file( self, file: Gio.File, columns: set[int], sheet_index: int, ) -> list[tuple[str, list[float]]]: """Parse ODS file and return list of requested columns.""" with file_io.open(file, "rb") as file_obj, \ zipfile.ZipFile(file_obj) as zip_file, \ zip_file.open("content.xml") as content_file: root = xml.etree.ElementTree.parse(content_file).getroot() namespaces = {"table": ODS_TABLE_NAMESPACE} repeat_key = f"{{{namespaces['table']}}}number-columns-repeated" sheets = root.findall(".//table:table", namespaces) max_col = max(columns) raw_columns = {col_index: [[], ""] for col_index in columns} table_rows = sheets[sheet_index].findall( "table:table-row", namespaces, ) for table_row in table_rows: cells = table_row.findall("table:table-cell", namespaces) current_col = 0 for table_cell in cells: repeat_count = int(table_cell.get(repeat_key, 1)) cell_value = "".join(table_cell.itertext()) for _count in range(repeat_count): if current_col > max_col: break if current_col in columns: try: val = Graphs.evaluate_string(cell_value) raw_columns[current_col][0].append(val) except GLib.Error: if len(raw_columns[current_col][0]) == 0: raw_columns[current_col][1] = \ cell_value.strip() else: break current_col += 1 return raw_columns class XlsxParser: """XLSX file parser.""" def get_sheet_names(self, file: Gio.File) -> list[str]: """Get sheet names from XLSX file.""" with file_io.open(file, "rb") as file_obj, \ zipfile.ZipFile(file_obj) as zip_file, \ zip_file.open("xl/workbook.xml") as workbook_file: root = xml.etree.ElementTree.parse(workbook_file).getroot() namespaces = {"main": XLSX_MAIN_NAMESPACE} sheets = root.findall(f".//{{{namespaces['main']}}}sheet") return [sheet.get("name") for sheet in sheets] def parse_file( self, file: Gio.File, columns: set[int], sheet_index: int, ) -> list[tuple[str, list[float]]]: """Parse XLSX file and return 2D array of cell values.""" with file_io.open(file, "rb") as file_obj, \ zipfile.ZipFile(file_obj) as zip_file: shared_strings = self._load_shared_strings(zip_file) return self._parse_worksheet( zip_file, columns, sheet_index, shared_strings, ) def _load_shared_strings(self, zip_file: zipfile.ZipFile) -> list[str]: """Load shared strings from XLSX file.""" try: with zip_file.open("xl/sharedStrings.xml") as strings_file: root = xml.etree.ElementTree.parse(strings_file).getroot() namespace = XLSX_MAIN_NAMESPACE text_elements = root.findall(f".//{{{namespace}}}t") return [element.text or "" for element in text_elements] except KeyError: return [] # No shared strings in this file def _parse_worksheet( self, zip_file: zipfile.ZipFile, columns: set[int], sheet_index: int, shared_strings: list[str], ) -> list[list[str]]: """Parse worksheet and return requested columns.""" sheet_file = f"xl/worksheets/sheet{sheet_index + 1}.xml" with zip_file.open(sheet_file) as worksheet_file: root = xml.etree.ElementTree.parse(worksheet_file).getroot() namespaces = {"main": XLSX_MAIN_NAMESPACE} raw_columns = {col_index: [[], ""] for col_index in columns} for row_element in root.findall(".//main:row", namespaces): row_data = self._parse_row( row_element, namespaces, shared_strings, columns, ) for col_index in columns: cell_value = row_data.get(col_index, "") try: val = Graphs.evaluate_string(cell_value) raw_columns[col_index][0].append(val) except GLib.Error: if len(raw_columns[col_index][0]) == 0: raw_columns[col_index][1] = cell_value.strip() else: break return raw_columns def _parse_row( self, row_element, namespaces: dict, shared_strings: list[str], columns: set, ) -> dict: """Parse a single row element, returning only requested columns.""" cell_elements = row_element.findall("main:c", namespaces) cell_data = {} for cell_element in cell_elements: ref = cell_element.get("r") column = "".join(c for c in ref if not c.isdigit()) column_index = Graphs.tools_alpha_to_int(column) if column_index in columns: cell_data[column_index] = self._get_cell_value( cell_element, namespaces, shared_strings, ) return cell_data def _get_cell_value( self, cell_element, namespaces: dict, shared_strings: list[str], ) -> str: """Extract cell value, handling shared strings.""" value = cell_element.find("main:v", namespaces) cell_string = value.text if value is not None else "" cell_type = cell_element.get("t") if cell_type == "s": # Type s is for shared strings string_index = int(cell_string) cell_string = shared_strings[string_index] return cell_string class SpreadsheetParser(Parser): """Main spreadsheet parser that delegates to ODS/XLSX parsers.""" def __init__(self): super().__init__( "spreadsheet", C_("import-mode", "Spreadsheet"), C_("file-filter", "Spreadsheet"), ["ods", "xlsx"], ) @staticmethod def init_settings(settings: Graphs.ImportSettings) -> bool: """Init settings with default spreadsheet sheet selection.""" file = settings.get_file() parser = \ OdsParser() if file.get_path().endswith(".ods") else XlsxParser() try: sheet_names = parser.get_sheet_names(file) string_list = Gtk.StringList.new(sheet_names) settings.set_item("sheet-names", string_list) return True except zipfile.BadZipFile: return False @staticmethod def init_settings_widgets( settings: Graphs.ImportSettings, box: Gtk.Box, ) -> None: """Append Spreadsheet-specific settings widgets.""" if not settings.get_item("sheet-names"): return box.append(Graphs.SpreadsheetGroup.new(settings)) box.append(Graphs.SpreadsheetBox.new(settings)) @staticmethod def parse( items: Graphs.ItemList, settings: Graphs.ImportSettings, data: Graphs.Data, ) -> None: """Import data from ODS or XLSX file.""" style = data.get_selected_style_params() file = settings.get_file() sheet_index = settings.get_int("sheet-index") column_indices = set() item_settings_list = [] variant = settings.get_value("items") for i in range(variant.n_children()): item_settings = Graphs.ColumnsItemSettings() item_settings.load_from_variant(variant.get_child_value(i)) item_settings_list.append(item_settings) column_indices.add(item_settings.column_y) if not item_settings.single_column: column_indices.add(item_settings.column_x) if item_settings.use_xerr: column_indices.add(item_settings.xerr_index) if item_settings.use_yerr: column_indices.add(item_settings.yerr_index) file_parser = \ OdsParser() if file.get_path().endswith(".ods") else XlsxParser() parsed_columns = file_parser.parse_file( file, column_indices, sheet_index, ) for item_settings in item_settings_list: ydata, ylabel = parsed_columns[item_settings.column_y] if len(ydata) == 0: raise ParseError(_("No numeric data found in column.")) if item_settings.single_column: xlabel = "" xdata = numexpr.evaluate( Graphs.preprocess_equation(item_settings.equation), local_dict={"n": numpy.arange(len(ydata))}, ) if xdata.ndim == 0: xdata = numpy.full(len(ydata), xdata) else: xdata, xlabel = parsed_columns[item_settings.column_x] if len(xdata) != len(ydata): raise ParseError(_("Columns do not have the same length.")) xerr, _label = parsed_columns[item_settings.xerr_index] \ if item_settings.use_xerr else (None, None) yerr, _label = parsed_columns[item_settings.yerr_index] \ if item_settings.use_yerr else (None, None) items.add( DataItem.new( style, xdata, ydata, xerr=xerr, yerr=yerr, xlabel=xlabel, ylabel=ylabel, name=settings.get_filename(), ), ) ui.vala000066400000000000000000000157121520337127000317340ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/spreadsheetusing Gtk; using Gee; namespace Graphs { [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/spreadsheet/main-group.ui")] public class SpreadsheetGroup : Adw.PreferencesGroup { [GtkChild] private unowned Adw.ComboRow sheet_selector; public SpreadsheetGroup (ImportSettings settings) { var string_list = (Gtk.StringList) settings.get_item ("sheet-names"); sheet_selector.set_model (string_list); sheet_selector.set_selected (settings.get_int ("sheet-index")); sheet_selector.notify["selected"].connect (() => { settings.set_int ("sheet-index", (int) sheet_selector.get_selected ()); }); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/spreadsheet/item-group.ui")] public class SpreadsheetItemGroup : Adw.PreferencesGroup { [GtkChild] private unowned Adw.SpinRow column_x { get; } [GtkChild] private unowned Adw.SpinRow column_y { get; } [GtkChild] private unowned Adw.SwitchRow single_column { get; } [GtkChild] private unowned Adw.EntryRow equation { get; } [GtkChild] private unowned Adw.SwitchRow use_xerr { get; } [GtkChild] private unowned Adw.SwitchRow use_yerr { get; } [GtkChild] private unowned Adw.SpinRow column_xerr { get; } [GtkChild] private unowned Adw.SpinRow column_yerr { get; } [GtkChild] private unowned Button remove_button { get; } public signal void settings_changed (ColumnsItemSettings new_settings); public signal void remove_request (); public SpreadsheetItemGroup (ColumnsItemSettings item_settings, bool removable) { remove_button.set_visible (removable); column_x.output.connect (on_output); column_x.input.connect (on_input); column_y.output.connect (on_output); column_y.input.connect (on_input); column_xerr.output.connect (on_output); column_xerr.input.connect (on_input); column_yerr.output.connect (on_output); column_yerr.input.connect (on_input); load_item_settings (item_settings); single_column.notify["active"].connect (on_settings_changed); column_x.notify["value"].connect (on_settings_changed); column_y.notify["value"].connect (on_settings_changed); equation.notify["text"].connect (on_settings_changed); use_xerr.notify["active"].connect (on_settings_changed); use_yerr.notify["active"].connect (on_settings_changed); column_xerr.notify["value"].connect (on_settings_changed); column_yerr.notify["value"].connect (on_settings_changed); } private void load_item_settings (ColumnsItemSettings item_settings) { column_x.set_value (item_settings.column_x); column_y.set_value (item_settings.column_y); single_column.set_active (item_settings.single_column); equation.set_text (item_settings.equation); use_xerr.set_active (item_settings.use_xerr); use_yerr.set_active (item_settings.use_yerr); column_xerr.set_value (item_settings.xerr_index); column_yerr.set_value (item_settings.yerr_index); } private ColumnsItemSettings get_item_settings () { var item_settings = ColumnsItemSettings (); item_settings.column_x = (int) column_x.get_value (); item_settings.column_y = (int) column_y.get_value (); item_settings.single_column = single_column.get_active (); item_settings.equation = equation.get_text ().replace (";", ""); item_settings.use_xerr = use_xerr.get_active (); item_settings.use_yerr = use_yerr.get_active (); item_settings.xerr_index = (int) column_xerr.get_value (); item_settings.yerr_index = (int) column_yerr.get_value (); return item_settings; } private void on_settings_changed () { settings_changed.emit (get_item_settings ()); } [GtkCallback] private void on_remove () { remove_request.emit (); } private bool on_output (Adw.SpinRow spin_button) { spin_button.set_text (Tools.int_to_alpha ((int) spin_button.get_value ())); return true; } private int on_input (Adw.SpinRow spin_button, out double new_value) { new_value = Tools.alpha_to_int (spin_button.get_text ().strip ().up ()); return 1; } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/spreadsheet/box.ui")] public class SpreadsheetBox : Box { [GtkChild] private unowned Box items_box { get; } private ImportSettings settings; private Gee.List items; public SpreadsheetBox (ImportSettings settings) { this.settings = settings; var iter = settings.get_value ("items").iterator (); size_t n_items = iter.n_children (); ColumnsItemSettings?[] item_settings_list = new ColumnsItemSettings?[n_items]; for (int i = 0; i < n_items; i++) { item_settings_list[i] = ColumnsItemSettings (); item_settings_list[i].load_from_variant (iter.next_value ()); } items = new ArrayList.wrap (item_settings_list); reload_item_groups (); } private void reload_item_groups () { Widget widget; while ((widget = items_box.get_last_child ()) != null) { items_box.remove (widget); } for (int i = 0; i < items.size; i++) { int index = i; var item_group = new SpreadsheetItemGroup (items[i], i > 0); item_group.set_title (_("Item %d").printf (i + 1)); item_group.settings_changed.connect ((new_settings) => { items[index] = new_settings; update_settings (); }); item_group.remove_request.connect (() => { items.remove_at (index); update_settings (); reload_item_groups (); }); items_box.append (item_group); } } [GtkCallback] private void add () { var new_settings = ColumnsItemSettings (); new_settings.load_from_variant (items[0].to_variant ()); items.add (new_settings); update_settings (); reload_item_groups (); } private void update_settings () { var builder = new VariantBuilder (new VariantType ("a(iiiibbbs)")); foreach (var item_settings in items) { builder.add_value (item_settings.to_variant ()); } settings.set_value ("items", builder.end ()); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/sql/000077500000000000000000000000001520337127000270135ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/sql/__init__.py000066400000000000000000000031161520337127000311250ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for parsing sql files.""" from gettext import pgettext as C_ from gi.repository import GLib, Graphs, Gtk from graphs.file_import.parsers import Parser from graphs.misc import ParseError class SqlParser(Parser): """SQL database parser.""" __gtype_name__ = "GraphsSqlParser" def __init__(self): super().__init__( "sql", C_("import-mode", "Database"), C_("file-filter", "SQLite Database"), ["db", "sqlite", "sqlite3"], ) @staticmethod def parse( items: Graphs.ItemList, settings: Graphs.ImportSettings, data: Graphs.Data, ) -> None: """Import data from sqlite database file.""" db_reader = settings.get_item("db-reader") msg = db_reader.parse(items, settings, data) if msg != "": raise ParseError(msg) @staticmethod def init_settings(settings: Graphs.ImportSettings) -> bool: """Init settings with default table and column selection.""" try: db_reader = Graphs.DatabaseReader.new(settings) db_reader.set_default_selection() settings.set_item("db-reader", db_reader) return True except GLib.GError: return False @staticmethod def init_settings_widgets( settings: Graphs.ImportSettings, box: Gtk.Box, ) -> None: """Append SQL-specific settings widgets.""" if not settings.get_item("db-reader"): return box.append(Graphs.SqlGroup.new(settings)) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/sql/reader.vala000066400000000000000000000142371520337127000311310ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Sqlite; namespace Graphs { /** * Database reader class that handles all database operations */ public class DatabaseReader : GLib.Object { private Sqlite.Database db; public string[] table_names; private ImportSettings settings; public DatabaseReader (ImportSettings settings) throws IOError { this.settings = settings; string file_path = settings.file.get_path (); if (Sqlite.Database.open (file_path, out db) != Sqlite.OK) { throw new IOError.FAILED ( "Failed to open SQL Database: %s".printf (db.errmsg ()) ); } this.table_names = get_table_names (); } public string[] get_columns (string table_name) throws IOError { var columns = new Array (); Sqlite.Statement stmt; string sql = "PRAGMA table_info(`%s`)".printf (table_name); if (db.prepare_v2 (sql, -1, out stmt) != Sqlite.OK) { throw new IOError.FAILED ( "Failed to retrieve SQL Column names: %s".printf (db.errmsg ()) ); } while (stmt.step () == Sqlite.ROW) { columns.append_val (stmt.column_text (1)); } return columns.data; } public string[] get_numeric_columns (string table_name) throws IOError { var columns = new Array (); Sqlite.Statement stmt; string sql = "PRAGMA table_info(`%s`)".printf (table_name); if (db.prepare_v2 (sql, -1, out stmt) != Sqlite.OK) { throw new IOError.FAILED ( "Failed to retrieve SQL Column names: %s".printf (db.errmsg ()) ); } while (stmt.step () == Sqlite.ROW) { string col_name = stmt.column_text (1); string col_type = stmt.column_text (2).up (); if (is_numeric_type (col_type)) { columns.append_val (col_name); } } return columns.data; } private bool is_numeric_type (string type) { return "INT" in type || "REAL" in type || "FLOAT" in type || "DOUBLE" in type || "NUMERIC" in type || "DECIMAL" in type; } public void set_default_selection () throws IOError { if (table_names.length == 0) { throw new IOError.FAILED ("No tables found in database"); } string first_table = table_names[0]; string[] columns = get_numeric_columns (first_table); settings.set_string ("table-name", first_table); if (columns.length == 0) { settings.set_string ("x-column", ""); settings.set_string ("y-column", ""); settings.set_string ("xerr-column", ""); settings.set_string ("yerr-column", ""); } else { settings.set_string ("x-column", columns[0]); settings.set_string ("y-column", columns[0]); settings.set_string ("xerr-column", columns[0]); settings.set_string ("yerr-column", columns[0]); } } private double[] get_column_data (string table_name, string column_name) throws IOError { double[] result = new double[64]; int n_results = 0; Sqlite.Statement stmt; string sql = "SELECT `%s` FROM `%s`".printf (column_name, table_name); if (db.prepare_v2 (sql, -1, out stmt) != Sqlite.OK) { throw new IOError.FAILED ( "Failed to prepare SQL statement: %s".printf (db.errmsg ()) ); } while (stmt.step () == Sqlite.ROW) { if (n_results == result.length) { result.resize (result.length * 2); } result[n_results++] = stmt.column_double (0); } result.resize (n_results); return result; } private string[] get_table_names () throws IOError { var names = new Array (); Sqlite.Statement stmt; string sql = "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"; if (db.prepare_v2 (sql, -1, out stmt) != Sqlite.OK) { throw new IOError.FAILED ( "Failed to get SQL Table names: %s".printf (db.errmsg ()) ); } while (stmt.step () == Sqlite.ROW) { names.append_val (stmt.column_text (0)); } return names.data; } public string parse (ItemList items, ImportSettings settings, Data data) throws IOError { string table_name = settings.get_string ("table-name"); if (get_numeric_columns (table_name).length == 0) { string msg = _("Could not import data from table \"%s\", no numeric columns were found"); return msg.printf (table_name); } string x_column = settings.get_string ("x-column"); string y_column = settings.get_string ("y-column"); double[] xdata = get_column_data (table_name, x_column); double[] ydata = get_column_data (table_name, y_column); if (xdata.length == 0) return _("No data found in table column"); double[]? xerr = null; double[]? yerr = null; if (settings.get_boolean ("use-xerr")) xerr = get_column_data (table_name, settings.get_string ("xerr-column")); if (settings.get_boolean ("use-yerr")) yerr = get_column_data (table_name, settings.get_string ("yerr-column")); DataItem item = ItemFactory.new_data_item (data, xdata, ydata, xerr, yerr); item.xlabel = x_column; item.ylabel = y_column; item.name = x_column + " vs " + y_column; items.add (item); return ""; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/sql/ui.vala000066400000000000000000000121721520337127000303000ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { /** * UI Widget for SQL file import */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/import/sql/main-group.ui")] public class SqlGroup : Adw.PreferencesGroup { [GtkChild] public unowned Adw.ComboRow table_row { get; } [GtkChild] public unowned Adw.ComboRow column_x { get; } [GtkChild] public unowned Adw.ComboRow column_y { get; } [GtkChild] public unowned Adw.SwitchRow use_xerr { get; } [GtkChild] public unowned Adw.SwitchRow use_yerr { get; } [GtkChild] public unowned Adw.ComboRow column_xerr { get; } [GtkChild] public unowned Adw.ComboRow column_yerr { get; } [GtkChild] public unowned Gtk.Label no_numeric_warning { get; } private DatabaseReader db_reader; private ImportSettings settings; private bool is_initial_setup = true; public SqlGroup (ImportSettings settings) throws IOError { this.db_reader = (DatabaseReader) settings.get_item ("db-reader"); this.settings = settings; setup_ui (); } private void setup_ui () throws IOError { string[] tables = db_reader.table_names; string table_name = settings.get_string ("table-name"); var table_model = new StringList (tables); table_row.set_model (table_model); table_row.set_selected (table_model.find (table_name)); use_xerr.set_active (settings.get_boolean ("use-xerr")); use_yerr.set_active (settings.get_boolean ("use-yerr")); update_columns (); is_initial_setup = false; } [GtkCallback] private void on_table_changed () { if (is_initial_setup) return; var selected_item = (StringObject) table_row.get_selected_item (); if (selected_item == null) return; settings.set_string ("table-name", selected_item.get_string ()); try { update_columns (); } catch (IOError e) { warning ("Could not update columns: %s", e.message); } } [GtkCallback] private void on_err_toggled () { if (is_initial_setup) return; settings.set_boolean ("use-xerr", use_xerr.get_active ()); settings.set_boolean ("use-yerr", use_yerr.get_active ()); } [GtkCallback] private void on_columns_changed () { if (is_initial_setup) return; var selected_x = (StringObject) column_x.get_selected_item (); var selected_y = (StringObject) column_y.get_selected_item (); if (selected_x == null || selected_y == null) return; settings.set_string ("x-column", selected_x.get_string ()); settings.set_string ("y-column", selected_y.get_string ()); var selected_xerr = (StringObject) column_xerr.get_selected_item (); var selected_yerr = (StringObject) column_yerr.get_selected_item (); if (selected_xerr != null) { settings.set_string ("xerr-column", selected_xerr.get_string ()); } if (selected_yerr != null) { settings.set_string ("yerr-column", selected_yerr.get_string ()); } } private void update_columns () throws IOError { string x_column = settings.get_string ("x-column"); string y_column = settings.get_string ("y-column"); string xerr_column = settings.get_string ("xerr-column"); string yerr_column = settings.get_string ("yerr-column"); string table_name = settings.get_string ("table-name"); string[] columns = db_reader.get_numeric_columns (table_name); if (columns.length == 0) { no_numeric_warning.visible = true; column_x.sensitive = false; column_y.sensitive = false; } else { no_numeric_warning.visible = false; column_x.sensitive = true; column_y.sensitive = true; } var column_model = new StringList (columns); column_x.set_model (column_model); column_y.set_model (column_model); column_xerr.set_model (column_model); column_yerr.set_model (column_model); uint found = 0; for (int i = 0; i < columns.length; i++) { if (columns[i] == x_column) { column_x.set_selected (i); found++; } if (columns[i] == y_column) { column_y.set_selected (i); found++; } if (columns[i] == xerr_column) { column_xerr.set_selected (i); found++; } if (columns[i] == yerr_column) { column_yerr.set_selected (i); found++; } if (found == 4) break; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/xrdml/000077500000000000000000000000001520337127000273425ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/xrdml/__init__.py000066400000000000000000000044341520337127000314600ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for parsing xrdml files.""" from gettext import gettext as _ from gettext import pgettext as C_ from gi.repository import Graphs from graphs import file_io from graphs.file_import.parsers import Parser from graphs.item import DataItem import numpy class XrdmlParser(Parser): """Xrdml parser.""" __gtype_name__ = "GraphsXrdmlParser" def __init__(self): super().__init__( "xrdml", C_("import-mode", "xrdml"), C_("file-filter", "PANalytical XRDML"), ["xrdml"], ) @staticmethod def parse( items: Graphs.ItemList, settings: Graphs.ImportSettings, data: Graphs.Data, ) -> None: """Import data from xrdml file.""" content = file_io.parse_xml(settings.get_file()) intensities = content.getElementsByTagName("intensities") counting_time = content.getElementsByTagName("commonCountingTime") counting_time = float(counting_time[0].firstChild.data) ydata = intensities[0].firstChild.data.split() ydata = [int(value) / counting_time for value in ydata] scan_type = content.getElementsByTagName("scan") scan_axis = scan_type[0].attributes["scanAxis"].value if scan_axis.startswith("2Theta"): scan_axis = "2Theta" if scan_axis.startswith("Omega"): scan_axis = "Omega" data_points = content.getElementsByTagName("positions") for position in data_points: axis = position.attributes["axis"] if axis.value == scan_axis: unit = position.attributes["unit"].value start_pos = position.getElementsByTagName("startPosition") end_pos = position.getElementsByTagName("endPosition") start_pos = float(start_pos[0].firstChild.data) end_pos = float(end_pos[0].firstChild.data) xdata = numpy.linspace(start_pos, end_pos, len(ydata)) items.add( DataItem.new( data.get_selected_style_params(), xdata, ydata, name=settings.get_filename(), xlabel=f"{scan_axis} ({unit})", ylabel=_("Intensity (cps)"), ), ) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/xry/000077500000000000000000000000001520337127000270365ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/xry/__init__.py000066400000000000000000000014201520337127000311440ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for parsing xry files.""" from gettext import pgettext as C_ from gi.repository import Graphs from graphs.file_import.parsers import Parser class XryParser(Parser): """Xry parser.""" __gtype_name__ = "GraphsPythonXryParser" def __init__(self): super().__init__( "xry", C_("import-mode", "xry"), C_("file-filter", "Leybold xry"), ["xry"], ) @staticmethod def parse( items: Graphs.ItemList, settings: Graphs.ImportSettings, data: Graphs.Data, ) -> None: """Import data from .xry files used by Leybold X-ray apparatus.""" parser = Graphs.XryParser.new() parser.parse(data, settings, items) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_import/parsers/xry/parser.vala000066400000000000000000000072411520337127000312030ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later namespace Graphs { [Compact] private class XryColumn { public double[] data; public int? first_val = null; public int last_val = 0; public XryColumn (int size) { this.data = new double[size]; } } /** * Reader class for parsing xry files */ public class XryParser : Object { private DataInputStream input; private XryColumn[] columns; private double[] xdata; private void skip (int n) throws Error { for (int i = 0; i < n; i++) input.read_line (); } public void parse (Data data, ImportSettings settings, ItemList items) throws Error { var converter = new CharsetConverter ("UTF-8", "ISO-8859-1"); var conv_stream = new ConverterInputStream (settings.file.read (), converter); this.input = new DataInputStream (conv_stream); skip (4); string[] b_params = input.read_line ().strip ().split (" "); double x_step = evaluate_string (b_params[3]); double x_value = evaluate_string (b_params[0]); skip (12); string[] info = input.read_line ().strip ().split (" "); int item_count = (int) evaluate_string (info[0]); int length = (int) evaluate_string (info[1]); columns = new XryColumn[item_count]; for (int i = 0; i < item_count; i++) { columns[i] = new XryColumn (length); } xdata = new double[length]; Regex whitespace = new Regex ("\\s+"); for (int i = 0; i < length; i++) { string line = input.read_line ().strip (); string[] values = whitespace.split (line); for (int j = 0; j < item_count; j++) { if (!(values[j].down () == "nan")) { columns[j].data[i] = evaluate_string (values[j]); if (columns[j].first_val == null) columns[j].first_val = i; columns[j].last_val = i; } } xdata[i] = x_value; x_value += x_step; } for (int i = 0; i < item_count; i++) { unowned XryColumn column = columns[i]; if (column.first_val != 0) column.data = column.data[column.first_val:]; if (column.last_val != column.data.length - 1 + column.first_val) column.data.resize (column.last_val - column.first_val + 1); string name = settings.filename; if (item_count > 1) name = "%s - %d".printf (name, i + 1); double[] xdata = this.xdata[column.first_val:column.last_val + 1]; DataItem item = ItemFactory.new_data_item (data, xdata, column.data); item.name = name; item.xlabel = _("β (°)"); item.ylabel = _("R (1/s)"); items.add (item); } skip (9 + item_count); int text_item_count = (int) evaluate_string (input.read_line ()); for (int i = 0; i < text_item_count; i++) { string[] values = input.read_line ().strip ().split (" "); double xanchor = evaluate_string (values[5]); double yanchor = evaluate_string (values[6]); string text = string.joinv (" ", values[7:]); TextItem item = ItemFactory.new_text_item (data, xanchor, yanchor, text); item.name = text; items.add (item); } input.close (); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/file_io.py000066400000000000000000000017601520337127000242100ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for file operations.""" import json from xml.dom import minidom from gi.repository import Gio import gio_pyio def open(*args, **kwargs): """ Python open wrapper. Currently based on gio_pyio, but may change in the future. """ return gio_pyio.open(*args, **kwargs) def parse_json(file: Gio.File) -> dict: """Parse a json file to a python dict.""" with gio_pyio.open(file, "rb") as wrapper: return json.load(wrapper) def write_json(file: Gio.File, json_object: dict, pretty_print=True) -> None: """Write a python dict to a python file.""" with gio_pyio.open(file, "wt") as wrapper: json.dump( json_object, wrapper, indent=4 if pretty_print else None, sort_keys=True, ) def parse_xml(file: Gio.File) -> dict: """Parse a xml file to a python dict.""" with gio_pyio.open(file, "rb") as wrapper: return minidom.parse(wrapper) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/generate_data.vala000066400000000000000000000072271520337127000256640ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { /** * Generate Data dialog. */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/generate-data.ui")] public class GenerateDataDialog : Adw.Dialog { [GtkChild] private unowned Adw.EntryRow equation { get; } [GtkChild] private unowned Adw.EntryRow xstart { get; } [GtkChild] private unowned Adw.EntryRow xstop { get; } [GtkChild] private unowned Adw.SpinRow steps { get; } [GtkChild] private unowned Adw.ComboRow scale { get; } [GtkChild] private unowned Button confirm_button { get; } [GtkChild] private unowned Adw.EntryRow item_name { get; } private Window window; private GLib.Settings settings; public GenerateDataDialog (Window window) { Object (); this.window = window; this.settings = Application.get_settings_child ("generate-data"); this.equation.set_text (settings.get_string ("equation")); this.xstart.set_text (settings.get_string ("xstart")); this.xstop.set_text (settings.get_string ("xstop")); this.steps.set_value (settings.get_int ("steps")); this.scale.set_selected (settings.get_enum ("scale")); present (window); } private void set_confirm_sensitivity () { bool invalid = false; Widget[] widgets = {equation, xstart, xstop}; foreach (Widget widget in widgets) { invalid = invalid || widget.has_css_class ("error"); } confirm_button.set_sensitive (!invalid); } [GtkCallback] private void on_accept () { string equation = this.equation.get_text (); string xstart = this.xstart.get_text (); string xstop = this.xstop.get_text (); int steps = (int) this.steps.get_value (); Scale scale = (Scale) this.scale.get_selected (); this.settings.set_string ("equation", equation); this.settings.set_string ("xstart", xstart); this.settings.set_string ("xstop", xstop); this.settings.set_int ("steps", steps); this.settings.set_enum ("scale", scale); string name = item_name.get_text (); if (name == "") name = "Y = " + equation; Item item = ItemFactory.new_generated_data_item (window.data, equation, xstart, xstop, steps, scale); item.name = name; Item[] items = {item}; window.data.add_items (items); window.data.optimize_limits (); close (); } [GtkCallback] private void on_equation_change () { if (PythonHelper.validate_equation (equation.get_text ())) { equation.remove_css_class ("error"); } else { equation.add_css_class ("error"); } set_confirm_sensitivity (); } [GtkCallback] private void on_entry_change (Object object, ParamSpec _param_spec) { var entry = object as Adw.EntryRow; if (try_evaluate_string (entry.get_text ())) { entry.remove_css_class ("error"); } else { entry.add_css_class ("error"); } set_confirm_sensitivity (); } [GtkCallback] private int on_steps_input (out double val) { if (try_evaluate_string (steps.get_text (), out val)) { return 1; } else { return Gtk.INPUT_ERROR; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/graphs.in000077500000000000000000000057571520337127000240610ustar00rootroot00000000000000#!/usr/bin/env python3 # Graphs # Plot and manipulate data # # @HOMEPAGE_URL@ # @VCS_URL@ # # Copyright @COPYRIGHT@ The Graphs Developers # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # SPDX-License-Identifier: GPL-3.0-or-later """Main graphs module.""" if __name__ == "__main__": import gi gi.require_version("Adw", "1") gi.require_version("Gtk", "4.0") gi.require_version("Graphs", "1") import asyncio import os import signal import sys from gi.events import GLibEventLoopPolicy asyncio.set_event_loop_policy(GLibEventLoopPolicy()) graph_path_dir = "@PKGDATADIR@" if os.environ.get("GRAPHS_DEVEL_PATH"): graph_path_dir = os.environ.get("GRAPHS_DEVEL_PATH") sys.path.insert(1, graph_path_dir) signal.signal(signal.SIGINT, signal.SIG_DFL) def on_startup(_application): """Handle Application setup.""" import logging logging.basicConfig( format="%(levelname)s: %(message)s", level=logging.DEBUG if "@DEBUG@" == "True" else logging.INFO, ) logging.getLogger("matplotlib.font_manager").disabled = True logging.debug("Begin Application startup") import gettext import locale localedir = "@LOCALEDIR@" if os.environ.get("GRAPHS_OVERRIDE_LOCALEDIR"): localedir = os.environ.get("GRAPHS_OVERRIDE_LOCALEDIR") locale.bindtextdomain("@GETTEXT_PACKAGE@", localedir) locale.textdomain("@GETTEXT_PACKAGE@") gettext.bindtextdomain("@GETTEXT_PACKAGE@", localedir) gettext.textdomain("@GETTEXT_PACKAGE@") from matplotlib import font_manager _ = gettext.gettext for f in font_manager.findSystemFonts(fontpaths=None, fontext="ttf"): try: font_manager.fontManager.addfont(f) except RuntimeError: logging.warning(_("Could not load {font}").format(font=f)) from graphs import scales scales.register_scales() from graphs.file_import import DataImporter from graphs.item import ItemFactory from graphs.python_helper import PythonHelper from graphs.styles import StyleManager PythonHelper() StyleManager() DataImporter() ItemFactory() from gi.repository import Graphs application = Graphs.Application.new() application.connect("startup", on_startup) sys.exit(application.run(sys.argv)) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/item.py000066400000000000000000000222331520337127000235360ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for data Items.""" from gi.repository import GObject, Graphs from graphs import misc, utilities from matplotlib import RcParams import numpy class _PythonItemMixin: def reset( self, old_style: tuple[RcParams, dict], new_style: tuple[RcParams, dict], ) -> None: """Reset all properties.""" if not hasattr(self, "_style_properties"): return # Combine rcparams and graphs_params into single dict: old_style = old_style[0] | old_style[1] new_style = new_style[0] | new_style[1] for prop, (key, function) in self._style_properties.items(): old_value = old_style[key] new_value = new_style[key] if function is not None: old_value = function(old_value) new_value = function(new_value) if self.get_property(prop) == old_value: self.set_property(prop, new_value) def override( self, style: tuple[RcParams, dict], ) -> None: """Override all properties.""" if not hasattr(self, "_style_properties"): return # Combine rcparams and graphs_params into single dict: style = style[0] | style[1] for prop, (key, function) in self._style_properties.items(): value = style[key] if function is None else function(style[key]) self.set_property(prop, value) @staticmethod def _extract_params( cls, style: tuple[RcParams, dict], kwargs: dict, ) -> dict: style = style[0] | style[1] # Add graphs_params to style dict return { prop: style[key] if function is None else function(style[key]) for prop, (key, function) in cls._style_properties.items() if prop not in kwargs } def to_dict(self) -> dict: """Convert item to dict.""" dictionary = { key: self.get_property(key) for key in dir(self.props) if key != "typename" } dictionary["type"] = self.__gtype_name__[12:] return dictionary class DataItem(Graphs.DataItem, _PythonItemMixin): """DataItem.""" __gtype_name__ = "GraphsPythonDataItem" _style_properties = { "errbarsabove": ("errorbar.barsabove", None), "errcapsize": ("errorbar.capsize", None), "errcapthick": ("errorbar.capthick", None), "errlinewidth": ("errorbar.linewidth", None), "linestyle": ("lines.linestyle", misc.LINESTYLES.index), "linewidth": ("lines.linewidth", None), "markerstyle": ("lines.marker", misc.MARKERSTYLES.index), "markersize": ("lines.markersize", None), } @classmethod def new( cls, style: tuple[RcParams, dict], xdata: list[float] = None, ydata: list[float] = None, xerr: list[float] = None, yerr: list[float] = None, **kwargs, ): """Create new DataItem.""" data = Graphs.DataHolder.new(xdata, ydata, xerr, yerr) return cls.new_with_data(style, data, **kwargs) @classmethod def new_with_data( cls, style: tuple[RcParams, dict], data: Graphs.DataHolder, **kwargs, ): """Create new DataItem with a DataHolder.""" return cls( data=data, **cls._extract_params(cls, style, kwargs), **kwargs, ) def to_dict(self) -> dict: """Convert item to dict.""" dictionary = super().to_dict() dictionary["data"] = self.get_data_tuple() return dictionary def get_data_tuple(self) -> tuple[list, list, list, list]: """Get the data as a picklable tuple.""" return ( self.get_xdata().tolist(), self.get_ydata().tolist(), self.get_xerr().tolist() if self.has_xerr() else None, self.get_yerr().tolist() if self.has_yerr() else None, ) def set_data_tuple(self, data: tuple[list, list, list, list]) -> None: """Set the data from a tuple.""" self.props.data = Graphs.DataHolder.new(*data) def get_xydata(self) -> tuple[numpy.ndarray, numpy.ndarray]: """Get x- and y-data.""" return self.get_xdata(), self.get_ydata() def set_xydata(self, xydata: tuple[numpy.ndarray, numpy.ndarray]) -> None: """Set x- and y-data.""" self.set_data_tuple((*xydata, self.get_xerr(), self.get_yerr())) def get_xdata(self) -> numpy.ndarray: """Get xdata.""" return utilities.bytes_to_ndarray(self.props.data.get_xdata_b()) def get_ydata(self) -> numpy.ndarray: """Get ydata.""" return utilities.bytes_to_ndarray(self.props.data.get_ydata_b()) def get_xerr(self) -> numpy.ndarray: """Get xerr.""" return utilities.bytes_to_ndarray(self.props.data.get_xerr_b()) def get_yerr(self) -> numpy.ndarray: """Get yerr.""" return utilities.bytes_to_ndarray(self.props.data.get_yerr_b()) class GeneratedDataItem(Graphs.GeneratedDataItem, DataItem): """Generated Dataitem.""" __gtype_name__ = "GraphsPythonGeneratedDataItem" @classmethod def new( cls, style: tuple[RcParams, dict], equation: str, xstart: str, xstop: str, steps: int, scale: Graphs.Scale, **kwargs, ): """Create new GeneratedDataItem.""" return cls( equation=equation, xstart=xstart, xstop=xstop, steps=steps, scale=scale, **cls._extract_params(cls, style, kwargs), **kwargs, ) class EquationItem(Graphs.EquationItem, _PythonItemMixin): """EquationItem.""" __gtype_name__ = "GraphsPythonEquationItem" _style_properties = { "linestyle": ( "lines.linestyle", lambda x: max(misc.LINESTYLES.index(x) - 1, 0), ), "linewidth": ("lines.linewidth", None), } @classmethod def new(cls, style: tuple[RcParams, dict], equation: str, **kwargs): """Create new EquationItem.""" return cls( equation=equation, **cls._extract_params(cls, style, kwargs), **kwargs, ) class TextItem(Graphs.TextItem, _PythonItemMixin): """TextItem.""" __gtype_name__ = "GraphsPythonTextItem" _style_properties = { "size": ("font.size", None), "color": ("text.color", None), } @classmethod def new( cls, style: tuple[RcParams, dict], xanchor: float = 0, yanchor: float = 0, text: str = "", **kwargs, ): """Create new textItem.""" return cls( xanchor=xanchor, yanchor=yanchor, text=text, **cls._extract_params(cls, style, kwargs), **kwargs, ) class FillItem(Graphs.FillItem, _PythonItemMixin): """FillItem.""" __gtype_name__ = "GraphsPythonFillItem" data = GObject.Property(type=object) @classmethod def new( cls, _params: tuple[RcParams, dict], data: tuple[list[float], list[float], list[float]], **kwargs, ): """Create new FillItem.""" return cls(data=data, **kwargs) def __init__(self, **kwargs): super().__init__(**kwargs) if self.props.data is None: self.props.data = ([], [], []) def get_data_tuple(self) -> tuple[list, list, list]: """Get the data as a picklable tuple.""" return self.props.data def set_data_tuple(self, data: tuple[list, list, list]) -> None: """Set the data from a tuple.""" self.props.data = data class ItemFactory(Graphs.ItemFactory): """Item factory.""" _constructors = { "data-item": DataItem.new_with_data, "generated-data-item": GeneratedDataItem.new, "equation-item": EquationItem.new, "text-item": TextItem.new, } def __init__(self): super().__init__() for item, callback in self._constructors.items(): self.connect(item + "-request", self._on_request, callback) @staticmethod def new_from_dict(dictionary: dict) -> Graphs.Item: """Instanciate item from dict.""" match dictionary["type"]: case "DataItem": dictionary.pop("type") dictionary["data"] = Graphs.DataHolder.new(*dictionary["data"]) return DataItem(**dictionary) case "GeneratedDataItem": dictionary.pop("type") dictionary["data"] = Graphs.DataHolder.new(*dictionary["data"]) return GeneratedDataItem(**dictionary) case "EquationItem": cls = EquationItem case "TextItem": cls = TextItem case "FillItem": cls = FillItem case _: raise ValueError(f"could not find type {dictionary['type']}") dictionary.pop("type") return cls(**dictionary) @staticmethod def _on_request(self, data: Graphs.Data, *args) -> Graphs.Item: *args, callback = args return callback(data.get_selected_style_params(), *args) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/item.vala000066400000000000000000000204731520337127000240350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gdk; namespace Graphs { /** * Small list class */ public class ItemList : Object { private Gee.List _items = new Gee.ArrayList (); public void add (Item item) { _items.add (item); } public void add_all (Item[] items) { foreach (Item item in items) { _items.add (item); } } public Item[] to_array () { return _items.to_array (); } } /** * Item factory for creating Python items. */ public class ItemFactory : Object { private static ItemFactory instance; construct { instance = this; } protected signal DataItem data_item_request (Data data, DataHolder holder); protected signal GeneratedDataItem generated_data_item_request (Data data, string equation, string xstart, string xstop, int steps, Scale scale); protected signal EquationItem equation_item_request (Data data, string equation); protected signal TextItem text_item_request (Data data, double xanchor, double yanchor, string text); public static DataItem new_data_item (Data data, double[] xdata, double[] ydata, double[]? xerr = null, double[]? yerr = null) { return instance.data_item_request.emit (data, new DataHolder (xdata, ydata, xerr, yerr)); } public static GeneratedDataItem new_generated_data_item (Data data, string equation, string xstart, string xstop, int steps, Scale scale) { return instance.generated_data_item_request.emit (data, equation, xstart, xstop, steps, scale); } public static EquationItem new_equation_item (Data data, string equation) { return instance.equation_item_request.emit (data, equation); } public static TextItem new_text_item (Data data, double xanchor, double yanchor, string text) { return instance.text_item_request.emit (data, xanchor, yanchor, text); } } /** * Base item class */ public class Item : Object { public string typename { get; construct set; } public string name { get; set; default = ""; } public string color { get; set; default = ""; } public float alpha { get; set; default = 1; } public bool selected { get; set; default = true; } public string xlabel { get; set; default = ""; } public string ylabel { get; set; default = ""; } public XPosition xposition { get; set; default = XPosition.BOTTOM; } public YPosition yposition { get; set; default = YPosition.LEFT; } public Gdk.RGBA get_rgba () { Gdk.RGBA rgba = Tools.hex_to_rgba (color); rgba.alpha = alpha; return rgba; } public void set_rgba (Gdk.RGBA rgba) { this.color = Tools.rgba_to_hex (rgba); this.alpha = rgba.alpha; } } public interface EquationBasedItem : Item { public abstract string equation { get; set; } } public class DataHolder : Object { private double[] _xdata; private double[] _ydata; private double[]? _xerr; private double[]? _yerr; public DataHolder (double[] xdata, double[] ydata, double[]? xerr, double[]? yerr) { _xdata = xdata; _ydata = ydata; _xerr = xerr; _yerr = yerr; } public DataHolder.empty () { _xdata = new double[0]; _ydata = new double[0]; _xerr = null; _yerr = null; } public unowned double[] get_xdata () { return _xdata; } public unowned double[] get_ydata () { return _ydata; } public unowned double[]? get_xerr () { return _xerr; } public unowned double[]? get_yerr () { return _yerr; } public GLib.Bytes get_xdata_b () { return new Bytes ((uint8[]) _xdata); } public GLib.Bytes get_ydata_b () { return new Bytes ((uint8[]) _ydata); } public GLib.Bytes? get_xerr_b () { return _xerr == null ? null : new Bytes ((uint8[]) _xerr); } public GLib.Bytes? get_yerr_b () { return _yerr == null ? null : new Bytes ((uint8[]) _yerr); } } public class DataItem : Item { public DataHolder data { get; set; default = new DataHolder.empty (); } public bool errbarsabove { get; set; default = false; } public double errcapsize { get; set; default = 0; } public double errcapthick { get; set; default = 1; } public string errcolor { get; set; default = ""; } public double errlinewidth { get; set; default = 1; } public int linestyle { get; set; default = 1; } public double linewidth { get; set; default = 3; } public int markerstyle { get; set; default = 0; } public double markersize { get; set; default = 7; } public bool showxerr { get; set; default = true; } public bool showyerr { get; set; default = true; } construct { typename = _("Dataset"); } public bool has_xerr () { return data.get_xerr () != null; } public bool has_yerr () { return data.get_yerr () != null; } } public class GeneratedDataItem : DataItem, EquationBasedItem { public string xstart { get; set; default = "0"; } public string xstop { get; set; default = "10"; } public int steps { get; set; default = 100; } public Scale scale { get; set; default = Scale.LINEAR; } private string _equation = ""; private string _preprocessed_equation = ""; public string equation { get { return _equation; } set { string old_equation = _equation; if (old_equation == value) return; _equation = value; try { _preprocessed_equation = preprocess_equation (value); } catch (MathError e) { assert_not_reached (); } if ("Y = " + old_equation == name) name = "Y = " + value; regenerate (); } } construct { typename = _("Generated Dataset"); const string[] PROPS = {"xstart", "xstop", "steps", "scale"}; foreach (string prop in PROPS) { this.notify[prop].connect (regenerate); } } private void regenerate () { try { data = PythonHelper.equation_to_data ( _preprocessed_equation, evaluate_string (xstart), evaluate_string (xstop), steps, scale); } catch (MathError e) { assert_not_reached (); } } } public class EquationItem : Item, EquationBasedItem { public int linestyle { get; set; default = 1; } public double linewidth { get; set; default = 3; } private string _equation = ""; private string _preprocessed_equation = ""; public string equation { get { return _equation; } set { string old_equation = _equation; if (old_equation == value) return; _equation = value; try { _preprocessed_equation = preprocess_equation (value); } catch (MathError e) { assert_not_reached (); } if ("Y = " + old_equation == name) name = "Y = " + value; } } construct { typename = _("Equation"); } public string get_preprocessed_equation () { return _preprocessed_equation; } } public class TextItem : Item { public double xanchor { get; set; default = 0; } public double yanchor { get; set; default = 0; } public string text { get; set; default = ""; } public double size { get; set; default = 12; } public int rotation { get; set; default = 0; } construct { typename = _("Label"); } } public class FillItem : Item { construct { typename = _("Fill"); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/item_box.vala000066400000000000000000000100741520337127000247010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gdk; using Gtk; namespace Graphs { /** * Item Box widget */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/item-box.ui")] public class ItemBox : Adw.ActionRow { [GtkChild] public unowned CheckButton check_button { get; } [GtkChild] private unowned Button color_button { get; } public Window window { get; construct set; } public Item item { get; construct set; } public uint index { get; construct set; } private CssProvider provider; public ItemBox (Window window, Item item, uint index) { Object ( window: window, item: item, index: index ); this.provider = new CssProvider (); color_button.get_style_context ().add_provider ( provider, STYLE_PROVIDER_PRIORITY_APPLICATION ); set_subtitle (item.typename); item.bind_property ("name", this, "title", 2); item.bind_property ("selected", check_button, "active", 2); item.notify["color"].connect (on_color_change); on_color_change (); } /** * Setup the actions for the ItemBox. This is omitted for rows created * for drag and drop. */ public void setup_interactions (bool is_data_item) { var action_group = new SimpleActionGroup (); var delete_action = new SimpleAction ("delete", null); delete_action.activate.connect (() => { string name = item.name; Item[] list = {item}; window.data.delete_items (list); window.add_undo_toast (_("Deleted %s").printf (name)); }); action_group.add_action (delete_action); if (is_data_item) { var curve_fitting_action = new SimpleAction ("curve_fitting", null); curve_fitting_action.activate.connect (() => { PythonHelper.create_curve_fitting_dialog (window, item); }); action_group.add_action (curve_fitting_action); } if (index > 0) { var move_up_action = new SimpleAction ("move_up", null); move_up_action.activate.connect (() => { change_position (index - 1); }); action_group.add_action (move_up_action); } if (index + 1 < window.data.get_n_items ()) { var move_down_action = new SimpleAction ("move_down", null); move_down_action.activate.connect (() => { change_position (index + 1); }); action_group.add_action (move_down_action); } insert_action_group ("item_box", action_group); } private void on_color_change () { string c = item.color; string o = item.alpha.to_string (); provider.load_from_string (@"button { color: $c; opacity: $o; }"); } [GtkCallback] private void on_toggle () { bool new_value = check_button.get_active (); if (item.selected != new_value) { item.selected = new_value; window.data.add_history_state (); } } [GtkCallback] private void choose_color () { var dialog = new ColorDialog (); dialog.choose_rgba.begin ( window, item.get_rgba (), null, (d, result) => { try { item.set_rgba (dialog.choose_rgba.end (result)); window.data.add_history_state (); } catch {} } ); } public void change_position (uint source_index) { window.data.change_position (index, source_index); window.data.add_history_state (); window.data.add_view_history_state (); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/math_parser/000077500000000000000000000000001520337127000245315ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/math_parser/evaluator.vala000066400000000000000000000160571520337127000274110ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later namespace Graphs.MathParser { private class Evaluator { private Lexer lexer = new Lexer (); private static Once _instance; public static unowned Evaluator instance () { return _instance.once (() => { return new Evaluator (); }); } public double parse (string src, unichar decimal_separator = '.') throws MathError { lexer.start_lexing (src, decimal_separator); double result = expr (); lexer.expect_end (); return result; } /* Grammar: expr -> term ((+|-) term)* term -> power ((*|/) power)* term -> power expr power -> unary ((^|**) power)? unary -> (- unary) | postfix postfix -> primary (!)* primary -> number | constant | func | '(' expr ')' */ private double expr () throws MathError { double v = term (); TokenType t; while (true) { t = lexer.current_type; if (!(t == TokenType.PLUS || t == TokenType.MINUS)) break; lexer.next (); double r = term (); v = (t == TokenType.PLUS) ? v + r : v - r; } return v; } private double term () throws MathError { double v = power (); while (true) { TokenType t = lexer.current_type; // explicit * or / if (t == TokenType.STAR || t == TokenType.SLASH) { lexer.next (); double r = power (); if (t == TokenType.SLASH && r == 0) throw new MathError.DIV_ZERO ("division by zero"); v = (t == TokenType.STAR) ? v * r : v / r; continue; } // implicit multiplication if (t == TokenType.NUMBER || t == TokenType.IDENT || t == TokenType.LPAREN) { v *= power (); continue; } break; } return v; } private double power () throws MathError { double v = unary (); if (lexer.current_type == TokenType.CARET) { lexer.next (); v = Math.pow (v, power ()); } return v; } private double unary () throws MathError { if (lexer.current_type == TokenType.MINUS) { lexer.next (); return -postfix (); } else if (lexer.current_type == TokenType.PLUS) { lexer.next (); } return postfix (); } private double postfix () throws MathError { double v = primary (); while (true) { if (lexer.current_type == TokenType.FACT) { if (v < 0 || v != Math.floor (v)) throw new MathError.DOMAIN ("invalid factorial"); v = factorial ((int) v); lexer.next (); continue; } if (lexer.current_type == TokenType.SUPERSCRIPT) { int exp = (int) lexer.current_val; lexer.next (); v = ipow (v, exp); continue; } break; } return v; } private double primary () throws MathError { switch (lexer.current_type) { case TokenType.NUMBER: double v = lexer.current_val; lexer.next (); return v; case TokenType.IDENT: Ident id = lexer.current_ident; lexer.next (); switch (id) { case Ident.PI: return Math.PI; case Ident.E: return Math.E; case Ident.INF: return double.INFINITY; default: break; } lexer.expect (TokenType.LPAREN); double arg = expr (); lexer.expect (TokenType.RPAREN); return call_function (id, arg); case TokenType.LPAREN: lexer.next (); double v = expr (); lexer.expect (TokenType.RPAREN); return v; default: throw new MathError.SYNTAX ("unexpected token"); } } private const double DEGREES_TO_RADIANS = 0.017453292519943295; // pi/180 private const double RADIANS_TO_DEGREES = 57.29577951308232; // 180/pi private static double call_function (Ident id, double x) { switch (id) { // trig radians case Ident.SIN: return Math.sin (x); case Ident.COS: return Math.cos (x); case Ident.TAN: return Math.tan (x); case Ident.COT: return 1d / Math.tan (x); case Ident.SEC: return 1d / Math.cos (x); case Ident.CSC: return 1d / Math.sin (x); // trig degrees case Ident.SIND: return Math.sin (x * DEGREES_TO_RADIANS); case Ident.COSD: return Math.cos (x * DEGREES_TO_RADIANS); case Ident.TAND: return Math.tan (x * DEGREES_TO_RADIANS); case Ident.COTD: return 1d / Math.tan (x * DEGREES_TO_RADIANS); case Ident.SECD: return 1d / Math.cos (x * DEGREES_TO_RADIANS); case Ident.CSCD: return 1d / Math.sin (x * DEGREES_TO_RADIANS); // inverse trig radians case Ident.ASIN: return Math.asin (x); case Ident.ACOS: return Math.acos (x); case Ident.ATAN: return Math.atan (x); case Ident.ACOT: return Math.asin (1d / Math.sqrt (1 + x * x)); case Ident.ASEC: return Math.acos (1d / x); case Ident.ACSC: return Math.asin (1d / x); // inverse trig degrees case Ident.ASIND: return Math.asin (x) * RADIANS_TO_DEGREES; case Ident.ACOSD: return Math.acos (x) * RADIANS_TO_DEGREES; case Ident.ATAND: return Math.atan (x) * RADIANS_TO_DEGREES; case Ident.ACOTD: return Math.asin (1d / Math.sqrt (1 + x * x)) * RADIANS_TO_DEGREES; case Ident.ASECD: return Math.acos (1d / x) * RADIANS_TO_DEGREES; case Ident.ACSCD: return Math.asin (1d / x) * RADIANS_TO_DEGREES; // misc case Ident.LOG: return Math.log (x); case Ident.LOG2: return Math.log2 (x); case Ident.LOG10: return Math.log10 (x); case Ident.SQRT: return Math.sqrt (x); case Ident.EXP: return Math.exp (x); case Ident.ABS: return Math.fabs (x); default: assert_not_reached (); } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/math_parser/lexer.vala000066400000000000000000000444071520337127000265260ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later namespace Graphs.MathParser { private class Lexer { private unowned string src; private unichar c; private unichar decimal_separator; private bool allow_custom_ident; public TokenType current_type; public Ident current_ident; public double current_val; private int current_start; private int current_end; public Lexer (bool allow_custom_ident = false) { this.allow_custom_ident = allow_custom_ident; } public void start_lexing (string src, unichar decimal_separator = '.') throws MathError { this.src = src; this.current_end = 0; this.decimal_separator = decimal_separator; next (); } public void next () throws MathError { current_start = current_end; do { if (src.get_next_char (ref current_end, out c)) continue; if (current_end == 0) throw new MathError.SYNTAX ("empty expression"); current_type = TokenType.END; return; } while (c.isspace ()); // Number if (c.isdigit () || c == decimal_separator) { handle_number (); return; } // Identifier if (c.isalpha () || c == 'Ï€') { handle_identifier (); return; } if (c == '*') { // look ahead and treat double asterisk as caret int tmp_idx = current_end; if (!src.get_next_char (ref tmp_idx, out c)) throw new MathError.SYNTAX ("expected token"); if (c == '*') { current_type = TokenType.CARET; current_end = tmp_idx; } else current_type = TokenType.STAR; return; } if (c == '+' || c == '-') { // look ahead and resolve stacked unary operators bool plus = c == '+'; int tmp_idx = current_end; while (true) { do { if (!src.get_next_char (ref tmp_idx, out c)) throw new MathError.SYNTAX ("expected token"); } while (c.isspace ()); if (c == '-') plus = !plus; else if (c != '+') break; current_end = tmp_idx; } current_type = plus ? TokenType.PLUS : TokenType.MINUS; return; } // Single-character token switch (c) { case '/': current_type = TokenType.SLASH; break; case '^': current_type = TokenType.CARET; break; case '!': current_type = TokenType.FACT; break; case '(': current_type = TokenType.LPAREN; break; case ')': current_type = TokenType.RPAREN; break; // Superscript case 'â°': current_type = TokenType.SUPERSCRIPT; current_val = 0; break; case '¹': current_type = TokenType.SUPERSCRIPT; current_val = 1; break; case '²': current_type = TokenType.SUPERSCRIPT; current_val = 2; break; case '³': current_type = TokenType.SUPERSCRIPT; current_val = 3; break; case 'â´': current_type = TokenType.SUPERSCRIPT; current_val = 4; break; case 'âµ': current_type = TokenType.SUPERSCRIPT; current_val = 5; break; case 'â¶': current_type = TokenType.SUPERSCRIPT; current_val = 6; break; case 'â·': current_type = TokenType.SUPERSCRIPT; current_val = 7; break; case 'â¸': current_type = TokenType.SUPERSCRIPT; current_val = 8; break; case 'â¹': current_type = TokenType.SUPERSCRIPT; current_val = 9; break; default: throw new MathError.SYNTAX ("invalid token"); } } private void handle_number () throws MathError { bool seen_dot = false; bool last_is_dot = false; bool seen_exp = false; int idx = current_end; int tmp_idx = idx; long int_part = 0; long frac_part = 0; int frac_digits = 0; int exp = 0; int exp_sign = 1; int digit; while (true) { digit = c.digit_value (); if (digit >= 0) { if (seen_exp) { exp = exp * 10 + digit; } else if (seen_dot) { frac_part = frac_part * 10 + digit; frac_digits++; } else { int_part = int_part * 10 + digit; } last_is_dot = false; } else if (c == decimal_separator) { if (seen_dot || seen_exp) throw new MathError.SYNTAX ("invalid number"); seen_dot = true; last_is_dot = true; } else if ((c == 'e' || c == 'E') && !seen_exp) { // Look ahead to see if this is really an exponent if (!src.get_next_char (ref tmp_idx, out c)) break; // Optional sign if (c == '+' || c == '-') { if (c == '-') exp_sign = -1; if (!src.get_next_char (ref tmp_idx, out c)) break; } // Must have at least one digit to be an exponent if (!c.isdigit ()) break; seen_exp = true; last_is_dot = false; idx = tmp_idx; continue; } else if (!(c == '.' || c == ',' || c.isspace ())) break; // advance to next character idx = tmp_idx; if (!src.get_next_char (ref tmp_idx, out c)) break; } // must contain at least one digit and must not have a trailing dot if (last_is_dot) throw new MathError.SYNTAX ("invalid number"); double val = int_part; if (seen_dot) val += frac_part / ipow (10d, frac_digits); if (seen_exp && exp != 0) { int e = exp_sign * exp; val *= (e > 0 && e <= 308) ? ipow (10d, e) : Math.pow (10d, e); } current_type = TokenType.NUMBER; current_val = val; current_end = idx; } private inline void fail_identifier (ref int state) throws MathError { if (!allow_custom_ident) throw new MathError.UNKNOWN_FUNCTION ("invalid identifier"); current_ident = Ident.CUSTOM; state = 200; } private void handle_identifier () throws MathError { current_type = TokenType.IDENT; current_ident = Ident.CUSTOM; int state = 0; int tmp_idx = current_end; c = c.tolower (); while (true) { // process current char in trie switch (state) { case 0: switch (c) { case 'Ï€': { current_ident = Ident.PI; state = 200; break; } case 'p': state = 1; break; case 'e': state = 10; break; case 'i': state = 15; break; case 's': state = 20; break; case 'c': state = 40; break; case 't': state = 60; break; case 'l': state = 70; break; case 'a': state = 80; break; default: fail_identifier (ref state); break; } break; // p case 1: if (c == 'i') { current_ident = Ident.PI; state = 200; } else fail_identifier (ref state); break; // e case 10: if (c == 'x') state = 11; else fail_identifier (ref state); break; // ex case 11: if (c == 'p') { current_ident = Ident.EXP; state = 200; } else fail_identifier (ref state); break; // i case 15: if (c == 'n') state = 16; else fail_identifier (ref state); break; // in case 16: if (c == 'f') { current_ident = Ident.INF; state = 200; } else fail_identifier (ref state); break; // s case 20: if (c == 'i') state = 21; else if (c == 'e') state = 25; else if (c == 'q') state = 28; else fail_identifier (ref state); break; // si case 21: if (c == 'n') { current_ident = Ident.SIN; state = 22; } else fail_identifier (ref state); break; // sin case 22: if (c == 'd') { current_ident = Ident.SIND; state = 200; } else fail_identifier (ref state); break; // se case 25: if (c == 'c') { current_ident = Ident.SEC; state = 26; } else fail_identifier (ref state); break; // sec case 26: if (c == 'd') { current_ident = Ident.SECD; state = 200; } else fail_identifier (ref state); break; // sq case 28: if (c == 'r') state = 29; else fail_identifier (ref state); break; // sqr case 29: if (c == 't') { current_ident = Ident.SQRT; state = 200; } else fail_identifier (ref state); break; // c case 40: if (c == 'o') state = 41; else if (c == 's') state = 45; else fail_identifier (ref state); break; // co case 41: if (c == 's') { current_ident = Ident.COS; state = 42; } else if (c == 't') { current_ident = Ident.COT; state = 43; } else fail_identifier (ref state); break; // cos case 42: if (c == 'd') { current_ident = Ident.COSD; state = 200; } else fail_identifier (ref state); break; // cot case 43: if (c == 'd') { current_ident = Ident.COTD; state = 200; } else fail_identifier (ref state); break; // cs case 45: if (c == 'c') { current_ident = Ident.CSC; state = 46; } else fail_identifier (ref state); break; // csc case 46: if (c == 'd') { current_ident = Ident.CSCD; state = 200; } else fail_identifier (ref state); break; // t case 60: if (c == 'a') state = 61; else fail_identifier (ref state); break; // ta case 61: if (c == 'n') { current_ident = Ident.TAN; state = 62; } else fail_identifier (ref state); break; // tan case 62: if (c == 'd') { current_ident = Ident.TAND; state = 200; } else fail_identifier (ref state); break; // l case 70: if (c == 'o') state = 71; else fail_identifier (ref state); break; // lo case 71: if (c == 'g') { current_ident = Ident.LOG; state = 72; } else fail_identifier (ref state); break; // log case 72: if (c == '2') { current_ident = Ident.LOG2; state = 200; } else if (c == '1') { current_ident = Ident.CUSTOM; state = 73; } else fail_identifier (ref state); break; // log1 case 73: if (c == '0') { current_ident = Ident.LOG10; state = 200; } else fail_identifier (ref state); break; // a case 80: if (c == 'b') state = 81; else if (c == 'r') state = 83; else if (c == 'c') state = 90; else if (c == 's') state = 96; else if (c == 't') state = 101; else fail_identifier (ref state); break; // ab case 81: if (c == 's') { current_ident = Ident.ABS; state = 200; } else fail_identifier (ref state); break; // ar case 83: if (c == 'c') state = 84; else fail_identifier (ref state); break; // arc case 84: if (c == 'c') state = 90; else if (c == 's') state = 96; else if (c == 't') state = 101; else fail_identifier (ref state); break; // a(rc)c case 90: if (c == 'o') state = 91; else if (c == 's') state = 94; else fail_identifier (ref state); break; // a(rc)co case 91: if (c == 's') { current_ident = Ident.ACOS; state = 92; } else if (c == 't') { current_ident = Ident.ACOT; state = 93; } else fail_identifier (ref state); break; // a(rc)cos case 92: if (c == 'd') { current_ident = Ident.ACOSD; state = 200; } else fail_identifier (ref state); break; // a(rc)cot case 93: if (c == 'd') { current_ident = Ident.ACOTD; state = 200; } else fail_identifier (ref state); break; // a(rc)cs case 94: if (c == 'c') { current_ident = Ident.ACSC; state = 95; } else fail_identifier (ref state); break; // a(rc)csc case 95: if (c == 'd') { current_ident = Ident.ACSCD; state = 200; } else fail_identifier (ref state); break; // a(rc)s case 96: if (c == 'e') state = 97; else if (c == 'i') state = 99; else fail_identifier (ref state); break; // a(rc)se case 97: if (c == 'c') { current_ident = Ident.ASEC; state = 98; } else fail_identifier (ref state); break; // a(rc)sec case 98: if (c == 'd') { current_ident = Ident.ASECD; state = 200; } else fail_identifier (ref state); break; // a(rc)si case 99: if (c == 'n') { current_ident = Ident.ASIN; state = 100; } else fail_identifier (ref state); break; // a(rc)sin case 100: if (c == 'd') { current_ident = Ident.ASIND; state = 200; } else fail_identifier (ref state); break; // a(rc)t case 101: if (c == 'a') state = 102; else fail_identifier (ref state); break; // a(rc)ta case 102: if (c == 'n') { current_ident = Ident.ATAN; state = 103; } else fail_identifier (ref state); break; // a(rc)tan case 103: if (c == 'd') { current_ident = Ident.ATAND; state = 200; } else fail_identifier (ref state); break; case 200: fail_identifier (ref state); break; default: assert_not_reached (); } if (!src.get_next_char (ref tmp_idx, out c) || !(c.isalnum () || c == 'Ï€') || is_superscript (c)) { if (state == 10) { current_ident = Ident.E; } else if (current_ident == Ident.CUSTOM && !allow_custom_ident) throw new MathError.UNKNOWN_FUNCTION ("invalid identifier"); break; } current_end = tmp_idx; c = c.tolower (); } } public inline void expect_end () throws MathError { if (current_type != TokenType.END) throw new MathError.SYNTAX ("trailing input"); } public inline void expect (TokenType t) throws MathError { if (current_type != t) throw new MathError.SYNTAX ("expected token"); next (); } public string get_current_token_as_string () { return src.substring (current_start, current_end - current_start); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/math_parser/main.vala000066400000000000000000000073541520337127000263330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later namespace Graphs { /** * Try evaluating a string to a double. * returns true if successfully parsed. */ public static bool try_evaluate_string (string expression, out double? result = null, unichar decimal_separator = '.') { try { result = MathParser.Evaluator.instance ().parse (expression, decimal_separator); return true; } catch (Error e) { result = 0; return false; } } // This method exists primarily to be used on the python side. Do note that // the potential MathError is intentional here as returning double? or using // an out variable leads to issues when automatically generating a binding. // with the compromise being, that the MathError has to be handled on the // python side when consuming this method. /** * Evaluate a string to a double. */ public static double evaluate_string (string expression) throws MathError { return MathParser.Evaluator.instance ().parse (expression); } // This method exists separately as optional arguments are not automatically // bound by python /** * Evaluate a string to a double with given decimal separator. */ public static double evaluate_string_with_separator (string expression, unichar separator) throws MathError { return MathParser.Evaluator.instance ().parse (expression, separator); } /** * Preprocess an equation to be compatible with numexpr syntax. */ public static string preprocess_equation (string equation) throws MathError { return MathParser.Preprocessor.instance ().preprocess (equation); } /** * Return an equation in a prettier, more humanly readable, format. */ public static string prettify_equation (string equation) throws MathError { string result = MathParser.Preprocessor.instance ().preprocess (equation, true); // remove asterisk between parentheses result = result.replace (")*(", "()"); return result; } public errordomain MathError { SYNTAX, UNKNOWN_FUNCTION, DOMAIN, DIV_ZERO } namespace MathParser { private enum TokenType { NUMBER, IDENT, PLUS, MINUS, STAR, SLASH, CARET, FACT, SUPERSCRIPT, LPAREN, RPAREN, END } private enum Ident { // constants PI, E, INF, // trig SIN, COS, TAN, COT, SEC, CSC, SIND, COSD, TAND, COTD, SECD, CSCD, // inverse trig ASIN, ACOS, ATAN, ACOT, ASEC, ACSC, ASIND, ACOSD, ATAND, ACOTD, ASECD, ACSCD, // misc math LOG, LOG2, LOG10, SQRT, EXP, ABS, CUSTOM } private static inline long factorial (int n) { long r = 1; for (int i = 2; i <= n; i++) r *= i; return r; } private static inline double ipow (double bas, int exp) { double result = 1; double b = bas; int e = exp; while (e > 0) { if ((e & 1) == 1) result *= b; b = b * b; e >>= 1; } return result; } private static inline bool is_superscript (unichar c) { switch (c) { case 'â°': case '¹': case '²': case '³': case 'â´': case 'âµ': case 'â¶': case 'â·': case 'â¸': case 'â¹': return true; default: return false; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/math_parser/preprocessor.vala000066400000000000000000000247631520337127000301400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later namespace Graphs.MathParser { private class Preprocessor { private Lexer lexer = new Lexer (true); private StringBuilder builder; private bool prettify; private static Once _instance; public static unowned Preprocessor instance () { return _instance.once (() => { return new Preprocessor (); }); } public string preprocess (string src, bool prettify = false) throws MathError { this.builder = new StringBuilder (); this.prettify = prettify; lexer.start_lexing (src); expr (); lexer.expect_end (); return builder.free_and_steal (); } /* Grammar: expr -> term ((+|-) term)* term -> power ((*|/) power)* term -> power expr power -> unary ((^|**) power)? unary -> (- unary) | postfix postfix -> primary (!)* primary -> number | constant | func | '(' expr ')' */ private void expr () throws MathError { term (); TokenType t; while (true) { t = lexer.current_type; if (!(t == TokenType.PLUS || t == TokenType.MINUS)) break; if (prettify) builder.append_c (' '); builder.append_c ((t == TokenType.PLUS) ? '+' : '-'); if (prettify) builder.append_c (' '); lexer.next (); term (); } } private void term () throws MathError { power (); while (true) { TokenType t = lexer.current_type; // explicit * or / if (t == TokenType.STAR || t == TokenType.SLASH) { if (prettify) builder.append_c (' '); builder.append_c ((t == TokenType.STAR) ? '*' : '/'); if (prettify) builder.append_c (' '); lexer.next (); power (); continue; } // implicit multiplication if (t == TokenType.NUMBER || t == TokenType.IDENT || t == TokenType.LPAREN) { if (!prettify) builder.append_c ('*'); power (); continue; } break; } } private void power () throws MathError { unary (); if (lexer.current_type == TokenType.CARET) { builder.append (prettify ? "^" : "**"); lexer.next (); power (); } } private void unary () throws MathError { if (lexer.current_type == TokenType.MINUS) { builder.append_c ('-'); lexer.next (); postfix (); return; } else if (lexer.current_type == TokenType.PLUS) { lexer.next (); } postfix (); } private void postfix () throws MathError { double? v = primary (); bool output = false; while (true) { if (lexer.current_type == TokenType.FACT) { if (v != null) { if (v < 0 || v != Math.floor (v)) throw new MathError.DOMAIN ("invalid factorial"); v = factorial ((int) v); builder.append ("%.15g".printf (v)); } else { builder.append_c ('!'); } output = true; lexer.next (); continue; } if (lexer.current_type == TokenType.SUPERSCRIPT) { int exp = (int) lexer.current_val; if (v != null) { lexer.next (); v = ipow (v, exp); builder.append ("%.15g".printf (v)); } else { builder.append (prettify ? "^" : "**"); builder.append (exp.to_string ()); lexer.next (); } output = true; continue; } break; } if (!output && v != null) builder.append ("%.15g".printf (v)); } private const double PI_THRESH = 0.00010000314159265359; // 1e-4 + 1e-9 * pi private const double E_THRESH = 0.00010000271828182846; // 1e-4 + 1e-9 * e private double? primary () throws MathError { switch (lexer.current_type) { case TokenType.NUMBER: double v = lexer.current_val; if (prettify) { // check if it is a multiple of pi double remainder = Math.fmod (v, Math.PI); if (remainder <= PI_THRESH || remainder >= Math.PI - PI_THRESH) { // fast rounding check evasion double factor = Math.floor (v / Math.PI + 0.5); if (factor != 0) { if (factor != 1) builder.append ("%.15g".printf (factor)); builder.append ("pi"); lexer.next (); return null; } } // or e remainder = Math.fmod (v, Math.E); if (remainder <= E_THRESH || remainder >= Math.E - E_THRESH) { // fast rounding check evasion double factor = Math.floor (v / Math.E + 0.5); if (factor != 0) { if (factor != 1) builder.append ("%.15g".printf (factor)); builder.append_c ('e'); lexer.next (); return null; } } } lexer.next (); return v; case TokenType.IDENT: Ident id = lexer.current_ident; if (id == Ident.CUSTOM) { builder.append (lexer.get_current_token_as_string ().down ()); lexer.next (); return null; } lexer.next (); switch (id) { case Ident.PI: return Math.PI; case Ident.E: return Math.E; case Ident.INF: return double.INFINITY; default: break; } lexer.expect (TokenType.LPAREN); function_pre (id); expr (); lexer.expect (TokenType.RPAREN); function_post (id); return null; case TokenType.LPAREN: builder.append_c ('('); lexer.next (); expr (); lexer.expect (TokenType.RPAREN); builder.append_c (')'); return null; default: throw new MathError.SYNTAX ("unexpected token"); } } private void function_pre (Ident id) { switch (id) { // trig radians case Ident.SIN: builder.append ("sin("); break; case Ident.COS: builder.append ("cos("); break; case Ident.TAN: builder.append ("tan("); break; case Ident.COT: builder.append ("1/tan("); break; case Ident.SEC: builder.append ("1/cos("); break; case Ident.CSC: builder.append ("1/sin("); break; // trig degrees case Ident.SIND: builder.append ("sin(0.017453292519943295*("); break; case Ident.COSD: builder.append ("cos(0.017453292519943295*("); break; case Ident.TAND: builder.append ("tan(0.017453292519943295*("); break; case Ident.COTD: builder.append ("1/tan(0.017453292519943295*("); break; case Ident.SECD: builder.append ("1/cos(0.017453292519943295*("); break; case Ident.CSCD: builder.append ("1/sin(0.017453292519943295*("); break; // inverse trig radians case Ident.ASIN: builder.append ("arcsin("); break; case Ident.ACOS: builder.append ("arccos("); break; case Ident.ATAN: builder.append ("arctan("); break; case Ident.ACOT: builder.append ("arcsin(1/sqrt(1+"); break; case Ident.ASEC: builder.append ("arccos(1/("); break; case Ident.ACSC: builder.append ("arcsin(1/("); break; // inverse trig degrees case Ident.ASIND: builder.append ("57.29577951308232*arcsin("); break; case Ident.ACOSD: builder.append ("57.29577951308232*arccos("); break; case Ident.ATAND: builder.append ("57.29577951308232*arctan("); break; case Ident.ACOTD: builder.append ("57.29577951308232*arcsin(1/sqrt(1+"); break; case Ident.ASECD: builder.append ("57.29577951308232*arccos(1/("); break; case Ident.ACSCD: builder.append ("57.29577951308232*arcsin(1/("); break; // misc case Ident.LOG: builder.append ("log("); break; case Ident.LOG2: builder.append ("log2("); break; case Ident.LOG10: builder.append ("log10("); break; case Ident.SQRT: builder.append ("sqrt("); break; case Ident.EXP: builder.append ("exp("); break; case Ident.ABS: builder.append ("abs("); break; default: assert_not_reached (); } } private void function_post (Ident id) { switch (id) { case Ident.ACOT: case Ident.ACOTD: builder.append ("**2))"); break; case Ident.SIND: case Ident.COSD: case Ident.TAND: case Ident.COTD: case Ident.SECD: case Ident.CSCD: case Ident.ASEC: case Ident.ACSC: case Ident.ASECD: case Ident.ACSCD: builder.append ("))"); break; default: builder.append_c (')'); break; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/math_utilities.vala000066400000000000000000000067741520337127000261330ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gee; namespace Graphs.MathTools { private const double REL_TOL = 1e-9; private const double ABS_TOL = 1e-4; private const double PI_THRESH = 0.00010000314159265359; // 1e-4 + 1e-9 * pi private const double E_THRESH = 0.00010000271828182846; // 1e-4 + 1e-9 * e /** * Whether or not two values are close to each other. */ public bool is_close (double a, double b) { return Math.fabs (a - b) <= Math.fmax (REL_TOL * Math.fmax (a.abs (), b.abs ()), ABS_TOL); } /** * Wether or not two values contain values close to each other. */ public bool all_close (double[] a, double[] b) requires (a.length == b.length) { for (uint i = 0; i < a.length; i++) { if (!is_close (a[i], b[i])) return false; } return true; } /** * String representation of a double, prettifies for typical constants * such as integer values of pi and e. */ public string prettyprint_double (double val) { if (val == 0) { return "0"; } StringBuilder builder = new StringBuilder (); if (val < 0) { val *= -1; builder.append_c ('-'); } // check if it is a multiple of pi double remainder = Math.fmod (val, Math.PI); if (remainder <= PI_THRESH || remainder >= Math.PI - PI_THRESH) { // fast rounding check evasion double factor = Math.floor (val / Math.PI + 0.5); if (factor != 0) { if (factor != 1) builder.append ("%.15g".printf (factor)); builder.append ("pi"); return builder.free_and_steal (); } } // or e remainder = Math.fmod (val, Math.E); if (remainder <= E_THRESH || remainder >= Math.E - E_THRESH) { // fast rounding check evasion double factor = Math.floor (val / Math.E + 0.5); if (factor != 0) { if (factor != 1) builder.append ("%.15g".printf (factor)); builder.append_c ('e'); return builder.free_and_steal (); } } builder.append ("%.15g".printf (val)); return builder.free_and_steal (); } /** * Round a number to specified digits. */ public static double sig_fig_round (double number, int digits) { if (number == 0) return 0.0; double abs_number = Math.fabs (number); int power = (int) Math.floor (Math.log10 (abs_number)); int scale_power = digits - power - 1; double factor = Math.pow (10.0, scale_power); return Math.round (number * factor) / factor; } /** * Get all free variables (without x) in an equation. */ public static string[] get_free_variables (string equation) throws MathError { HashSet strings = new HashSet (); MathParser.Lexer lexer = new MathParser.Lexer (true); lexer.start_lexing (equation); // we assume a correct input so we are only interested in custom idents while (lexer.current_type != MathParser.TokenType.END) { if (lexer.current_type == MathParser.TokenType.IDENT && lexer.current_ident == MathParser.Ident.CUSTOM) { string token = lexer.get_current_token_as_string (); if (token.down () != "x") strings.add (token); } lexer.next (); } return strings.to_array (); } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/meson.build000066400000000000000000000064131520337127000243720ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later configure_file( input: 'graphs.in', output: 'graphs', configuration: conf, install: true, install_mode: 'rwxr-xr-x', install_dir: bindir, ) python.install_sources( files( 'file_import/parsers/__init__.py', 'file_import/parsers/columns/__init__.py', 'file_import/parsers/sql/__init__.py', 'file_import/parsers/spreadsheet/__init__.py', 'file_import/parsers/project/__init__.py', 'file_import/parsers/xrdml/__init__.py', 'file_import/parsers/xry/__init__.py', 'file_import/__init__.py', 'style_editor/__init__.py', 'style_editor/editor_box.py', 'artist.py', 'canvas.py', 'curve_fitting.py', 'data.py', 'export_items.py', 'figure.py', 'file_io.py', 'item.py', 'migrate.py', 'misc.py', 'operations.py', 'project.py', 'python_helper.py', 'scales.py', 'style_io.py', 'styles.py', 'utilities.py', 'window.py', ), preserve_path: true, subdir: 'graphs', ) configure_file( output: 'config.h', configuration: vala_conf, ) config_dep = valac.find_library('config', dirs: join_paths(meson.project_source_root(), 'graphs'), ) graphs_lib = shared_library('graphs', files( 'file_import/parsers/columns/main.vala', 'file_import/parsers/columns/parser.vala', 'file_import/parsers/columns/ui.vala', 'file_import/parsers/sql/reader.vala', 'file_import/parsers/spreadsheet/ui.vala', 'file_import/parsers/sql/ui.vala', 'file_import/parsers/xry/parser.vala', 'file_import/dialog.vala', 'file_import/file_import.vala', 'math_parser/evaluator.vala', 'math_parser/lexer.vala', 'math_parser/main.vala', 'math_parser/preprocessor.vala', 'sidebar/edit_item.vala', 'sidebar/figure_settings.vala', 'sidebar/main.vala', 'sidebar/operations.vala', 'style_editor/add_style.vala', 'style_editor/color_manager.vala', 'style_editor/color_row.vala', 'style_editor/editor_box.vala', 'style_editor/item_color_row.vala', 'style_editor/window.vala', 'actions.vala', 'add_equation.vala', 'application.vala', 'canvas.vala', 'curve_fitting.vala', 'data.vala', 'export_figure.vala', 'export_items.vala', 'figure_settings.vala', 'generate_data.vala', 'item.vala', 'item_box.vala', 'math_utilities.vala', 'misc.vala', 'project.vala', 'python_helper.vala', 'smoothen_settings.vala', 'styles.vala', 'transform.vala', 'utilities.vala', 'window.vala', ), gresource, vala_gir: 'Graphs-1.gir', dependencies: dependencies + config_dep, include_directories: include_directories('.'), link_args: ['-lm'], vala_args: ['--pkg=posix'], install: true, install_dir: [true], ) custom_target('graphs typelib', output: 'Graphs-1.typelib', depends: graphs_lib, install: true, install_dir: join_paths(libdir, 'girepository-1.0'), command: [ find_program('g-ir-compiler'), '--shared-library', 'libgraphs.so', '--output', '@OUTPUT@', join_paths(meson.current_build_dir(), 'Graphs-1.gir'), ], ) devenv.set('GI_TYPELIB_PATH', meson.current_build_dir()) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/migrate.py000066400000000000000000000150541520337127000242330ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for migrating old data to new structures.""" import contextlib import logging import pickle import sys from gi.repository import Gio import gio_pyio LIMITS = [ "min_bottom", "max_bottom", "min_top", "max_top", "min_left", "max_left", "min_right", "max_right", ] ITEM_MIGRATION_TABLE = { "plot_x_position": "xposition", "plot_y_position": "yposition", "x_anchor": "xanchor", "y_anchor": "yanchor", "key": "uuid", } ITEM_VALUE_MIGRATION_TABLE = { "linestyle": ["none", "solid", "dotted", "dashed", "dashdot"], "markerstyle": [ "none", ".", ",", "o", "v", "^", "<", ">", "8", "s", "p", "*", "h", "H", "+", "x", "D", "d", "|", "_", "P", "X", ], "xposition": ["bottom", "top"], "yposition": ["left", "right"], } PLOT_SETTINGS_MIGRATION_TABLE = { "xlabel": "bottom_label", "ylabel": "left_label", "xscale": "bottom_scale", "yscale": "left_scale", "use_custom_plot_style": "use_custom_style", "custom_plot_style": "custom_style", "mix_right": "min_right", } LEGEND_POSITIONS = [ "best", "upper right", "upper left", "lower left", "lower right", "center left", "center right", "lower center", "upper center", "center", ] class PlotSettings: """Old PlotSettings standin.""" def migrate(self) -> dict: """Migrate class to dict.""" dictionary = {} for key, value in self.__dict__.items(): with contextlib.suppress(KeyError): key = PLOT_SETTINGS_MIGRATION_TABLE[key] if "scale" in key: value = 0 if value == "linear" else 1 elif key == "legend_position": value = LEGEND_POSITIONS.index(value) dictionary[key] = value return dictionary class ItemBase: """Old ItemBase standin.""" def migrate(self) -> dict: """Migrate class to dict.""" dictionary = {"type": self.item_type} for key, value in self.__dict__.items(): with contextlib.suppress(KeyError): key = ITEM_MIGRATION_TABLE[key] if key in ITEM_VALUE_MIGRATION_TABLE: try: value = ITEM_VALUE_MIGRATION_TABLE[key].index(value) except IndexError: value = 0 dictionary[key] = value return dictionary class Item(ItemBase): """Old Item standin.""" item_type = "GraphsDataItem" class TextItem(ItemBase): """Old TextItem standin.""" item_type = "GraphsTextItem" _DEFAULT_VIEW = [0, 1, 0, 10, 0, 1, 0, 10] def migrate_project(file: Gio.File) -> dict: """Migrate pickle-based project.""" logging.debug("Migrating legacy project") sys.modules["graphs.misc"] = sys.modules[__name__] sys.modules["graphs.item"] = sys.modules[__name__] with gio_pyio.open(file, "rb") as wrapper: project = pickle.load(wrapper) figure_settings = project["plot_settings"].migrate() current_limits = [figure_settings[key] for key in LIMITS] history_pos = int(project["clipboard_pos"]) history_states = _migrate_clipboard( project["datadict_clipboard"], history_pos, current_limits, ) return { "version": str(project["version"]), "project-version": 1, "data": [item.migrate() for item in project["data"].values()], "figure-settings": figure_settings, "history-states": history_states, "history-position": history_pos, "view-history-states": [_DEFAULT_VIEW.copy(), current_limits], "view-history-position": -1, } def _migrate_clipboard(clipboard, clipboard_pos, current_limits): if not clipboard: return [] new_clipboard = [] if len(clipboard) > 100: clipboard = list(clipboard[len(clipboard) - 100:]) states = [{ item.key: item.migrate() for item in state.values() } for state in clipboard] new_clipboard.append([[], _DEFAULT_VIEW.copy()]) initial_items = states[1].values() new_clipboard.append(( [[1, item] for item in initial_items], _get_limits(initial_items), )) if len(states) > 2: for count in range(len(states) - 2): batch = [] previous_state = states[count + 1] current_state = states[count + 2] if len(current_state) < len(previous_state): for key, item in previous_state.copy().items(): if key not in current_state: batch.append([2, [previous_state.index(item), item]]) previous_state.pop(item) for count_2, (key, item) in enumerate(current_state.items()): if key in previous_state: previous_index = list(previous_state.keys()).index(key) if previous_index != count_2: batch.append([3, [previous_index, count_2]]) else: for key_2, value in item.items(): previous_value = previous_state[key][key_2] if value != previous_value: batch.append([ 0, [key, key_2, previous_value, value], ]) else: batch.append([1, item]) if clipboard_pos == count - len(states) + 1: limits = _get_limits(current_state.values()) else: limits = current_limits new_clipboard.append([batch, limits]) return new_clipboard def _get_limits(items): limits = [None] * 8 for item in items: if item["type"] != "Item": continue for count, x_or_y in enumerate(["x", "y"]): index = item[f"{x_or_y}position"] * 2 + 4 * count data = item[f"{x_or_y}data"] try: limits[index] = min(limits[index], data) except TypeError: limits[index] = min(data) try: limits[index + 1] = max(limits[index + 1], data) except TypeError: limits[index + 1] = max(data) for count in range(8): default_view_copy = _DEFAULT_VIEW.copy() if limits[count] is None: limits[count] = default_view_copy[count] return limits Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/misc.py000066400000000000000000000016221520337127000235320ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Miscallaneous constants.""" import sympy class ParseError(Exception): """Custom Error for parsing files.""" def __init__(self, message): self.message = message super().__init__(self.message) class InvalidEquationError(Exception): """Custom Error for invalid equation.""" def __init__(self, message): self.message = message super().__init__(self.message) X = sympy.Symbol("x") LINESTYLES = ["none", "solid", "dotted", "dashed", "dashdot"] MARKERSTYLES = [ "none", ".", ",", "o", "v", "^", "<", ">", "8", "s", "p", "*", "h", "H", "+", "x", "D", "d", "|", "_", "P", "X", ] DIRECTIONS = ["bottom", "top", "left", "right"] LIMITS = [ f"{prefix}-{direction}" for direction in DIRECTIONS for prefix in ("min", "max") ] Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/misc.vala000066400000000000000000000070301520337127000240240ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gtk; namespace Graphs { public ListModel get_mplstyle_file_filters () { var filter = Tools.create_file_filter ( C_("file-filter", "Matplotlib Style File"), "mplstyle" ); return Tools.create_file_filters (false, filter); } public enum XPosition { BOTTOM, TOP; public string friendly_string () { switch (this) { case BOTTOM: return "bottom"; case TOP: return "top"; default: assert_not_reached (); } } } public enum YPosition { LEFT, RIGHT; public string friendly_string () { switch (this) { case LEFT: return "left"; case RIGHT: return "right"; default: assert_not_reached (); } } } public enum Scale { LINEAR, LOG, LOG2, RADIANS, SQUAREROOT, INVERSE; public static Scale from_string (string str) { switch (str) { case "linear": return LINEAR; case "log": return LOG; case "log2": return LOG2; case "radians": return RADIANS; case "squareroot": return SQUAREROOT; case "inverse": return INVERSE; default: assert_not_reached (); } } } public static string scale_to_string (Scale scale) { return scale.to_string ()[13:].down (); } public enum LegendPosition { BEST, UPPER_RIGHT, UPPER_LEFT, LOWER_LEFT, LOWER_RIGHT, CENTER_LEFT, CENTER_RIGHT, LOWER_CENTER, UPPER_CENTER, CENTER; public static LegendPosition from_string (string str) { switch (str) { case "best": return BEST; case "upper right": return UPPER_RIGHT; case "upper left": return UPPER_LEFT; case "lower left": return LOWER_LEFT; case "lower right": return LOWER_RIGHT; case "center left": return CENTER_LEFT; case "center right": return CENTER_RIGHT; case "lower center": return LOWER_CENTER; case "upper center": return UPPER_CENTER; case "center": return CENTER; default: assert_not_reached (); } } public string friendly_string () { switch (this) { case BEST: return "best"; case UPPER_RIGHT: return "upper right"; case UPPER_LEFT: return "upper left"; case LOWER_LEFT: return "lower left"; case LOWER_RIGHT: return "lower right"; case CENTER_LEFT: return "center left"; case CENTER_RIGHT: return "center right"; case LOWER_CENTER: return "lower center"; case UPPER_CENTER: return "upper center"; case CENTER: return "center"; default: assert_not_reached (); } } } // Python cannot bind Enum instance methods public static string legend_position_to_string (LegendPosition pos) { return pos.friendly_string (); } public enum ChangeType { ITEM_PROPERTY_CHANGED, ITEM_ADDED, ITEM_REMOVED, ITEMS_SWAPPED, FIGURE_SETTINGS_CHANGED } public enum Mode { PAN, ZOOM, SELECT } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/operations.py000066400000000000000000000702641520337127000247720ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for data transformations.""" import logging import re from gettext import gettext as _ from gi.repository import Gio, Graphs from graphs import misc, utilities from graphs.item import DataItem import numexpr import numpy import scipy import sympy def perform_operation(window: Graphs.Window, name: str) -> None: """Perform an operation.""" interaction_mode = window.get_mode() if name == "cut" and interaction_mode != Graphs.Mode.SELECT: return args = [] actions_settings = Graphs.Application.get_settings_child("actions") if name in ("center", "smoothen"): args = [actions_settings.get_enum(name)] if name == "smoothen": args.append(actions_settings.get_child(name)) elif "translate" in name or "multiply" in name: args.append(window.get_operation_value(name)) data = window.get_data() figure_settings = data.get_figure_settings() if hasattr(CommonOperations, name): all_success = getattr(CommonOperations, name)(window) else: all_success = False for item in data: if not item.get_selected(): continue if isinstance(item, Graphs.EquationItem): operations_class = EquationOperations elif isinstance(item, Graphs.DataItem): operations_class = DataOperations else: continue success, message = operations_class.execute( item, name, figure_settings, interaction_mode, *args, ) if message: window.add_toast_string(message) all_success = success or all_success if all_success: data.add_history_state() data.optimize_limits() class DataHelper(): """Helper methods that assist with the handling of the data.""" @staticmethod def get_xydata( interaction_mode: Graphs.Mode, selected_limits: tuple[float, float], item: Graphs.DataItem, ) -> tuple[numpy.ndarray, numpy.ndarray]: """Get the X and Y data of a DataItem.""" xdata, ydata = item.get_xydata() if interaction_mode != Graphs.Mode.SELECT: return xdata, ydata startx, stopx = selected_limits # If startx and stopx are not out of range, that is, # if the item data is within the highlight if stopx < min(xdata) or startx > max(xdata): return None, None mask = numpy.greater_equal(xdata, startx) mask &= numpy.less_equal(xdata, stopx) return xdata[mask], ydata[mask] @staticmethod def get_selected_limits( figure_settings: Graphs.FigureSettings, interaction_mode: Graphs.Mode, item: Graphs.DataItem, ) -> tuple[float, float]: """Get the min and max value of the item within the selected range.""" if item.get_xposition() == Graphs.XPosition.BOTTOM: min_bottom = figure_settings.get_min_bottom() max_bottom = figure_settings.get_max_bottom() if interaction_mode != Graphs.Mode.SELECT: return min_bottom, max_bottom scale = figure_settings.get_bottom_scale() min_x = Graphs.get_value_at_fraction( figure_settings.get_min_selected(), min_bottom, max_bottom, scale, ) max_x = Graphs.get_value_at_fraction( figure_settings.get_max_selected(), min_bottom, max_bottom, scale, ) else: min_top = figure_settings.get_min_top() max_top = figure_settings.get_max_top() if interaction_mode != Graphs.Mode.SELECT: return min_top, max_top scale = figure_settings.get_top_scale() min_x = Graphs.get_value_at_fraction( figure_settings.get_min_selected(), min_top, max_top, scale, ) max_x = Graphs.get_value_at_fraction( figure_settings.get_max_selected(), min_top, max_top, scale, ) return min_x, max_x @staticmethod def sort_data( xdata: numpy.ndarray, ydata: numpy.ndarray, ) -> tuple[numpy.ndarray, numpy.ndarray]: """Sort data.""" idx = numpy.argsort(xdata) return xdata[idx], ydata[idx] class CommonOperations(): """Operations to be performed on all kind of items.""" @staticmethod def custom_transformation(window: Graphs.Window) -> bool: """Perform a custom operation on the dataset.""" def on_accept(_dialog, input_x, input_y, discard): data = window.get_data() figure_settings = data.get_figure_settings() for item in data: if not item.get_selected(): continue if isinstance(item, Graphs.EquationItem): operations_class = EquationOperations elif isinstance(item, Graphs.DataItem): operations_class = DataOperations success, message = operations_class.execute( item, "transform", figure_settings, window.get_mode(), input_x, input_y, discard, ) if message: fail_message = _( "Unable to perform transformation, " "make sure the syntax is correct", ) toast = message if success else fail_message window.add_toast_string(toast) data.add_history_state() data.optimize_limits() dialog = Graphs.TransformDialog.new(window) dialog.connect("accept", on_accept) return False @staticmethod def combine(window: Graphs.Window) -> bool: """Combine the selected data into a new data set.""" data = window.get_data() mode = window.get_mode() settings = data.get_figure_settings() new_xdata, new_ydata, new_xerr, new_yerr = [], [], [], [] some_x, some_y = False, False for item in data: if not item.get_selected(): continue lims = DataHelper.get_selected_limits(settings, mode, item) xdata, ydata = None, None if isinstance(item, Graphs.EquationItem): eq = item.get_preprocessed_equation() xdata, ydata = utilities.equation_to_data(eq, lims) new_xerr, new_yerr = None, None elif isinstance(item, Graphs.DataItem): xdata, ydata = DataHelper().get_xydata(mode, lims, item) xerr = item.get_xerr() if xerr is not None and new_xerr is not None: new_xerr.extend(xerr) some_x = True else: new_xerr = None yerr = item.get_yerr() if yerr is not None and new_yerr is not None: new_yerr.extend(yerr) some_y = True else: new_yerr = None if xdata is not None and ydata is not None: new_xdata.extend(xdata) new_ydata.extend(ydata) if not new_xdata or not new_ydata: window.add_toast_string(_("No data found in highlighted area")) return False if (some_x and new_xerr is None) or (some_y and new_yerr is None): msg = _("Some items lack error bars; they will be discarded") window.add_toast_string(msg) new_xdata, new_ydata = DataHelper.sort_data(new_xdata, new_ydata) data.add_items([ DataItem.new( data.get_selected_style_params(), new_xdata, new_ydata, xerr=new_xerr, yerr=new_yerr, name=_("Combined Data"), ), ]) return True @staticmethod def shift(window: Graphs.Window) -> None: """Shift data.""" interaction_mode = window.get_mode() data = window.get_data() figure_settings = data.get_figure_settings() data_list = ([ item for item in data if item.get_selected() and isinstance(item, (Graphs.EquationItem, Graphs.DataItem)) ]) ranges = [ figure_settings.get_max_left() - figure_settings.get_min_left(), figure_settings.get_max_right() - figure_settings.get_min_right(), ] left_scale = figure_settings.get_left_scale() right_scale = figure_settings.get_right_scale() for index, item in enumerate(data_list): selected_limits = DataHelper.get_selected_limits( figure_settings, interaction_mode, item, ) startx, stopx = selected_limits scale = right_scale if item.get_yposition() else left_scale if isinstance(item, Graphs.EquationItem): xdata, ydata = utilities.equation_to_data( item.get_preprocessed_equation(), selected_limits, ) elif isinstance(item, Graphs.DataItem): xdata, ydata = item.get_xydata() if interaction_mode == Graphs.Mode.SELECT: # If startx and stopx are not out of range, that is, # if the item data is within the highlight if stopx < min(xdata) or startx > max(xdata): continue data_mask = numpy.greater_equal(xdata, startx) data_mask &= numpy.less_equal(xdata, stopx) xdata, ydata = xdata[data_mask], ydata[data_mask] if min(xdata.size, ydata.size) == 0: continue shift_value = 0 item = data_list[0] for i in range(index + 1): previous_item = item item = data_list[i] y_range = ranges[item.get_yposition()] if isinstance(previous_item, Graphs.EquationItem): prev_min, prev_max = startx, stopx else: prev_xdata = previous_item.get_xdata() prev_min, prev_max = min(prev_xdata), max(prev_xdata) if interaction_mode == Graphs.Mode.SELECT: prev_min = max(prev_min, startx) prev_min = min(prev_max, stopx) xmin, xmax = min(xdata), max(xdata) if xmin >= prev_min and xmax <= prev_max: mask = numpy.greater_equal(xdata, xmin) mask &= numpy.less_equal(xdata, xmax) ydata = ydata[mask] nonzero_data = ydata[ydata != 0] ymin = nonzero_data.min() ymax = nonzero_data.max() if scale == Graphs.Scale.LOG: shift_value += \ numpy.log10(abs(ymax / ymin)) \ + 0.1 * numpy.log10(y_range) elif scale == Graphs.Scale.LOG2: shift_value += \ numpy.log2(abs(ymax / ymin)) \ + 0.1 * numpy.log2(y_range) else: shift_value += (ymax - ymin) + 0.1 * y_range if shift_value == 0: continue shift_value = Graphs.math_tools_sig_fig_round(shift_value, 3) if isinstance(item, Graphs.EquationItem): equation = item.get_preprocessed_equation() if scale == Graphs.Scale.LOG: equation = f"({equation})*10**{shift_value}" elif scale == Graphs.Scale.LOG2: equation = f"({equation})*2**{shift_value}" else: equation = f"{equation}+{shift_value}" equation = str(sympy.simplify(equation)) item.set_equation(Graphs.prettify_equation(equation)) continue if isinstance(item, Graphs.DataItem): if scale == Graphs.Scale.LOG: new_ydata = ydata * 10**shift_value elif scale == Graphs.Scale.LOG2: new_ydata = ydata * 2**shift_value else: # Apply linear scaling new_ydata = ydata + shift_value if interaction_mode == Graphs.Mode.SELECT: item_ydata = item.get_ydata().copy() item_ydata[data_mask] = new_ydata new_ydata = item_ydata item.set_xydata((item.get_xdata(), new_ydata)) continue return True XDATA = numpy.linspace(0, 10, 10) class EquationOperations(): """Operations to be performed on equation items.""" @staticmethod def execute( item: Graphs.EquationItem, name: str, figure_settings: Graphs.FigureSettings, _interaction_mode: Graphs.Mode, *args, ) -> tuple[bool, str]: """Execute the operation on the given item.""" old_limits = figure_settings.get_limits().values() try: callback = getattr(EquationOperations, name) if name in ("normalize", "center", "transform"): args = [( old_limits[item.get_xposition()], old_limits[item.get_yposition() + 1], )] + list(args) equation = item.get_preprocessed_equation() equation = str(sympy.simplify(callback(equation, *args))) try: numexpr.evaluate(equation, local_dict={"x": XDATA}) except (KeyError, SyntaxError, ValueError, TypeError) as e: raise misc.InvalidEquationError( _( "The operation on {name} " "did not result in a plottable equation", ).format(name=item.get_name()), ) from e item.set_equation(Graphs.prettify_equation(equation)) except misc.InvalidEquationError as error: return False, error.message except (NotImplementedError, AttributeError, KeyError): return False, _("Operation not supported for equations.") return True, "" @staticmethod def translate_x(equation, offset) -> str: """Translate all selected data on the x-axis.""" return re.sub(r"(? str: """Translate all selected data on the y-axis.""" return f"({equation})+{offset}" @staticmethod def multiply_x(equation, multiplier: float) -> str: """Multiply all selected data on the x-axis.""" return re.sub(r"(? str: """Multiply all selected data on the y-axis.""" return f"({equation})*{multiplier}" @staticmethod def normalize(equation, limits) -> str: """Normalize all selected data.""" ydata = utilities.equation_to_data(equation, limits)[1] return f"({equation})/{max(ydata)}" @staticmethod def center(equation, limits, center_maximum: int) -> str: """ Center all selected data. Depending on the key, will center either on the middle coordinate, or on the maximum value of the data """ xdata, ydata = utilities.equation_to_data(equation, limits) if center_maximum == 0: # Center at maximum Y x = misc.X equation = sympy.sympify(equation) derivative = sympy.diff(equation, x) critical_points = sympy.solveset( derivative, x, domain=sympy.Interval(limits[0], limits[1]), ) endpoints = \ [equation.subs(x, limits[0]), equation.subs(x, limits[1])] try: critical_values = \ [equation.subs(x, cp) for cp in critical_points] if critical_values: max_index = critical_values.index(max(critical_values)) middle_value = list(critical_points)[max_index] else: max_index = endpoints.index(max(endpoints)) middle_value = [limits[0], limits[1]][max_index] # If we don't manage to solve this analytically, just find # the maximum by calculating except TypeError: middle_index = numpy.argmax(ydata) middle_value = xdata[middle_index] elif center_maximum == 1: # Center at middle middle_value = (min(xdata) + max(xdata)) / 2 return re.sub(r"(? str: """Calculate derivative of all selected data.""" return str(sympy.diff(equation, misc.X)) @staticmethod def integral(equation) -> str: """Calculate indefinite integral of all selected data.""" return str(sympy.integrate(equation, misc.X)) @staticmethod def fft(equation) -> str: """Perform Fourier transformation on all selected data.""" k = sympy.Symbol("k") equation = str(sympy.fourier_transform(equation, misc.X, k)) return equation.replace("k", "x") @staticmethod def inverse_fft(equation) -> str: """Perform Inverse Fourier transformation on all selected data.""" k = sympy.Symbol("k") equation = str(sympy.fourier_transform(equation, misc.X, k)) return equation.replace("k", "x") @staticmethod def transform( equation: str, limits: list, input_x: str, input_y: str, _discard: bool, ) -> str: """Perform custom transformation.""" xdata, ydata = utilities.equation_to_data(equation, limits) local_dict = { "x": xdata, "y": ydata, "x_min": min(xdata), "x_max": max(xdata), "y_min": min(ydata), "y_max": max(ydata), "counts": len(xdata), "x_mean": numpy.mean(xdata), "y_mean": numpy.mean(ydata), "x_std": numpy.std(xdata), "y_std": numpy.std(ydata), "x_median": numpy.median(xdata), "y_median": numpy.median(ydata), "x_sum": sum(xdata), "y_sum": sum(ydata), } for key, value in local_dict.items(): if key not in ("x", "y"): input_x = input_x.lower().replace(key, str(value)) input_y = input_y.lower().replace(key, str(value)) equation = re.sub(r"(? tuple[bool, str]: """Execute the operation on the given item.""" xdata, ydata = item.get_xydata() if interaction_mode == Graphs.Mode.SELECT: startx, stopx = DataHelper.get_selected_limits( figure_settings, interaction_mode, item, ) # If startx and stopx are not out of range, that is, # if the item data is within the highlight xmin = min(xdata) if not (startx < xmin and stopx < xmin or (startx > max(xdata))): mask = numpy.greater_equal(xdata, startx) mask &= numpy.less_equal(xdata, stopx) xdata, ydata = xdata[mask], ydata[mask] else: xdata, ydata = None, None if not (xdata is not None and len(xdata) != 0): return False, _("No data found within the highlighted area") try: callback = getattr(DataOperations, name) message = "" new_xdata, new_ydata, sort, discard = callback( item, xdata, ydata, *args, ) except NotImplementedError: return False, _("Operation not supported for data items") # May run into this exception for custom transformations: except (RuntimeError, ValueError, KeyError, SyntaxError) as exception: message = _("{name}: Error performing the operation") return False, message.format(name=exception.__class__.__name__) xerr = item.get_xerr() yerr = item.get_yerr() if interaction_mode == Graphs.Mode.SELECT: if discard: logging.debug("Discard is true") message = _( "Data that was outside of the highlighted area has" " been discarded", ) elif new_xdata is None: # If cut action was performed new_xdata = item.get_xdata()[~mask] new_ydata = item.get_ydata()[~mask] xerr = xerr[~mask] if xerr is not None else None yerr = yerr[~mask] if yerr is not None else None else: logging.debug("Discard is false") xdata = item.get_xdata().copy() ydata = item.get_ydata().copy() xdata[mask] = new_xdata ydata[mask] = new_ydata new_xdata, new_ydata = xdata, ydata if sort: logging.debug("Sorting data") new_xdata, new_ydata = DataHelper.sort_data(new_xdata, new_ydata) item.set_data_tuple((new_xdata, new_ydata, xerr, yerr)) return True, message @staticmethod def translate_x(_item, xdata: list, ydata: list, offset: float) -> _return: """ Translate all selected data on the x-axis. Amount to be shifted is equal to the value in the translate_x entry widget. Will show a toast if a ValueError is raised, typically when a user entered an invalid number (e.g. comma instead of point separators) """ return xdata + offset, ydata, True, False @staticmethod def translate_y(_item, xdata: list, ydata: list, offset: float) -> _return: """ Translate all selected data on the y-axis. Amount to be shifted is equal to the value in the translate_y entry widget. Will show a toast if a ValueError is raised, typically when a user entered an invalid number (e.g. comma instead of point separators) """ return xdata, ydata + offset, False, False @staticmethod def multiply_x( _item, xdata: list, ydata: list, multiplier: float, ) -> _return: """ Multiply all selected data on the x-axis. Amount to be multiplied is equal to the value in the multiply_x entry widget Will show a toast if a ValueError is raised, typically when a user entered an invalid number (e.g. comma instead of point separators) """ return xdata * multiplier, ydata, True, False @staticmethod def multiply_y( _item, xdata: list, ydata: list, multiplier: float, ) -> _return: """ Multiply all selected data on the y-axis. Amount to be multiplied is equal to the value in the multiply_y entry widget Will show a toast if a ValueError is raised, typically when a user entered an invalid number (e.g. comma instead of point separators) """ return xdata, ydata * multiplier, False, False @staticmethod def normalize(_item, xdata: list, ydata: list) -> _return: """Normalize all selected data.""" return xdata, ydata / max(ydata), False, False @staticmethod def smoothen( _item, xdata: list, ydata: list, smooth_type: int, settings: Gio.Settings, ) -> _return: """Smoothen y-data.""" if smooth_type == 0: minimum = settings.get_int("savgol-polynomial") + 1 window_percentage = settings.get_int("savgol-window") / 100 window = max(minimum, int(len(xdata) * window_percentage)) new_ydata = scipy.signal.savgol_filter( ydata, window, settings.get_int("savgol-polynomial"), ) elif smooth_type == 1: box_points = settings.get_int("moving-average-box") box = numpy.ones(box_points) / box_points new_ydata = numpy.convolve(ydata, box, mode="same") return xdata, new_ydata, False, False @staticmethod def center( _item, xdata: list, ydata: list, center_maximum: int, ) -> _return: """ Center all selected data. Depending on the key, will center either on the middle coordinate, or on the maximum value of the data """ if center_maximum == 0: # Center at maximum Y middle_index = numpy.argmax(ydata) middle_value = xdata[middle_index] elif center_maximum == 1: # Center at middle middle_value = (min(xdata) + max(xdata)) / 2 return xdata - middle_value, ydata, True, False @staticmethod def cut(_item, _xdata, _ydata) -> _return: """Cut selected data over the span that is selected.""" return None, None, False, False @staticmethod def derivative(_item, xdata: list, ydata: list) -> _return: """Calculate derivative of all selected data.""" return xdata, numpy.gradient(ydata, xdata), False, True @staticmethod def integral(_item, xdata: list, ydata: list) -> _return: """Calculate indefinite integral of all selected data.""" indefinite_integral = scipy.integrate.cumulative_trapezoid( ydata, xdata, initial=0, ) return xdata, indefinite_integral, False, True @staticmethod def fft(_item, xdata: list, ydata: list) -> _return: """Perform Fourier transformation on all selected data.""" y_fourier = numpy.fft.fft(ydata) x_fourier = numpy.fft.fftfreq(len(xdata), xdata[1] - xdata[0]) y_fourier = [value.real for value in y_fourier] return x_fourier, y_fourier, False, True @staticmethod def inverse_fft(_item, xdata: list, ydata: list) -> _return: """Perform Inverse Fourier transformation on all selected data.""" y_fourier = numpy.fft.ifft(ydata) x_fourier = numpy.fft.fftfreq(len(xdata), xdata[1] - xdata[0]) y_fourier = [value.real for value in y_fourier] return x_fourier, y_fourier, False, True @staticmethod def transform( _item, xdata: list, ydata: list, input_x: str, input_y: str, discard: bool = False, ) -> _return: """Perform custom transformation.""" local_dict = { "x": xdata, "y": ydata, "x_min": min(xdata), "x_max": max(xdata), "y_min": min(ydata), "y_max": max(ydata), "counts": len(xdata), "x_mean": numpy.mean(xdata), "y_mean": numpy.mean(ydata), "x_std": numpy.std(xdata), "y_std": numpy.std(ydata), "x_median": numpy.median(xdata), "y_median": numpy.median(ydata), "x_sum": sum(xdata), "y_sum": sum(ydata), } # Add array of zeros to return values, such that output remains a list # of the correct size, even when a float is given as input. return ( numexpr.evaluate( Graphs.preprocess_equation(input_x) + "+ 0*x", local_dict, ), numexpr.evaluate( Graphs.preprocess_equation(input_y) + "+ 0*y", local_dict, ), True, discard, ) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/project.py000066400000000000000000000323051520337127000242470ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for saving and loading projects.""" import copy import logging import re from gettext import gettext as _ from operator import itemgetter from gi.repository import Gio, Graphs from graphs import file_io, migrate from graphs.item import ItemFactory CURRENT_PROJECT_VERSION = 2 class ProjectParseError(Exception): """Custom error for parsing projects.""" def __init__(self, message: str, log: bool = True): super().__init__() self.message = message self.log = log PROJECT_KEYS = [ "version", "data", "figure-settings", "history-states", "history-position", "view-history-states", "view-history-position", ] class ProjectMigrator: """ Migrate project data to be compatible with the current version of Graphs. Migration is based on version to version basis, so migrating from v1 to v3 would involve migrating from v1 to v2 first and then migrating from v2 to v3. """ beta_pattern = re.compile(r"^\d+\.\d+\.\d+-[0-9a-f]{8}$") def __init__( self, project_dict: dict, parse_flags: Graphs.ProjectParseFlags, ): # Verify all keys are present try: for key in PROJECT_KEYS: project_dict[key] except KeyError as e: raise ProjectParseError(_("Project file is missing data")) from e self._project_dict = project_dict self.parse_flags = parse_flags # check beta version beta_version = bool(self.beta_pattern.match(project_dict["version"])) check_beta = not parse_flags & Graphs.ProjectParseFlags.ALLOW_BETA if beta_version and check_beta: raise ProjectParseError("BETA_DISALLOWED", False) def migrate(self) -> dict: """Perform needed migrations.""" try: project_version = int(self._project_dict["project-version"]) assert project_version > 0 except KeyError: project_version = 1 if project_version > CURRENT_PROJECT_VERSION: raise ProjectParseError( _("Project is from a newer incompatible version of Graphs"), ) if CURRENT_PROJECT_VERSION == project_version: return self._project_dict # Migrate a project one version at a time current_version = project_version while current_version < CURRENT_PROJECT_VERSION: current_version += 1 getattr(self, f"_migrate_v{current_version}")() return self._project_dict def _migrate_v2(self): logging.debug("migrating project v1 to v2") # Figure settings entries are now properly stored in hyphon-case self._project_dict["figure-settings"] = { key.replace("_", "-"): value for (key, value) in self._project_dict["figure-settings"].items() } self._migrate_inserted_scale(2) # log2 scale added # Handle items no longer making use of uuid as well as xdata and ydata # being stored in a tuple as data. Also truncate the Graphs prefix # before the typename def _item_dict(item): return_item = { key: value for (key, value) in item.items() if key not in ("uuid", "xdata", "ydata") } return_item["data"] = (item["xdata"], item["ydata"], None, None) return_item["type"] = return_item["type"][6:] return return_item item_positions = [] data = [] for item in self._project_dict["data"]: item_positions.append(item["uuid"]) data.append(_item_dict(item)) self._project_dict["data"] = data history_states = self._project_dict["history-states"] n_states = len(history_states) history_pos = self._project_dict["history-position"] while history_pos < 1: for (change_type, change) in history_states[history_pos][0]: match change_type: case Graphs.ChangeType.ITEM_ADDED: item_positions.append(change["uuid"]) case Graphs.ChangeType.ITEM_REMOVED: item_positions.remove(change[1]["uuid"]) case Graphs.ChangeType.ITEMS_SWAPPED: uuid = item_positions.pop(change[0]) item_positions.insert(change[1], uuid) history_pos += 1 data_changes = {} for state_index, state in enumerate(reversed(history_states)): state_index = n_states - state_index - 1 new_state = [] for change_type, change in reversed(state[0]): match change_type: case Graphs.ChangeType.ITEM_ADDED: item_positions.remove(change["uuid"]) change = _item_dict(change) case Graphs.ChangeType.ITEM_REMOVED: item_positions.insert(change[0], change[1]["uuid"]) change = [change[0], _item_dict(change[1])] case Graphs.ChangeType.ITEMS_SWAPPED: uuid = item_positions.pop(change[1]) item_positions.insert(change[0], uuid) case Graphs.ChangeType.ITEM_PROPERTY_CHANGED: change[0] = item_positions.index(change[0]) if change[1] in ("xdata", "ydata"): # Consolidate two change entries into a single one try: data_change = data_changes[state_index] if change[1] == "xdata": data_change[0] = change[2:] else: data_change[1] = change[2:] change = [ Graphs.ChangeType.ITEM_PROPERTY_CHANGED, "data", ( data_change[0][0], data_change[1][0], None, None, ), ( data_change[0][1], data_change[1][1], None, None, ), ] except KeyError: if change[1] == "xdata": xdata = change[2:] ydata = None else: xdata = None ydata = change[2:] data_changes[state_index] = [xdata, ydata] continue new_state.insert(0, [change_type, change]) history_states[state_index][0] = new_state self._project_dict["history-states"] = history_states def _migrate_inserted_scale(self, scale_index: int) -> None: """Handle a new scale being inserted at scale_index.""" figure_settings = self._project_dict["figure-settings"] for prefix in ("left", "right", "top", "bottom"): axis = prefix + "-scale" if figure_settings[axis] >= scale_index: figure_settings[axis] = figure_settings[axis] + 1 for state_index, history_state in enumerate( self._project_dict["history-states"], ): for change_index, changeset in enumerate(history_state[0]): change_type, change = changeset if change_type != 4: continue if change[0][-6:] != "-scale": continue for i, val in enumerate(change[1:], 1): if val >= scale_index: self._project_dict["history-states"][state_index][0][ change_index][1][i] = val + 1 class ProjectValidator: """Validate the project.""" def __init__( self, project_dict: dict, parse_flags: Graphs.ProjectParseFlags, ): self.project_dict = copy.deepcopy(project_dict) self.parse_flags = parse_flags def validate(self): """Run through the history states.""" # Validate Figure Settings self.figure_settings = Graphs.FigureSettings( **{ key.replace("-", "_"): val for (key, val) in self.project_dict["figure-settings"].items() }, ) # Validate items data = self.project_dict["data"] self.items = [ItemFactory.new_from_dict(d) for d in data] # Validate view history view_history_states = self.project_dict["view-history-states"] for history_state in view_history_states: self.figure_settings.set_limits(Graphs.Limits.new(history_state)) view_history_pos = int(self.project_dict["view-history-position"]) assert view_history_pos < 0 assert abs(view_history_pos) <= len(view_history_states) # Validate data history history_states = self.project_dict["history-states"] history_pos = int(self.project_dict["history-position"]) assert history_pos < 0 assert abs(history_pos) <= len(history_states) while history_pos < -1: for (change_type, change) in history_states[history_pos][0]: match change_type: case Graphs.ChangeType.ITEM_PROPERTY_CHANGED: index, prop, value = itemgetter(0, 1, 3)(change) if prop == "data": self.items[index].set_data_tuple(value) else: self.items[index].set_property(prop, value) case Graphs.ChangeType.ITEM_ADDED: data = copy.deepcopy(change) self.items.append(ItemFactory.new_from_dict(data)) case Graphs.ChangeType.ITEM_REMOVED: self.items.pop(change[0]) case Graphs.ChangeType.ITEMS_SWAPPED: self.items.insert(change[1], self.items.pop(change[0])) case Graphs.ChangeType.FIGURE_SETTINGS_CHANGED: self.figure_settings.set_property(change[0], change[2]) history_pos += 1 for history_state in reversed(history_states): limits = history_state[1] self.figure_settings.set_limits(Graphs.Limits.new(limits)) for change_type, change in reversed(history_state[0]): match change_type: case Graphs.ChangeType.ITEM_PROPERTY_CHANGED: index, prop, value = itemgetter(0, 1, 2)(change) if prop == "data": self.items[index].set_data_tuple(value) else: self.items[index].set_property(prop, value) case Graphs.ChangeType.ITEM_ADDED: self.items.pop() case Graphs.ChangeType.ITEM_REMOVED: data = copy.deepcopy(change[1]) item = ItemFactory.new_from_dict(data) self.items.insert(change[0], item) case Graphs.ChangeType.ITEMS_SWAPPED: self.items.insert(change[0], self.items.pop(change[1])) case Graphs.ChangeType.FIGURE_SETTINGS_CHANGED: self.figure_settings.set_property(change[0], change[1]) def read_project_file( file: Gio.File, parse_flags: Graphs.ProjectParseFlags = Graphs.ProjectParseFlags.NONE, ) -> dict: """Read a project dict from file and account for migration.""" try: project_dict = file_io.parse_json(file) except UnicodeDecodeError: if not parse_flags & Graphs.ProjectParseFlags.ALLOW_LEGACY_MIGRATION: raise ProjectParseError("LEGACY_MIGRATION_DISALLOWED", False) try: project_dict = migrate.migrate_project(file) except Exception as e: raise ProjectParseError(_("Failed to do legacy migration")) from e except Exception as e: raise ProjectParseError(_("Failed to parse project file")) from e try: project_dict = ProjectMigrator(project_dict, parse_flags).migrate() except ProjectParseError: raise except Exception as e: raise ProjectParseError(_("Failed to migrate project")) from e try: ProjectValidator(project_dict, parse_flags).validate() except ProjectParseError: raise except Exception as e: raise ProjectParseError(_("Failed to validate project")) from e return project_dict def save_project_dict(file: Gio.File, project_dict: dict) -> None: """Save a project dict to a file.""" project_dict["project-version"] = CURRENT_PROJECT_VERSION file_io.write_json(file, project_dict, pretty_print=False) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/project.vala000066400000000000000000000112431520337127000245400ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { public errordomain ProjectParseError { INVALID_PROJECT, LEGACY_MIGRATION_DISALLOWED, BETA_DISALLOWED } [Flags] public enum ProjectParseFlags { NONE = 0, ALLOW_LEGACY_MIGRATION = 1 << 0, ALLOW_BETA = 1 << 1 } namespace Project { public FileFilter get_project_file_filter () { return Tools.create_file_filter ( C_("file-filter", "Graphs Project File"), "graphs" ); } private void _save (Window window) { window.data.save (); window.add_toast_string_with_file ( _("Saved Project"), window.data.file ); } private ListModel get_project_file_filters () { return Tools.create_file_filters (false, get_project_file_filter ()); } public async bool save (Window window, bool require_dialog) { if (window.data.file != null && !require_dialog) { _save (window); return true; } var dialog = new FileDialog (); dialog.set_filters (get_project_file_filters ()); dialog.set_initial_name (_("Project") + ".graphs"); try { window.data.file = yield dialog.save (window, null); _save (window); return true; } catch { return false; } } public async bool load ( Window window, Data data, File file, ProjectParseFlags flags = ProjectParseFlags.NONE ) { try { data.load (file, flags); return true; } catch (ProjectParseError e) { // Handle warnings & general error string dialog_name; ProjectParseFlags new_flags; switch (e.code) { case ProjectParseError.LEGACY_MIGRATION_DISALLOWED: dialog_name = "legacy_migration_disallowed"; new_flags = flags | ProjectParseFlags.ALLOW_LEGACY_MIGRATION; break; case ProjectParseError.BETA_DISALLOWED: dialog_name = "beta_disallowed"; new_flags = flags | ProjectParseFlags.ALLOW_BETA; break; default: var error_dialog = (Adw.AlertDialog) Tools.build_dialog ("invalid_project"); error_dialog.set_body (e.message); error_dialog.present (window); return false; } var dialog = (Adw.AlertDialog) Tools.build_dialog (dialog_name); var response = yield dialog.choose (window, null); if (response != "continue") return false; return yield load (window, data, file, new_flags); } } public async void open (Window window) { var dialog = new FileDialog (); dialog.set_filters (get_project_file_filters ()); try { var file = yield dialog.open (window, null); if (!window.data.unsaved && window.data.file == null) { yield load (window, window.data, file); return; } var application = (Application) GLib.Application.get_default (); Window new_window = application.create_main_window (); if (yield load (window, new_window.data, file)) { new_window.present (); return; }; application.on_main_window_closed (new_window); } catch {} } public void close (Window window) { if (!window.data.unsaved) { window.data.clear (); return; } var dialog = (Adw.AlertDialog) Tools.build_dialog ("save_project_changes"); dialog.response.connect ((d, response) => { switch (response) { case "discard": { window.data.clear (); break; } case "save": { save.begin (window, false, (o, result) => { if (save.end (result)) { window.data.clear (); } }); break; } } }); dialog.present (window); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/python_helper.py000066400000000000000000000106341520337127000254620ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Python Helper - Python part.""" from gi.repository import Gio, Graphs from graphs import curve_fitting, export_items, file_io, operations, utilities from graphs.figure import Figure from graphs.style_editor import PythonStyleEditor from graphs.window import PythonWindow import numexpr import numpy import sympy _REQUESTS = ( "create-style-editor", "create-window", "curve-fitting-dialog", "equation-to-data", "evaluate-expression", "export-figure", "export-items", "perform-operation", "python-method", "simplify-equation", "validate-equation", ) XDATA = numpy.linspace(0, 10, 10) class PythonHelper(Graphs.PythonHelper): """Python helper for python only calls.""" def __init__(self): super().__init__() for request in _REQUESTS: request = request + "-request" self.connect( request, getattr(self, "_on_" + request.replace("-", "_")), ) @staticmethod def _on_create_style_editor_request(self) -> Graphs.StyleEditor: return PythonStyleEditor() @staticmethod def _on_create_window_request(self) -> Graphs.Window: return PythonWindow() @staticmethod def _on_curve_fitting_dialog_request( self, window: Graphs.Window, item: Graphs.Item, ) -> None: return curve_fitting.CurveFittingDialog(window, item) @staticmethod def _on_equation_to_data_request( self, equation: str, xstart: float, xstop: float, steps: int, scale: Graphs.Scale, ) -> Graphs.DataHolder: xdata, ydata = utilities.equation_to_data( equation, [xstart, xstop], steps, scale, ) return Graphs.DataHolder.new(xdata, ydata, None, None) @staticmethod def _on_evaluate_expression_request( self, equation: str, steps: int, var: str, ) -> bool: local_dict = {var: numpy.arange(steps)} try: data = numexpr.evaluate(equation, local_dict=local_dict) if data.ndim == 0: data = numpy.full(steps, data) self.set_evaluate_expression_result(data) return True except (KeyError, SyntaxError, ValueError, TypeError): return False @staticmethod def _on_export_items_request( self, window: Graphs.Window, mode: str, file: Gio.File, items: list[Graphs.Item], _n_items: int, ) -> None: figure_settings = window.get_data().get_figure_settings() return export_items.export_items(mode, file, items, figure_settings) @staticmethod def _on_export_figure_request( self, file: Gio.File, settings: Gio.Settings, data: Graphs.Data, ) -> None: with file_io.open(file, "wb") as file_like: figure = Figure( data.get_selected_style_params(), data, figure_settings=data.get_figure_settings(), ) vector_formats = ["pdf", "eps", "ps", "svg"] fmt = settings.get_string("file-format") dpi = 100 if fmt.lower() in vector_formats else figure.get_dpi() width_inches = settings.get_int("width") / dpi height_inches = settings.get_int("height") / dpi figure.set_size_inches(width_inches, height_inches) figure.savefig( file_like, format=fmt, dpi=dpi, transparent=settings.get_boolean("transparent"), bbox_inches=None, ) @staticmethod def _on_perform_operation_request( self, window: Graphs.Window, name: str, ) -> None: operations.perform_operation(window, name) @staticmethod def _on_python_method_request(self, obj, method: str) -> None: getattr(obj, method)() @staticmethod def _on_simplify_equation_request(self, equation: str) -> str: return str(sympy.simplify(equation)) @staticmethod def _on_validate_equation_request(self, equation: str) -> bool: try: ydata = numexpr.evaluate(equation, local_dict={"x": XDATA}) return numpy.isfinite(ydata).any() except (KeyError, SyntaxError, ValueError, TypeError): return False Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/python_helper.vala000066400000000000000000000070541520337127000257570ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later // Python Helper - Vala Part using Gtk; namespace Graphs { public class PythonHelper : Object { private static PythonHelper instance; construct { instance = this; } protected signal StyleEditor create_style_editor_request (); public static StyleEditor create_style_editor () { return instance.create_style_editor_request.emit (); } protected signal Window create_window_request (); public static Window create_window () { return instance.create_window_request (); } protected signal CurveFittingDialog curve_fitting_dialog_request (Window window, Item item); public static CurveFittingDialog create_curve_fitting_dialog (Window window, Item item) { return instance.curve_fitting_dialog_request.emit (window, item); } protected signal DataHolder equation_to_data_request (string equation, double xstart, double xstop, int steps, Scale scale); public static DataHolder equation_to_data (string equation, double xstart, double xstop, int steps, Scale scale) { return instance.equation_to_data_request.emit (equation, xstart, xstop, steps, scale); } private static double[] _evaluate_expression_result; protected signal bool evaluate_expression_request (string equation, int steps, string variable); protected static void set_evaluate_expression_result (double[] result) { _evaluate_expression_result = result; } public static double[] evaluate_expression (string equation, int steps, string variable = "x") throws MathError { if (!instance.evaluate_expression_request.emit (equation, steps, variable)) throw new MathError.SYNTAX ("invalid equation"); return (owned) _evaluate_expression_result; } protected signal void export_items_request (Window window, string mode, File file, Item[] items); public static void export_items (Window window, string mode, File file, Item[] items) { instance.export_items_request.emit (window, mode, file, items); window.add_toast_string_with_file ( _("Exported Data"), file ); } public signal void export_figure_request (File file, GLib.Settings settings, Data data); public static void export_figure (File file, GLib.Settings settings, Data data) { instance.export_figure_request.emit (file, settings, data); } protected signal void perform_operation_request (Window window, string name); public static void perform_operation (Window window, string name) { instance.perform_operation_request.emit (window, name); } protected signal void python_method_request (Object object, string method); public static void run_method (Object object, string method) { instance.python_method_request.emit (object, method); } protected signal string simplify_equation_request (string input); public static string simplify_equation (string input) { return instance.simplify_equation_request.emit (input); } protected signal bool validate_equation_request (string input); public static bool validate_equation (string input) { try { return instance.validate_equation_request.emit (preprocess_equation (input)); } catch (MathError e) { return false; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/scales.py000066400000000000000000000203201520337127000240450ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Scales Module.""" from matplotlib import scale, ticker, transforms import numpy class Log2Scale(scale.LogScale): """ Logarithmic Base 2 Scale. Small utility for implementing logarithmic base 2 scaling easily using the scale name system. """ name = "log2" def __init__(self, axis, *args, **kwargs): kwargs["base"] = 2 super().__init__(axis, *args, **kwargs) class RadiansScale(scale.LinearScale): """Radians Scale.""" name = "radians" def set_default_locators_and_formatters(self, axis): """Handle locators and formatters.""" super().set_default_locators_and_formatters(axis) axis.set_major_formatter( ticker.FuncFormatter(lambda x, _pos=None: f"{x / numpy.pi:.3g}Ï€"), ) axis.set_major_locator(RadianLocator()) class SquareRootScale(scale.ScaleBase): """Class for generating custom square root scale.""" name = "squareroot" def set_default_locators_and_formatters(self, axis): """Handle locators and formatters.""" axis.set_major_locator(CustomScaleLocator()) axis.set_minor_locator(CustomScaleLocator(is_minor=True)) axis.set_major_formatter(ticker.ScalarFormatter()) axis.set_minor_formatter(ticker.NullFormatter()) def limit_range_for_scale(self, vmin, vmax, _minpos): """Limit scale range.""" return max(0, vmin), vmax class SquareRootTransform(transforms.Transform): """The transform to convert from linear to square root scale.""" input_dims = 1 # Amount of input params in transform output_dims = 1 # Amount of output params in transform is_separable = True # Seperable in X and Y dimension def transform_non_affine(self, a): """Transform data.""" # Don't spam about invalid divide by zero errors with numpy.errstate(divide="ignore", invalid="ignore"): return numpy.array(a)**0.5 def inverted(self): """Get the inverse transform.""" return SquareRootScale.InvertedSquareRootTransform() class InvertedSquareRootTransform(transforms.Transform): """Inverse transform to convert from square root to linear scale.""" input_dims = 1 # Amount of input params in transform output_dims = 1 # Amount of output params in transform is_separable = True # Seperable in X and Y dimension def transform_non_affine(self, a): """Transform data.""" # Don't spam about invalid divide by zero errors with numpy.errstate(divide="ignore", invalid="ignore"): return numpy.array(a)**2 def inverted(self): """Get the inverse transform.""" return SquareRootScale.SquareRootTransform() def get_transform(self): """Get the transform.""" return self.SquareRootTransform() class InverseScale(scale.ScaleBase): """Inverse scale.""" name = "inverse" def set_default_locators_and_formatters(self, axis): """Handle locators and formatters.""" axis.set_major_locator(CustomScaleLocator()) axis.set_minor_locator(CustomScaleLocator(is_minor=True)) axis.set_major_formatter(ticker.ScalarFormatter()) axis.set_minor_formatter(ticker.NullFormatter()) def limit_range_for_scale(self, vmin, vmax, minpos): """Limit scale range.""" if not numpy.isfinite(minpos): minpos = 1e-300 return ( minpos if vmin <= 0 else vmin, minpos if vmax <= 0 else vmax, ) def get_transform(self): """Get the transform.""" return InverseScale.InverseTransform() class InverseTransform(transforms.Transform): """The transform to invert the scaling on the axis.""" input_dims = 1 output_dims = 1 is_separable = True has_inverse = True def inverted(self): """Get the inverse transform.""" return InverseScale.InverseTransform() def transform_non_affine(self, a): """Transform data.""" # Don't spam about invalid divide by zero errors with numpy.errstate(divide="ignore", invalid="ignore"): return 1 / numpy.array(a) class CustomScaleLocator(ticker.MaxNLocator): """Dynamically find tick positions on custom scales.""" def __init__(self, is_minor=False): self.is_minor = is_minor @property def numticks(self): """Get number of ticks.""" if self.axis is not None: numticks = max(1, self.axis.get_tick_space() - 4) # Amount of ticks is set between 3 and 9 self._numticks = numpy.clip(numticks, 3, 9) else: self._numticks = 9 if self.is_minor: # Amount of minor ticks is equal to amount of major ticks # times (N+1) minus N. Where N is the amount of minor ticks # in between the major ticks. self._numticks = len(self.axis.get_majorticklocs()) * 4 - 3 return self._numticks @numticks.setter def numticks(self, numticks): """Set number of ticks.""" self._numticks = numticks def tick_values(self, vmin, vmax): """Get tick values.""" vmin, vmax = transforms.nonsingular(vmin, vmax, expander=0.05) vmin, vmax = min(vmin, vmax), max(vmin, vmax) # Swap values if needed lin_tick_pos = numpy.linspace(vmin, vmax, self.numticks) lin_tick_pos = lin_tick_pos[lin_tick_pos != 0] # Remove zeroes if self.axis.get_scale() == "squareroot": tick_pos = lin_tick_pos**2 elif self.axis.get_scale() == "inverse": tick_pos = 1 / lin_tick_pos else: raise ValueError("Wrong locator for the axis type") tick_pos = tick_pos * ((vmax - vmin) / (max(tick_pos) - min(tick_pos))) tick_pos *= 2 if self.axis.get_scale() == "squareroot" else 1 return tick_pos class RadianLocator(ticker.MultipleLocator): """ Dynamically place tick positions on radian scale. Places ticks at a distance of pi if there's between 4 and 8 ticks Otherwise it places ticks at a distance of 2pi if reasonable, or with a multiple of 5 pi such that a number between 3 and 8 ticks are placed At smaller values, the distances between the ticks are a power of 2, multiplied by pi. e.g. (1/2)pi, (1/4)pi, (1/8)pi etc.. """ def __init__(self): super().__init__(base=self.base) def tick_values(self, vmin, vmax): """Get tick values.""" if vmax < vmin: vmin, vmax = vmax, vmin self._edge = ticker._Edge_integer(self.base, 0) step = self._edge.step vmin -= self._offset vmax -= self._offset vmin = self._edge.ge(vmin) * step n = (vmax - vmin + 0.001 * step) // step locs = vmin - step + numpy.arange(n + 3) * step + self._offset return self.raise_if_exceeds(locs) @property def base(self): """Get base.""" if self.axis is None: return numpy.pi vmin, vmax = self.axis.get_view_interval() distance = numpy.pi # Amount of ticks if we use a multiple of pi num_ticks = (vmax - vmin) / distance # Desired amount of ticks, should be between 3 and 8 numticks_goal = max(1, self.axis.get_tick_space() - 4) numticks_goal = numpy.clip(numticks_goal, 3, 7) ratio = num_ticks / numticks_goal if num_ticks > 8: if ratio < 2: # Use a distance of 2pi if reasonable return distance * 2 # Make sure ratio is never rounded to 0: ratio = 5 if round(ratio / 5) == 0 else ratio return distance * round(ratio / 5) * 5 if num_ticks < 4: ratio = num_ticks / numticks_goal exponent = int(numpy.log2(abs(ratio))) result = 2**exponent # Return distance as a power of 2 return distance * result return distance def register_scales(): """Register custom scales.""" scale.register_scale(Log2Scale) scale.register_scale(RadiansScale) scale.register_scale(SquareRootScale) scale.register_scale(InverseScale) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/sidebar/000077500000000000000000000000001520337127000236355ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/sidebar/edit_item.vala000066400000000000000000000245661520337127000264620ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/edit-item/page.ui")] public class EditItemPage : Adw.NavigationPage { [GtkChild] private unowned Box edit_item_box { get; } public void load_item (Item item) { Widget widget; while ((widget = edit_item_box.get_last_child ()) != null) { edit_item_box.remove (widget); } edit_item_box.append (new EditItemBaseBox (item)); if (item is GeneratedDataItem) { edit_item_box.append (new EditItemGeneratedDataItemBox ((GeneratedDataItem) item)); } if (item is DataItem) { DataItem data_item = (DataItem) item; edit_item_box.append (new EditItemDataItemBox (data_item)); if (data_item.has_xerr () || data_item.has_yerr ()) { edit_item_box.append (new EditItemErrorBarGroup (data_item)); } } else if (item is EquationItem) { edit_item_box.append (new EditItemEquationItemBox ((EquationItem) item)); } } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/edit-item/base.ui")] public class EditItemBaseBox : Box { [GtkChild] private unowned Adw.EntryRow name_entry { get; } [GtkChild] private unowned Adw.ComboRow xposition { get; } [GtkChild] private unowned Adw.ComboRow yposition { get; } public EditItemBaseBox (Item item) { item.bind_property ( "name", name_entry, "text", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "xposition", xposition, "selected", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "yposition", yposition, "selected", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/edit-item/data.ui")] public class EditItemDataItemBox : Box { [GtkChild] private unowned Adw.ComboRow linestyle { get; } [GtkChild] private unowned Gtk.Scale linewidth { get; } [GtkChild] private unowned Adw.ComboRow markerstyle { get; } [GtkChild] private unowned Gtk.Scale markersize { get; } public EditItemDataItemBox (DataItem item) { item.bind_property ( "linestyle", linestyle, "selected", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "linewidth", linewidth.adjustment, "value", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "markerstyle", markerstyle, "selected", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "markersize", markersize.adjustment, "value", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); } [GtkCallback] private void on_linestyle () { linewidth.set_sensitive (linestyle.get_selected () != 0); } [GtkCallback] private void on_markers () { markersize.set_sensitive (markerstyle.get_selected () != 0); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/edit-item/errorbar-group.ui")] public class EditItemErrorBarGroup : Box { [GtkChild] private unowned Adw.SwitchRow use_xerr { get; } [GtkChild] private unowned Adw.SwitchRow use_yerr { get; } [GtkChild] private unowned Adw.SwitchRow errbarsabove { get; } [GtkChild] private unowned StyleColorRow errcolor_row { get; } [GtkChild] private unowned Gtk.Scale errcapsize { get; } [GtkChild] private unowned Gtk.Scale errcapthick { get; } [GtkChild] private unowned Gtk.Scale errlinewidth { get; } public EditItemErrorBarGroup (DataItem item) { if (item.has_xerr ()) { use_xerr.set_visible (true); item.bind_property ( "showxerr", use_xerr, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); } if (item.has_yerr ()) { use_yerr.set_visible (true); item.bind_property ( "showyerr", use_yerr, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); } item.bind_property ( "errbarsabove", errbarsabove, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "errcapsize", errcapsize.adjustment, "value", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "errcapthick", errcapthick.adjustment, "value", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "errlinewidth", errlinewidth.adjustment, "value", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); errcolor_row.color = Tools.hex_to_rgba (item.errcolor); errcolor_row.notify["color"].connect ((obj, pspec) => { item.errcolor = Tools.rgba_to_hex (errcolor_row.color); }); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/edit-item/equation-group.ui")] public class EditItemEquationGroup : Adw.PreferencesGroup { [GtkChild] private unowned Adw.EntryRow equation { get; } [GtkChild] private unowned Adw.ButtonRow simplify { get; } private EquationBasedItem item; public void setup (EquationBasedItem item) { this.item = item; equation.set_text (item.equation); } [GtkCallback] private void on_equation_change () { if (PythonHelper.validate_equation (equation.get_text ())) { equation.remove_css_class ("error"); equation.set_show_apply_button (true); } else { equation.add_css_class ("error"); equation.set_show_apply_button (false); } } [GtkCallback] private void on_equation_apply () { item.equation = equation.get_text (); } [GtkCallback] private void on_simplify () { try { string equation_str = equation.get_text (); equation_str = preprocess_equation (equation_str); equation_str = PythonHelper.simplify_equation (equation_str); equation_str = prettify_equation (equation_str); equation.set_text (equation_str); item.equation = equation_str; } catch (MathError e) {} } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/edit-item/equation.ui")] public class EditItemEquationItemBox : Box { [GtkChild] private unowned EditItemEquationGroup equation_group { get; } [GtkChild] private unowned Adw.ComboRow linestyle { get; } [GtkChild] private unowned Gtk.Scale linewidth { get; } public EditItemEquationItemBox (EquationItem item) { equation_group.setup (item); item.bind_property ( "linestyle", linestyle, "selected", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "linewidth", linewidth.adjustment, "value", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/edit-item/generated-data.ui")] public class EditItemGeneratedDataItemBox : Box { [GtkChild] private unowned EditItemEquationGroup equation_group { get; } [GtkChild] private unowned Adw.EntryRow xstart { get; } [GtkChild] private unowned Adw.EntryRow xstop { get; } [GtkChild] private unowned Adw.SpinRow steps { get; } [GtkChild] private unowned Adw.ComboRow scale { get; } private GeneratedDataItem item; public EditItemGeneratedDataItemBox (GeneratedDataItem item) { this.item = item; equation_group.setup (item); xstart.set_text (item.xstart); xstop.set_text (item.xstop); item.bind_property ( "steps", steps, "value", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); item.bind_property ( "scale", scale, "selected", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL ); } [GtkCallback] private void on_entry_change (Object object, ParamSpec spec) { var entry = (Adw.EntryRow) object; if (try_evaluate_string (entry.get_text ())) { entry.remove_css_class ("error"); entry.set_show_apply_button (true); } else { entry.add_css_class ("error"); entry.set_show_apply_button (false); } } [GtkCallback] private void on_entry_apply (Editable editable) { item.set (editable.get_buildable_id (), editable.get_text ()); } [GtkCallback] private int on_steps_input (out double val) { if (try_evaluate_string (steps.get_text (), out val)) { return 1; } else { return Gtk.INPUT_ERROR; } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/sidebar/figure_settings.vala000066400000000000000000000234221520337127000277060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { private const BindingFlags SYNC = BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE; [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/figure-settings/settings-page.ui")] public class FigureSettingsPage : Adw.NavigationPage { [GtkChild] private unowned Adw.EntryRow title_entry { get; } [GtkChild] public unowned Adw.EntryRow bottom_label { get; } [GtkChild] public unowned Adw.EntryRow top_label { get; } [GtkChild] public unowned Adw.EntryRow left_label { get; } [GtkChild] public unowned Adw.EntryRow right_label { get; } [GtkChild] public unowned Box bottom_limits { get; } [GtkChild] public unowned Adw.EntryRow min_bottom { get; } [GtkChild] public unowned Adw.EntryRow max_bottom { get; } [GtkChild] public unowned Box top_limits { get; } [GtkChild] public unowned Adw.EntryRow min_top { get; } [GtkChild] public unowned Adw.EntryRow max_top { get; } [GtkChild] public unowned Box left_limits { get; } [GtkChild] public unowned Adw.EntryRow min_left { get; } [GtkChild] public unowned Adw.EntryRow max_left { get; } [GtkChild] public unowned Box right_limits { get; } [GtkChild] public unowned Adw.EntryRow min_right { get; } [GtkChild] public unowned Adw.EntryRow max_right { get; } [GtkChild] public unowned Adw.ComboRow bottom_scale { get; } [GtkChild] public unowned Adw.ComboRow top_scale { get; } [GtkChild] public unowned Adw.ComboRow left_scale { get; } [GtkChild] public unowned Adw.ComboRow right_scale { get; } [GtkChild] private unowned Adw.SwitchRow legend { get; } [GtkChild] private unowned Adw.ComboRow legend_position { get; } [GtkChild] private unowned Adw.SwitchRow hide_unselected { get; } [GtkChild] private unowned Label style_name { get; } private Window window; public FigureSettingsPage (Window window) { this.window = window; FigureSettings figure_settings = window.data.figure_settings; figure_settings.bind_property ("title", title_entry, "text", SYNC); figure_settings.bind_property ("bottom_label", bottom_label, "text", SYNC); figure_settings.bind_property ("top_label", top_label, "text", SYNC); figure_settings.bind_property ("left_label", left_label, "text", SYNC); figure_settings.bind_property ("right_label", right_label, "text", SYNC); figure_settings.bind_property ("legend", legend, "active", SYNC); figure_settings.bind_property ("legend_position", legend_position, "selected", SYNC); figure_settings.bind_property ("hide_unselected", hide_unselected, "active", SYNC); window.data.bind_property ("selected_stylename", style_name, "label", BindingFlags.SYNC_CREATE); bool[] visible_axes = window.data.get_used_positions (); bool both_x = visible_axes[0] && visible_axes[1]; bool both_y = visible_axes[2] && visible_axes[3]; string direction; if (visible_axes[0]) { direction = XPosition.BOTTOM.friendly_string (); handle_widgets (figure_settings, direction, true, both_x, both_y); } if (visible_axes[1]) { direction = XPosition.TOP.friendly_string (); handle_widgets (figure_settings, direction, true, both_x, both_y); } if (visible_axes[2]) { direction = YPosition.LEFT.friendly_string (); handle_widgets (figure_settings, direction, false, both_x, both_y); } if (visible_axes[3]) { direction = YPosition.RIGHT.friendly_string (); handle_widgets (figure_settings, direction, false, both_x, both_y); } } private void handle_widgets (FigureSettings figure_settings, string direction, bool x, bool both_x, bool both_y) { Adw.EntryRow entry; string prop; prop = "min-" + direction; this.get (prop, out entry); bind_entry (entry, figure_settings, prop); // Remove direction prefix if only one is present if (x && !both_x) entry.set_title (_("X Axis Minimum")); else if (!x && !both_y) entry.set_title (_("Y Axis Minimum")); prop = "max-" + direction; this.get (prop, out entry); bind_entry (entry, figure_settings, prop); // Remove direction prefix if only one is present if (x && !both_x) entry.set_title (_("X Axis Maximum")); else if (!x && !both_y) entry.set_title (_("Y Axis Maximum")); Adw.ComboRow scale; prop = direction + "-scale"; this.get (prop, out scale); Adw.EntryRow label; this.get (direction + "-label", out label); Box limits; this.get (direction + "-limits", out limits); figure_settings.bind_property (prop, scale, "selected", SYNC); scale.set_visible (true); label.set_visible (true); limits.set_visible (true); // Remove direction prefix if only one is present if (x && !both_x) { scale.set_title (_("X Axis Scale")); label.set_title (_("X Axis Label")); } else if (!x && !both_y) { scale.set_title (_("Y Axis Scale")); label.set_title (_("Y Axis Label")); } } private void bind_entry (Adw.EntryRow entry, FigureSettings figure_settings, string prop) { figure_settings.bind_property ( prop, entry, "text", BindingFlags.SYNC_CREATE, prettyprint_transform ); entry.apply.connect (() => { double new_val; try_evaluate_string (entry.get_text (), out new_val); figure_settings.set (prop, new_val); window.data.add_view_history_state (); window.canvas.view_changed (); // workaround button not disappearing when pressed entry.set_show_apply_button (false); entry.set_show_apply_button (true); }); } public void focus_widget (string name) { Widget widget; this.get (name, out widget); widget.grab_focus (); } private static bool prettyprint_transform (Binding binding, Value source, ref Value target) { target.set_string (MathTools.prettyprint_double (source.get_double ())); return true; } [GtkCallback] private void on_limit_entry_change (Object object, ParamSpec spec) { var entry = (Adw.EntryRow) object; if (try_evaluate_string (entry.get_text ())) { entry.remove_css_class ("error"); entry.set_show_apply_button (true); } else { entry.add_css_class ("error"); entry.set_show_apply_button (false); } } [GtkCallback] private void open_style_page () { var style_page = new StylePage (window); window.push_sidebar_page (style_page); } [GtkCallback] private void set_as_default () { GLib.Settings settings = Application.get_settings_child ("figure"); string[] strings = { "custom-style", "title", "bottom-label", "left-label", "top-label", "right-label" }; string[] bools = {"hide-unselected", "legend", "use-custom-style"}; string[] enums = { "legend-position", "top-scale", "bottom-scale", "left-scale", "right-scale" }; FigureSettings figure_settings = window.data.figure_settings; foreach (string key in strings) { string val; figure_settings.get (key.replace ("-", "_"), out val); settings.set_string (key, val); } foreach (string key in bools) { bool val; figure_settings.get (key.replace ("-", "_"), out val); settings.set_boolean (key, val); } foreach (string key in enums) { int val; figure_settings.get (key.replace ("-", "_"), out val); settings.set_enum (key, val); } window.add_toast_string (_("Defaults Updated")); } } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/figure-settings/style-page.ui")] public class StylePage : Adw.NavigationPage { [GtkChild] private unowned GridView style_grid { get; } private Window window; public StylePage (Window window) { this.window = window; var factory = new SignalListItemFactory (); factory.setup.connect (on_factory_setup); factory.bind.connect (on_factory_bind); style_grid.set_factory (factory); style_grid.set_model (window.data.style_selection_model); } private void on_factory_setup (Object object) { ListItem item = (ListItem) object; item.set_child (new StylePreview ()); } private void on_factory_bind (Object object) { ListItem item = (ListItem) object; StylePreview preview = (StylePreview) item.get_child (); preview.style = (Style) item.get_item (); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/sidebar/main.vala000066400000000000000000000036261520337127000254350ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/main.ui")] public class MainSidebarPage : Adw.NavigationPage { [GtkChild] private unowned ScrolledWindow scrollwindow_itemlist { get; } [GtkChild] private unowned ToggleButton pan_button { get; } [GtkChild] private unowned ToggleButton zoom_button { get; } [GtkChild] private unowned ToggleButton select_button { get; } [GtkChild] private unowned Adw.Bin operations_bin { get; } [GtkChild] private unowned Stack itemlist_stack { get; } [GtkChild] public unowned ListBox item_list { get; } public bool height_limited { set { scrollwindow_itemlist.set_policy ( PolicyType.AUTOMATIC, value ? PolicyType.NEVER : PolicyType.AUTOMATIC ); } get { return false; } // needed to be registered as valid property } public Mode mode { set { pan_button.set_active (value == Mode.PAN); zoom_button.set_active (value == Mode.ZOOM); select_button.set_active (value == Mode.SELECT); } get { if (pan_button.get_active ()) return Mode.PAN; if (zoom_button.get_active ()) return Mode.ZOOM; if (select_button.get_active ()) return Mode.SELECT; return -1; } } public Operations operations { get { return (Operations) operations_bin.get_child (); } set { operations_bin.set_child (value); } } public MainSidebarPage () {} public void set_show_empty_data_page (bool val) { itemlist_stack.get_pages ().select_item (val ? 0 : 1, true); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/sidebar/operations.vala000066400000000000000000000065261520337127000266760ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/sidebar/operations.ui")] public class Operations : Box { [GtkChild] public unowned Button shift_button { get; } [GtkChild] public unowned Adw.SplitButton smoothen_button { get; } [GtkChild] private unowned Button cut_button { get; } [GtkChild] public unowned Entry translate_x_entry { get; } [GtkChild] public unowned Entry translate_y_entry { get; } [GtkChild] public unowned Entry multiply_x_entry { get; } [GtkChild] public unowned Entry multiply_y_entry { get; } [GtkChild] public unowned Button translate_x_button { get; } [GtkChild] public unowned Button translate_y_button { get; } [GtkChild] public unowned Button multiply_x_button { get; } [GtkChild] public unowned Button multiply_y_button { get; } private Window _window; private bool entries_sensitive = false; private bool cut_sensitive = false; public Operations (Window window) { this._window = window; window.notify["mode"].connect (on_mode_change); string[] action_names = { "multiply_x", "multiply_y", "translate_x", "translate_y" }; foreach (string action_name in action_names) { Entry entry; Button button; get (action_name + "_entry", out entry); get (action_name + "_button", out button); entry.notify["text"].connect (() => { validate_entry (entry, button); }); _window.data.notify["items-selected"].connect (() => { validate_entry (entry, button); }); validate_entry (entry, button); } } [GtkCallback] private void perform_operation (Button button) { var action = _window.lookup_action ( "perform_operation" ); string name = button.get_buildable_id ()[0:-7]; action.activate (new Variant.string (name)); } public void set_entry_sensitivity (bool entries_sensitive) { this.entries_sensitive = entries_sensitive; validate_entry (translate_x_entry, translate_x_button); validate_entry (translate_y_entry, translate_y_button); validate_entry (multiply_x_entry, multiply_x_button); validate_entry (multiply_y_entry, multiply_y_button); } public void set_cut_sensitivity (bool sensitive) { this.cut_sensitive = sensitive; on_mode_change (); } private void on_mode_change () { cut_button.set_sensitive (cut_sensitive && _window.mode == 2); } private void validate_entry (Entry entry, Button button) { if (try_evaluate_string (entry.get_text ())) { entry.remove_css_class ("error"); button.set_sensitive (entries_sensitive); } else { entry.add_css_class ("error"); button.set_sensitive (false); } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/smoothen_settings.vala000066400000000000000000000021141520337127000266430ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { /** * Smoothen settings dialog */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/smoothen-settings.ui")] public class SmoothenDialog : Adw.Dialog { [GtkChild] private unowned Adw.SpinRow savgol_window { get; } [GtkChild] private unowned Adw.SpinRow savgol_polynomial { get; } [GtkChild] private unowned Adw.SpinRow moving_average_box { get; } private GLib.Settings settings { get; set; } public SmoothenDialog (Window window) { Object (); this.settings = Application.get_settings_child ("actions/smoothen"); settings.bind ("savgol-window", savgol_window, "value", 0); settings.bind ("savgol-polynomial", savgol_polynomial, "value", 0); settings.bind ("moving-average-box", moving_average_box, "value", 0); present (window); } [GtkCallback] private void on_reset () { Tools.reset_settings (settings); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/000077500000000000000000000000001520337127000247325ustar00rootroot00000000000000Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/__init__.py000066400000000000000000000106601520337127000270460ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Style editor.""" import asyncio from gettext import gettext as _ from gi.repository import Gio, Graphs from graphs.canvas import Canvas from graphs.item import DataItem from graphs.style_editor.editor_box import StyleEditorBox import numpy _PREVIEW_XDATA1 = numpy.linspace(0, 10, 10) _PREVIEW_YDATA1 = numpy.linspace(0, numpy.power(numpy.e, 10), 10) _PREVIEW_XERR1 = numpy.linspace(0.1, 0.5, 10) _PREVIEW_YERR1 = numpy.linspace(500, 2500, 10) _PREVIEW_XDATA2 = numpy.linspace(0, 10, 60) _PREVIEW_YDATA2 = numpy.power(numpy.e, _PREVIEW_XDATA2) CSS_TEMPLATE = """ .canvas-view#{name} {{ background-color: {background_color}; color: {color}; }} """ class PythonStyleEditor(Graphs.StyleEditor): """Graphs Style Editor Window.""" __gtype_name__ = "GraphsPythonStyleEditor" def __init__(self): super().__init__() style_editor = StyleEditorBox(self) style_editor.connect("params-changed", self._on_params_changed) self.set_editor_box(style_editor) self._test_items = Gio.ListStore() self._initialize_test_items() self.connect("load_request", self._on_load_request) self.connect("save_request", self._on_save_request) self._background_task = asyncio.create_task( self._reload_canvas(style_editor), ) def _initialize_test_items(self): """Initialize example test items with predefined preview data.""" preview_data = [ (_PREVIEW_XDATA1, _PREVIEW_YDATA1, _PREVIEW_XERR1, _PREVIEW_YERR1), (_PREVIEW_XDATA2, _PREVIEW_YDATA2, None, None), ] style_manager = Graphs.StyleManager.get_instance() test_style = style_manager.get_system_style_params() for xdata, ydata, xerr, yerr in preview_data: self._test_items.append( DataItem.new( test_style, xdata=xdata, ydata=ydata, xerr=xerr, yerr=yerr, name=_("Example Item"), color="#000000", errcolor="#000000", ), ) def _on_params_changed(self, style_editor, changes_unsaved=True): self._background_task.cancel() self._background_task = asyncio.create_task( self._reload_canvas(style_editor, changes_unsaved, 0.5), ) async def _reload_canvas( self, style_editor: StyleEditorBox, changes_unsaved: bool = False, timeout: int = 0, ) -> None: await asyncio.sleep(timeout) if style_editor.params is None: style_manager = Graphs.StyleManager.get_instance() params, graphs_params = style_manager.get_system_style_params() else: params = style_editor.params graphs_params = style_editor.graphs_params self.set_stylename(style_editor.graphs_params["name"]) color_cycle = params["axes.prop_cycle"].by_key()["color"] errbar_cycle = graphs_params["errorbar.color_cycle"].by_key()["color"] for index, item in enumerate(self._test_items): item.set_color(color_cycle[index % len(color_cycle)]) item.set_errcolor(errbar_cycle[index % len(errbar_cycle)]) item.override((params, graphs_params)) all_params = params, graphs_params canvas = Canvas(all_params, self._test_items, False) canvas.figure.props.title = _("Title") canvas.figure.props.bottom_label = _("X Label") canvas.figure.props.left_label = _("Y Label") self.set_canvas(canvas) # Set headerbar color css = CSS_TEMPLATE.format( name=self.props.content_view.get_name(), background_color=params["figure.facecolor"], color=params["text.color"], ) self.props.css_provider.load_from_string(css) if changes_unsaved: self.set_unsaved(True) @staticmethod def _on_load_request(self, file: Gio.File) -> None: """Load a style.""" style_editor = self.get_editor_box() name = style_editor.load_style(file) self.set_title(name) self._background_task = asyncio.create_task( self._reload_canvas(style_editor, False, 0), ) @staticmethod def _on_save_request(self, file: Gio.File) -> None: """Save current style.""" self.get_editor_box().save_style(file) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/add_style.vala000066400000000000000000000024461520337127000275550ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gtk; namespace Graphs { /** * Add style dialog */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/style-editor/add-style.ui")] public class AddStyleDialog : Adw.Dialog { [GtkChild] private unowned Adw.EntryRow new_style_name { get; } [GtkChild] private unowned Adw.ComboRow style_templates { get; } public signal void accept (File file); public AddStyleDialog (Widget parent) { style_templates.set_expression (new PropertyExpression (typeof (Style), null, "name")); style_templates.set_model (StyleManager.filtered_style_model); present (parent); } [GtkCallback] private void on_template_changed () { string[] stylenames = StyleManager.list_stylenames (); string template = stylenames[style_templates.get_selected ()]; new_style_name.set_text (Tools.get_duplicate_string (template, stylenames)); } [GtkCallback] private void on_accept () { uint template = style_templates.get_selected () + 1; var file = StyleManager.create_style (template, new_style_name.get_text ()); close (); accept.emit (file); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/color_manager.vala000066400000000000000000000104041520337127000304060ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gee; using Gtk; namespace Graphs { public class StyleColorManager : Object { private ListBox box; private ArrayList colors = new ArrayList (); public signal void colors_changed (); public StyleColorManager (ListBox box) { this.box = box; var drop_target = new Gtk.DropTarget (typeof (StyleItemColorRow), Gdk.DragAction.MOVE); drop_target.drop.connect ((drop, val, x, y) => { var value_row = (StyleItemColorRow?) val.get_object (); var target_row = (StyleItemColorRow?) box.get_row_at_y ((int) y); // If value or the target row is null, do not accept the drop if (value_row == null || target_row == null) return false; // Reject if the value row is not from this instance if (value_row.color_manager != this) return false; change_position (target_row.index, value_row.index); target_row.set_state_flags (Gtk.StateFlags.NORMAL, true); return true; }); box.add_controller (drop_target); } public void set_colors (string[] colors) { this.colors.clear (); this.colors.add_all_array (colors); reload_color_boxes (); } public void add_color (string color) { this.colors.add (color); append_style_color_box (this.colors.size - 1); colors_changed.emit (); } public string[] get_colors () { return this.colors.to_array (); } public void change_position (int index1, int index2) { if (index1 == index2) return; string color = this.colors[index2]; this.colors.remove_at (index2); this.colors.insert (index1, color); reload_color_boxes (); colors_changed.emit (); } private void append_style_color_box (int index) { var row = new StyleItemColorRow (this, index, this.colors[index]); row.color_removed.connect (() => { this.colors.remove_at (index); reload_color_boxes (); colors_changed.emit (); }); row.color_changed.connect ((b, color) => { this.colors[index] = color; colors_changed.emit (); }); double drag_x = 0.0; double drag_y = 0.0; var drop_controller = new Gtk.DropControllerMotion (); var drag_source = new Gtk.DragSource () { actions = Gdk.DragAction.MOVE }; row.add_controller (drag_source); row.add_controller (drop_controller); // Drag handling drag_source.prepare.connect ((x, y) => { drag_x = x; drag_y = y; Value val = Value (typeof (StyleItemColorRow)); val.set_object (row); return new Gdk.ContentProvider.for_value (val); }); drag_source.drag_begin.connect ((drag) => { var drag_widget = new Gtk.ListBox (); drag_widget.set_size_request (row.get_width (), row.get_height ()); drag_widget.add_css_class ("boxed-list"); var drag_row = new StyleItemColorRow (this, index, this.colors[index]); drag_widget.append (drag_row); drag_widget.drag_highlight_row (drag_row); var icon = (Gtk.DragIcon) new Gtk.DragIcon.get_for_drag (drag); icon.child = drag_widget; drag.set_hotspot ((int) drag_x, (int) drag_y); }); // Update row visuals during DnD operation drop_controller.enter.connect (() => this.box.drag_highlight_row (row)); drop_controller.leave.connect (() => this.box.drag_unhighlight_row ()); this.box.append (row); } private void reload_color_boxes () { if (this.colors.is_empty) this.colors.add ("#000000"); this.box.remove_all (); for (int i = 0; i < this.colors.size; i++) { append_style_color_box (i); } } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/color_row.vala000066400000000000000000000021711520337127000276050ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gdk; using Gtk; namespace Graphs { /** * Style Color Box */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/style-editor/color-row.ui")] public class StyleColorRow : Adw.ActionRow { [GtkChild] private unowned Image image { get; } public RGBA color { get; set; } private CssProvider provider = new CssProvider (); construct { this.image.get_style_context ().add_provider ( this.provider, STYLE_PROVIDER_PRIORITY_APPLICATION ); this.notify["color"].connect (on_color); } private void on_color () { string hex = Tools.rgba_to_hex (color); this.provider.load_from_string (@"image { color: $hex; }"); } [GtkCallback] private async void on_color_choose () { var dialog = new ColorDialog () { with_alpha = false }; try { this.color = yield dialog.choose_rgba ( (Gtk.Window) this.get_root (), color, null ); } catch {} } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/editor_box.py000066400000000000000000000250611520337127000274460ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Style editor Box.""" import contextlib from cycler import cycler from gi.repository import Adw, Gio, Graphs, Gtk, Pango from graphs import misc, style_io STYLE_DICT = { "linestyle": ["lines.linestyle"], "linewidth": ["lines.linewidth"], "markers": ["lines.marker"], "markersize": ["lines.markersize"], "draw_frame": [ "axes.spines.bottom", "axes.spines.left", "axes.spines.top", "axes.spines.right", ], "tick_direction": ["xtick.direction", "ytick.direction"], "minor_ticks": ["xtick.minor.visible", "ytick.minor.visible"], "major_tick_width": ["xtick.major.width", "ytick.major.width"], "minor_tick_width": ["xtick.minor.width", "ytick.minor.width"], "major_tick_length": ["xtick.major.size", "ytick.major.size"], "minor_tick_length": ["xtick.minor.size", "ytick.minor.size"], "tick_bottom": ["xtick.bottom"], "tick_left": ["ytick.left"], "tick_top": ["xtick.top"], "tick_right": ["ytick.right"], "tick_labels": ["ticklabels"], "show_grid": ["axes.grid"], "grid_linewidth": ["grid.linewidth"], "value_padding": [ "xtick.major.pad", "xtick.minor.pad", "ytick.major.pad", "ytick.minor.pad", ], "label_padding": ["axes.labelpad"], "title_padding": ["axes.titlepad"], "axis_width": ["axes.linewidth"], "text_color": [ "text.color", "axes.labelcolor", "xtick.labelcolor", "ytick.labelcolor", ], "tick_color": ["xtick.color", "ytick.color"], "axis_color": ["axes.edgecolor"], "grid_color": ["grid.color"], "grid_opacity": ["grid.alpha"], "background_color": ["axes.facecolor"], "outline_color": ["figure.facecolor", "figure.edgecolor"], "errorbar_capsize": ["errorbar.capsize"], "errorbar_capthick": ["errorbar.capthick"], "errorbar_linewidth": ["errorbar.linewidth"], "errorbar_barsabove": ["errorbar.barsabove"], } VALUE_DICT = { "linestyle": misc.LINESTYLES, "markers": misc.MARKERSTYLES, "tick_direction": ["in", "out"], } FONT_STYLE_DICT = { 0: "normal", 1: "oblique", 2: "italic", } FONT_VARIANT_DICT = { 0: "normal", 1: "small-caps", } class StyleEditorBox(Graphs.StyleEditorBox): """Style editor widget.""" __gtype_name__ = "GraphsPythonStyleEditorBox" def __init__(self, window): super().__init__(window=window) self.params = None # Setup Widgets for key, _value in STYLE_DICT.items(): widget = self.get_property(key.replace("-", "_")) if isinstance(widget, Adw.EntryRow): widget.connect("changed", self._on_entry_change, key) elif isinstance(widget, Adw.ComboRow): widget.connect("notify::selected", self._on_combo_change, key) elif isinstance(widget, Gtk.Scale): widget.connect("value-changed", self._on_scale_change, key) elif isinstance(widget, Graphs.StyleColorRow): widget.connect("notify::color", self._on_color_change, key) elif isinstance(widget, Adw.SwitchRow): widget.connect("notify::active", self._on_switch_change, key) else: raise ValueError self.props.style_name.connect("changed", self._on_name_change) self.props.font_chooser.connect( "notify::font-desc", self._on_font_change, ) self.props.titlesize.connect( "value-changed", self._on_titlesize_change, ) self.props.labelsize.connect( "value-changed", self._on_labelsize_change, ) self.props.color_manager.connect( "colors-changed", self._on_line_colors_changed, ) self.props.errbar_color_manager.connect( "colors-changed", self._on_errbar_colors_changed, ) def load_style(self, file: Gio.File) -> None: """Load style params from file.""" self.params = None style_params, graphs_params = style_io.parse( file, Graphs.StyleManager.get_instance().get_system_style_params(), ) stylename = graphs_params["name"] self.props.style_name.set_text(stylename) for key, value in STYLE_DICT.items(): value = value[0] value = graphs_params[ value ] if value in style_io.STYLE_CUSTOM_PARAMS else style_params[value] with contextlib.suppress(KeyError): value = VALUE_DICT[key].index(value) widget = self.get_property(key.replace("-", "_")) if isinstance(widget, Adw.EntryRow): widget.set_text(str(value)) elif isinstance(widget, Adw.ComboRow): widget.set_selected(int(value)) elif isinstance(widget, Gtk.Scale): widget.set_value(value) elif isinstance(widget, Graphs.StyleColorRow): widget.set_color(Graphs.tools_hex_to_rgba(value)) elif isinstance(widget, Adw.SwitchRow): widget.set_active(bool(value)) else: raise ValueError # font font_description = Pango.FontDescription.new() self.font_size = style_params["font.size"] font_description.set_size(self.font_size * Pango.SCALE) self.props.titlesize.set_value( round(style_params["figure.titlesize"] * 2 / self.font_size, 1), ) self.props.labelsize.set_value( round(style_params["axes.labelsize"] * 2 / self.font_size, 1), ) font_description.set_family(style_params["font.sans-serif"][0]) font_description.set_weight(style_params["font.weight"]) inverted_style_dict = {b: a for a, b in FONT_STYLE_DICT.items()} font_description.set_style( inverted_style_dict[style_params["font.style"]], ) inverted_variant_dict = {b: a for a, b in FONT_VARIANT_DICT.items()} font_description.set_variant( inverted_variant_dict[style_params["font.variant"]], ) self.props.font_chooser.set_font_desc(font_description) self.check_contrast() # line colors self.props.color_manager.set_colors( style_params["axes.prop_cycle"].by_key()["color"], ) # error bar colors self.props.errbar_color_manager.set_colors( graphs_params["errorbar.color_cycle"].by_key()["color"], ) self.params, self.graphs_params = style_params, graphs_params return stylename def save_style(self, file: Gio.File) -> None: """Save style params to file.""" style_io.write(file, self.params, self.graphs_params) def _on_line_colors_changed( self, color_manager: Graphs.StyleColorManager, ) -> None: """Update line colors in params.""" if self.params is None: return line_colors = color_manager.get_colors() self.params["axes.prop_cycle"] = cycler(color=line_colors) self.params["patch.facecolor"] = line_colors[0] self.emit("params-changed") def _on_errbar_colors_changed( self, color_manager: Graphs.StyleColorManager, ) -> None: """Update errorbar colors in graph-params.""" if self.graphs_params is None: return err_colors = color_manager.get_colors() self.graphs_params["errorbar.color_cycle"] = cycler(color=err_colors) self.emit("params-changed") def _on_font_change(self, chooser: Gtk.FontChooser, _param) -> None: if self.params is None: return font_description = chooser.get_font_desc() self.params["font.sans-serif"] = [font_description.get_family()] self.font_size = font_description.get_size() / Pango.SCALE for key in ( "font.size", "xtick.labelsize", "ytick.labelsize", "legend.fontsize", "figure.labelsize", ): self.params[key] = self.font_size font_weight = font_description.get_weight() for key in ( "font.weight", "axes.titleweight", "axes.labelweight", "figure.titleweight", "figure.labelweight", ): self.params[key] = font_weight self.params["font.style"] = \ FONT_STYLE_DICT[font_description.get_style()] self.params["font.variant"] = \ FONT_VARIANT_DICT[font_description.get_variant()] self.emit("params-changed") def _on_titlesize_change(self, entry: Gtk.Entry) -> None: if self.params is None: return titlesize = round(entry.get_value() / 2 * self.font_size, 1) self.params["figure.titlesize"] = titlesize self.params["axes.titlesize"] = titlesize self.emit("params-changed") def _on_labelsize_change(self, entry: Gtk.Entry) -> None: if self.params is None: return labelsize = round(entry.get_value() / 2 * self.font_size, 1) self.params["axes.labelsize"] = labelsize self.emit("params-changed") def _on_name_change(self, entry: Gtk.Entry) -> None: if self.params is None: return self.graphs_params["name"] = entry.get_text() self.emit("params-changed") def _apply_value(self, key: str, value) -> None: if self.params is None: return with contextlib.suppress(KeyError): value = VALUE_DICT[key][value] for item in STYLE_DICT[key]: if item in style_io.STYLE_CUSTOM_PARAMS: self.graphs_params[item] = value else: self.params[item] = value self.emit("params-changed") def _on_color_change( self, row: Graphs.StyleColorRow, _param, key: str, ) -> None: self._apply_value(key, Graphs.tools_rgba_to_hex(row.get_color())) self.check_contrast() def _on_entry_change(self, entry: Gtk.Entry, key: str) -> None: self._apply_value(key, str(entry.get_text())) def _on_combo_change( self, comborow: Adw.ComboRow, _param, key: str, ) -> None: self._apply_value(key, comborow.get_selected()) def _on_scale_change(self, scale: Gtk.Scale, key: str) -> None: self._apply_value(key, scale.get_value()) def _on_switch_change( self, switchrow: Adw.SwitchRow, _param, key: str, ) -> None: self._apply_value(key, bool(switchrow.get_active())) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/editor_box.vala000066400000000000000000000125471520337127000277460ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gdk; using Gtk; namespace Graphs { private string title_format_function (Gtk.Scale scale, double value) { // Format a float value as a percentage string (integer part only) double percentage = (value / 2.0) * 100.0; return "%d%%".printf ((int) percentage); } [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/style-editor/editor-box.ui")] public class StyleEditorBox : Box { [GtkChild] protected unowned Adw.EntryRow style_name { get; } [GtkChild] protected unowned FontDialogButton font_chooser { get; } [GtkChild] protected unowned Gtk.Scale titlesize { get; } [GtkChild] protected unowned Gtk.Scale labelsize { get; } [GtkChild] protected unowned Adw.ComboRow linestyle { get; } [GtkChild] protected unowned Gtk.Scale linewidth { get; } [GtkChild] protected unowned Adw.ComboRow markers { get; } [GtkChild] protected unowned Gtk.Scale markersize { get; } [GtkChild] protected unowned Gtk.Scale axis_width { get; } [GtkChild] protected unowned Adw.SwitchRow draw_frame { get; } [GtkChild] protected unowned Adw.ComboRow tick_direction { get; } [GtkChild] protected unowned Adw.SwitchRow minor_ticks { get; } [GtkChild] protected unowned Gtk.Scale major_tick_width { get; } [GtkChild] protected unowned Gtk.Scale minor_tick_width { get; } [GtkChild] protected unowned Gtk.Scale major_tick_length { get; } [GtkChild] protected unowned Gtk.Scale minor_tick_length { get; } [GtkChild] protected unowned Adw.SwitchRow tick_labels { get; } [GtkChild] protected unowned Adw.SwitchRow tick_bottom { get; } [GtkChild] protected unowned Adw.SwitchRow tick_left { get; } [GtkChild] protected unowned Adw.SwitchRow tick_right { get; } [GtkChild] protected unowned Adw.SwitchRow tick_top { get; } [GtkChild] protected unowned Adw.SwitchRow show_grid { get; } [GtkChild] protected unowned Gtk.Scale grid_linewidth { get; } [GtkChild] protected unowned Gtk.Scale grid_opacity { get; } [GtkChild] protected unowned Gtk.Scale value_padding { get; } [GtkChild] protected unowned Gtk.Scale label_padding { get; } [GtkChild] protected unowned Gtk.Scale title_padding { get; } [GtkChild] protected unowned StyleColorRow text_color { get; } [GtkChild] protected unowned StyleColorRow tick_color { get; } [GtkChild] protected unowned StyleColorRow axis_color { get; } [GtkChild] protected unowned StyleColorRow grid_color { get; } [GtkChild] protected unowned StyleColorRow background_color { get; } [GtkChild] protected unowned StyleColorRow outline_color { get; } [GtkChild] private unowned ListBox line_colors_box { get; } [GtkChild] private unowned ListBox errbar_line_colors_box { get; } [GtkChild] private unowned Box poor_contrast_warning { get; } [GtkChild] protected unowned Gtk.Scale errorbar_capsize { get; } [GtkChild] protected unowned Gtk.Scale errorbar_capthick { get; } [GtkChild] protected unowned Gtk.Scale errorbar_linewidth { get; } [GtkChild] protected unowned Adw.SwitchRow errorbar_barsabove { get; } public signal void params_changed (); protected StyleColorManager color_manager { get; set; } protected StyleColorManager errbar_color_manager { get; set; } protected Gtk.Window window { get; set; } construct { this.color_manager = new StyleColorManager (line_colors_box); this.errbar_color_manager = new StyleColorManager (errbar_line_colors_box); titlesize.set_format_value_func (title_format_function); labelsize.set_format_value_func (title_format_function); } protected void check_contrast () { double contrast = Tools.get_contrast (outline_color.color, text_color.color); poor_contrast_warning.set_visible (contrast < 4.5); } [GtkCallback] private void on_linestyle () { linewidth.set_sensitive (linestyle.get_selected () != 0); } [GtkCallback] private void on_markers () { markersize.set_sensitive (markers.get_selected () != 0); } [GtkCallback] private async void add_color () { var dialog = new ColorDialog () { with_alpha = false }; try { RGBA color = yield dialog.choose_rgba (window, null, null); string hex = Tools.rgba_to_hex (color); color_manager.add_color (hex); } catch {} } [GtkCallback] private async void add_errbar_color () { var dialog = new ColorDialog () { with_alpha = false }; try { RGBA color = yield dialog.choose_rgba (window, null, null); string hex = Tools.rgba_to_hex (color); errbar_color_manager.add_color (hex); } catch {} } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/item_color_row.vala000066400000000000000000000035051520337127000306250ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gdk; using Gtk; namespace Graphs { /** * Style Color Box */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/style-editor/item-color-row.ui")] public class StyleItemColorRow : Adw.ActionRow { public int index { get; construct set; } [GtkChild] private unowned Gtk.Button color_button { get; } private CssProvider provider = new CssProvider (); private string color; public StyleColorManager color_manager; public signal void color_changed (string color); public signal void color_removed (); construct { this.color_button.get_style_context ().add_provider ( this.provider, STYLE_PROVIDER_PRIORITY_APPLICATION ); } public StyleItemColorRow (StyleColorManager color_manager, int index, string color) { Object (index: index); this.set_title (_("Color %d").printf (index + 1)); this.color_manager = color_manager; this.color = color; load_color (); } private void load_color () { this.provider.load_from_string (@"button { color: $color; }"); } [GtkCallback] private async void on_color_choose () { var dialog = new ColorDialog () { with_alpha = false }; try { RGBA rgba = yield dialog.choose_rgba ( (Gtk.Window) this.get_root (), Tools.hex_to_rgba (color), null ); color = Tools.rgba_to_hex (rgba); load_color (); color_changed.emit (color); } catch {} } [GtkCallback] private void on_delete () { color_removed.emit (); } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_editor/window.vala000066400000000000000000000247721520337127000271220ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Adw; using Gdk; using Gtk; namespace Graphs { /** * Style Editor Window window */ [GtkTemplate (ui = "/se/sjoerd/Graphs/ui/style-editor/window.ui")] public class StyleEditor : Adw.ApplicationWindow { [GtkChild] private unowned Adw.Bin editor_bin { get; } [GtkChild] private unowned Adw.Bin canvas_bin { get; } [GtkChild] private unowned Stack stack { get; } [GtkChild] private unowned GridView style_grid { get; } [GtkChild] protected unowned Adw.ToolbarView content_view { get; } protected Gtk.Box editor_box { get { return (Gtk.Box) editor_bin.get_child (); } set { editor_bin.set_child (value); } } protected Canvas canvas { get { return (Canvas) canvas_bin.get_child (); } set { canvas_bin.set_child (value); } } protected string stylename { set { this._stylename = value; // Translators: Window title that will be formatted with the stylename. set_title (_("Graphs Style Editor — %s").printf (value)); if (_inhibit_cookie > 0) { application.uninhibit (_inhibit_cookie); _inhibit_cookie = application.inhibit ( this, ApplicationInhibitFlags.LOGOUT, value ); } } } protected CssProvider css_provider { get; private set; } protected bool unsaved { get; set; default = false; } private File _file; private bool _force_close = false; private uint _inhibit_cookie = 0; private string _stylename; protected signal void load_request (File file); protected signal void save_request (File file); construct { this.css_provider = new CssProvider (); StyleContext.add_provider_for_display ( Display.get_default (), css_provider, STYLE_PROVIDER_PRIORITY_APPLICATION ); content_view.set_name (Application.get_next_css_name ()); var save_action = new SimpleAction ("save-style", null); save_action.activate.connect (() => { if (_file == null) return; save (); }); save_action.set_enabled (false); add_action (save_action); var save_as_action = new SimpleAction ("save-style-as", null); save_as_action.activate.connect (() => { if (_file == null) return; var dialog = new FileDialog (); dialog.set_filters (get_mplstyle_file_filters ()); dialog.set_initial_name (_("Style") + ".mplstyle"); dialog.save.begin (this, null, (d, response) => { try { _file = dialog.save.end (response); save (); } catch {} }); }); add_action (save_as_action); var open_action = new SimpleAction ("open-style", null); open_action.activate.connect (() => { var dialog = new FileDialog (); dialog.set_filters (get_mplstyle_file_filters ()); dialog.open.begin (this, null, (d, response) => { try { var file = dialog.open.end (response); if (_file == null || !unsaved) { load (file); } else { var new_window = ((Application) application).create_style_editor (); new_window.load (file); new_window.present (); } } catch {} }); }); add_action (open_action); var close_action = new SimpleAction ("close-style", null); close_action.activate.connect (() => { if (!unsaved) { close_style (); return; } var dialog = (Adw.AlertDialog) Tools.build_dialog ("save_style_changes"); dialog.response.connect ((d, response) => { switch (response) { case "discard": { close_style (); break; } case "save": { save (); close_style (); break; } } }); dialog.present (this); }); add_action (close_action); var show_shortcuts_action = new SimpleAction ("show-shortcuts", null); show_shortcuts_action.activate.connect (() => { string path = "/se/sjoerd/Graphs/ui/style-editor/shortcuts.ui"; var builder = new Builder.from_resource (path); var shortcuts_dialog = (Adw.ShortcutsDialog) builder.get_object ("shortcuts"); shortcuts_dialog.present (this); }); add_action (show_shortcuts_action); var import_action = new SimpleAction ("import-style", null); import_action.activate.connect (() => { import_style.begin (this); }); add_action (import_action); var create_action = new SimpleAction ("create-style", null); create_action.activate.connect (() => { var dialog = new AddStyleDialog (this); dialog.accept.connect ((file) => { load (file); }); }); add_action (create_action); // Inhibit session end when there is unsaved data present notify["unsaved"].connect (() => { if (unsaved) { if (_inhibit_cookie == 0) _inhibit_cookie = application.inhibit ( this, ApplicationInhibitFlags.LOGOUT, _stylename ); save_action.set_enabled (true); } else { if (_inhibit_cookie > 0) { application.uninhibit (_inhibit_cookie); _inhibit_cookie = 0; } save_action.set_enabled (false); } }); var factory = new SignalListItemFactory (); factory.setup.connect (on_factory_setup); factory.bind.connect (on_factory_bind); style_grid.set_factory (factory); style_grid.set_model (new NoSelection (StyleManager.filtered_style_model)); } public void load (File file) { this._file = file; load_request.emit (file); stack.get_pages ().select_item (1, true); } public void save () { save_request.emit (_file); this.unsaved = false; } public void close_style () { this.unsaved = false; set_title (_("Graphs Style Editor")); stack.get_pages ().select_item (0, true); } private void on_factory_setup (Object object) { ListItem item = (ListItem) object; item.set_child (new StylePreview ()); } private void on_factory_bind (Object object) { ListItem item = (ListItem) object; StylePreview preview = (StylePreview) item.get_child (); Style style = (Style) item.get_item (); preview.style = style; if (style.mutable && !preview.menu_button.get_visible ()) { preview.menu_button.set_visible (true); var action_group = new SimpleActionGroup (); var open_action = new SimpleAction ("open", null); open_action.activate.connect (() => { load (style.file); }); action_group.add_action (open_action); var open_with_action = new SimpleAction ("open_with", null); open_with_action.activate.connect (() => { var launcher = new FileLauncher (style.file); launcher.set_always_ask (true); launcher.launch.begin (this, null); }); action_group.add_action (open_with_action); var delete_action = new SimpleAction ("delete", null); delete_action.activate.connect (() => { var dialog = (Adw.AlertDialog) Tools.build_dialog ("delete_style"); string msg = _("Are you sure you want to delete %s?"); dialog.set_body (msg.printf (style.name)); dialog.response.connect ((d, response) => { if (response != "delete") return; try { style.file.trash (); } catch { assert_not_reached (); } }); dialog.present (this); }); action_group.add_action (delete_action); preview.menu_button.insert_action_group ("style", action_group); } } public override bool close_request () { var application = (Application) application; if (_force_close) { application.on_style_editor_closed (this); return false; } if (unsaved) { var dialog = (Adw.AlertDialog) Tools.build_dialog ("save_style_changes"); dialog.response.connect ((d, response) => { switch (response) { case "discard": { _force_close = true; close (); break; } case "save": { save (); _force_close = true; close (); break; } } }); dialog.present (this); return true; } application.on_style_editor_closed (this); return false; } } } Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/style_io.py000066400000000000000000000214611520337127000244310ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """ Module for parsing and writing styles. This module is intended to be used at build time and thus must not depend on other graphs modules. """ import contextlib import logging import typing from gettext import gettext as _ from cycler import cycler from gi.repository import Gio from matplotlib import RcParams, cbook, rc_context from matplotlib.figure import Figure from matplotlib.font_manager import font_scalings, weight_dict from matplotlib.style.core import STYLE_BLACKLIST import numpy STYLE_IGNORELIST = [ "savefig.dpi", "savefig.facecolor", "savefig.edgecolor", "savefig.format", "savefix.bbox", "savefig.pad_inches", "savefig.transparent", "savefig.orientation", ] FONT_SIZE_KEYS = [ "font.size", "axes.labelsize", "xtick.labelsize", "ytick.labelsize", "legend.fontsize", "figure.labelsize", "figure.titlesize", "axes.titlesize", ] STYLE_CUSTOM_PARAMS = [ "name", "ticklabels", "errorbar.capsize", "errorbar.capthick", "errorbar.linewidth", "errorbar.barsabove", "errorbar.color_cycle", ] class StyleParseError(Exception): """Custom Error for when a style cannot be parsed.""" def parse( file: Gio.File, validate: tuple[RcParams, dict] = None, ) -> (RcParams, dict): """ Parse a style to RcParams. This is an improved version of matplotlibs '_rc_params_in_file()' function. It is also modified to work with GFile instead of the python builtin functions. """ def _apply_defaults( target_dict: dict | RcParams, defaults: dict, filename, ) -> None: for key, value in defaults.items(): if key not in target_dict: msg = ( "Parameter {key} not found in {filename}, using" " default value: {value}" ) msg = msg.format(key=key, filename=filename, value=value) logging.debug(msg) target_dict[key] = value style = RcParams() graphs_params = {"name": None} filename = file.get_basename() try: stream = Gio.DataInputStream.new(file.read(None)) for line_number, line in enumerate(stream, 1): if line[:9] == "#~graphs ": graphs_param = True line = line[9:] else: graphs_param = False # legacy support for names at second line if line_number == 2 and graphs_params["name"] is None \ and line[:2] == "# ": graphs_params["name"] = line[2:] line = cbook._strip_comment(line) if not line: continue try: key, value = line.split(":", 1) except ValueError: msg = _("Missing colon in file {file}, line {line}") logging.warning(msg.format(file=filename, line=line_number)) continue key = key.strip() value = value.strip() if value.startswith('"') and value.endswith('"'): value = value[1:-1] # strip double quotes if key in STYLE_BLACKLIST: msg = _("Non-style related parameter {param} in file {file}") logging.warning(msg.format(param=key, file=filename)) elif key in STYLE_IGNORELIST: msg = _("Ignoring parameter {param} in file {file}") logging.warning(msg.format(param=key, file=filename)) elif key != "name" and \ key in (graphs_params if graphs_param else style): msg = _("Duplicate key in file {file}, on line {line}") logging.warning(msg.format(file=filename, line=line_number)) else: if key in FONT_SIZE_KEYS \ and not value.replace(".", "", 1).isdigit(): try: value = font_scalings[value] except KeyError: continue elif key == "font.weight" and not value.isdigit(): try: value = weight_dict[value] except KeyError: continue try: if graphs_param: if key not in STYLE_CUSTOM_PARAMS: msg = _( "Bad value in file {file} on line {line}," " custom parameter {key} is not supported", ) logging.warning( msg.format( file=filename, line=line_number, key=key, ), ) continue # Convert boolean-strings to boolean: bool_mapping = {"false": False, "true": True} value = bool_mapping.get(value.lower(), value) if key == "errorbar.color_cycle": color = ["#" + c.strip() for c in value.split(",")] value = cycler(color=color) else: with contextlib.suppress(ValueError): value = float(value) graphs_params[key] = value else: style[key] = value except (KeyError, ValueError): msg = _("Bad value in file {file} on line {line}") logging.warning( msg.format(file=filename, line=line_number), ) except UnicodeDecodeError as error: msg = _("Could not parse {filename}").format(filename=filename) raise StyleParseError(msg) from error finally: stream.close() if validate is not None: style_defaults, graph_defaults = validate _apply_defaults(style, style_defaults, filename) _apply_defaults(graphs_params, graph_defaults, filename) if graphs_params["name"] is None: msg = _("File {file}, does not contain name tag") logging.warning(msg.format(file=filename)) graphs_params["name"] = filename return style, graphs_params WRITE_IGNORELIST = STYLE_IGNORELIST + [ "lines.dashdot_pattern", "lines.dashed_pattern", "lines.dotted_pattern", "lines.dash_capstyle", "lines.dash_joinstyle", "lines.solid_capstyle", "lines.solid_joinstyle", ] def write(file: Gio.File, style: RcParams, graphs_params: dict) -> None: """Write a style to a file.""" stream = Gio.DataOutputStream.new(file.replace(None, False, 0, None)) stream.put_string("# Generated via Graphs\n") for key, value in graphs_params.items(): if key == "errorbar.color_cycle": value = ", ".join(c.lstrip("#") for c in value.by_key()["color"]) stream.put_string(f"#~graphs {key}: {value}\n") for key, value in style.items(): if key not in STYLE_BLACKLIST and key not in WRITE_IGNORELIST: value = str(value).replace("#", "") if key != "axes.prop_cycle": value = value.replace("[", "").replace("]", "") value = value.replace("'", "").replace("'", "") value = value.replace('"', "").replace('"', "") stream.put_string(f"{key}: {value}\n") stream.close() _PREVIEW_XDATA = numpy.linspace(0, 10, 30) _PREVIEW_YDATA1 = numpy.sin(_PREVIEW_XDATA) _PREVIEW_YDATA2 = numpy.cos(_PREVIEW_XDATA) def create_preview( file: typing.IO, params: tuple[RcParams, dict], file_format: str = "svg", dpi: int = 100, ) -> None: """Create preview of params and write it to file.""" style_params, graphs_params = params with rc_context(style_params): # set render size in inch figure = Figure(figsize=(5, 3)) axis = figure.add_subplot() axis.spines.bottom.set_visible(True) axis.spines.left.set_visible(True) if style_params["axes.spines.top"] and graphs_params["ticklabels"]: tick_params = { "labelleft": style_params["ytick.left"], "labelright": style_params["ytick.right"], "labeltop": style_params["xtick.top"], "labelbottom": style_params["xtick.bottom"], } axis.tick_params(which="both", **tick_params) else: axis.tick_params(which="both", top=False, right=False) axis.plot(_PREVIEW_XDATA, _PREVIEW_YDATA1) axis.plot(_PREVIEW_XDATA, _PREVIEW_YDATA2) axis.set_xlabel(_("X Label")) axis.set_xlabel(_("Y Label")) figure.savefig(file, format=file_format, dpi=dpi) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/styles.py000066400000000000000000000071441520337127000241270ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-3.0-or-later """Module for style utilities.""" import io import os from gi.repository import Adw, GLib, Gdk, Gio, Graphs, Gtk from graphs import style_io from matplotlib import RcParams CSS_TEMPLATE = """ .system-canvas-view {{ background-color: {background_color}; color: {color}; }} """ def _is_style_bright(params: RcParams): return Graphs.tools_get_luminance_from_hex(params["axes.facecolor"]) < 0.4 def _generate_preview(params: tuple[RcParams, dict]) -> Gdk.Texture: buffer = io.BytesIO() style_io.create_preview(buffer, params, "png", 31) return Gdk.Texture.new_from_bytes(GLib.Bytes.new(buffer.getvalue())) def _params_for_bundled_style(name: str) -> tuple[RcParams, dict]: filename = Graphs.filename_from_stylename(name) uri = "resource:///se/sjoerd/Graphs/styles/" + filename return style_io.parse(Gio.File.new_for_uri(uri)) class StyleManager(Graphs.StyleManager): """ Main Style Manager. Keeps track of all files in the style dir and represents them in the `selection_model` property. """ __gtype_name__ = "GraphsPythonStyleManager" def __init__(self): # Check for Ubuntu gtk_theme = Gtk.Settings.get_default().get_property("gtk-theme-name") system_style_name = "Yaru" \ if "SNAP" in os.environ \ and gtk_theme.lower().startswith("yaru") \ else "Adwaita" super().__init__() self.connect("style-request", self._on_style_request) self.connect("create-style-request", self._on_create_style_request) Adw.StyleManager.get_default().connect("notify", self._on_system_style) self._system_style_light_params = \ _params_for_bundled_style(system_style_name) self._system_style_dark_params = \ _params_for_bundled_style(system_style_name + " Dark") self._on_system_style() self.setup(system_style_name.lower()) @staticmethod def _on_style_request(self, file: Gio.File) -> Graphs.Style: try: params = style_io.parse( file, self.get_system_style_params(), ) style_params, graphs_params = params name = graphs_params["name"] preview = _generate_preview(params) light = _is_style_bright(style_params) except style_io.StyleParseError: name = "" preview = None light = False return Graphs.Style( name=name, file=file, mutable=True, preview=preview, light=light, ) def get_system_style_params(self) -> tuple[RcParams, dict]: """Get the system style properties.""" if Adw.StyleManager.get_default().get_dark(): return self._system_style_dark_params else: return self._system_style_light_params def _on_system_style(self, *_args) -> None: params = self.get_system_style_params() css = CSS_TEMPLATE.format( background_color=params[0]["figure.facecolor"], color=params[0]["text.color"], ) self.props.css_provider.load_from_string(css) @staticmethod def _on_create_style_request( self, template: Graphs.Style, destination: Gio.File, new_name: str, ) -> None: """Copy a style.""" style_params, graphs_params = style_io.parse( template.get_file(), self.get_system_style_params(), ) graphs_params["name"] = new_name style_io.write(destination, style_params, graphs_params) Graphs-v2.0.2-9adcc5cf03c88525ef883d6ccaf16a918346ea44/graphs/styles.vala000066400000000000000000000260451520337127000244230ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-3.0-or-later using Gdk; using Gee; using Gtk; namespace Graphs { public int style_cmp (Style a, Style b) { if (a.file == null) return -1; else if (b.file == null) return 1; return strcmp (a.name.down (), b.name.down ()); } public string filename_from_stylename (string name) { var filename = name.replace (" ", "-"); filename = filename.replace ("(", ""); filename = filename.replace (")", ""); filename = filename.down (); return filename + ".mplstyle"; } private bool filter_system_style (Object style) { return ((Style) style).file != null; } /** * Style manager */ public class StyleManager : Object { public static GLib.ListStore style_model { get; private set; } public static FilterListModel filtered_style_model { get; private set; } public static File style_dir { get; private set; } public signal void style_changed (string stylename); public signal void style_deleted (string stylename); public signal void style_renamed (string old_name, string new_name); protected CssProvider css_provider { get; private set; } protected signal void create_style_request (Style template, File destination, string name); protected signal Style style_request (File file); public static StyleManager instance { get; private set; } construct { this.css_provider = new CssProvider (); StyleContext.add_provider_for_display ( Display.get_default (), css_provider, STYLE_PROVIDER_PRIORITY_APPLICATION ); } protected void setup (string system_style) { StyleManager.instance = this; style_model = new GLib.ListStore (typeof (Style)); filtered_style_model = new FilterListModel ( style_model, new CustomFilter (filter_system_style) ); try { File config_dir = Tools.get_config_directory (); style_dir = config_dir.get_child_for_display_name ("styles"); if (!style_dir.query_exists ()) { style_dir.make_directory_with_parents (); } } catch { assert_not_reached (); } style_model.append ( new Style ( _("System"), null, Gdk.Texture.from_resource ( @"/se/sjoerd/Graphs/system-style-$system_style.png" ), false ) ); File style_list = File.new_for_uri ("resource:///se/sjoerd/Graphs/styles.txt"); try { var stream = new DataInputStream (style_list.read ()); string line; while ((line = stream.read_line (null)) != null) { string[] strings = line.chomp ().split (";", 3); style_model.append ( new Style ( strings[0], File.new_for_uri ("resource://" + strings[1]), Gdk.Texture.from_resource (strings[2]), false ) ); } } catch { assert_not_reached (); } try { FileEnumerator enumerator = style_dir.enumerate_children ( "standard::*", FileQueryInfoFlags.NONE ); Gee.List stylenames = new Gee.ArrayList.wrap (list_stylenames ()); CompareDataFunc