pax_global_header00006660000000000000000000000064150173311270014512gustar00rootroot0000000000000052 comment=f6247f0c9b8c15b19e8ddca2f600ceb2cf48beb9 mastodon.el/000077500000000000000000000000001501733112700133015ustar00rootroot00000000000000mastodon.el/.elpaignore000066400000000000000000000001251501733112700154250ustar00rootroot00000000000000*.*~ .woodpecker.yml lisp/.dir-locals.el Cask fixture Makefile stubfile.plstore test mastodon.el/.gitignore000066400000000000000000000003251501733112700152710ustar00rootroot00000000000000# Compiled *.elc # Packaging .cask # Other .DS_Store stubfile.plstore *~ dist/ /mastodon.org # ELPA-generted files /mastodon-pkg.el /mastodon-autoloads.el /lisp/mastodon-autoloads.el # ELSA files /lisp/.elsa/ mastodon.el/.woodpecker.yml000066400000000000000000000006161501733112700162470ustar00rootroot00000000000000pipeline: current: image: silex/emacs:cask commands: - emacs --version - cask install - cask emacs -batch -l test/ert-helper.el -f ert-run-tests-batch-and-exit last: image: silex/emacs:27-ci-cask commands: - emacs --version - cask install - cask emacs -batch -l test/ert-helper.el -f ert-run-tests-batch-and-exit branches: [ main, develop ] mastodon.el/Cask000066400000000000000000000003371501733112700141100ustar00rootroot00000000000000(source gnu) (source melpa) (package-file "lisp/mastodon.el") (files "lisp/*.el") (development (depends-on "ert-runner") (depends-on "el-mock") (depends-on "ecukes") (depends-on "package-lint") (depends-on "async")) mastodon.el/LICENSE000066400000000000000000001045121501733112700143110ustar00rootroot00000000000000 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 .mastodon.el/Makefile000066400000000000000000000021321501733112700147370ustar00rootroot00000000000000PKG = mastodon CP = cp LN = ln EMACS = emacs MAKEINFO = makeinfo INSTALL-INFO = install-info ORG_DIR = $(word 1,$(wildcard $(HOME)/.emacs.d/elpa/org-9*)) ORG_PATH = -L $(ORG_DIR) ORG_ARGS = --batch $(ORG_PATH) -l org -l ol-man ORG_EVAL1 = --funcall org-texinfo-export-to-texinfo ORG_EVAL2 = --funcall org-texinfo-export-to-info ## ################################################################ .PHONY: infoclean tests testsclean all: $(PKG).info dir infoclean: rm -f $(PKG).org $(PKG).texi $(PKG).info dir tests: cask emacs -batch -load test/ert-helper.el -f ert-run-tests-batch-and-exit testsclean: rm -f stubfile.plstore~ ## ################################################################ # May look at this in the future # # %.info: %.texi # @printf "Generating $@\n" # $(MAKEINFO) --no-split $< -o $@ # # %.texi: %.org # @printf "Generating $@\n" # $(EMACS) $(ORG_ARGS) $@ $(ORG_EVAL1) %.info: %.org @printf "Generating $@\n" $(EMACS) $(ORG_ARGS) $< $(ORG_EVAL2) dir: $(PKG).info printf "Generating $@\n" echo $^ | xargs -n 1 $(INSTALL-INFO) --dir=$@ $(PKG).org: README.org $(CP) $< $@ mastodon.el/README.org000066400000000000000000000666361501733112700147700ustar00rootroot00000000000000#+title: A Mastodon client #+export_file_name: mastodon #+TEXINFO_DIR_CATEGORY: Emacs #+TEXINFO_DIR_TITLE: Mastodon: (mastodon). #+TEXINFO_DIR_DESC: Client for fediverse services using the Mastodon API. @@html: ELPA@@ @@html: MELPA@@ # @@html: Build Status@@ * README =mastodon.el= is an Emacs client for the ActivityPub social networks that implement the Mastodon API. For info see [[https://joinmastodon.org/][joinmastodon.org]]. NB: =mastodon.el= now ships this readme as an .info file, so if you have it installed you should be able to browse this readme inside emacs. =C-h i= for info, then =m masto RET= should load it for you. ** Installation You can install =mastodon.el= from ELPA, MELPA, or directly from this repo. It is also available as a GUIX package. *** ELPA You should be able to directly install with: =M-x package-refresh-contents RET= =M-x package-install RET mastodon RET= *** MELPA Add =MELPA= to your archives: #+BEGIN_SRC emacs-lisp (require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t) #+END_SRC Update and install: =M-x package-refresh-contents RET= =M-x package-install RET mastodon RET= *** Repo Clone this repository and add the lisp directory to your load path. Then, require it and go. #+BEGIN_SRC emacs-lisp (add-to-list 'load-path "/path/to/mastodon.el/lisp") (require 'mastodon) #+END_SRC Or, with =use-package=: #+BEGIN_SRC emacs-lisp (use-package mastodon :ensure t) #+END_SRC The minimum Emacs version is now 28.1. But if you are running an older version it shouldn't be very hard to get it working. *** Emoji Since Emacs 28, it has builtin emoji support with =emoji.el=. If you prefer to use [[https://github.com/iqbalansari/emacs-emojify][Emojify]], =require= it and set =mastodon-use-emojify= to non-nil to display emoji in timelines and to use it when composing toots. =Emoji.el= is the better option, but for now only =emojify= supports downloading and using custom emoji from your instance. From personal experience, =emojify= also tends to result in less TOFU. *** Discover =mastodon-mode= can provide a context menu for its keybindings if [[https://github.com/mickeynp/discover.el][Discover]] is installed. It is not required. if you have Discover, add the following to your Emacs init configuration: #+BEGIN_SRC emacs-lisp (require 'mastodon-discover) (with-eval-after-load 'mastodon (mastodon-discover)) #+END_SRC Or, with =use-package=: #+BEGIN_SRC emacs-lisp (use-package mastodon :ensure t :config (mastodon-discover)) #+END_SRC ** Usage *** Logging in to your instance You need to set 2 variables in your init file to get started: 1. =mastodon-instance-url= 2. =mastodon-active-user= (see their doc strings for details). For example If you want to post toots as "example_user@social.instance.org", then put this in your init file: #+BEGIN_SRC emacs-lisp (setq mastodon-instance-url "https://social.instance.org" mastodon-active-user "example_user") #+END_SRC Then *restart* Emacs and run =M-x mastodon=. Make sure you are connected to internet before you do this. If you have multiple mastodon accounts you can activate one at a time by changing those two variables and restarting Emacs. If you were using mastodon.el before 2FA was implemented and the above steps do not work, call =(mastodon-forget-all-logins)=, restart Emacs and follow the steps again. **** encrypted access tokens (from 2.0.0) By default, user access tokens are now stored in the user's auth source file (typically =~/.authinfo.gpg=, check the value of =auth-sources=). When you first update to 2.0.0, or if you encounter issues due to old credentials, call =(mastodon-forget-all-logins)= to remove the old mastodon.el plstore, and then authenticate again. If you don't want to use the auth source file, set =mastodon-auth-use-auth-source= to nil. Entries will instead be stored encrypted in =mastodon-client--token-file=, a plstore. If for some reason you reauthenticate, you'll need to either remove the entry in your auth sources file, or manually update the token in it after doing so, as mastodon.el is unable to reliably update (or even remove) entires. The format for a mastodon.el auth source entry is as follows: =machine INSTANCE login USERNAME password AUTHTOKEN= with the token being what you copy from the browser when authenticating. If you have =auth-source-save-behavior= set to nil, you'll also need to add such an entry manually. Finally, if you find you're asked for your key passphrase too often while authenticating, consider setting =epa-file-encrypt-to= (for auth-source encryption) and =plstore-encrypt-to= (for plstore encryption) to your preferred key ID. *** Timelines =M-x mastodon= Opens a =*mastodon-home*= buffer in the major mode and displays toots. If your credentials are not yet saved, you will be prompted for email and password. The app registration process will take place if your =mastodon-token-file= does not contain =:client_id= and =:client_secret=. **** Keybindings For a full list of commands and variables, see [[file:mastodon-index.org][mastodon-index.org]]. |----------------+---------------------------------------------------------------------------------| | Key | Action | |----------------+---------------------------------------------------------------------------------| | | *Help* | | =?= | Show discover menu of all bindings, if =discover= is available | |----------------+---------------------------------------------------------------------------------| | | *Timeline actions* | | =n= | Go to next item (toot, notification, user) | | =p= | Go to previous item (toot, notification, user) | | =M-n/= | Go to the next interesting thing that has an action | | =M-p/= | Go to the previous interesting thing that has an action | | =F= | Open federated timeline (1 prefix arg: hide-replies, 2 prefix args: media only) | | =H= | Open home timeline (1 prefix arg: hide-replies) | | =L= | Open local timeline (1 prefix arg: hide-replies, 2 prefix args: media only) | | =N= | Open notifications timeline | | =@= | Open mentions-only notifications timeline | | =u= | Update current timeline | | =T= | Open thread for toot at point | | =#= | Prompt for tag and open its timeline | | =A= | Open author profile of toot at point | | =P= | Open profile of user attached to toot at point | | =O= | View own profile | | =U= | update your profile bio note | | =;= | view instance description for toot at point | | =:= | view followed tags and load a tag timeline | | =C-:= | view timeline of all followed tags | | =,= | view favouriters of toot at point | | =.= | view boosters of toot at point | | =/= | switch between mastodon buffers | | =\= | prompt for an instance domain and view its local timeline (if poss) | | =Z= | report user/toot at point to instances moderators | |----------------+---------------------------------------------------------------------------------| | | *Other views* | | =s= | search (posts, users, tags) (NB: only posts you have interacted with) | | =I=, =c=, =d= | view, create, and delete filters | | =R=, =a=, =j= | view/accept/reject follow requests | | =G= | view follow suggestions | | =V= | view your favourited toots | | =K= | view bookmarked toots | | =X= | view/edit/create/delete lists | | =S= | view your scheduled toots | | =S-:= | view profile/account settings transient menu | |----------------+---------------------------------------------------------------------------------| | | *Toot actions* | | =t= | Compose a new toot | | =c= | Toggle content warning content | | =b= | Boost toot under =point= | | =f= | Favourite toot under =point= | | =k= | toggle bookmark of toot at point | | =r= | Reply to toot under =point= | | =v= | Vote on poll at point | | =C= | copy url of toot at point | | =C-RET= | play video/gif at point (requires =mpv=) | | =e= | edit your toot at point | | =E= | view edits of toot at point | | =i= | (un)pin your toot at point | | =d= | delete your toot at point, and reload current timeline | | =D= | delete and redraft toot at point, preserving reply/CW/visibility | | =!= | toggle folding of toot at point | | (=S-C-=) =W=, =M=, =B= | (un)follow, (un)mute, (un)block author of toot at point | |----------------+---------------------------------------------------------------------------------| | | *Profile view* | | =C-c C-c= | cycle between statuses, statuses without boosts, followers, and following | | | =mastodon-profile--add-account-to-list= (see lists view) | |----------------+---------------------------------------------------------------------------------| | | *Notifications view* | | =a=, =j= | accept/reject follow request | | =C-k= | clear notification at point | | =C-c C-c= | cycle between notification types | | | see =mastodon-notifications--get-*= functions for filtered views | |----------------+---------------------------------------------------------------------------------| | | *Quitting* | | =q= | Quit mastodon buffer, leave window open | | =Q= | Quit mastodon buffer and kill window | | =C-M-q= | Quit and kill all mastodon buffers | |----------------+---------------------------------------------------------------------------------| **** Toot byline legend |---------------+------------------------| | Marker | Meaning | |---------------+------------------------| | =(🔁)= (or =(B)=) | I boosted this toot | | =(⭐)= (or =(F)=) | I favourited this toot | | =(🔖)= (or =(K)=) | I bookmarked this toot | |---------------+------------------------| *** Composing toots =M-x mastodon-toot= (or =t= from a mastodon.el buffer) opens a new buffer/window in =text-mode= and =mastodon-toot= minor mode. Enter the contents of your toot here. =C-c C-c= sends the toot. =C-c C-k= cancels. Both actions kill the buffer and window. Further keybindings are displayed in the buffer, and in the following subsection. Replies preserve visibility status/content warnings, and include boosters by default. If the region is active when you start a reply, it will be yanked into the compose buffer prefixed with =>= to form a rough reply quote. Server's max toot length, with running char count, and attachment previews, are shown. You can download and use your instance's custom emoji (=mastodon-toot--download-custom-emoji=, =mastodon-toot--enable-custom-emoji=). If you want to view some of the toot being replied to in the compose buffer, set =mastodon-toot-display-orig-in-reply-buffer= to non-nil. The compose buffer uses =text-mode= so any configuration you have for that mode will be enabled. If any of your existing config conflicts with =mastodon-toot=, you can disable it in the =mastodon-toot-mode-hook=. For example, the default value of that hook is as follows: #+begin_src emacs-lisp (add-hook 'mastodon-toot-mode-hook (lambda () (auto-fill-mode -1))) #+end_src **** Keybindings |---------+-------------------------------| | Key | Action | |---------+-------------------------------| | =C-c C-c= | Send toot | | =C-c C-k= | Cancel toot | | =C-c C-w= | Add content warning | | =C-c C-v= | Change toot visibility | | =C-c C-n= | Add sensitive media/nsfw flag | | =C-c C-a= | Upload attachment(s) | | =C-c != | Remove all attachments | | =C-c C-e= | Insert emoji | | =C-c C-p= | Create a poll | | =C-c C-o= | Cancel poll | | =C-c C-l= | Set toot language | | =C-c C-s= | Schedule toot | |---------+-------------------------------| **** Autocompletion of mentions, tags and emoji Autocompletion of mentions, tags, and emojis is provided by =completion-at-point-functions= (capf) backends. =mastodon-toot--enable-completion= is enabled by default. To trigger completion, type a prefix followed by a few letters, =@= for mentions, =#= for tags, and =:= for emoji (for now this only works when using =emojify.el=). If you want to enable =company-mode= in the toot compose buffer, set =mastodon-toot--use-company-for-completion= to =t=. (=mastodon.el= used to run its own native company backends, but these have been removed in favour of capfs.) If you don’t run =company= and want immediate, keyless completion, you’ll need to have another completion engine running that handles capfs. A common combination is =consult= and =corfu=. **** Draft toots - Compose buffer text is saved as you type, kept in =mastodon-toot-current-toot-text=. - =mastodon-toot--save-draft=: save the current toot as a draft. - =mastodon-toot--open-draft-toot=: Open a compose buffer and insert one of your draft toots. - =mastodon-toot--delete-draft-toot=: Delete a draft toot. - =mastodon-toot--delete-all-drafts=: Delete all your drafts. *** Other commands and account settings: In addition to =mastodon=, the following three functions are autoloaded and should work without first loading a =mastodon.el= buffer: - =mastodon-toot=: Compose new toot - =mastodon-notifications-get=: View all notifications - =mastodon-url-lookup=: Attempt to load a URL in =mastodon.el=. URL may be at point or provided in the minibuffer. - =mastodon-tl--view-instance-description=: View information about the instance that the author of the toot at point is on. - =mastodon-tl--view-own-instance=: View information about your own instance. - =mastodon-search--trending-tags=: View a list of trending hashtags on your instance. - =mastodon-search--trending-statuses=: View a list of trending statuses on your instance. - =mastodon-search--trending-links=: View a list of trending links on your instance (+ click through to a timeline of posts featuring a given link) - =mastodon-tl--add-toot-account-at-point-to-list=: Add the account of the toot at point to a list. - =mastodon-tl--dm-user=: Send a direct message to one of the users at point. - =mastodon-profile--add-private-note-to-account=: Add a private note to another user’s account. - =mastodon-profile--view-account-private-note=: View a private note on a user’s account. - =mastodon-profile--show-familiar-followers=: Show a list of “familiar followers” for a given account. Familiar followers are accounts that you follow, and that follow the account. - =mastodon-tl--follow-tag=: Follow a tag (works like following a user) - =mastodon-tl--unfollow-tag=: Unfollow a tag - =mastodon-tl--list-followed-tags=: View a list of tags you're following. - =mastodon-tl--followed-tags-timeline=: View a timeline of all your followed tags. - =mastodon-tl--some-followed-tags-timleine=: View a timeline of multiple tags, from your followed tags or any other. - =mastodon-switch-to-buffer=: switch between mastodon buffers. - =mastodon-tl--get-remote-local-timeline=: View a local timeline of a remote instance. - =mastodon-tl--remote-tag-timeline=: View a tag timeline on a remote instance. - =mastodon-user-settings=: Launch a transient menu to update various account settings. *** Notifications Mastodon from 4.3 supports grouped notifications. These are implemented by =mastodon.el= but disabled by default out of consideration to users on instances that don't support them. If you are on an instance that implements grouped notifications, set =mastodon-group-notifications= to =t= to enable them. *** Customization See =M-x customize-group RET mastodon= to view all customize options. - Timeline options: - Use proportional fonts - Default number of posts displayed - Timestamp format - Relative timestamps - Display user avatars - Avatar image height - Enable image caching - Hide replies in timelines - Show toot stats in byline - Compose options: - Completion style for mentions and tags - Enable custom emoji - Display toot being replied to - Set default reply visibility - Nofitication options: - Display user's profile note in follow requests - Group notifications *** Commands and variables index An index of all user-facing commands and custom variables is available here: [[file:mastodon-index.org][mastodon-index.org]]. You can also hit =?= in any =mastodon.el= buffer to see the available bindings, or run =M-X= (upper-case =X=) to view all commands in the buffer with completion, and call one. *** Packages related to =mastodon.el= **** Alternative timeline layout The incomparable Nicholas Rougier has written an alternative timeline layout for =mastodon.el=. The repo is at [[https://github.com/rougier/mastodon-alt][mastodon-alt]]. **** Org links, archive search [[https://codeberg.org/chrmoe/toot-suite][toot-suite]] implements an org link type for fediverse posts, and also provides a way to browse an offline archive of your account. **** Mastodon hydra A user made a hydra for handling basic =mastodon.el= commands. It's available at https://holgerschurig.github.io/en/emacs-mastodon-hydra/. **** Narrow to timeline item A simple code snippet to enable narrowing to current item in timelines: http://takeonrules.com/2024/10/31/hacking-on-mastodon-emacs-package-to-narrow-viewing/ **** Sachac's config goodies The incomparable sachac has a bunch of =mastodon.el= extensions and goodies in their literate config, available here: https://sachachua.com/dotemacs/index.html#mastodon. *** Live-updating timelines: =mastodon-async-mode= (code taken from [[https://github.com/alexjgriffith/mastodon-future.el][mastodon-future]].) Works for federated, local, and home timelines and for notifications. It's a little touchy, one thing to avoid is trying to load a timeline more than once at a time. It can go off the rails a bit, but it's still pretty cool. The current maintainer of =mastodon.el= is unable to debug or improve this feature. To enable, it, add =(require 'mastodon-async)= to your =init.el=. Then you can view a timeline with one of the commands that begin with =mastodon-async--stream-=. *** Translating toots You can translate toots with =mastodon-toot--translate-toot-text= (=a= in a timeline). At the moment this requires [[https://codeberg.org/martianh/lingva.el][lingva.el]], a little interface I wrote to [[https://lingva.ml][lingva.ml]], to be installed to work. You could easily modify the simple function to use your Emacs translator of choice (=libretrans.el= , =google-translate=, =babel=, =go-translate=, etc.), you just need to fetch the toot's content with =(mastodon-tl--content toot)= and pass it to your translator function as its text argument. Here's what =mastodon-toot--translate-toot-text= looks like: #+begin_src emacs-lisp (defun mastodon-toot-translate-toot-text () "Translate text of toot at point. Uses `lingva.el'." (interactive) (let* ((toot (mastodon-tl--property 'item-json))) (if toot (lingva-translate nil (mastodon-tl--content toot)) (message "No toot to translate?")))) #+end_src *** Bookmarks and =mastodon.el= =mastodon.el= implements a basic bookmark record and handler. Currently, this means that you can bookmark a post item and later load it in thread view. This could be expanded to any item with an id, but probably not to things like timeline views. If you want to be able to bookmark something, open an issue and ask, as it's trivial to expand the bookmarking code. ** Dependencies Hard dependencies (should all install with =mastodon.el=): - =request= (for uploading attachments, [[https://github.com/tkf/emacs-request][emacs-request]]) - =persist= (for storing some settings across sessions, [[https://elpa.gnu.org/packages/persist.html][persist]]) - =tp.el= (for transient menus, [[https://codeberg.org/martianh/tp.el][tp.el]]) Optional dependencies (install yourself, =mastodon.el= can use them): - =emojify= to use custom emoji (else we use builtin =emoji.el=) - =mpv= and =mpv.el= for viewing videos and gifs - =lingva.el= for translating toots ** Network compatibility =mastodon.el= should work with ActivityPub servers that implement the Mastodon API. Apart from Mastodon itself, it is currently known to work with: - Pleroma ([[https://pleroma.social/][pleroma.social]]) - Akkoma ([[https://akkoma.social/][akkoma.social]]) - Gotosocial ([[https://gotosocial.org/][gotosocial.org]]) - Sharkey ([[https://joinsharkey.org][joinsharkey.org]]) It does not support the non-Mastodon API servers Misskey ([[https://misskey.io/][misskey.io]]), Firefish ([[https://joinfirefish.org/][joinfirefish.org]], formerly Calkey) and Friendica, but it should fully support displaying and interacting with posts and users on those platforms. If you attempt to use =mastodon.el= with a server and run into problems, feel free to open an issue. ** Contributing PRs, issues, feature requests, and general feedback are very welcome! If you prefer emailing patches to the process described below, feel free to send them on. Ideally they'd be patches that can be applied with =git am=, if you want to actually contribute a commit. *** Bug reports 1. =mastodon.el= has bugs, as well as lots of room for improvement. 2. I receive very little feedback, so if I don't run into the bug it often doesn't get fixed. 3. If you run into something that seems broken, first try running =mastodon.el= in emacs with no init file (i.e. =emacs -q= (instructions and code for doing this are [[https://codeberg.org/martianh/mastodon.el/issues/300][here]]) to see if it also happens independently of your own config (it probably does). 4. Else enable debug on error (=toggle-debug-on-error=), make the bug happen again, and copy the backtrace that appears. 5. Open an issue here and explain what is going on. Provide your emacs version and what kind of server your account is on. *** Fixes and features 1. Install [[https://cask.readthedocs.io/en/latest/guide/installation.html][Cask]] if you don't already have it installed 2. Create an [[https://codeberg.org/martianh/mastodon.el/issues][issue]] detailing what you'd like to do. 3. Fork the repository and create a branch off of =develop=. 4. Run the tests (with =make tests=) and ensure that your code doesn't break any of them. 5. Create a pull request (to develop) referencing the issue created in step 2. *** Coding style - This library uses an unconvential double dash (=--=) between file namespaces and function names, which contradicts normal Elisp style. This needs to be respected until the whole library is changed. - Use =aggressive-indent-mode= or similar to keep your code indented. - Single spaces end sentences in docstrings. - There's no need for a blank line after the first docstring line (one is added automatically when documentation is displayed). ** Supporting =mastodon.el= If you'd like to support continued development of =mastodon.el=, I accept donations via paypal: [[https://paypal.me/martianh][paypal.me/martianh]]. If you would prefer a different payment method, please write to me at and I can provide IBAN or other bank account details. I don't have a tech worker's income, so even a small tip would help out. ** Contributors =mastodon.el= is the work of a number of people. Some significant contributors are: - https://github.com/jdenen [original author] - http://atomized.org - https://alexjgriffith.itch.io - https://github.com/hdurer - https://codeberg.org/Red_Starfish ** Screenshots Here's a (federated) timeline: [[file:screenshot-tl.png]] Here's a notifcations view plus a compose buffer: [[file:screenshot-notifs+compose.png]] Here's a user settings transient (active values green, current server values commented and, if a boolean, underlined): [[file:screenshot-transient-1.jpg]] Here's a user profile fields transient (changed fields green, current server values commented): [[file:screenshot-transient-2.jpg]] mastodon.el/dir000066400000000000000000000012351501733112700140030ustar00rootroot00000000000000This is the file .../info/dir, which contains the topmost node of the Info hierarchy, called (dir)Top. The first time you invoke Info you start off looking at this node.  File: dir, Node: Top This is the top of the INFO tree This (the Directory node) gives a menu of major topics. Typing "q" exits, "H" lists all Info commands, "d" returns here, "h" gives a primer for first-timers, "mEmacs" visits the Emacs manual, etc. In Emacs, you can click mouse button 2 on a menu item or cross reference to select it. * Menu: Emacs * Mastodon: (mastodon). Client for fediverse services using the Mastodon API. mastodon.el/fixture/000077500000000000000000000000001501733112700147675ustar00rootroot00000000000000mastodon.el/fixture/client.plstore000066400000000000000000000012621501733112700176600ustar00rootroot00000000000000;;; public entries -*- mode: plstore -*- (("mastodon-http://other.example" :client_id "id1" :client_secret "secret1") ("mastodon-http://mastodon.example" :client_id "id2" :client_secret "secret2") ("user-test8000@mastodon.example" :username "test8000@mastodon.example" :instance "http://mastodon.example" :client_id "id2" :client_secret "secret2" :access_token "token2") ("active-user" :username "test9000@other.example" :instance "http://other.example" :client_id "id1" :client_secret "secret1" :access_token "token1") ("user-test9000@other.example" :username "test9000@other.example" :instance "http://other.example" :client_id "id1" :client_secret "secret1" :access_token "token1")) mastodon.el/fixture/empty.plstore000066400000000000000000000001371501733112700175400ustar00rootroot00000000000000;;; public entries -*- mode: plstore -*- (("ignore" :client_id "id" :client_secret "secret")) mastodon.el/lisp/000077500000000000000000000000001501733112700142505ustar00rootroot00000000000000mastodon.el/lisp/.dir-locals.el000066400000000000000000000003541501733112700167030ustar00rootroot00000000000000;;; Directory Local Variables -*- no-byte-compile: t -*- ;;; For more information see (info "(emacs) Directory Variables") ((nil . ((indent-tabs-mode . nil))) (emacs-lisp-mode . ((package-lint-main-file . "mastodon.el")))) mastodon.el/lisp/mastodon-async.el000066400000000000000000000345241501733112700175410ustar00rootroot00000000000000;;; mastodon-async.el --- Async streaming functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017 Alex J. Griffith ;; Author: Alex J. Griffith ;; Maintainer: Marty Hiatt ;; Package-Requires: ((emacs "27.1")) ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; Rework sync code so it does not mess up the async-buffer ;;; Code: (require 'mastodon-tl) (require 'json) (require 'url-http) (defvar url-http-end-of-headers) (autoload 'mastodon-auth--access-token "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-mode "mastodon") (autoload 'mastodon-notifications--timeline "mastodon-notifications") (autoload 'mastodon-tl--timeline "mastodon-tl") (defgroup mastodon-async nil "An async module for mastodon streams." :prefix "mastodon-async-" :group 'external) ;;;###autoload (define-minor-mode mastodon-async-mode "Async Mastodon." :lighter " MasA") (defvar mastodon-instance-url) (defvar mastodon-tl--enable-relative-timestamps) (defvar mastodon-tl--display-media-p) (defvar mastodon-tl--buffer-spec) (defvar-local mastodon-async--queue "" ;;"*mastodon-async-queue*" "The intermediate queue buffer name.") (defvar-local mastodon-async--buffer "" ;;"*mastodon-async-buffer*" "User facing output buffer name.") (defvar-local mastodon-async--http-buffer "" ;;"" "Buffer variable bound to http output.") (defun mastodon-async--display-http () "Display the async HTTP input buffer." (display-buffer mastodon-async--http-buffer)) (defun mastodon-async--display-buffer () "Display the async user facing buffer." (interactive) (display-buffer mastodon-async--buffer)) (defun mastodon-async--display-queue () "Display the async queue buffer." (display-buffer mastodon-async--queue)) (defun mastodon-async--stop-http () "Stop the http processs and close the async and http buffer." (interactive) (let ((inhibit-read-only t)) (stop-process (get-buffer-process mastodon-async--http-buffer)) (delete-process (get-buffer-process mastodon-async--http-buffer)) (kill-buffer mastodon-async--http-buffer) (setq mastodon-async--http-buffer "") (when (not (string= "" mastodon-async--queue)) ; error handle on kill async buffer (kill-buffer mastodon-async--queue)))) (defun mastodon-async--stream-notifications () "Open a stream of user notifications." (interactive) (mastodon-async--mastodon "user" "home" "notifications" 'mastodon-async--process-queue-string-notifications)) (defun mastodon-async--stream-home () "Open a stream of the home timeline." (interactive) (mastodon-async--mastodon "user" "home" "home" 'mastodon-async--process-queue-string)) (defun mastodon-async--stream-federated () "Open a stream of Federated." (interactive) (mastodon-async--mastodon "public" "public" "federated" 'mastodon-async--process-queue-string)) (defun mastodon-async--stream-local () "Open a stream of Local." (interactive) ;; Need to add another layer of filtering for this to work ;; apparently it the local flag does not work (mastodon-async--mastodon "public" "public?local=true" "local" 'mastodon-async--process-queue-local-string)) (defun mastodon-async--mastodon (endpoint timeline name filter) "Make sure that the previous async process has been closed. Then start an async stream at ENDPOINT filtering toots using FILTER. TIMELINE is a specific target, such as federated or home. NAME is the center portion of the buffer name for *mastodon-async-buffer and *mastodon-async-queue." (ignore timeline) ;; TODO: figure out what this is meant to be used for (let ((buffer (mastodon-async--start-process endpoint filter name))) (with-current-buffer buffer (mastodon-async--display-buffer) (goto-char (point-max)) (goto-char 1)))) (defun mastodon-async--get (url callback) "An async GET request to URL with CALLBACK." (let ((url-request-method "GET") (url-request-extra-headers `(("Authorization" . ,(concat "Bearer " (mastodon-auth--access-token)))))) (url-retrieve url callback))) (defun mastodon-async--set-http-buffer (buffer http-buffer) "Initialize for BUFFER a local variable `mastodon-async--http-buffer'. HTTP-BUFFER is the initializing value. Use this funcion if HTTP-BUFFER is not known when `mastodon-async--setup-buffer' is called." (with-current-buffer (get-buffer-create buffer) (setq mastodon-async--http-buffer http-buffer))) (defun mastodon-async--set-local-variables (buffer http-buffer buffer-name queue-name) "Set local variables for BUFFER, HTTP-BUFFER, BUFFER-NAME, and QUEUE-NAME." (with-current-buffer (get-buffer-create buffer) (let ((value mastodon-instance-url)) (make-local-variable 'mastodon-instance-url) (setq-local mastodon-instance-url value)) (setq mastodon-async--http-buffer http-buffer) (setq mastodon-async--buffer buffer-name) (setq mastodon-async--queue queue-name))) (defun mastodon-async--setup-http (http-buffer name) "Add local variables to HTTP-BUFFER. NAME is used to generate the display buffer and the queue." (let ((queue-name (concat " *mastodon-async-queue-" name "-" mastodon-instance-url "*")) (buffer-name (concat "*mastodon-async-display-" name "-" mastodon-instance-url "*"))) (mastodon-async--set-local-variables http-buffer http-buffer buffer-name queue-name))) (defun mastodon-async--setup-queue (http-buffer name) "Set up HTTP-BUFFER buffer for the async queue. NAME is used to generate the display buffer and the queue." (let ((queue-name (concat " *mastodon-async-queue-" name "-" mastodon-instance-url "*")) (buffer-name(concat "*mastodon-async-display-" name "-" mastodon-instance-url "*"))) (mastodon-async--set-local-variables queue-name http-buffer buffer-name queue-name) queue-name)) (defun mastodon-async--setup-buffer (http-buffer name endpoint) "Set up the buffer timeline like `mastodon-tl--init'. HTTP-BUFFER the name of the http-buffer, if unknown, set to... NAME is the name of the stream for the buffer name. ENDPOINT is the endpoint for the stream and timeline." (let ((queue-name (concat " *mastodon-async-queue-" name "-" mastodon-instance-url "*")) (buffer-name (concat "*mastodon-async-display-" name "-" mastodon-instance-url "*")) ;; if user stream, we need "timelines/home" not "timelines/user" ;; if notifs, we need "notifications" not "timelines/notifications" (endpoint (cond ((string= name "notifications") "notifications") ((string= name "home") "timelines/home") (t (format "timelines/%s" endpoint))))) (mastodon-async--set-local-variables buffer-name http-buffer buffer-name queue-name) ;; Similar to timeline init. (with-current-buffer (get-buffer-create buffer-name) (setq inhibit-read-only t) ; for home timeline? (make-local-variable 'mastodon-tl--enable-relative-timestamps) (make-local-variable 'mastodon-tl--display-media-p) (message (mastodon-http--api endpoint)) (if (string= name "notifications") (mastodon-notifications--timeline (mastodon-http--get-json (mastodon-http--api "notifications"))) (mastodon-tl--timeline (mastodon-http--get-json (mastodon-http--api endpoint)))) (mastodon-mode) (mastodon-tl--set-buffer-spec buffer-name endpoint (if (string= name "notifications") 'mastodon-notifications--timeline 'mastodon-tl--timeline)) (setq-local mastodon-tl--enable-relative-timestamps nil) (setq-local mastodon-tl--display-media-p t) (current-buffer)))) (defun mastodon-async--start-process (endpoint filter &optional name) "Start an async mastodon stream at ENDPOINT. Filter the toots using FILTER. NAME is used for the queue and display buffer." (let* ((stream (concat "streaming/" endpoint)) (async-queue (mastodon-async--setup-queue "" (or name stream))) (async-buffer (mastodon-async--setup-buffer "" (or name stream) endpoint)) (http-buffer (mastodon-async--get (mastodon-http--api stream) (lambda (status) (ignore status) (message "HTTP SOURCE CLOSED"))))) (mastodon-async--setup-http http-buffer (or name stream)) (mastodon-async--set-http-buffer async-buffer http-buffer) (mastodon-async--set-http-buffer async-queue http-buffer) (set-process-filter (get-buffer-process http-buffer) (mastodon-async--http-hook filter)) http-buffer)) (defun mastodon-async--http-hook (filter) "Return a lambda with a custom FILTER for processing toots." (let ((filter filter)) (lambda (proc data) (with-current-buffer (process-buffer proc) (let* ((string (mastodon-async--stream-filter (mastodon-async--http-layer proc data))) (queue-string (mastodon-async--cycle-queue string))) (when queue-string (mastodon-async--output-toot (funcall filter queue-string)))))))) (defun mastodon-async--process-queue-string (string) "Parse the output STRING of the queue buffer, returning only update events." (let ((split-strings (split-string string "\n" t))) (when split-strings ; do nothing if we get nothing; just postpones the error (let ((event-type (replace-regexp-in-string "^event: " "" (car split-strings))) (data (replace-regexp-in-string "^data: " "" (cadr split-strings)))) (when (string= "update" event-type) ;; in some casses the data is not fully formed ;; for now return nil if malformed using `ignore-errors' (ignore-errors (json-read-from-string data))))))) (defun mastodon-async--process-queue-string-notifications (string) "Parse the output STRING of the queue buffer, returning only notification events." ;; NB notification events in streams include follow requests (let* ((split-strings (split-string string "\n" t)) (event-type (replace-regexp-in-string "^event: " "" (car split-strings))) (data (replace-regexp-in-string "^data: " "" (cadr split-strings)))) (when (string= "notification" event-type) ;; in some casses the data is not fully formed ;; for now return nil if malformed using `ignore-errors' (ignore-errors (json-read-from-string data))))) (defun mastodon-async--process-queue-local-string (string) "Use STRING to limit the public endpoint to displaying local steams only." (let ((json (mastodon-async--process-queue-string string))) (when json (when (mastodon-async--account-local-p json) json)))) (defun mastodon-async--account-local-p (json) "Test JSON to see if account is local." (not (string-match-p "@" (alist-get 'acct (alist-get 'account json))))) (defun mastodon-async--output-toot (toot) "Process TOOT and prepend it to the async user-facing buffer." (if (not (bufferp (get-buffer mastodon-async--buffer))) (mastodon-async--stop-http) (when toot (with-current-buffer mastodon-async--buffer (let* ((inhibit-read-only t) (old-max (point-max)) (previous (point)) (mastodon-tl--enable-relative-timestamps t) (mastodon-tl--display-media-p t)) (goto-char (point-min)) (if (equal (buffer-name) (concat "*mastodon-async-display-notifications-" mastodon-instance-url "*")) (mastodon-notifications--timeline (list toot)) (mastodon-tl--timeline (list toot))) (if (eq previous 1) (goto-char 1) (goto-char (+ previous (- (point-max) old-max))))))))) (defun mastodon-async--cycle-queue (string) "Append the most recent STRING from http buffer to queue buffer. Then determine if a full message has been recived. If so return it. Full messages are seperated by two newlines" (with-current-buffer mastodon-async--queue (goto-char (max-char)) (insert (decode-coding-string string 'utf-8)) (goto-char 0) (let ((next (re-search-forward "\n\n" nil t))) (when next (let ((return-string (buffer-substring 1 next)) (inhibit-read-only t)) (delete-region 1 next) return-string))))) (defun mastodon-async--http-layer (proc data) "Passes PROC and DATA to ‘url-http-generic-filter’. It then processes its output." (with-current-buffer (process-buffer proc) (let ((start (max 1 (- (point-max) 2)))) (url-http-generic-filter proc data) (when (> url-http-end-of-headers start) (setq start url-http-end-of-headers)) (let ((end (- (point-max) 2))) (buffer-substring start end))))) (defun mastodon-async--stream-filter (string) "Remove comments from STRING." (replace-regexp-in-string "^:.*\n" "" string)) (provide 'mastodon-async) ;;; mastodon-async.el ends here mastodon.el/lisp/mastodon-auth.el000066400000000000000000000316641501733112700173670ustar00rootroot00000000000000;;; mastodon-auth.el --- Auth functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2021 Abhiseck Paira ;; Copyright (C) 2025 Marty Hiatt ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-auth.el supports authorizing and authenticating with Mastodon. ;;; Code: (require 'plstore) (require 'auth-source) (require 'json) (require 'url) (eval-when-compile (require 'subr-x)) ; for if-let* (autoload 'mastodon-client "mastodon-client") (autoload 'mastodon-client--active-user "mastodon-client") (autoload 'mastodon-client--form-user-from-vars "mastodon-client") (autoload 'mastodon-client--make-user-active "mastodon-client") (autoload 'mastodon-client--store-access-token "mastodon-client") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--concat-params-to-url "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-return-credential-account "mastodon") (autoload 'mastodon-client--general-read "mastodon-client") (autoload 'mastodon-client--token-file "mastodon-client") (defvar mastodon-instance-url) (defvar mastodon-client-scopes) (defvar mastodon-client-redirect-uri) (defvar mastodon-active-user) (defgroup mastodon-auth nil "Authenticate with Mastodon." :prefix "mastodon-auth-" :group 'mastodon) (defcustom mastodon-auth-use-auth-source t "Whether to use auth sources for user credentials. If t, save and read user access token in the user's auth source file (see `auth-sources'). If nil, use `mastodon-client--token-file' instead. If you change the value of this variable, call `mastodon-forget-all-logins' and log in again. If for some reason you generate a new token, you'll have to update your auth souce file manually, or at least remove the entry and authenticate again, as auth-source.el only provides unreliable tools for updating entries." :type 'boolean) (defvar mastodon-auth-source-file nil "This variable is obsolete. This variable currently serves no purpose and will be removed in the future.") (defvar mastodon-auth--token-alist nil "Alist of User access tokens keyed by instance url.") (defvar mastodon-auth--acct-alist nil "Alist of account accts (name@domain) keyed by instance url.") (defvar mastodon-auth--user-unaware " ** MASTODON.EL - NOTICE ** User variables not set: mastodon.el requires that you set both `mastodon-active-user' and `mastodon-instance-url' in your init file. Please see its documentation to understand what value it accepts by running M-x describe-variable on it or visiting our web page: https://codeberg.org/martianh/mastodon.el. ") (defun mastodon-auth--get-browser-login-url () "Return properly formed browser login url." (let ((client-id (plist-get (mastodon-client) :client_id))) (if (not client-id) (error "Failed to set up client id") (mastodon-http--concat-params-to-url (concat mastodon-instance-url "/oauth/authorize/") `(("response_type" . "code") ("redirect_uri" . ,mastodon-client-redirect-uri) ("scope" . ,mastodon-client-scopes) ("client_id" . ,client-id)))))) (defvar mastodon-auth--explanation (format " 1. A URL has been copied to your clipboard. Open this URL in a javascript capable browser and your browser will take you to your Mastodon instance's login page. 2. Login to your account (%s) and authorize \"mastodon.el\". 3. After authorization you will be presented an authorization code. Copy this code and paste it in the minibuffer prompt." (mastodon-client--form-user-from-vars))) (defun mastodon-auth--show-notice (notice buffer-name &optional ask) "Display NOTICE to user. By default NOTICE is displayed in vertical split occupying 50% of total width. The buffer name of the buffer being displayed in the window is BUFFER-NAME. When optional argument ASK is given which should be a string, use ASK as the minibuffer prompt. Return whatever user types in response to the prompt. When ASK is absent return nil." (let ((buffer (get-buffer-create buffer-name)) (inhibit-read-only t) ask-value window) (set-buffer buffer) (erase-buffer) (insert notice) (fill-region (point-min) (point-max)) (read-only-mode) (setq window (select-window (split-window (frame-root-window) nil 'below) t)) (switch-to-buffer buffer t) (when ask (setq ask-value (read-string ask)) (kill-buffer buffer) (delete-window window)) ask-value)) (defun mastodon-auth--request-authorization-code () "Ask authorization code and return it." (let ((url (mastodon-auth--get-browser-login-url)) (select-enable-clipboard t) authorization-code) (kill-new url) (message "%s" url) (setq authorization-code (mastodon-auth--show-notice mastodon-auth--explanation "*mastodon-notice*" "Authorization Code: ")) authorization-code)) (defun mastodon-auth--generate-token () "Generate access_token for the user. Return response buffer." (let ((authorization-code (mastodon-auth--request-authorization-code))) (mastodon-http--post (concat mastodon-instance-url "/oauth/token") `(("grant_type" . "authorization_code") ("client_secret" . ,(plist-get (mastodon-client) :client_secret)) ("client_id" . ,(plist-get (mastodon-client) :client_id)) ("code" . ,authorization-code) ("redirect_uri" . ,mastodon-client-redirect-uri)) nil :unauthenticated))) (defun mastodon-auth--get-token () "Make a request to generate an auth token and return JSON response." (with-current-buffer (mastodon-auth--generate-token) (goto-char (point-min)) (re-search-forward "^$" nil 'move) (let ((json-object-type 'plist) (json-key-type 'keyword) (json-array-type 'vector) (json-string (buffer-substring-no-properties (point) (point-max)))) (json-read-from-string json-string)))) (defun mastodon-auth--plstore-token-check (&optional auth-source) "Signal an error if plstore contains unencrypted access-token. If AUTH-SOURCE, and if `mastodon-auth-use-auth-source' is non-nil, return non-nil if it contains any access token. Used to help users switch to the new encrypted auth token flow." ;; FIXME: is it poss to move this plstore read to have one less read? ;; e.g. inside of `mastodon-client--active-user'? the issue is that ;; ideally we want to test "user-" entry, even if fetching "active-user" ;; entry, so we would have to re-do the plstore read functions. (when (mastodon-auth--plstore-access-token-member auth-source) (if auth-source (user-error "Auth source storage of tokens is enabled,\ but there is also an access token in your plstore.\ If you're seeing this message after updating,\ call `mastodon-forget-all-logins', and try again. If you don't want to use auth sources,\ also set `mastodon-auth-use-auth-source' to nil.\ If this message is in error, contact us on the mastodon.el repo") (user-error "Unencrypted access token in your plstore.\ If you're seeing this message after updating,\ call `mastodon-forget-all-logins', and log in again. If this message is in error, contact us on the mastodon.el repo")))) (defun mastodon-auth--plstore-access-token-member (&optional auth-source) "Return non-nil if the user entry of the plstore contains :access_token. If AUTH-SOURCE, also check if it contains :secret-access_token." (let* ((plstore (plstore-open (mastodon-client--token-file))) (name (concat "user-" (mastodon-client--form-user-from-vars))) ;; get alist like plstore.el does, so that keys will display with ;; ":secret-" prefix if encrypted: (alist (assoc name (plstore--get-merged-alist plstore)))) (if (and auth-source mastodon-auth-use-auth-source) (or (member :access_token alist) (member :secret-access_token alist)) (member :access_token alist)))) (defun mastodon-auth--access-token () "Return the access token to use with `mastodon-instance-url'. Generate/save token if none known yet." (cond (mastodon-auth--token-alist ;; user variables are known and initialised. (alist-get mastodon-instance-url mastodon-auth--token-alist nil nil #'string=)) ;; if auth source enabled, but we have an access token in plstore, ;; error out and tell user to remove plstore and start over or disable ;; auth source: ((mastodon-auth--plstore-token-check)) ((plist-get (mastodon-client--active-user) :access_token) ;; user variables need to be read from plstore active-user entry. (push (cons mastodon-instance-url (plist-get (mastodon-client--active-user) :access_token)) mastodon-auth--token-alist) (alist-get mastodon-instance-url mastodon-auth--token-alist nil nil #'string=)) ((null mastodon-active-user) ;; user not aware of 2FA-related changes and has not set ;; `mastodon-active-user'. Make user aware and error out. (mastodon-auth--show-notice mastodon-auth--user-unaware "*mastodon-notice*") (user-error "Variables not set properly")) (t ;; user access-token needs to fetched from the server and ;; stored and variables initialised. (mastodon-auth--handle-token-response (mastodon-auth--get-token))))) (defun mastodon-auth--handle-token-response (response) "Add token RESPONSE to `mastodon-auth--token-alist'. The token is returned by `mastodon-auth--get-token'. Handle any errors from the server." (pcase response ((and (let token (plist-get response :access_token)) (guard token)) (mastodon-client--make-user-active (mastodon-client--store-access-token token)) (cdar (push (cons mastodon-instance-url token) mastodon-auth--token-alist))) (`(:error ,class :error_description ,error) (error "Mastodon-auth--access-token: %s: %s" class error)) (_ (error "Unknown response from mastodon-auth--get-token!")))) (defun mastodon-auth-source-get (user host &optional token create) "Fetch an auth source token, searching by USER and HOST. If CREATE, use TOKEN or prompt for it, and save it if there is no such entry. Return a list of user, password/secret, and the item's save-function." (let* ((auth-source-creation-prompts '((secret . "%u access token: "))) (source (car (auth-source-search :host host :user user :require '(:user :secret) :secret (if token token nil) ;; "create" alone doesn't work here!: :create (if create t nil))))) (when source (let ((creds `(,(plist-get source :user) ,(auth-info-password source) ,(plist-get source :save-function)))) (when create ;; call save function: (when (functionp (nth 2 creds)) (funcall (nth 2 creds)))) creds)))) (defun mastodon-auth-source-token (url handle &optional token create) "Parse URL, search auth sources with it, user HANDLE and TOKEN. Calls `mastodon-auth-source-get', returns only the token. If CREATE, create an entry is none is found." (let ((host (url-host (url-generic-parse-url url))) (username (car (split-string handle "@")))) (nth 1 (mastodon-auth-source-get username host token create)))) (defun mastodon-auth--get-account-name () "Request user credentials and return an account name." (alist-get 'acct (mastodon-return-credential-account))) (defun mastodon-auth--get-account-id () "Request user credentials and return an account name." (alist-get 'id (mastodon-return-credential-account))) (defun mastodon-auth--user-acct () "Return a mastodon user acct name." (or (cdr (assoc mastodon-instance-url mastodon-auth--acct-alist)) (let ((acct (mastodon-auth--get-account-name))) (push (cons mastodon-instance-url acct) mastodon-auth--acct-alist) acct))) (provide 'mastodon-auth) ;;; mastodon-auth.el ends here mastodon.el/lisp/mastodon-client.el000066400000000000000000000245061501733112700177010ustar00rootroot00000000000000;;; mastodon-client.el --- Client functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2021 Abhiseck Paira ;; Copyright (C) 2025 Marty Hiatt ;; Author: Johnson Denen ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-client.el supports registering the Emacs client with your Mastodon instance. ;;; Code: (require 'plstore) (require 'json) (require 'url) (defvar mastodon-instance-url) (defvar mastodon-active-user) (defvar mastodon-auth-use-auth-source) (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-auth-source-token "mastodon-auth") (defcustom mastodon-client--token-file (concat user-emacs-directory "mastodon.plstore") "File path where Mastodon access tokens are stored." :group 'mastodon :type 'file) (defvar mastodon-client--client-details-alist nil "An alist of Client id and secrets keyed by the instance url.") (defvar mastodon-client--active-user-details-plist nil "A plist of active user details.") (defvar mastodon-client-scopes "read write follow" "Scopes to pass to oauth during registration.") (defvar mastodon-client-website "https://codeberg.org/martianh/mastodon.el" "Website of mastodon.el.") (defvar mastodon-client-redirect-uri "urn:ietf:wg:oauth:2.0:oob" "Redirect_uri as required by oauth.") (defun mastodon-client--register () "POST client to Mastodon." (mastodon-http--post (mastodon-http--api "apps") `(("client_name" . "mastodon.el") ("redirect_uris" . ,mastodon-client-redirect-uri) ("scopes" . ,mastodon-client-scopes) ("website" . ,mastodon-client-website)) nil :unauthenticated)) (defun mastodon-client--fetch () "Return JSON from `mastodon-client--register' call." (let ((buf (mastodon-client--register))) (if (not buf) (user-error "Client registration failed.\ Is `mastodon-instance-url' correct?") (with-current-buffer buf (goto-char (point-min)) (re-search-forward "^$" nil 'move) (let* ((json-object-type 'plist) (json-key-type 'keyword) (json-array-type 'vector) (json-string (buffer-substring-no-properties (point) (point-max))) (parsed (json-read-from-string json-string))) (if (eq :error (car parsed)) (error "Error: %s" (cadr parsed)) parsed)))))) (defun mastodon-client--token-file () "Return `mastodon-client--token-file'." mastodon-client--token-file) (defun mastodon-client--store () "Store client_id and client_secret in `mastodon-client--token-file'. Make `mastodon-client--fetch' call to determine client values. Return a plist of secret and non-secret key/val pairs." (let* ((plstore (plstore-open (mastodon-client--token-file))) (client (mastodon-client--fetch)) (secrets `( :client_id ,(plist-get client :client_id) :client_secret ,(plist-get client :client_secret))) (sans-secrets (dolist (x '(:client_id :client_secret) client) (cl-remf client x))) ;; alexgriffith reported seeing ellipses in the saved output ;; which indicate some output truncating. Nothing in ;; `plstore-save' seems to ensure this cannot happen so let's do ;; that ourselves: (print-length nil) (print-level nil)) (plstore-put plstore (concat "mastodon-" mastodon-instance-url) sans-secrets secrets) ;; FIXME: breaks tests: prompts for gpg passphrase (plstore-save plstore) (plstore-close plstore) (append secrets sans-secrets))) (defun mastodon-client--remove-key-from-plstore (plstore) "Remove KEY from PLSTORE." (cdr plstore)) ;; Actually it returns a plist with client-details if such details are ;; already stored in mastodon.plstore (defun mastodon-client--read () "Retrieve client_id and client_secret from `mastodon-client--token-file'." (let* ((plstore (plstore-open (mastodon-client--token-file))) (mastodon (plstore-get plstore (concat "mastodon-" mastodon-instance-url)))) (plstore-close plstore) (mastodon-client--remove-key-from-plstore mastodon))) (defun mastodon-client--general-read (key) "Retrieve the plstore item keyed by KEY. Return plist without the KEY." (let* ((plstore (plstore-open (mastodon-client--token-file))) (plstore-item (plstore-get plstore key))) (plstore-close plstore) (mastodon-client--remove-key-from-plstore plstore-item))) (defun mastodon-client--make-user-details-plist () "Make a plist with current user details. Return it." `( :username ,(mastodon-client--form-user-from-vars) :instance ,mastodon-instance-url :client_id ,(plist-get (mastodon-client) :client_id) :client_secret ,(plist-get (mastodon-client) :client_secret))) (defun mastodon-client--store-access-token (token) "Save TOKEN as :access_token encrypted in the plstore. Return the plist after the operation. If `mastodon-auth-use-auth-source', encrypt it in auth source file." (let* ((user-details (mastodon-client--make-user-details-plist)) (plstore (plstore-open (mastodon-client--token-file))) (username (mastodon-client--form-user-from-vars)) (key (concat "user-" username)) (secrets `( :client_id ,(plist-get user-details :client_id) :client_secret ,(plist-get user-details :client_secret))) (sans-secrets (dolist (x '(:client_id :client_secret) user-details) (cl-remf user-details x))) (print-length nil) (print-level nil)) (if mastodon-auth-use-auth-source ;; auth-source: (progn (mastodon-auth-source-token mastodon-instance-url username token :create) (plstore-put plstore key sans-secrets secrets)) ;; plstore encrypted: (plstore-put plstore key sans-secrets (append secrets `(:access_token ,token)))) (plstore-save plstore) (plstore-close plstore) (cdr (plstore-get plstore key)))) (defun mastodon-client--make-user-active (user-details) "USER-DETAILS is a plist consisting of user details. Save it to plstore under key \"active-user\". If `mastodon-auth-use-auth-source' is non-nil, fetch the access token from the user's auth source file and add it to the active user entry. Return a plist of secret and non-secret key/val pairs." (let* ((plstore (plstore-open (mastodon-client--token-file))) (handle (plist-get user-details :username)) (token (if mastodon-auth-use-auth-source (mastodon-auth-source-token mastodon-instance-url handle) (plist-get user-details :access_token))) (secrets `( :access_token ,token :client_id ,(plist-get user-details :client_id) :client_secret ,(plist-get user-details :client_secret))) (deets (copy-sequence user-details)) (sans-secrets (dolist (x '(:client_id :client_secret :access_token) deets) (cl-remf deets x))) (print-length nil) (print-level nil)) (plstore-put plstore "active-user" sans-secrets secrets) (plstore-save plstore) (plstore-close plstore) (append secrets sans-secrets))) (defun mastodon-client--form-user-from-vars () "Create a username from user variable. Return that username. Username in the form user@instance.com is formed from the variables `mastodon-instance-url' and `mastodon-active-user'." (concat mastodon-active-user "@" (url-host (url-generic-parse-url mastodon-instance-url)))) (defun mastodon-client--make-current-user-active () "Make the user specified by user variables active user. Return the details (plist)." (let* ((username (mastodon-client--form-user-from-vars)) (user-plist (mastodon-client--general-read (concat "user-" username)))) (when user-plist (mastodon-client--make-user-active user-plist) user-plist))) (defun mastodon-client--current-user-active-p () "Return user-details if the current user is active. Otherwise return nil." (let ((username (mastodon-client--form-user-from-vars)) (user-details (mastodon-client--general-read "active-user"))) (when (and user-details (string= (plist-get user-details :username) username)) user-details))) (defun mastodon-client--active-user () "Return the details of the currently active user. Details is a plist." (or mastodon-client--active-user-details-plist (setq mastodon-client--active-user-details-plist (or (mastodon-client--current-user-active-p) (mastodon-client--make-current-user-active))))) (defun mastodon-client () "Return variable client secrets to use for `mastodon-instance-url'. If `mastodon-client--client-details-alist' is nil, read plist from `mastodon-client--token-file'. Fetch and store plist if `mastodon-client--read' returns nil. Return a plist." (let ((client-details (cdr (assoc mastodon-instance-url mastodon-client--client-details-alist)))) (or client-details (let ((client-details (or (mastodon-client--read) (mastodon-client--store)))) (push (cons mastodon-instance-url client-details) mastodon-client--client-details-alist) client-details)))) (provide 'mastodon-client) ;;; mastodon-client.el ends here mastodon.el/lisp/mastodon-discover.el000066400000000000000000000133321501733112700202340ustar00rootroot00000000000000;;; mastodon-discover.el --- Use Mastodon.el with discover.el -*- lexical-binding: t -*- ;; Copyright (C) 2019 Johnson Denen ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; This adds optional functionality that can be used if the dicover package ;; is present. ;; ;; See the README file for how to use this. ;;; Code: (declare-function discover-add-context-menu "discover") (autoload 'mastodon-kill-window "mastodon") (defun mastodon-discover () "Plug Mastodon functionality into `discover'." (interactive) (when (require 'discover nil :noerror) (discover-add-context-menu :bind "?" :mode 'mastodon-mode :mode-hook 'mastodon-mode-hook :context-menu '(mastodon (description "Mastodon feed viewer") (actions ("Toots" ("A" "View profile of author" mastodon-profile-get-toot-author) ("b" "Boost" mastodon-toot--boost) ("f" "Favourite" mastodon-toot--favourite) ("c" "Toggle hidden text (CW)" mastodon-tl-toggle-spoiler-text-in-toot) ("k" "Bookmark toot" mastodon-toot-toggle-bookmark) ("v" "Vote on poll" mastodon-tl-poll-vote) ("n" "Next" mastodon-tl-goto-next-item) ("p" "Prev" mastodon-tl-goto-prev-item) ("TAB" "Next link item" mastodon-tl-next-tab-item) ("S-TAB" "Prev link item" mastodon-tl-previous-tab-item) ;; NB: (when (require 'mpv etc. calls don't work here ("C-RET" "Play media" mastodon-tl-mpv-play-video-at-point) ("t" "New toot" mastodon-toot) ("r" "Reply" mastodon-toot-reply) ("C" "Copy toot URL" mastodon-toot-copy-toot-url) ("o" "Open toot URL" mastodon-toot-browse-toot-url) ("d" "Delete (your) toot" mastodon-toot-delete-toot) ("D" "Delete and redraft (your) toot" mastodon-toot-delete-toot) ("e" "Edit (your) toot" mastodon-toot-edit-toot-at-point) ("E" "View edits of (your) toot" mastodon-toot-view-toot-edits) ("i" "Pin/Unpin (your) toot" mastodon-toot-pin-toot-toggle) ("P" "View user profile" mastodon-profile-show-user) ("a" "Translate toot at point" mastodon-toot-translate-toot-text) ("T" "View thread" mastodon-tl-thread) ("v" "Vote on poll" mastodon-tl-poll-vote) ("," "View toot's favouriters" mastodon-toot--list-toot-favouriters) ("." "View toot's boosters" mastodon-toot--list-toot-boosters) ("/" "Switch buffers" mastodon-switch-to-buffer)) ("Views" ("h/?" "View mode help/keybindings" describe-mode) ("#" "Tag search" mastodon-tl-get-tag-timeline) ("\"" "List followed tags" mastodon-tl-list-followed-tags) ("'" "Followed tags timeline" mastodon-tl-followed-tags-timeline) ("F" "Federated" mastodon-tl-get-federated-timeline) ("H" "Home" mastodon-tl-get-home-timeline) ("L" "Local" mastodon-tl-get-local-timeline) ("N" "Notifications" mastodon-notifications-get) ("@" "Notifications with mentions" mastodon-notifications-get-mentions) ("g/u" "Update timeline" mastodon-tl-update) ("s" "Search" mastodon-search-query) ("O" "Jump to your profile" mastodon-profile-my-profile) ("U" "Update your profile note" mastodon-profile-update-user-profile-note) ("K" "View bookmarks" mastodon-profile-view-bookmarks) ("V" "View favourites" mastodon-profile-view-favourites) ("R" "View follow requests" mastodon-profile--view-follow-requests) ("G" "View follow suggestions" mastodon-tl--get-follow-suggestions) ("I" "View filters" mastodon-tl--view-filters) ("X" "View lists" mastodon-tl--view-lists) ("S" "View scheduled toots" mastodon-tl--view-scheduled-toots) (";" "View instance description" mastodon-tl--view-instance-description)) ("Users" ("W" "Follow" mastodon-tl-follow-user) ("C-S-W" "Unfollow" mastodon-tl-unfollow-user) ("M" "Mute" mastodon-tl-mute-user) ("C-S-M" "Unmute" mastodon-tl-unmute-user) ("B" "Block" mastodon-tl-block-user) ("C-S-B" "Unblock" mastodon-tl-unblock-user)) ("Images" ;; RET errors here also :/ ("/i" "Load full image in browser" 'shr-browse-image) ("r" "rotate" 'image-rotate) ("+" "zoom in" 'image-increase-size) ("-" "zoom out" 'image-decrease-size) ("u" "copy URL" 'shr-maybe-probe-and-copy-url)) ("Profile view" ("C-c C-c" "Cycle profile views" mastodon-profile-account-view-cycle)) ("Quit" ("q" "Quit mastodon and bury buffer." kill-this-buffer) ("Q" "Quit mastodon buffer and kill window." mastodon--kill-window) ("M-C-q" "Quit mastodon and kill all buffers." mastodon-kill-all-buffers))))))) (provide 'mastodon-discover) ;;; mastodon-discover.el ends here mastodon.el/lisp/mastodon-http.el000066400000000000000000000442771501733112700174110ustar00rootroot00000000000000;;; mastodon-http.el --- HTTP request/response functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-http.el provides HTTP request/response functions. ;;; Code: (require 'json) (require 'url) (require 'url-http) (require 'shr) (defvar mastodon-instance-url) (defvar mastodon-toot--media-attachment-ids) (defvar mastodon-toot--media-attachment-filenames) (autoload 'mastodon-auth--access-token "mastodon-auth") (autoload 'mastodon-toot--update-status-fields "mastodon-toot") (autoload 'url-insert "url-handlers") (defvar mastodon-http--api-version "v1") (defconst mastodon-http--timeout 15 "HTTP request timeout, in seconds. Has no effect on Emacs < 26.1.") (defun mastodon-http--api (endpoint &optional version) "Return Mastodon API URL for ENDPOINT. Optionally specify VERSION in format vX." (concat mastodon-instance-url "/api/" (or version mastodon-http--api-version) "/" endpoint)) (defun mastodon-http--api-v2 (endpoint) "Return Mastodon API v2 URL for ENDPOINT." (mastodon-http--api endpoint "v2")) (defun mastodon-http--url-retrieve-synchronously (url &optional silent) "Retrieve URL asynchronously. This is a thin abstraction over the system `url-retrieve-synchronously'. Depending on which version of this is available we will call it with or without a timeout. SILENT means don't message." (if (< (cdr (func-arity 'url-retrieve-synchronously)) 4) (url-retrieve-synchronously url) (url-retrieve-synchronously url (or silent nil) nil mastodon-http--timeout))) (defun mastodon-http--triage (response success) "Determine if RESPONSE was successful. Call SUCCESS on RESPONSE if successful. Message status and JSON error from RESPONSE if unsuccessful." (let ((status (with-current-buffer response ;; FIXME: breaks tests, as url-http-end-of-headers not set (url-http-parse-response)))) (if (and (>= 200 status) (<= status 299)) ;; (string-prefix-p "2" (number-to-string status)) (funcall success response) (if (= 404 status) (message "Error %s: page not found" status) (let ((json-response (with-current-buffer response (mastodon-http--process-json)))) (message "Error %s: %s" status (alist-get 'error json-response))))))) (defun mastodon-http--read-file-as-string (filename &optional url) "Read a file FILENAME as a string. Used to generate image preview. URL means FILENAME is a URL." (with-temp-buffer (if url (url-insert-file-contents filename) (insert-file-contents filename)) (string-to-unibyte (buffer-string)))) (defmacro mastodon-http--authorized-request (method body &optional unauthenticated-p) "Make a METHOD type request using BODY, with Mastodon authorization. Unless UNAUTHENTICATED-P is non-nil." (declare (debug 'body) (indent 1)) `(let ((url-request-method ,method) (url-request-extra-headers (unless ,unauthenticated-p (list (cons "Authorization" (concat "Bearer " (mastodon-auth--access-token))))))) ,body)) (defun mastodon-http--build-params-string (params) "Build a request parameters string from parameters alist PARAMS." ;; (url-build-query-string args nil)) ;; url-build-query-string adds 'nil' for empty params so lets stick with our ;; own: (mapconcat (lambda (p) (when (cdr p) ; only when value (concat (url-hexify-string (car p)) "=" (url-hexify-string (cdr p))))) params "&")) (defun mastodon-http--build-array-params-alist (param-str array) "Return parameters alist using PARAM-STR and ARRAY param values. Used for API form data parameters that take an array." (cl-loop for x in array collect (cons param-str x))) (defun mastodon-http--concat-params-to-url (url params) "Build a query string with PARAMS and concat to URL." (if params (concat url "?" (mastodon-http--build-params-string params)) url)) (defun mastodon-http--post (url &optional params headers unauthenticated-p json) "POST synchronously to URL, optionally with PARAMS and HEADERS. Authorization header is included by default unless UNAUTHENTICATED-P is non-nil. If JSON is :json, encode PARAMS as JSON for the request data. If it is :raw, just use the plain params." ;; NB: raw is used by `mastodon-tl-unfilter-user-languages'; not sure if ;; there's a way around it? (mastodon-http--authorized-request "POST" (let* ((url-request-data (when params (cond ((eq json :json) (json-encode params)) ((eq json :raw) params) (t (mastodon-http--build-params-string params))))) (url-request-extra-headers (append url-request-extra-headers ; auth set in macro (if json '(("Content-Type" . "application/json") ("Accept" . "application/json")) (unless (assoc "Content-Type" headers) ; pleroma compat: '(("Content-Type" . "application/x-www-form-urlencoded")))) headers))) (with-temp-buffer (mastodon-http--url-retrieve-synchronously url))) unauthenticated-p)) (defun mastodon-http--get (url &optional params silent) "Make synchronous GET request to URL. PARAMS is an alist of any extra parameters to send with the request. SILENT means don't message." (mastodon-http--authorized-request "GET" ;; url-request-data doesn't seem to work with GET requests?: (let ((url (mastodon-http--concat-params-to-url url params))) (mastodon-http--url-retrieve-synchronously url silent)))) (defun mastodon-http--get-response (url &optional params no-headers silent vector) "Make synchronous GET request to URL. Return JSON and response headers. PARAMS is an alist of any extra parameters to send with the request. SILENT means don't message. NO-HEADERS means don't collect http response headers. VECTOR means return json arrays as vectors." (let ((buf (mastodon-http--get url params silent))) ;; --get can return nil if instance unresponsive: (if (not buf) (user-error "Looks like the server response borked. \ Is your instance up?") (with-current-buffer buf (mastodon-http--process-response no-headers vector))))) (defun mastodon-http--get-json (url &optional params silent vector) "Return only JSON data from URL request. PARAMS is an alist of any extra parameters to send with the request. SILENT means don't message. VECTOR means return json arrays as vectors." (car (mastodon-http--get-response url params :no-headers silent vector))) (defun mastodon-http--process-json () "Return only JSON data from async URL request. Callback to `mastodon-http--get-json-async', usually `mastodon-tl--init*', is run on the result." (car (mastodon-http--process-response :no-headers))) (defun mastodon-http--render-html-err (string) "Render STRING as HTML in a temp buffer. STRING should be a HTML for a 404 errror." (with-temp-buffer (insert string) (shr-render-buffer (current-buffer)) (view-mode))) ; for 'q' to kill buffer and window ;; (error ""))) ; stop subsequent processing (defun mastodon-http--process-response (&optional no-headers vector) "Process http response. Return a cons of JSON list and http response headers. If NO-HEADERS is non-nil, just return the JSON. VECTOR means return json arrays as vectors. Callback to `mastodon-http--get-response-async', usually `mastodon-tl--init*', is run on the result." ;; view raw response: ;; (switch-to-buffer (current-buffer)) (let ((headers (unless no-headers (mastodon-http--process-headers)))) (goto-char (point-min)) (re-search-forward "^$" nil 'move) (let ((json-array-type (if vector 'vector 'list)) (json-string (string-trim-right (decode-coding-string (buffer-substring-no-properties (point) (point-max)) 'utf-8)))) (kill-buffer) (cond ((or (string-empty-p json-string) (null json-string)) nil) ;; if we get html, just render it and error: ;; ideally we should handle the status code in here rather than ;; this crappy hack? ((string-prefix-p "\n<" json-string) ; html hack ;; NB: in this case, process-response returns t!: (mastodon-http--render-html-err json-string) nil) ;; return nil instead of t ;; if no json or html, maybe we have a plain string error message ;; (misskey does this, but there are probably better ways to do ;; this): ((not (or (string-prefix-p "\n{" json-string) (string-prefix-p "\n[" json-string))) (error "%s" json-string)) (t ;; instance may return error in JSON e.g. ((error . "Record not ;; found")) for a null endpoint. but we don't error here because ;; sometimes we just want to check for such an error in an ;; if/cond. `(,(json-read-from-string json-string) . ,headers)))))) (defun mastodon-http--process-headers () "Return an alist of http response headers." (goto-char (point-min)) (let* ((head-str (buffer-substring-no-properties (point-min) (re-search-forward "^$" nil 'move))) (head-list (split-string head-str "\n"))) (mapcar (lambda (x) (let ((list (split-string x ": "))) (cons (car list) (cadr list)))) head-list))) (defun mastodon-http--delete (url &optional params) "Make DELETE request to URL. PARAMS is an alist of any extra parameters to send with the request." ;; url-request-data only works with POST requests? (let ((url (mastodon-http--concat-params-to-url url params))) (mastodon-http--authorized-request "DELETE" (with-temp-buffer (mastodon-http--url-retrieve-synchronously url))))) (defun mastodon-http--put (url &optional params headers) "Make PUT request to URL. PARAMS is an alist of any extra parameters to send with the request. HEADERS is an alist of any extra headers to send with the request." (mastodon-http--authorized-request "PUT" (let ((url-request-data (when params (mastodon-http--build-params-string params))) (url-request-extra-headers (append url-request-extra-headers ; auth set in macro (unless (assoc "Content-Type" headers) ; pleroma compat: '(("Content-Type" . "application/x-www-form-urlencoded"))) headers))) (with-temp-buffer (mastodon-http--url-retrieve-synchronously url))))) ;; profile update functions (defun mastodon-http--patch-json (url &optional params) "Make synchronous PATCH request to URL. Return JSON response. Optionally specify the PARAMS to send." (with-current-buffer (mastodon-http--patch url params) (mastodon-http--process-json))) (defun mastodon-http--patch (url &optional params json) "Make synchronous PATCH request to URL. Optionally specify the PARAMS to send. JSON means send params as JSON data." (mastodon-http--authorized-request "PATCH" ;; NB: unlike POST, PATCHing only works if we use query params! ;; so here, unless JSON arg, we use query params and do not set ;; `url-request-data'. this is probably an error, i don't understand it. (let* ((url-request-data (when (and params json) (encode-coding-string (json-encode params) 'utf-8))) ;; (mastodon-http--build-params-string params)))) (url (if (not json) (mastodon-http--concat-params-to-url url params) url)) (headers (when json '(("Content-Type" . "application/json") ("Accept" . "application/json")))) (url-request-extra-headers (append url-request-extra-headers headers))) (mastodon-http--url-retrieve-synchronously url)))) ;; Asynchronous functions (defun mastodon-http--get-async (url &optional params callback &rest cbargs) "Make GET request to URL. Pass response buffer to CALLBACK function with args CBARGS. PARAMS is an alist of any extra parameters to send with the request." (let ((url (mastodon-http--concat-params-to-url url params))) (mastodon-http--authorized-request "GET" (url-retrieve url callback cbargs)))) (defun mastodon-http--get-response-async (url &optional params callback &rest cbargs) "Make GET request to URL. Call CALLBACK with http response and CBARGS. PARAMS is an alist of any extra parameters to send with the request." (mastodon-http--get-async url params (lambda (status) (when status ; for flakey servers (apply callback (mastodon-http--process-response) cbargs))))) (defun mastodon-http--get-json-async (url &optional params callback &rest cbargs) "Make GET request to URL. Call CALLBACK with json-list and CBARGS. PARAMS is an alist of any extra parameters to send with the request." (mastodon-http--get-async url params (lambda (status) (when status ;; only when we actually get sth? (apply callback (mastodon-http--process-json) cbargs))))) (defun mastodon-http--post-async (url params _headers &optional callback &rest cbargs) "POST asynchronously to URL with PARAMS and HEADERS. Then run function CALLBACK with arguements CBARGS. Authorization header is included by default unless UNAUTHENTICED-P is non-nil." (mastodon-http--authorized-request "POST" (let ((url-request-data (when params (mastodon-http--build-params-string params)))) (with-temp-buffer (url-retrieve url callback cbargs))))) (defun mastodon-http--get-cb-data (status) "Return data using `json-read' after a successful async request. If STATUS includes an error, emit a message describing it and return nil." (let* ((buf (current-buffer)) (data (with-temp-buffer (url-insert buf) (goto-char (point-min)) (json-read)))) (if-let* ((error-thrown (plist-get status :error))) ;; not necessarily a user error, but we want its functionality: (user-error "%S %s" error-thrown (alist-get 'error data)) data))) (defun mastodon-http--post-media-callback (status file caption buffer) "Callback function called after posting FILE as an attachment with CAPTION. The toot is being composed in BUFFER. See `url-retrieve' for STATUS." (unwind-protect (when-let* ((data (mastodon-http--get-cb-data status))) (with-current-buffer buffer (let ((id (alist-get 'id data))) ;; update ids: (if (not mastodon-toot--media-attachment-ids) ;; add first id: (push id mastodon-toot--media-attachment-ids) ;; add new id to end of list to preserve order: (push id (cdr (last mastodon-toot--media-attachment-ids)))) ;; pleroma, PUT the description: ;; this is how the mangane akkoma web client does it ;; and it seems easier than the other options! (when (and caption (not (string= caption (alist-get 'description data)))) (let ((url (mastodon-http--api (format "media/%s" id)))) ;; (message "PUTting image description") (mastodon-http--put url `(("description" . ,caption))))) (message "Uploading %s... (done)" file) (mastodon-toot--update-status-fields)))) (kill-buffer (current-buffer)))) (defun mastodon-http--post-media-prep-file (filename) "Return the request data to upload FILENAME." (with-temp-buffer (set-buffer-multibyte nil) (insert-file-contents-literally filename) (let ((boundary (buffer-hash))) (goto-char (point-min)) (insert "--" boundary "\r\n" (format "Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n\r\n" (file-name-nondirectory filename))) (goto-char (point-max)) (insert "\r\n" "--" boundary "--" "\r\n") `(,boundary . ,(buffer-substring-no-properties (point-min) (point-max)))))) (defun mastodon-http--post-media-attachment (url filename caption) "Make POST request to upload FILENAME with CAPTION to the server's media URL. The upload is asynchronous. On succeeding, `mastodon-toot--media-attachment-ids' is set to the id(s) of the item uploaded, and `mastodon-toot--update-status-fields' is run." (mastodon-http--authorized-request "POST" (let* ((data (mastodon-http--post-media-prep-file filename)) (url-request-extra-headers (append url-request-extra-headers ; auth set in macro `(("Content-Type" . ,(format "multipart/form-data; boundary=%s" (car data)))))) (url-request-data (cdr data)) (params `(("description" . ,caption))) (url (mastodon-http--concat-params-to-url url params))) (url-retrieve url #'mastodon-http--post-media-callback `(,filename ,caption ,(current-buffer)))))) (provide 'mastodon-http) ;;; mastodon-http.el ends here mastodon.el/lisp/mastodon-inspect.el000066400000000000000000000110521501733112700200600ustar00rootroot00000000000000;;; mastodon-inspect.el --- Client for Mastodon -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; Some tools to help inspect / debug mastodon.el ;;; Code: (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-http--get-search-json "mastodon-http") (autoload 'mastodon-media--inline-images "mastodon-media") (autoload 'mastodon-mode "mastodon") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--property "mastodon-tl") (autoload 'mastodon-tl--toot "mastodon-tl") (defvar mastodon-instance-url) (defgroup mastodon-inspect nil "Tools to help inspect toots." :prefix "mastodon-inspect-" :group 'external) (defun mastodon-inspect--dump-json-in-buffer (name json) "Buffer NAME is opened and JSON in printed into it." (switch-to-buffer-other-window name) (erase-buffer) (let ((print-level nil) (print-length nil)) (insert (pp json t))) (goto-char (point-min)) (emacs-lisp-mode) (message "success")) (defun mastodon-inspect--toot () "Find next toot and dump its meta data into new buffer." (interactive) (mastodon-inspect--dump-json-in-buffer (concat "*mastodon-inspect-toot-" (mastodon-tl--as-string (mastodon-tl--property 'item-id)) "*") (mastodon-tl--property 'item-json))) (defun mastodon-inspect--download-single-toot (item-id) "Download the toot/status represented by ITEM-ID." (mastodon-http--get-json (mastodon-http--api (concat "statuses/" item-id)))) (defun mastodon-inspect--view-single-toot (item-id) "View the toot/status represented by ITEM-ID." (interactive "s Toot ID: ") (let ((buffer (get-buffer-create (concat "*mastodon-status-" item-id "*")))) (with-current-buffer buffer (let ((toot (mastodon-inspect--download-single-toot item-id ))) (mastodon-tl--toot toot) (goto-char (point-min)) (while (search-forward "\n\n\n | " nil t) (replace-match "\n | ")) (mastodon-media--inline-images (point-min) (point-max)))) (switch-to-buffer-other-window buffer) (mastodon-mode))) (defun mastodon-inspect--view-single-toot-source (item-id) "View the ess source of a toot/status represented by ITEM-ID." (interactive "s Toot ID: ") (mastodon-inspect--dump-json-in-buffer (concat "*mastodon-status-raw-" item-id "*") (mastodon-inspect--download-single-toot item-id))) (defvar mastodon-inspect--search-query-accounts-result) (defvar mastodon-inspect--single-account-json) (defvar mastodon-inspect--search-query-full-result) (defvar mastodon-inspect--search-result-tags) (defun mastodon-inspect--get-search-result (query) "Inspect function for a search result for QUERY." (interactive) (setq mastodon-inspect--search-query-full-result (append ; convert vector to list (mastodon-http--get-search-json (format "%s/api/v2/search" mastodon-instance-url) query) nil)) (setq mastodon-inspect--search-result-tags (append (cdr (caddr mastodon-inspect--search-query-full-result)) nil))) (defun mastodon-inspect--get-search-account (query) "Return JSON for a single account after search QUERY." (interactive) (setq mastodon-inspect--search-query-accounts-result (append ; convert vector to list (mastodon-http--get-search-json (format "%s/api/v1/accounts/search" mastodon-instance-url) query) nil)) (setq mastodon-inspect--single-account-json (car mastodon-inspect--search-query-accounts-result))) (provide 'mastodon-inspect) ;;; mastodon-inspect.el ends here mastodon.el/lisp/mastodon-iso.el000066400000000000000000000144331501733112700172130ustar00rootroot00000000000000;;; mastodon-iso.el --- ISO language code lists for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2022 Marty Hiatt ;; Author: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;;; Code: ;; via ;; https://github.com/VyrCossont/mastodon/blob/0836f4a656d5486784cadfd7d0cd717bb67ede4c/app/helpers/languages_helper.rb ;; and ;; https://github.com/Shinmera/language-codes/blob/master/data/iso-639-3.lisp (defvar mastodon-iso-639-1 '(("Abkhazian" . "ab") ("Afar" . "aa") ("Afrikaans" . "af") ("Akan" . "ak") ("Albanian" . "sq") ("Amharic" . "am") ("Arabic" . "ar") ("Aragonese" . "an") ("Armenian" . "hy") ("Assamese" . "as") ("Avaric" . "av") ("Avestan" . "ae") ("Aymara" . "ay") ("Azerbaijani" . "az") ("Bambara" . "bm") ("Bashkir" . "ba") ("Basque" . "eu") ("Belarusian" . "be") ("Bengali" . "bn") ("Bihari languages" . "bh") ("Bislama" . "bi") ("Bosnian" . "bs") ("Breton" . "br") ("Bulgarian" . "bg") ("Burmese" . "my") ("Central Khmer" . "km") ("Chamorro" . "ch") ("Chechen" . "ce") ("Chinese" . "zh") ("Chuvash" . "cv") ("Cornish" . "kw") ("Corsican" . "co") ("Cree" . "cr") ("Croatian" . "hr") ("Czech" . "cs") ("Danish" . "da") ("Dzongkha" . "dz") ("English" . "en") ("Esperanto" . "eo") ("Estonian" . "et") ("Ewe" . "ee") ("Faroese" . "fo") ("Fijian" . "fj") ("Finnish" . "fi") ("Dutch" . "nl") ("French" . "fr") ("Fulah" . "ff") ("Galician" . "gl") ("Ganda" . "lg") ("Georgian" . "ka") ("German" . "de") ("Greek" . "el") ("Guarani" . "gn") ("Gujarati" . "gu") ("Haitian" . "ht") ("Hausa" . "ha") ("Hebrew" . "he") ("Herero" . "hz") ("Hindi" . "hi") ("Hiri Motu" . "ho") ("Hungarian" . "hu") ("Icelandic" . "is") ("Ido" . "io") ("Igbo" . "ig") ("Indonesian" . "id") ("Interlingua" . "ia") ("Inuktitut" . "iu") ("Inupiaq" . "ik") ("Irish" . "ga") ("Italian" . "it") ("Japanese" . "ja") ("Japanese" . "jp") ("Javanese" . "jv") ("Kalaallisut" . "kl") ("Kannada" . "kn") ("Kanuri" . "kr") ("Kashmiri" . "ks") ("Kazakh" . "kk") ("Kikuyu" . "ki") ("Kinyarwanda" . "rw") ("Komi" . "kv") ("Kongo" . "kg") ("Korean" . "ko") ("Kurdish" . "ku") ("Kuanyama" . "kj") ("Kirghiz" . "ky") ("Lao" . "lo") ("Latin" . "la") ("Latvian" . "lv") ("Limburgan" . "li") ("Lingala" . "ln") ("Lithuanian" . "lt") ("Luba-Katanga" . "lu") ("Luxembourgish" . "lb") ("Macedonian" . "mk") ("Malagasy" . "mg") ("Malay" . "ms") ("Malayalam" . "ml") ("Divehi" . "dv") ("Maltese" . "mt") ("Manx" . "gv") ("Maori" . "mi") ("Marathi" . "mr") ("Marshallese" . "mh") ("Mongolian" . "mn") ("Nauru" . "na") ("Navajo" . "nv") ("Ndonga" . "ng") ("Nepali" . "ne") ("Ndebele, North" . "nd") ("Northern Sami" . "se") ("Norwegian" . "no") ("BokmĂĽl, Norwegian" . "nb") ("Chichewa" . "ny") ("Norwegian Nynorsk" . "nn") ("Interlingue" . "ie") ("Occitan" . "oc") ("Ojibwa" . "oj") ("Church Slavic" . "cu") ("Oriya" . "or") ("Oromo" . "om") ("Ossetian" . "os") ("Pali" . "pi") ("Persian" . "fa") ("Polish" . "pl") ("Portuguese" . "pt") ("Panjabi" . "pa") ("Pushto" . "ps") ("Quechua" . "qu") ("Romanian" . "ro") ("Romansh" . "rm") ("Rundi" . "rn") ("Russian" . "ru") ("Samoan" . "sm") ("Sango" . "sg") ("Sanskrit" . "sa") ("Sardinian" . "sc") ("Gaelic" . "gd") ("Serbian" . "sr") ("Shona" . "sn") ("Sichuan Yi" . "ii") ("Sindhi" . "sd") ("Sinhala" . "si") ("Slovak" . "sk") ("Slovenian" . "sl") ("Somali" . "so") ("Sotho, Southern" . "st") ("Ndebele, South" . "nr") ("Spanish" . "es") ("Sundanese" . "su") ("Swahili" . "sw") ("Swati" . "ss") ("Swedish" . "sv") ("Tagalog" . "tl") ("Tahitian" . "ty") ("Tajik" . "tg") ("Tamil" . "ta") ("Tatar" . "tt") ("Telugu" . "te") ("Thai" . "th") ("Tibetan" . "bo") ("Tigrinya" . "ti") ("Tonga (Tonga Islands)" . "to") ("Tsonga" . "ts") ("Tswana" . "tn") ("Turkish" . "tr") ("Turkmen" . "tk") ("Twi" . "tw") ("Ukrainian" . "uk") ("Urdu" . "ur") ("Uighur" . "ug") ("Uzbek" . "uz") ("Catalan" . "ca") ("Venda" . "ve") ("Vietnamese" . "vi") ("VolapĂźk" . "vo") ("Walloon" . "wa") ("Welsh" . "cy") ("Western Frisian" . "fy") ("Wolof" . "wo") ("Xhosa" . "xh") ("Yiddish" . "yi") ("Yoruba" . "yo") ("Zhuang" . "za") ("Zulu" . "zu"))) ;; web UI doesn't respect these for now (defvar mastodon-iso-639-regional '(("es-AR" "EspaĂąol (Argentina)") ("es-MX" "EspaĂąol (MĂŠxico)") ("pt-BR" "PortuguĂŞs (Brasil)") ("pt-PT" "PortuguĂŞs (Portugal)") ("sr-Latn" "Srpski (latinica)") ("zh-CN" "简体中文") ("zh-HK" "繁體中文(香港)") ("zh-TW" "繁體中文(臺灣)"))) (defvar mastodon-iso-639-3 '(("ast" "Asturian" "Asturianu") ("ckb" "Sorani (Kurdish)" "سۆرانی") ("jbo" "Lojban" "la .lojban.") ("kab" "Kabyle" "Taqbaylit") ("kmr" "Kurmanji (Kurdish)" "KurmancĂŽ") ("ldn" "LĂĄadan" "LĂĄadan") ("lfn" "Lingua Franca Nova" "lingua franca nova") ("tok" "Toki Pona" "toki pona") ("zba" "Balaibalan" "باليبلن") ("zgh" "Standard Moroccan Tamazight" "ⵜⴰⵎⴰⵣⵉⵖⵜ"))) (provide 'mastodon-iso) ;;; mastodon-iso.el ends here mastodon.el/lisp/mastodon-media.el000066400000000000000000000720571501733112700175060ustar00rootroot00000000000000;;; mastodon-media.el --- Functions for inlining Mastodon media -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-media.el provides functions for inlining media. ;; Known bug gnutls -12 when trying to access images on some systems. ;; It looks like their may be a version mismatch between the encryption ;; required by the server and client. ;;; Code: (require 'url-cache) (require 'mm-decode) (require 'image-mode) (autoload 'mastodon-tl--propertize-img-str-or-url "mastodon-tl") (autoload 'mastodon-tl--image-trans-check "mastodon-tl") (autoload 'mastodon-image-mode "mastodon-tl") (defvar url-show-status) (defvar mastodon-tl--shr-image-map-replacement) (defgroup mastodon-media nil "Inline Mastadon media." :prefix "mastodon-media-" :group 'mastodon) (defcustom mastodon-media--avatar-height 20 "Height of the user avatar images (if shown)." :type 'integer) (defcustom mastodon-media--preview-max-height 250 "Max height of any media attachment preview to be shown in timelines." :type 'integer) (defcustom mastodon-media--enable-image-caching nil "Whether images should be cached." :type 'boolean) (defcustom mastodon-media--hide-sensitive-media t "Whether media marked as sensitive should be hidden." :type 'boolean) (defvar mastodon-media--generic-avatar-data (base64-decode-string "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA B3RJTUUH4QUIFCg2lVD1hwAAABZ0RVh0Q29tbWVudABHZW5lcmljIGF2YXRhcsyCnMsAAAcGSURB VHja7dzdT1J/HAfwcw7EQzMKW0pGRMK4qdRZbdrs6aIRbt506V1b/AV1U2td9l9UXnmhW6vgwuko SbcOD/a0RB4CCRCRg0AIR4Hz8LvgN2cKCMI5wOH7uXBuugO+eH8+fM/3HIFpmoZAVVYIIABYAAtg ASyABbAAAcACWAALYAEsgAUIABbAAlgAC2ABLEAAsAAWwAJYAAtgAQKAxUjxm+R50DRN0zRFUf+8 kggCwzAMwwDrfyOSJGmattlsdrvd5XLlcrndnyoUir6+vpGRkZMnT/J4vIarwY26MaTAZLVap6en fT7f9vY2QRA7Ozv/vJJ8vkgk4vP5XV1dWq1Wq9VKpdIGkjUGi6IoFEWnp6ddLlcymSRJsvzv83g8 kUikUCi0Wq1Opzt16lS7YBEE8ebNG6PRiGHYoUwHyW7cuPHo0SOlUsl9LIIgXrx4Ybfb//79e7Qj CIXC3t7ex48fX7lyhctYBSkURTOZTC3H4fF4SqXy6dOnLHuxh0VR1PPnz2uX2uv17Nmzy5cvc21R StP0q1ev7HZ7XaQgCCJJ0u/3T0xMBINBrmGhKGo0Go88p0p5Wa1Wg8GQSqW4g0XT9NTUFIZhdT9y Npudn59nLVwIO7FyuVxVrRIqr1AoZDab2QkXG1hTU1PJZJKhg5MkOT8/HwqFuIBF07TP52MoVrvh YqLHG4BlsVi2t7cZfQiSJB0OBwudyDiWzWYjCILpR1lZWeECltPp3LeXwEQFg8FoNNryWPl8noVp ws6jgG1lgAWwuI914cIFPp/xnX6ZTCYSiVoeq7+/n4U/Q61Wy+Xylse6desWC8kaGBiQSCQtjyWR SGQyGY/HY+4hpFJpV1cXRwa8TqdjtBOHh4fVajVHsLRarVKpZChcUqn07t27LPQgS1gSiUSn04nF 4rofGYbh4eHhgYEBTq2ztFrtyMhI3ZtRo9GMjY2xEyv2sCQSiV6vV6lUdWzGzs7O8fHxwcFBDq7g 5XL5kydPent76+LV2dmp1+vv37/P5gqe7SvSDofj5cuXteydwjAslUr1ev2DBw9YPt1pwL0ODodj YmLCYrEcYZ8LhmGNRjM+Ps5yphqGBUFQKBQyGo0mk2l1dTWfz5MkSVFUPp8/+GSEQiEMw8eOHYNh uLu7e2hoaGxsjM05tbfYvpkNx/FQKBSJRCAI6unpwTBsbW0tmUwWbtc6mCMEQSAIOn78+Llz586f P9/T05PL5QKBgEKh4GyyCkZfvnwJhULhcHhzczOTyRRuYMtms/l8PpPJZDKZnZ2dvc9HIBCIxeIT J04Uvil87ejoOH36tEwm02g0V69evXjxIkewCkZer/fr16+/f/+OxWKlrvQQBEEQxL7dYQRBhEJh 0fNwBEHEYrFMJlOpVP39/RqNhgU1prAKTDMzMy6XKxqNJhIJptY+CHLmzBmZTHbp0qXbt2+rVKpW wtplWl5eDofDTF803Bs0tVrNKFmdsXAcn52dnZ2dDQaD7DAVJRsdHb1z507dT93rhoXj+MrKytzc 3NLSEnNNVyHZ2bNnr127NjQ0NDg4WEey+mDhOP7u3bu5ubkyI5z9iMnl8nv37o2OjgoEgmbBisVi r1+/ttlsjQ1UmYg9fPiwo6OjwVg4jn///v3Dhw/Ly8vNEKiiXhKJpK+vT6fT1d6S/FqkUBSdnJz0 +/1QsxZFUclkEkXReDxOkuT169dr8TpisnAcN5lMb9++ZfP+11pKIBAUdgpv3rx55BGGtIMUBEG5 XM7tdhsMhoWFhb3/S8UsVitK1curaqzV1dX379+3nNQ+r42NjSPsPlaH5fP5mnyiV+Ll9XonJyfD 4XC1XkhVDTgzM/Pz50+oxSubzX779u3z58/VLneQyqUMBsOnT5+acz1V7XoiHo9//PjRZDKl0+n6 Y3k8HrPZ3Gxr9Fq81tfXl5aWAoFA5cO+IqxIJFLYSIA4VARBuN3uxcXFyoc9v5IGNJvNVquVAw14 sBktFkt3d7dUKq3k5BGpJFYLCwucacCizZhIJCoJF3JorBYXF//8+QNxtAiCKFwiqKRvkEPnOoqi HGvAfeFKJBIVTnqkfKx+/PjBsbleKlwej6cmLI/H43A4OByr3XClUimn03louMphra2teb1eqA0q m836fL6tra0jYkUiEb/fz8k3waLhikQiXq+3/NtiSayNjY1fv35BbVP5fN7pdG5tbR0Fy+12c360 Hxzz5a8KI6V6EMMwzo/2fZ2YTqej0WgqlSoVLqRUDwYCAajNiqKoYDBYphOLY8ViscItVG1VJEmu r6+XeU8sjhWPxzc3N9sNiyAIDMOqS1YbDqwKx1YRrFQqxc7HJDRnpdPpUuEqgoVhWL0+i6hFz6tL ja3iM4u1zw1qwhlfJihI0bfCNhxYe4NSqg3/A862hQAbrdtHAAAAAElFTkSuQmCC") "The PNG data for a generic 100x100 avatar.") (defvar mastodon-media--generic-broken-image-data (base64-decode-string "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA B3RJTUUH4QUIFQUVFt+0LQAAABZ0RVh0Q29tbWVudABHZW5lcmljIGF2YXRhcsyCnMsAAAdoSURB VHja7d1NSFRrAIfx//iB6ZDSMJYVkWEk0ceYFUkkhhQlEUhEg0FlC1eBoRTUwlbRok0TgRQURZAE FgpjJmFajpK4kggxpXHRQEGWUJZizpy7uPfC5eKiV+dD5zw/mN05jrxnnjnfcxyWZVkCMKc0SXI4 HIwEMIcUhgAgEIBAAAIBCAQgEIBAAAIBCAQgEAAEAhAIQCAAgQAEAhAIQCAAgQA2kBaNP8Jt7ViM onErOWsQgEAAAgEIBCAQgEAAAgEIBCAQgEAAEAhAIACBAAQCEAhAIACBAAQCEAhAIAAIBCAQgEAA AgEIBCAQgEAAAgEIBACBAAQCEAhAIACBAAQCEAhAIACBAAQCgEAAAgEIBCAQgECAxSyNIYitz58/ a3BwUIODgxoZGVEoFFIoFNK3b980NTWlX79+SZIyMzOVlZWlVatWae3atSooKJDH49HOnTvl8XiU ksJ3WSI4LMuyHA7Hgv6IZVmM5D8mJyf1/PlzdXZ2qrOzU8FgcMF/0+126+DBg6qqqlJFRYXS0vhe +6MP9wI/1wQSJeFwWH6/X01NTWpra9PU1FTM3isvL0/nz5/XuXPntHz5ciqIcSCy/v50L+hlV+Pj 49a1a9esdevWLXgMTV8ul8u6c+eOFYlELMwtKmNNIOa+fv1qXbp0yXI6nXEP4/+v0tJS6+PHj9RA IIk3PT1tXb161crOzk54GP995ebmWt3d3RRBIInj9/utgoKCRRXGf18ZGRmW3++niigHwk56PHf4 Yiw9PV0dHR0qLy9nD52jWAQylxUrVmhgYEAbN24kkCgsM84+JZmJiQmdPn1akUiEweBE4eL/NsrN zVVZWZlKSkpUWFioTZs2yeVyKTs7W7Ozs5qYmNDExITev3+v/v5+9fX1qb+/f8FjevPmTdXW1rIG IZDFN9gbNmyQ1+uV1+uVx+MxXlAjIyNqbGzU3bt39fPnz3n9vytXrlQwGJTT6SQQThQm/ohIamqq VVlZaXV1dUXtPT98+GCVlZXNe7n4fD6OYnGYN7GDnZ6ebtXU1FhjY2Mxed9IJGLV19fPa7kUFRUR CIEkZrAdDod15syZmIXxf7W1tfNaNqOjowSygBdHseZh7969GhgY0IMHD5Sfnx+X97xx44Z2795t PF93dzcLjMO88TvHcP/+ffX19WnXrl3xXVApKbp9+7bxfSFv3rxhwRFI7B07dkxDQ0Oqrq5O2P9Q XFysffv2Gc0zOjrKwiOQ2Hv69Kny8vIS/n8cP37caPqxsTEWHoHYa//HxPfv3xk0ArGP1atXG03/ 7z3vIBBbyM3NNZo+KyuLQSMQ+5icnDSaPicnh0EjEPsYHh42mp7L3gnEVnp6eoymLyoqYtAIxD4e PXpkNP3+/fsZtAXgcvclpL29XUeOHPnj6Z1Op8bHx7Vs2TJ7fri5o9A+ZmZmdPHiRaN5vF6vbeNg E8tmGhoaNDQ0ZPTteeHCBQaOQJLfkydPdP36daN5Tp48qc2bNzN47IMkt9evX+vw4cOanp7+43ly cnI0PDy8KK4dYx8EMRMIBHT06FGjOCTJ5/PZPg42sZJce3u7Dh06pB8/fhjNV11dndBL8tnEYhMr 5lpaWuT1evX792+j+YqLixUIBLj+ik2s5NXc3KwTJ04Yx5Gfn69nz54RB5tYyaupqUlVVVWanZ01 ms/tdqujo4P9DgJJXg8fPtSpU6cUDoeN43j58qUKCwsZRAJJTvfu3dPZs2eNf0/X7Xarq6tL27dv ZxAJJDn5fD7V1NQYx7FmzRq9evVK27ZtYxAJJDk1NDSorq7O+ChgQUGBent7tWXLFgYxxniecILU 1dXJ5/MZz7d161a9ePHC+N50sAZZMq5cuTKvOEpKStTT00McccSJwji7devWvJ7bceDAAbW2ttr6 cQbGH26eD7K0BAIBlZeXG5/nqKioUEtLizIyMhhEAklOX758kcfj0adPn4zXHG1tbcSRoEDYB4mT y5cvG8exZ88etba2Egf7IMnt7du32rFjh9G5jvz8fA0MDBj/UBxYgyw5jY2NRnGkpqaqubmZOBYB AomxmZkZPX782Gie+vr6uD9/BGxiJURvb69KS0v/ePrMzEyFQiG5XC4Gj02s5BcIBIymr6ysJA42 sezj3bt3RtObPv8DBLKkBYNBo+m5r4NAbCUUChlNv379egaNQOzD9FdJ2P8gEFsxfQQaFyMuLhzm jfUAG45tOBw2fhY6ojP2rEGWwiqdONjEAggEIBCAQAACAUAgAIEA0cIPx8UYJ1FZgwAEAhAIAAIB CAQgEIBAAAIBFiNOFMaY6V1tnFhkDQIQCEAgAIEABAKAQAACAQgEIBCAQAACAQgEIBCAQABIXO4e c1y+zhoEIBCAQAAQCEAgAIEABAIQCEAgAIEABAIQCEAgAAgEIBCAQAACAQgEIBCAQAACAQgEAIEA BAIQCEAgAIEABAIsJVH58WqHw8FIgjUIQCAACAQgEIBAAAIBCAQgEIBAAAIBCAQgEAAEAhAIQCBA fKRJkmVZjAQwh78A6vCRWJE8K+8AAAAASUVORK5CYII=") "The PNG data for a generic 200x200 \"broken image\" view.") (defvar mastodon-media--sensitive-image-data (base64-decode-string "iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAA6npUWHRSYXcgcHJvZmlsZSB0eXBl IGV4aWYAAHjajVHbjcQwCPx3FVcCr/hRjvOSroMtfyc2Ts4rrXRIxjAQPEzC8fo9w89lkiXYknIs MRLMihWpCDJ1W5tnsuabbaPGMx7uggBS3NrTIo4fwBGz58X7efSPQSPgimh5CrU6vs746gMlfw5y Bsr9Zdr9Ax+k4oxsXi2WnKbV9o1my88xTRKXyMngTSilWBBnIUvQc7+InpuUNmjpgt7AyEergJMc ykrwqtZZ6nVMK+7YvAU0skMMb9qFJ/xKUADz4g9VusX8q82j0Rf7z1rhDfqGdxgpcULlAAABhWlD Q1BJQ0MgcHJvZmlsZQAAeJx9kT1Iw0AcxV8/tKJVBzuIOGSoTnZREd1qFYpQIdQKrTqYXPohNGlI UlwcBdeCgx+LVQcXZ10dXAVB8APE2cFJ0UVK/F9SaBHjwXE/3t173L0D/PUyU81gHFA1y0gnE0I2 tyKEXtGJIHowgz6JmfqsKKbgOb7u4ePrXYxneZ/7c/QqeZMBPoE4znTDIl4nntq0dM77xBFWkhTi c+Ixgy5I/Mh12eU3zkWH/TwzYmTSc8QRYqHYxnIbs5KhEk8SRxVVo3x/1mWF8xZntVxlzXvyF4bz 2vIS12kOI4kFLEKEABlVbKAMCzFaNVJMpGk/4eEfcvwiuWRybYCRYx4VqJAcP/gf/O7WLEyMu0nh BNDxYtsfI0BoF2jUbPv72LYbJ0DgGbjSWv5KHZj+JL3W0qJHQP82cHHd0uQ94HIHGHzSJUNypABN f6EAvJ/RN+WAgVuge9XtrbmP0wcgQ12lboCDQ2C0SNlrHu/uau/t3zPN/n4Ag31yra/8+kkAAA14 aVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBN cENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEv IiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0 dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3Jp cHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94 YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAv c1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2Vs ZW1lbnRzLzEuMS8iCiAgICB4bWxuczpHSU1QPSJodHRwOi8vd3d3LmdpbXAub3JnL3htcC8iCiAg ICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnht cD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgeG1wTU06RG9jdW1lbnRJRD0iZ2lt cDpkb2NpZDpnaW1wOmYyYjU4MzUwLTc3ZWMtNDAxNC1hNDVlLTE1N2QyZjljOGM5NyIKICAgeG1w TU06SW5zdGFuY2VJRD0ieG1wLmlpZDowOTk5MzZhMi1jOGM5LTRkYTAtYTI0Yi02YTM1MmUyNmNi NmUiCiAgIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDphMDliYmZhMi03MzA2LTQ3 NWQtOGExNC05YzA3ZTE1NmFiMTYiCiAgIGRjOkZvcm1hdD0iaW1hZ2UvcG5nIgogICBHSU1QOkFQ ST0iMi4wIgogICBHSU1QOlBsYXRmb3JtPSJMaW51eCIKICAgR0lNUDpUaW1lU3RhbXA9IjE3MTc1 MDI1MDIzNDQ1NzIiCiAgIEdJTVA6VmVyc2lvbj0iMi4xMC4zNCIKICAgdGlmZjpPcmllbnRhdGlv bj0iMSIKICAgeG1wOkNyZWF0b3JUb29sPSJHSU1QIDIuMTAiCiAgIHhtcDpNZXRhZGF0YURhdGU9 IjIwMjQ6MDY6MDRUMTQ6MDE6NDArMDI6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDI0OjA2OjA0 VDE0OjAxOjQwKzAyOjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8 cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8i CiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NTRmM2I5NDktOTlkMS00Mzk2LWI2NzIt Y2ZkYjRlZWFiYTA1IgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHaW1wIDIuMTAgKExpbnV4 KSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyNC0wNi0wNFQxNDowMTo0MiswMjowMCIvPgogICAgPC9y ZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpS REY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg ICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz6w3d0DAAAABmJLR0QA/wD/AP+gvaeTAAAA CXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH6AYEDAEq/VtQSwAAABl0RVh0Q29tbWVudABDcmVh dGVkIHdpdGggR0lNUFeBDhcAAAtOSURBVHja7dvbT5R3Hsfxz5xwhtOsjkgFGQZRTlFOCjJSkpVe YFltmpZNuo3t9qLdu/4Pa/+L3jVZL9pEU2q7aGirEkUkWw+IM5SpOELxgICcUXjmsBfKBOooo2Za 3H2/Ei+EeRif74/3c5gnmj47fDgqAHGZGQFAIACBAAQCEAhAIACBAAQCEAhAIAAIBCAQgEAAAgEI BCAQgEAAAgEIBCAQAAQCEAhAIACBAAQCEAhAIACBAAQCgEAAAgEIBCAQgEAAAgEIBCAQgEAAAgFA IACBAAQCEAhAIACBAAQCEAhAIAAIBCAQgEAAAgEIBCAQgEAAAgEIBCAQAAQCEAhAIACBAAQCEAjw CrIm+w0ikYiCwaB8Pp8GBweVk5OjoqIiOZ1OjY+Pq6qq6g8fwuLiov7d1qbFhQUdOHhQaampSd0O BBLT2dmp8+fP6/3331dzc7Oi0ahu3bql1tZW7dixY00MIRqNKhQKyWyxyPQ7bAcCkSSNjY3p7Nmz anzjDeXl5cW+7vF41NLSos7OzjUxhHXr1umvLS2/23bgHkSSNDk5+ahC65Md5uTkaMuyaID/u0BS UlIkSd0XLmhubu6J73vr6tb8gO7fv69gMMhvyhqfV7LeN6mBZGdnKysrS1NTU2r95htNTU29Uou9 uLiojo4OhUIhfvPX8LyS+b6mzw4fjibzHz8+Pq6jx45pfGxMqamp+suBA9pWWCiTKf5tbSgU0vXr 1+X3+3Xnzh1t2bJFFRUV8ng8kqSBgQF99dVXkiTXxo36xyefaGBgQD6/X0ODg8rNzVVdXZ1ycnJW DNDn86nv55/1YH5excXF8nq9slgsikajmpiY0PDwsPx+v5qbm5WZmamJiQmdOHlSN4NB2Ww2paWn a252Vk1NTSovL3/qdsePH1dfX5/WrVsnm82mSCSiAwcOqKCgQF1dXeru7pbNZpNhGCoqKlJzc3NC +53oJW0gEND1gQGNjY4qNzdXZWVlKikpic07EolocHBQgUBAwWBQVqtVnoICFW3frry8vNjrnnfO q80rWeub6Pu+KMu+ffv+mcxAUlNTVVxUpLm5Od2+fVt+n0/z8/PavHlz7BJsiWEYOnXqlDwej6qr q1VVVaUHDx+qtbVVm7KztdHlktPp1I4dOxQIBDQ5OSmTySSXy6Vd1dWqrKxU8OZNnTl9Wrt27Yrd +5w5c0YOh0NvNDYqPz9f7e3tqq6ultVq1YMHD+T3+3X+/HmNjIyourpaDodDDodDmzZt0uXLl/XO O+9o//79qq+vV3Z2tiQ9dbvCwkLl5ubqypUrcjqd+vjjj+VyuSRJW7ZsUVlZmX755Rft3r1bDQ0N MpvNCe33avoDAXV0dKi2pkY1u3erpLRU83Nz8vv9Ki4ultVq1eLiotrb2zU8PKz6+nrt3btXZWVl j87wra0yDENut1tms/m557zavJK1vom875q9xFqSkZGhgwcP6t1335XdbtelS5f0xRdf6N69eyte 19PTo/T0dL322muyWCxKSUlRdVWVcnJzdaKtTXNzc7JYLHK5XMrKypLNZtOePXvkdrtjw6qsqJBh GLo3Oho7e3R3dys9I0MWi0UbN25UQ0ODotFoLOC6ujo1NDQ8eXp9fDQ1m81xw4+3ndVqVWFhocrL y3Xv3r0V914mk0l2u102m01VVVWyWCwJ7/ezDA0N6djRo3pz/365XC6ZzWb9yenU66+/rg8++EB2 u12SdOHCBQUCATU1NWnDhg2yWCxKTU1VbW2tGhsb1d3drf/89NOjI+dzznm1eSVrfRN53zX7Me+K Es1mFRcXKycnR6dOnZLP59OXX36pjz76SJmZmVpYWNCPP/6ocDisjo6OuD/jRjConY+fnVgsltiQ l3M4HLEj/NLrsrOz9e3x42ppaZHb7Y77cNJifbFRPG276upqXb16VYFAQLW1tbGvDwwMaE9dXezs 9rz7/VuRSEQ//PCDamtrtWHDhqf+O2dmZnTu3DnVeb1KS0t74vuVlZU6e/asTp86pfKdO2OvSXTO q0nW+ibb7xbI8rNJc3OzZDLJd+2aenp61NDQoKmpKYXDYR06dEhut1vRaDR2lF86SjztviXeUT8S DscG/fbbb+vosWM6cuSIvF6v9uzZo9QkP/XevHmztm/fro6ODu0sL5fDblcoFNJPFy/qb++9F3vd y+735OSk7t69q5plEcaz9AFJZkZG3O/b7Xbt2LlTly9d0vT0dNyInjXn1SRrfV/pj3mnp6cViUSe +LrNZtNer1eS1HvtWuz6dPkATCaTzGZz7E8iw5MUG/ryZy8ul0t///BD7WtsVFdXl/515IhmZmaS OliTyaSamhoZhqEbAwOxS6GqykrZbLYV1+Uvs98PHz58tJAJzmd2dvbpB6/09IT3L96cnyWZ6/vK BjI4NPTEfcaStMeLsbQo6x5fJ48uu7Z8EeHHR5blv4ThcFh2u13eujodOnRI42Njunr1asI/MxJ9 sQ/68vLylJObq3OdnVpcXNTFixe1bdu2Fa952f1eugQZGxt75uucTuejA1Jvb+yXNd6zBEnKzMx8 oTk/a17JXN+XXac/LJBUh0NdXV1xP58ef7ygFRUVkqQN69fLnZ+vzs7OuEe5Bw8famJiYsXfw3FO s4uLiyuOMAsLC7p0+XLs+263W6VlZU9su3SmW37aX7qJfjA/v+KsuPw18bZbvv1er1fjY2P6/vvv lZ+fH7uGXvK8+/1b69ev1+acHHV2dsZ9znT37l3Nzs4qIyND9fX1mpmZkc/ni3updu3aNf15374V l1eJznm1eSVrfRNdpzUZSHp6uvr6+vTtd99pZGREoVBIhmFoeHhYJ0+eVEVFhUpLS2M38fubmhQO h/XN8eMaGRlROBxWKBTSnTt3dDMYjB0FZ2ZmNPzrrzIMY8WlkmEYGhwcjIURjUZltVp15vRp3b59 W5FIRGNjYxq8eVNFRUUrbiBHRkZig10KOjMzU66NG+Xz+zU/P6/Z2Vn19vauut1yHo9HTqdTPT09 KikpifvhRaL7HfdDAotFb+7fL5vNphMnTmh0dFSRSESGYSgYDOr+/ftKf3yW9nq9qqysVFtbm65c uRL7JRwdHVXbiRPaXVOj2pqaFTf2ic55tXkla30TWac1+6BwYWFBP/f3y5mZqVu3bmngxg3NTE/L 4/GoqLhYWwsKYvUvL7+3t1d9fX2ypaRoa0GBSkpKlJWVJUnq6+vT119/vWKbt956S263W59//nns 5xmGIYfDoU8//VTt7e1KS0tTf3+/srKytGvXLuXm5kqSgsGg2tralJKSonA4LMMw5PF4dPDgwUeX LuPjOt/ZqZGREe0sL1d1VZVSUlJW3W45n9+vyYkJ1dfXP/N+7Vn7vZqJiQn19vaqv79fZrNZhYWF Ki0tfeJ5QCQS0dDQkAKBgG7cuCFJ2rp1q4qKimLPQF50ziaT6anzSub6JvK+a/ZJejIsfQKy/IYP /ztzXkvra30VFy7RjwTxas55La0v/+UWIBCAQAACAQgEIBCAQAACAQgEIBAABAIQCEAgAIEABAIQ CEAgAIEABAIQCAACAQgEIBCAQAACAQgEIBCAQAACAUAgAIEABAIQCEAgAIEABAIQCEAgAIEAIBCA QAACAQgEIBCAQAACAQgEIBAABAIQCEAgAIEABAIQCEAgAIEABAIQCAACAQgEIBCAQAACAQgEIBCA QAACAUAgAIEABAIQCEAgAIEABAIQCEAgAIEAIBCAQAACAQgEIBCAQAACAQgEIBAABAIQCEAgAIEA BAIQCEAgAIEABAIQCAACAQgEIBCAQAACAQgEIBCAQAACAQgEAIEABAIQCEAgAIEABAIQCEAgAIEA IBCAQICX9F8/bNVInwJ8BAAAAABJRU5ErkJggg==") "The PNG data for a sensitive image placeholder.") (defun mastodon-media--process-image-response (status-plist url marker image-options region-length) "Callback function processing the url retrieve response for URL. STATUS-PLIST is the usual plist of status events as per `url-retrieve'. IMAGE-OPTIONS are the precomputed options to apply to the image. MARKER is the marker to where the response should be visible. REGION-LENGTH is the length of the region that should be replaced with the image." (when (marker-buffer marker) ; if buffer hasn't been killed (let ((url-buffer (current-buffer)) (is-error-response-p (eq :error (car status-plist)))) (let* ((data (unless is-error-response-p (goto-char (point-min)) (and (search-forward "\n\n" nil t) (buffer-substring (point) (point-max))))) (image (when data (apply #'create-image data ;; inbuilt scaling in 27.1: (when (version< emacs-version "27.1") (when image-options 'imagemagick)) t image-options)))) (when mastodon-media--enable-image-caching (unless (url-is-cached url) ; cache if not already cached (url-store-in-cache url-buffer))) (with-current-buffer (marker-buffer marker) ;; Save narrowing in our buffer (let ((inhibit-read-only t)) (save-restriction (widen) (put-text-property marker (+ marker region-length) 'media-state 'loaded) (when image ;; We only set the image to display if we could load ;; it; we already have set a default image when we ;; added the tag. (mastodon-media--display-image-or-sensitive marker region-length image)) ;; We are done with the marker; release it: (set-marker marker nil))) (kill-buffer url-buffer)))))) (defun mastodon-media--display-image-or-sensitive (marker region-length image) "Display image using display property, or add sensitive mask. MARKER, REGION-LENGTH and IMAGE are from `mastodon-media--process-image-response'. If the image is marked sensitive, the image is stored in image-data prop so it can be toggled." (if (or (not (eq t (get-text-property marker 'sensitive))) (not mastodon-media--hide-sensitive-media)) ;; display image (put-text-property marker (+ marker region-length) 'display image) ;; display sensitive placeholder and save image data as prop: (add-text-properties marker (+ marker region-length) `(display ;; (image :type png :data ,mastodon-media--sensitive-image-data) ,(create-image mastodon-media--sensitive-image-data nil t) sensitive-state hidden image-data ,image)))) (defvar mastodon-media--attachments nil "A list attachment details for full sized image view buffer. The first element is the URL of the image displayed, followed by plists of details of all of a toot's attachments.") (defun mastodon-media--process-full-sized-image-response (status-plist url attachments &optional prev-buf) ;; FIXME: refactor this with but not into ;; `mastodon-media--process-image-response'. "Callback function processing the `url-retrieve' response for URL. URL is a full-sized image URL attached to a timeline image. STATUS-PLIST is a plist of status events as per `url-retrieve'." (if-let* ((error-response (plist-get status-plist :error))) (user-error "error in loading image: %S" error-response) (when mastodon-media--enable-image-caching (unless (url-is-cached url) ;; cache if not already cached (url-store-in-cache))) ;; thanks to rahguzar for this idea: ;; https://codeberg.org/martianh/mastodon.el/issues/540 (let* ((handle (mm-dissect-buffer t)) (image (mm-get-image handle)) (str (image-property image :data)) (buf "*masto-image*")) (with-current-buffer (get-buffer-create buf) (let ((inhibit-read-only t)) (erase-buffer) (insert-image image str) (special-mode) ; prevent image-mode loop bug (mastodon-image-mode) ;; for our keymap (goto-char (point-min)) (image-transform-fit-both) ;; set image metadata for view cycling: (setq-local mastodon-media--attachments (cons url attachments)))) ;; switch to buf if not already viewing it: (unless (equal buf prev-buf) (switch-to-buffer-other-window buf)) ;; display bindings if multiple images: (when (< 1 (length (cdr mastodon-media--attachments))) (message (substitute-command-keys "\\`.'/\\`>'/\\`' to cycle images")))))) (defun mastodon-media--image-or-cached (url process-fun args) "Fetch URL from cache or fro host. Call PROCESS-FUN on it with ARGS, a list of callback args as specified by `url-retrieve'." (if (and mastodon-media--enable-image-caching (url-is-cached url)) ;; if cached, decompress and use: (with-current-buffer (url-fetch-from-cache url) (set-buffer-multibyte nil) (goto-char (point-min)) (zlib-decompress-region (goto-char (search-forward "\n\n")) (point-max)) (apply process-fun args)) ;; no status-plist arg from cache ;; fetch as usual and process-image-response will cache it: ;; cbargs fun will be called with status-plist by url-retrieve: (url-retrieve url process-fun (cdr args)))) (defun mastodon-media--load-image-from-url (url media-type start region-length) "Take a URL and MEDIA-TYPE and load the image asynchronously. MEDIA-TYPE is a symbol and either `avatar' or `media-link'. START is the position where we start loading the image. REGION-LENGTH is the range from start to propertize." (let ((image-options (when (mastodon-tl--image-trans-check) (cond ((eq media-type 'avatar) `(:height ,mastodon-media--avatar-height)) ((eq media-type 'media-link) `(:max-height ,mastodon-media--preview-max-height))))) (buffer (current-buffer)) (marker (copy-marker start)) (url-show-status nil)) ; stop url.el from spamming us about connecting (condition-case nil ;; catch errors in url-retrieve to not break our caller (mastodon-media--image-or-cached url #'mastodon-media--process-image-response (list nil url marker image-options region-length)) (error (with-current-buffer buffer ;; TODO: Add retries (put-text-property marker (+ marker region-length) 'media-state 'loading-failed) :loading-failed))))) (defun mastodon-media--select-next-media-line (end-pos) "Find coordinates of the next media to load before END-POS. Returns the list of (`start' . `end', `media-symbol') points of that line and string found or nil no more media links were found." (let ((next-pos (point))) (while (and (setq next-pos (next-single-property-change next-pos 'media-state)) (or (not (eq 'needs-loading (get-text-property next-pos 'media-state))) (null (get-text-property next-pos 'media-url)) (null (get-text-property next-pos 'media-type)))) ;; do nothing - the loop will proceed ) (when (and next-pos (< next-pos end-pos)) (let ((media-type (get-text-property next-pos 'media-type))) (cond ((eq media-type 'avatar) ; avatars are one character (list next-pos (+ next-pos 1) 'avatar)) ((eq media-type 'media-link) ; media links are 5 characters: [img] (list next-pos (+ next-pos 5) 'media-link))))))) (defun mastodon-media--valid-link-p (link) "Check if LINK is valid. Checks to make sure the missing string has not been returned." (and link (> (length link) 8) (or (string= "http://" (substring link 0 7)) (string= "https://" (substring link 0 8))))) (defun mastodon-media--inline-images (search-start search-end) "Find all `Media_Links:' in the range from SEARCH-START to SEARCH-END. Replace them with the referenced image." (save-excursion (goto-char search-start) (let (line-details) (while (setq line-details (mastodon-media--select-next-media-line search-end)) (let* ((start (car line-details)) (end (cadr line-details)) (media-type (cadr (cdr line-details))) (type (get-text-property start 'mastodon-media-type)) (image-url (get-text-property start 'media-url))) (if (not (mastodon-media--valid-link-p image-url)) ;; mark it at least as not needing loading any more (put-text-property start end 'media-state 'invalid-url) ;; proceed to load this image asynchronously (put-text-property start end 'media-state 'loading) (mastodon-media--load-image-from-url image-url media-type start (- end start)) (when (or (string= type "gifv") (string= type "video")) (mastodon-media--moving-image-overlay start end)))))))) ;; (defvar-local mastodon-media--overlays nil ;; "Holds a list of overlays in the buffer.") (defun mastodon-media--moving-image-overlay (start end) "Add play symbol overlay to moving image media items. START and END are the beginning and end of the media item to overlay." (let ((ov (make-overlay start end))) (overlay-put ov 'after-string (propertize "" 'help-echo "Video" 'face '((:height 3.5 :inherit mastodon-toot-docs-face)))))) ;; (cl-pushnew ov mastodon-media--overlays))) (defun mastodon-media--get-avatar-rendering (avatar-url) "Return the string to be written that renders the avatar at AVATAR-URL." ;; We use just an empty space as the textual representation. ;; This is what a user will see on a non-graphical display ;; where not showing an avatar at all is preferable. (let ((image-options (when (mastodon-tl--image-trans-check) `(:height ,mastodon-media--avatar-height)))) (concat (propertize " " 'media-url avatar-url 'media-state 'needs-loading 'media-type 'avatar 'display (apply #'create-image mastodon-media--generic-avatar-data ;; inbuilt scaling in 27.1 (when (version< emacs-version "27.1") (when image-options 'imagemagick)) t image-options)) " "))) (defun mastodon-media--get-media-link-rendering (media-url &optional full-remote-url type caption sensitive) "Return the string to be written that renders the image at MEDIA-URL. FULL-REMOTE-URL is used for `shr-browse-image'. TYPE is the attachment's type field on the server. CAPTION is the image caption if provided. SENSITIVE is a flag from the item's JSON data." (let* ((help-echo-base (substitute-command-keys (concat "\\`RET': load full image or play video,\ \\`i' for image options" (when (not (eq sensitive :json-false)) ", \\`S': toggle sensitive media")))) (help-echo (if caption (concat help-echo-base "\n\"" caption "\"") help-echo-base))) (concat (mastodon-tl--propertize-img-str-or-url "[img]" media-url full-remote-url type help-echo (create-image mastodon-media--generic-broken-image-data nil t) nil caption sensitive) " "))) (provide 'mastodon-media) ;;; mastodon-media.el ends here mastodon.el/lisp/mastodon-notifications.el000066400000000000000000001143011501733112700212650ustar00rootroot00000000000000;;; mastodon-notifications.el --- Notification functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-notification.el provides notification functions for Mastodon. ;;; Code: (require 'subr-x) (require 'cl-lib) (require 'mastodon-widget) (require 'map) (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-params-async-json "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-http--triage "mastodon-http") (autoload 'mastodon-media--inline-images "mastodon-media") (autoload 'mastodon-tl--byline "mastodon-tl") (autoload 'mastodon-tl--byline-author "mastodon-tl") (autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl") (autoload 'mastodon-tl--content "mastodon-tl") (autoload 'mastodon-tl--field "mastodon-tl") (autoload 'mastodon-tl--find-property-range "mastodon-tl") (autoload 'mastodon-tl--has-spoiler "mastodon-tl") (autoload 'mastodon-tl--init "mastodon-tl") (autoload 'mastodon-tl--property "mastodon-tl") (autoload 'mastodon-tl--reload-timeline-or-profile "mastodon-tl") (autoload 'mastodon-tl--spoiler "mastodon-tl") (autoload 'mastodon-tl--item-id "mastodon-tl") (autoload 'mastodon-tl-update "mastodon-tl") (autoload 'mastodon-views-view-follow-requests "mastodon-views") (autoload 'mastodon-tl--current-filters "mastodon-views") (autoload 'mastodon-tl--render-text "mastodon-tl") (autoload 'mastodon-notifications-get "mastodon") (autoload 'mastodon-tl--byline-uname-+-handle "mastodon-tl") (autoload 'mastodon-tl--byline-handle "mastodon-tl") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-media--get-avatar-rendering "mastodon-media") (autoload 'mastodon-tl--image-trans-check "mastodon-tl") (autoload 'mastodon-tl--symbol "mastodon-tl") (autoload 'mastodon-tl--display-or-uname "mastodon-tl") (autoload 'mastodon-tl-goto-next-item "mastodon-tl") (autoload 'mastodon-tl--buffer-type-eq "mastodon-tl") (autoload 'mastodon-tl--buffer-property "mastodon-tl") (autoload 'mastodon-http--patch "mastodon-http") (autoload 'mastodon-views--minor-view "mastodon-views") (autoload 'mastodon-tl--goto-first-item "mastodon-tl") (autoload 'mastodon-tl--init-sync "mastodon-tl") ;; notifications defcustoms moved into mastodon.el ;; as some need to be available without loading this file (defvar mastodon-tl--shr-map-replacement) (defvar mastodon-tl--horiz-bar) (defvar mastodon-active-user) (defvar mastodon-instance-url) (defvar mastodon-tl--buffer-spec) (defvar mastodon-tl--display-media-p) (defvar mastodon-mode-map) (defvar mastodon-tl--fold-toots-at-length) (defvar mastodon-tl--show-avatars) (defvar mastodon-profile-note-in-foll-reqs) (defvar mastodon-profile-note-in-foll-reqs-max-length) (defvar mastodon-group-notifications) (defvar mastodon-notifications-grouped-names-count) (defvar mastodon-tl--link-keymap) (defvar mastodon-tl--update-point) ;;; VARIABLES (defvar mastodon-notifications--map (let ((map (make-sparse-keymap))) (set-keymap-parent map mastodon-mode-map) (define-key map (kbd "a") #'mastodon-notifications-follow-request-accept) (define-key map (kbd "j") #'mastodon-notifications-follow-request-reject) (define-key map (kbd "C-k") #'mastodon-notifications-clear-current) (define-key map (kbd "C-c C-c") #'mastodon-notifications-cycle-type) map) "Keymap for viewing notifications.") (defvar mastodon-notifications--types '("all" "favourite" "reblog" "mention" "poll" "follow_request" "follow" "status" "update" "severed_relationships" "moderation_warning") "A list of notification types according to their name on the server, plus \"all\".") (defvar mastodon-notifications--filter-types-alist '(("all" . mastodon-notifications-get) ("favourite" . mastodon-notifications-get-favourites) ("reblog" . mastodon-notifications-get-boosts) ("mention" . mastodon-notifications-get-mentions) ("poll" . mastodon-notifications-get-polls) ("follow_request" . mastodon-notifications-get-follow-requests) ("follow" . mastodon-notifications-get-follows) ("status" . mastodon-notifications-get-statuses) ("update" . mastodon-notifications-get-edits)) "An alist of notification types and their corresponding load functions. Notification types are named according to their name on the server.") (defvar mastodon-notifications--response-alist '(("Followed" . "you") ("Favourited" . "your post") ("Boosted" . "your post") ("Mentioned" . "you") ("Posted a poll" . "that has now ended") ("Requested to follow" . "you") ("Posted" . "a post") ("Edited" . "their post")) "Alist of subjects for notification types.") (defvar mastodon-notifications--action-alist '((reblog . "Boosted") (favourite . "Favourited") (follow_request . "Requested to follow") (follow . "Followed") (mention . "Mentioned") (status . "Posted") (poll . "Posted a poll") (update . "Edited") (severed_relationships . "Relationships severed") (moderation_warning . "Moderation warning")) "Action strings keyed by notification type. Types are those of the Mastodon API.") (defvar mastodon-notifications--no-status-notif-alist '(("moderation_warning" . moderation_warning) ("severed_relationships" . event) ("follow" . follow) ("follow_request" . follow_request))) ;;; VAR FETCHERS (defun mastodon-notifications--action-alist-get (type) "Return an action string for notification TYPE. Fetch from `mastodon-notifications--action-alist'. If no match, return empty string." (or (alist-get type mastodon-notifications--action-alist) "")) (defun mastodon-notifications--response-alist-get (message) "Return a response string for MESSAGE. Fetch from `mastodon-notifications--response-alist'. If no match, return empty string." (or (alist-get message mastodon-notifications--response-alist nil nil #'equal) "")) ;;; UTILS (defun mastodon-notifications--api (endpoint) "Return a notifications API ENDPOINT. If `mastodon-group-notifications' is non-nil, use API v2." (mastodon-http--api endpoint (when mastodon-group-notifications "v2"))) ;;; FOLL REQS (defun mastodon-notifications--follow-request-process (&optional reject) "Process the follow request at point. With no argument, the request is accepted. Argument REJECT means reject the request. Can be called in notifications view or in follow-requests view." (if (not (mastodon-tl--find-property-range 'item-json (point))) (user-error "No follow request at point?") (let* ((item-json (mastodon-tl--property 'item-json)) (f-reqs-view-p (string= "follow_requests" (plist-get mastodon-tl--buffer-spec 'endpoint))) (f-req-p (or (string= "follow_request" (mastodon-tl--property 'notification-type :no-move)) f-reqs-view-p))) (if (not f-req-p) (user-error "No follow request at point?") (let-alist (or (alist-get 'account item-json) ;notifs item-json) ;f-reqs (if (not .id) (user-error "No account result at point?") (let ((response (mastodon-http--post (mastodon-http--api (format "follow_requests/%s/%s" .id (if reject "reject" "authorize")))))) (mastodon-http--triage response (lambda (_) (if f-reqs-view-p (mastodon-views-view-follow-requests) (mastodon-tl--reload-timeline-or-profile)) (message "Follow request of %s (@%s) %s!" .username .acct (if reject "rejected" "accepted"))))))))))) (defun mastodon-notifications-follow-request-accept () "Accept a follow request. Can be called in notifications view or in follow-requests view." (interactive) (mastodon-notifications--follow-request-process)) (defun mastodon-notifications-follow-request-reject () "Reject a follow request. Can be called in notifications view or in follow-requests view." (interactive) (mastodon-notifications--follow-request-process :reject)) ;;; FORMAT NON-STANDARD NOTIFS (defun mastodon-notifications--severance-body (json) "Return a body for a severance notification JSON." ;; https://docs.joinmastodon.org/entities/RelationshipSeveranceEvent/ (let-alist json (concat .type ": " .target_name "\nRelationships affected: " "\nFollowers: " (number-to-string .followers_count) "\nFollowing: " (number-to-string .following_count)))) (defun mastodon-notifications--mod-warning-body (json) "Return a body for a moderation warning notification JSON." ;; https://docs.joinmastodon.org/entities/AccountWarning/ (let-alist json (concat .action ": \"" (string-trim .text) "\"" "\nStatuses: " (mastodon-notifications--render-mod-status-links .status_ids) "\nfor account: " .target_account.acct (if .appeal (concat "\nYour appeal: \"" (alist-get 'text .appeal) "\"") "") "\nMore info/appeal: " (mastodon-notifications--render-mod-link .id)))) (defun mastodon-notifications--propertize-link (url help-echo) "Render a plain URL link with HELP-ECHO." (propertize url 'face 'shr-link ;; mastodon-display-name-face 'keymap mastodon-tl--shr-map-replacement 'mastodon-tab-stop 'shr-url 'help-echo help-echo 'follow-link t 'mouse-face 'highlight 'shr-url url 'keymap mastodon-tl--shr-map-replacement)) (defun mastodon-notifications--render-mod-status-links (ids) "Render moderation status IDS as URLs." (mapconcat (lambda (id) (let ((str (format "%s/@%s/%s" mastodon-instance-url mastodon-active-user id))) (mastodon-notifications--propertize-link str "view toot"))) ids ", ")) (defun mastodon-notifications--render-mod-link (id) "Render a moderation link for item with ID." (let ((str (format "%s/disputes/strikes/%s" mastodon-instance-url id))) (mastodon-notifications--propertize-link str "View mod warning"))) ;;; FORMAT/INSERT SINGLE NOTIF (defun mastodon-notifications--format-note (note) "Format for a NOTE, a non-grouped notification." (let* ((type (intern (alist-get 'type note))) (profile-note (when (eq 'follow_request type) (let ((str (mastodon-tl--field 'note (mastodon-tl--field 'account note)))) (if mastodon-profile-note-in-foll-reqs-max-length (string-limit str mastodon-profile-note-in-foll-reqs-max-length) str)))) (status (mastodon-tl--field 'status note)) (follower (alist-get 'account note)) (follower-name (mastodon-notifications--follower-name follower)) (filtered (mastodon-tl--field 'filtered status)) (filters (when filtered (mastodon-tl--current-filters filtered)))) (if (and filtered (assoc "hide" filters)) nil (mastodon-notifications--insert-note ;; toot ;; should always be note, otherwise notif data not avail ;; later on: note ;; body (mastodon-notifications--body-arg type filters status profile-note follower-name nil note) ;; action-byline (top) (mastodon-notifications--action-byline type nil nil note follower-name) ;; base toot (always provide) status nil nil nil type)))) (defun mastodon-notifications--format-group-note (group status accounts) "Format for a GROUP notification. STATUS is the status's JSON. ACCOUNTS is data of the accounts that have reacted to the notification." (let ((folded nil)) ;; FIXME: apply/refactor filtering as per/with `mastodon-tl--toot' (let-alist group (let* ((type (intern .type)) (profile-note (when (member type '(follow_request)) (let ((str (mastodon-tl--field 'note (car accounts)))) (if mastodon-profile-note-in-foll-reqs-max-length (string-limit str mastodon-profile-note-in-foll-reqs-max-length) str)))) (follower (when (member type '(follow follow_request)) (car accounts))) (follower-name (mastodon-notifications--follower-name follower)) (filtered (mastodon-tl--field 'filtered status)) (filters (when filtered (mastodon-tl--current-filters filtered)))) (unless (and filtered (assoc "hide" filters)) (mastodon-notifications--insert-note ;; toot (if (member type '(follow follow_request)) follower status) ;; body (mastodon-notifications--body-arg type filters status profile-note follower-name group) ;; action-byline (mastodon-notifications--action-byline type accounts group) ;; base toot (no need for update/poll/?) (when (member type '(favourite reblog)) status) folded group accounts)))))) (defun mastodon-notifications--follower-name (follower) "Return display_name or username of FOLLOWER." (if (not (string= "" (alist-get 'display_name follower))) (alist-get 'display_name follower) (alist-get 'username follower))) (defun mastodon-notifications--comment-note-text (str) "Add comment face to all text in STR with `shr-text' face only." (with-temp-buffer (insert str) (goto-char (point-min)) (let (prop) (while (setq prop (text-property-search-forward 'face 'shr-text t)) (add-text-properties (prop-match-beginning prop) (prop-match-end prop) '(face (mastodon-toot-docs-face shr-text))))) (buffer-string))) (defun mastodon-notifications--body-arg (type &optional filters status profile-note follower-name group note) "Prepare a notification body argument. The string returned is passed to `mastodon-notifications--insert-note'. TYPE is a symbol, a member of `mastodon-notifiations--types'. FILTERS STATUS PROFILE-NOTE FOLLOWER-NAME GROUP NOTE." (let ((body (if-let* ((match (assoc "warn" filters))) (mastodon-tl--spoiler status (cadr match)) (mastodon-tl--clean-tabs-and-nl (cond ((mastodon-tl--has-spoiler status) (mastodon-tl--spoiler status)) ((eq type 'follow_request) (mastodon-tl--render-text profile-note)) (t (mastodon-tl--content status))))))) (cond ((not (member (symbol-name type) mastodon-notifications--types)) "Unknown notification type.") ((eq type 'follow) (propertize "Congratulations, you have a new follower!" 'face 'default 'item-type 'follow-request)) ;; nav ((eq type 'follow_request) (concat (propertize (format "You have a follow request from %s" follower-name) 'face 'default 'item-type 'follow-request) ;; nav (when mastodon-profile-note-in-foll-reqs (concat ":\n" (mastodon-notifications--comment-note-text body))))) ((eq type 'severed_relationships) (mastodon-notifications--severance-body (alist-get 'event (or group note)))) ((eq type 'moderation_warning) (mastodon-notifications--mod-warning-body (alist-get 'moderation_warning (or group note)))) ((member type '(favourite reblog)) (propertize (mastodon-notifications--comment-note-text body))) (t body)))) (defun mastodon-notifications--insert-note (toot body action-byline &optional base-toot unfolded group accounts type) "Display the content and byline of timeline element TOOT. BODY will form the section of the toot above the byline. AUTHOR-BYLINE is an optional function for adding the author portion of the byline that takes one variable. By default it is `mastodon-tl--byline-author'. ACTION-BYLINE is a string, obtained by calling `mastodon-notifications--action-byline'. BASE-TOOT is the JSON of the toot responded to. UNFOLDED is a boolean meaning whether to unfold or fold item if foldable. GROUP is the notification group data. ACCOUNTS is the notification accounts data. TYPE is notification type, used for non-group notifs." (let* ((type (if type (symbol-name type) ;; non-group (alist-get 'type group))) (toot-foldable (and mastodon-tl--fold-toots-at-length (length> body mastodon-tl--fold-toots-at-length))) (ts ;; types listed here use base item timestamp, else we use ;; group's latest timestamp: (when (and group (not (member type '("favourite" "reblog" "edit" "poll")))) (mastodon-tl--field 'latest_page_notification_at group)))) (insert (propertize ;; top byline, body + byline: (concat (if (equal type "mention") ;; top (action) byline "" action-byline) (propertize body ;; body only 'toot-body t) ;; includes newlines etc. for folding "\n" ;; actual byline: (if (member type '("severed_relationships" "moderation_warning")) (propertize (concat mastodon-tl--horiz-bar "\n") 'byline t) (mastodon-tl--byline toot nil nil base-toot group ts))) 'item-type 'toot ;; for nav, actions, etc. 'item-id (or (alist-get 'page_max_id group) ;; newest notif (alist-get 'id toot)) ; toot id 'base-item-id (mastodon-tl--item-id ;; if status is a notif, get id from base-toot ;; (-tl--item-id toot) will not work here: (or base-toot toot)) ; else normal toot with reblog check 'item-json toot 'base-toot base-toot 'cursor-face 'mastodon-cursor-highlight-face 'toot-foldable toot-foldable 'toot-folded (and toot-foldable (not unfolded)) ;; grouped notifs data: 'notification-type type 'notification-id (alist-get 'group_key group) 'notification-group group 'notification-accounts accounts ;; for pagination: 'notifications-min-id (alist-get 'page_min_id group) 'notifications-max-id (alist-get 'page_max_id group)) "\n"))) ;;; BYLINES (defun mastodon-notifications--action-byline (type &optional accounts group note follower-name) "Return an action (top) byline for notification of TYPE. ACCOUNTS and GROUP group are used by grouped notifications. NOTE and FOLLOWER-NAME are used for non-grouped notifs." (let* ((str-prefix (mastodon-notifications--action-alist-get type)) (action-str (unless (member type '(follow follow_request mention)) (downcase (mastodon-notifications--byline-action-str str-prefix)))) (action-symbol (if (eq type 'mention) "" (mastodon-tl--symbol type))) (action-authors (cond ((not (member (symbol-name type) mastodon-notifications--types)) "") ((member type '(follow follow_request mention severed_relationships moderation_warning)) "") ;; mentions are normal statuses (group (mastodon-notifications--byline-accounts accounts group)) (t (mastodon-tl--byline-handle note nil follower-name 'mastodon-display-name-face))))) (propertize (concat action-symbol " " action-authors action-str) 'byline-top t))) (defun mastodon-notifications--byline-action-str (message) "Return an action (top) byline string for TOOT with MESSAGE." (let ((resp (mastodon-notifications--response-alist-get message))) (concat " " (propertize message 'face 'mastodon-boosted-face) " " resp "\n"))) (defun mastodon-notifications--alist-by-value (str field json) "From JSON, return the alist whose FIELD value matches STR. JSON is a list of alists." (cl-some (lambda (y) (when (string= str (alist-get field y)) y)) json)) (defun mastodon-notifications--group-accounts (ids json) "For IDS, return account data in JSON." (cl-loop for x in ids collect (mastodon-notifications--alist-by-value x 'id json))) (defun mastodon-notifications--byline-accounts (accounts group &optional avatar) "Propertize author byline ACCOUNTS. GROUP is the group notification data. When AVATAR, include the account's avatar image." (let ((total (alist-get 'notifications_count group)) (accts mastodon-notifications-grouped-names-count)) (concat (string-trim ;; remove trailing newline (cl-loop for account in accounts repeat accts concat (let-alist account (concat ;; avatar insertion moved up to `mastodon-tl--byline' by ;; default to be outside 'byline propt. (when (and avatar ; used by `mastodon-profile--format-user' mastodon-tl--show-avatars mastodon-tl--display-media-p (mastodon-tl--image-trans-check)) (mastodon-media--get-avatar-rendering .avatar)) (let ((uname (mastodon-tl--display-or-uname account))) (mastodon-tl--byline-handle account nil uname 'mastodon-display-name-face)) ", "))) nil ", ") (if (< accts total) (let ((diff (- total accts))) (propertize ;; help-echo remaining notifs authors: (format " and %s other%s" diff (if (= 1 diff) "" "s")) 'help-echo (mapconcat (lambda (a) (propertize (alist-get 'username a) 'face 'mastodon-display-name-face)) (cddr accounts) ;; not first two ", "))))))) ;;; LOAD TIMELINE (defun mastodon-notifications--render (json no-group) "Display grouped notifications in JSON. NO-GROUP means don't render grouped notifications." ;; (setq masto-grouped-notifs json) (let ((start-pos (point))) (if no-group (cl-loop for x in json do (mastodon-notifications--format-note x)) (cl-loop for g in (alist-get 'notification_groups json) for accounts = (mastodon-notifications--group-accounts (alist-get 'sample_account_ids g) (alist-get 'accounts json)) for type = (alist-get 'type g) for status = (mastodon-notifications--status-or-event g type json) do (mastodon-notifications--format-group-note g status accounts))) (when mastodon-tl--display-media-p ;; images-in-notifs custom is handeld in ;; `mastodon-tl--media-attachment', not here (mastodon-media--inline-images start-pos (point))))) (defun mastodon-notifications--status-or-event (group type json) "Return a notification's status or event data. Using GROUP data, notification TYPE, and overall notifs JSON." (if (member type (map-keys mastodon-notifications--no-status-notif-alist)) ;; notifs w no status data: (let ((key (alist-get type mastodon-notifications--no-status-notif-alist nil nil #'equal))) (alist-get key group)) (mastodon-notifications--alist-by-value (alist-get 'status_id group) 'id (alist-get 'statuses json)))) (defun mastodon-notifications--empty-group-json-p (json) "Non-nil if JSON is empty grouped notifs data." (equal json '((accounts) (statuses) (notification_groups)))) (defun mastodon-notifications--timeline (json &optional type update) "Format JSON in Emacs buffer. Optionally specify TYPE. UPDATE means we are updating, so skip some things." (if (seq-empty-p json) (user-error "Looks like you have no (more) notifications for now") (unless update (mastodon-widget--create "Filter" mastodon-notifications--types (or type "all") (lambda (widget &rest _ignore) (let ((value (widget-value widget))) (mastodon-notifications-get-type value))) :newline) (insert "\n")) ;; filtered/requests message: (when (mastodon-notifications--notif-requests) (insert (substitute-command-keys "You have filtered notifications. \ \\[mastodon-notifications-requests] to view requests.\n\n"))) ;; set update point: (setq mastodon-tl--update-point (point)) ;; render: (mastodon-notifications--render json (not mastodon-group-notifications)) (goto-char (point-min)) ;; set last read notif ID: (save-excursion (mastodon-tl-goto-next-item :no-refresh) (let ((id (mastodon-tl--property 'item-id))) ;; notif not base (mastodon-notifications--set-last-read id))) (unless update ;; already in tl--update (mastodon-tl-goto-next-item)))) ;;; VIEW LOADING FUNCTIONS (defun mastodon-notifications-get-type (&optional type) "Read a notification type and load its timeline. Optionally specify TYPE." (interactive) (let ((choice (or type (completing-read "View notifications: " mastodon-notifications--filter-types-alist)))) (funcall (alist-get choice mastodon-notifications--filter-types-alist nil nil #'equal)))) (defun mastodon-notifications-cycle-type (&optional prefix) "Cycle the current notifications view. With arg PREFIX, `completing-read' a type and load it." (interactive "P") ;; FIXME: do we need a sept buffer-type result for all notifs views? (if (not (or (mastodon-tl--buffer-type-eq 'notifications) (mastodon-tl--buffer-type-eq 'mentions))) (user-error "Not in a notifications view") (let* ((choice (if prefix (completing-read "Notifs by type: " mastodon-notifications--types) (mastodon-notifications--get-next-type))) (fun (alist-get choice mastodon-notifications--filter-types-alist nil nil #'equal))) (funcall fun)))) (defun mastodon-notifications--current-type () "Return the current notification type or nil." (let* ((update-params (mastodon-tl--buffer-property 'update-params nil :no-error))) (alist-get "types[]" update-params nil nil #'equal))) (defun mastodon-notifications--get-next-type () "Return the next notif type based on current buffer spec." (let* ((type (mastodon-notifications--current-type))) (if (not type) (cadr mastodon-notifications--types) (or (cadr (member type mastodon-notifications--types)) (car mastodon-notifications--types))))) (defun mastodon-notifications-get-mentions () "Display mention notifications in buffer." (interactive) (mastodon-notifications-get "mention" "mentions")) (defun mastodon-notifications-get-favourites () "Display favourite notifications in buffer." (interactive) (mastodon-notifications-get "favourite" "favourites")) (defun mastodon-notifications-get-boosts () "Display boost notifications in buffer." (interactive) (mastodon-notifications-get "reblog" "boosts")) (defun mastodon-notifications-get-polls () "Display poll notifications in buffer." (interactive) (mastodon-notifications-get "poll" "polls")) (defun mastodon-notifications-get-statuses () "Display status notifications in buffer. Status notifications are created when you call `mastodon-tl-enable-notify-user-posts'." (interactive) (mastodon-notifications-get "status" "statuses")) (defun mastodon-notifications-get-follows () "Display follow notifications in buffer." (interactive) (mastodon-notifications-get "follow" "follows")) (defun mastodon-notifications-get-follow-requests () "Display follow request notifications in buffer." (interactive) (mastodon-notifications-get "follow_request" "follow-requests")) (defun mastodon-notifications-get-edits () "Display edited post notifications in buffer." (interactive) (mastodon-notifications-get "update" "edits")) (defun mastodon-notifications--filter-types-list (type) "Return a list of notification types with TYPE removed." (remove type mastodon-notifications--types)) ;;; CLEAR/DISMISS NOTIFS (defun mastodon-notifications-clear-all () "Clear all notifications." (interactive) (when (y-or-n-p "Clear all notifications?") (let ((response (mastodon-http--post (mastodon-notifications--api "notifications/clear")))) (mastodon-http--triage response (lambda (_) (when mastodon-tl--buffer-spec (mastodon-tl--reload-timeline-or-profile)) (message "All notifications cleared!")))))) (defun mastodon-notifications-clear-current () "Dismiss the notification at point." (interactive) (let* ((id (or ;; grouping enabled ;; (*should* also work for ungrouped items): (mastodon-tl--property 'notification-id) ;; FIXME: are these all required? (mastodon-tl--property 'item-id) (mastodon-tl--field 'id (mastodon-tl--property 'item-json)))) (endpoint (mastodon-notifications--api (format "notifications/%s/dismiss" id))) (response (mastodon-http--post endpoint))) (mastodon-http--triage response (lambda (_) (when mastodon-tl--buffer-spec (mastodon-tl--reload-timeline-or-profile)) (message "Notification dismissed!"))))) ;;; MISC (defun mastodon-notifications--set-last-read (id) "Set the last read notification ID on the server." (let ((endpoint (mastodon-http--api "markers")) (params `(("notifications[last_read_id]" . ,id)))) (mastodon-http--post endpoint params))) (defun mastodon-notifications--get-last-read () "Return the last read notification ID from the server." (let* ((params '(("timeline[]" . "notifications"))) (endpoint (mastodon-http--api "markers")) (resp (mastodon-http--get-json endpoint params))) (map-nested-elt resp '(notifications last_read_id)))) (defun mastodon-notifications-get-single-notif () "Return a single notification JSON for v2 notifs." (interactive) (let* ((id ;; grouped (should work for ungrouped items): (mastodon-tl--property 'notification-id)) (endpoint (mastodon-notifications--api (format "notifications/%s" id))) (response (mastodon-http--get-json endpoint))) (message "%s" (prin1-to-string response)))) (defun mastodon-notifications--get-unread-count () "Return the number of unread notifications for the current account." ;; params: limit - max 1000, default 100, types[], exclude_types[], account_id (let* ((endpoint "notifications/unread_count") (url (mastodon-http--api endpoint (when mastodon-group-notifications "v2"))) (resp (mastodon-http--get-json url))) (alist-get 'count resp))) ;;; NOTIFICATION REQUESTS / FILTERING / POLICY (defvar mastodon-notifications--requests-map (let ((map (make-sparse-keymap))) (set-keymap-parent map mastodon-mode-map) (define-key map (kbd "j") #'mastodon-notifications-request-reject) (define-key map (kbd "a") #'mastodon-notifications-request-accept) (define-key map (kbd "g") #'mastodon-notifications-requests) map) "Keymap for viewing follow requests.") ;; FIXME: these are only for grouped notifs, else the fields are JSON bools (defvar mastodon-notifications-policy-vals '("accept" "filter" "drop")) (defun mastodon-notifications-get-policy () "Return the notification filtering policy." (let ((url (mastodon-notifications--api "notifications/policy"))) (mastodon-http--get-json url))) (defun mastodon-notifications--notif-requests () "Non-nil if the user currently has pending/filtered notifications. Returns" (let* ((policy (mastodon-notifications-get-policy)) (count (map-nested-elt policy '(summary pending_notifications_count)))) (if (and count (> count 0)) count))) (defun mastodon-notifications--pending-p () "Non-nil if there are any pending requests or notifications." (let* ((json (mastodon-notifications-get-policy)) (summary (alist-get 'summary json))) (or (not (= 0 (alist-get 'pending_requests_count summary))) (not (= 0 (alist-get 'pending_notifications_count summary)))))) (defun mastodon-notifications--update-policy (&optional params) "Update notifications filtering policy. PARAMS is an alist of parameters." ;; https://docs.joinmastodon.org/methods/notifications/#update-the-filtering-policy-for-notifications (let ((url (mastodon-notifications--api "notifications/policy"))) (mastodon-http--patch url params))) (defun mastodon-notifications--get-requests (&optional params) "Get a list of notification requests data from the server. PARAMS is an alist of parameters." ;; NB: link header pagination (let ((url (mastodon-notifications--api "notifications/requests"))) (mastodon-http--get-json url params))) (defun mastodon-notifications-request-accept (&optional reject) "Accept a notification request for a user. This will merge any filtered notifications from them into the main notifications and accept any future notification from them. REJECT means reject notifications instead." ;; POST /api/v1/notifications/requests/:id/accept (interactive) (let* ((id (mastodon-tl--property 'item-id)) (user (mastodon-tl--property 'notif-req-user)) (url (mastodon-http--api (format "notifications/requests/%s/%s" id (if reject "dismiss" "accept")))) (resp (mastodon-http--post url))) (mastodon-http--triage resp (lambda (_resp) (message "%s notifications from %s" (if reject "Not accepting" "Accepting") user) ;; reload view: (mastodon-notifications-requests))))) (defun mastodon-notifications-request-reject () "Reject a notification request for a user. Rejecting a request means any notifications from them will continue to be filtered." (interactive) (mastodon-notifications-request-accept :reject)) (defun mastodon-notifications-requests () "Open a new buffer displaying the user's notification requests." ;; calqued off `mastodon-views-view-follow-requests' (interactive) (mastodon-tl--init-sync "notification-requests" "notifications/requests" 'mastodon-views--insert-notification-requests nil '(("limit" . "40")) ; server max is 80 :headers "notification requests" "a/j - accept/reject request at point\n\ n/p - go to next/prev request\n\ \\[mastodon-notifications-policy] - set filtering policy") (mastodon-tl--goto-first-item) (with-current-buffer "*mastodon-notification-requests*" (use-local-map mastodon-notifications--requests-map))) (defun mastodon-views--insert-notification-requests (json) "Insert the user's current notification requests. JSON is the data returned by the server." (mastodon-views--minor-view "notification requests" #'mastodon-notifications--insert-users json)) ;; masto-notif-req)) (defun mastodon-notifications--insert-users (json) "Insert users list into the buffer. JSON is the data from the server." ;; calqued off `mastodon-views--insert-users-propertized-note' ;; and `mastodon-search--insert-users-propertized' (cl-loop for req in json do (insert (concat (mastodon-notifications--format-req-user req) mastodon-tl--horiz-bar "\n\n")))) (defun mastodon-notifications--format-req-user (req &optional note) "Format a notification request user, REQ. NOTE means to include a profile note." ;; calqued off `mastodon-search--propertize-user' (let-alist req (propertize (concat (propertize .account.username 'face 'mastodon-display-name-face 'byline t 'notif-req-user .account.username 'item-type 'notif-req 'item-id .id) ;; notif req id " : \n : " (propertize (concat "@" .account.acct) 'face 'mastodon-handle-face 'mouse-face 'highlight 'mastodon-tab-stop 'user-handle 'keymap mastodon-tl--link-keymap 'mastodon-handle (concat "@" .account.acct) 'help-echo (concat "Browse user profile of @" .account.acct)) " : \n" (when note (mastodon-tl--render-text .account.note .account)) "\n") 'item-json req))) (provide 'mastodon-notifications) ;;; mastodon-notifications.el ends here mastodon.el/lisp/mastodon-profile.el000066400000000000000000001352341501733112700200640ustar00rootroot00000000000000;;; mastodon-profile.el --- Functions for inspecting Mastodon profiles -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-profile.el generates a stream of users toots. ;; To add ;; - Option to follow ;; - wheather they follow you or not ;; - Show only Media ;;; Code: (require 'seq) (require 'cl-lib) (require 'persist) (require 'parse-time) (require 'mastodon-http) (eval-when-compile (require 'mastodon-tl)) (require 'mastodon-widget) (autoload 'mastodon-auth--get-account-id "mastodon-auth") (autoload 'mastodon-auth--get-account-name "mastodon-auth.el") (autoload 'mastodon-http--api "mastodon-http.el") (autoload 'mastodon-http--get-json "mastodon-http.el") (autoload 'mastodon-http--get-json-async "mastodon-http.el") (autoload 'mastodon-http--get-response "mastodon-http") (autoload 'mastodon-http--patch "mastodon-http") (autoload 'mastodon-http--patch-json "mastodon-http") (autoload 'mastodon-http--post "mastodon-http.el") (autoload 'mastodon-http--triage "mastodon-http.el") (autoload 'mastodon-kill-window "mastodon") (autoload 'mastodon-media--get-media-link-rendering "mastodon-media.el") (autoload 'mastodon-media--inline-images "mastodon-media.el") (autoload 'mastodon-mode "mastodon.el") (autoload 'mastodon-notifications-follow-request-accept "mastodon-notifications") (autoload 'mastodon-notifications-follow-request-reject "mastodon-notifications") (autoload 'mastodon-search--insert-users-propertized "mastodon-search") (autoload 'mastodon-tl--as-string "mastodon-tl.el") (autoload 'mastodon-tl--buffer-type-eq "mastodon tl") (autoload 'mastodon-tl--byline-author "mastodon-tl.el") (autoload 'mastodon-tl--find-property-range "mastodon-tl.el") (autoload 'mastodon-tl--get-link-header-from-response "mastodon-tl") (autoload 'mastodon-tl--init "mastodon-tl.el") (autoload 'mastodon-tl--user-handles-get "mastodon-tl") (autoload 'mastodon-tl--map-alist "mastodon-tl") (autoload 'mastodon-tl--map-alist-vals-to-alist "mastodon-tl") (autoload 'mastodon-tl--profile-buffer-p "mastodon tl") (autoload 'mastodon-tl--property "mastodon-tl.el") (autoload 'mastodon-tl--render-text "mastodon-tl.el") (autoload 'mastodon-tl--set-buffer-spec "mastodon-tl") (autoload 'mastodon-tl--set-face "mastodon-tl.el") (autoload 'mastodon-tl--symbol "mastodon-tl") (autoload 'mastodon-tl--timeline "mastodon-tl.el") (autoload 'mastodon-tl--toot "mastodon-tl") (autoload 'mastodon-tl--item-id "mastodon-tl") (autoload 'mastodon-toot--count-toot-chars "mastodon-toot") (autoload 'mastodon-toot--get-max-toot-chars "mastodon-toot") (autoload 'mastodon-views-add-account-to-list "mastodon-views") (autoload 'mastodon-return-credential-account "mastodon") (autoload 'mastodon-tl--buffer-property "mastodon-tl") (autoload 'mastodon-search-query "mastodon-search") (autoload 'mastodon-tl--field-status "mastodon-tl") (autoload 'mastodon-toot--with-toot-item "mastodon-toot" nil nil 'macro) (autoload 'mastodon-tl--toot-or-base "mastodon-tl") (defvar mastodon-active-user) (defvar mastodon-tl--horiz-bar) (defvar mastodon-tl--update-point) (defvar mastodon-toot--max-toot-chars) (defvar mastodon-toot--visibility) (defvar mastodon-toot--content-nsfw) (defvar mastodon-tl--timeline-posts-count) (defvar-local mastodon-profile--account nil "The data for the account being described in the current profile buffer.") (defvar mastodon-profile-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'mastodon-profile-account-view-cycle) (define-key map (kbd "C-c C-s") #'mastodon-profile-account-search) (define-key map (kbd "C-c #") #'mastodon-profile-open-statuses-tagged) map) "Keymap for `mastodon-profile-mode'.") (define-minor-mode mastodon-profile-mode "Toggle mastodon profile minor mode. This minor mode is used for mastodon profile pages and adds a couple of extra keybindings." :init-value nil :lighter " Profile" :keymap mastodon-profile-mode-map :group 'mastodon :global nil) (defvar mastodon-profile-credential-account nil "Holds the JSON data of the CredentialAccount entity. It contains details of the current user's account.") (defvar mastodon-profile-acccount-preferences-data nil "Holds the JSON data of the current user's preferences.") (defvar mastodon-profile-update-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'mastodon-profile-user-profile-send-updated) (define-key map (kbd "C-c C-k") #'mastodon-profile-update-profile-note-cancel) map) "Keymap for `mastodon-profile-update-mode'.") (persist-defvar mastodon-profile-account-settings nil "An alist of account settings saved from the server. Other clients can change these settings on the server at any time, so this list is not the canonical source for settings. It is updated on entering mastodon mode and on toggle any setting it contains. This variable is set from data in `mastodon-profile-credential-account' not `mastodon-profile-account-preferences-data'.") (define-minor-mode mastodon-profile-update-mode "Minor mode to update user profile." :group 'mastodon-profile :keymap mastodon-profile-update-mode-map :global nil) (defun mastodon-profile--item-json () "Get the next item-json." (mastodon-tl--property 'item-json)) (defun mastodon-profile--make-author-buffer (account &optional no-reblogs no-replies only-media tag max-id) "Take an ACCOUNT json and insert a user account into a new buffer. NO-REBLOGS means do not display boosts in statuses. NO-REPLIES means to exlude replies. ONLY-MEDIA means show only posts containing attachments. TAG is a hashtag to restrict posts to. MAX-ID is a flag to include the max_id pagination parameter." (mastodon-profile--make-profile-buffer-for account "statuses" #'mastodon-tl--timeline no-reblogs nil no-replies only-media tag max-id)) ;;; PROFILE VIEW COMMANDS (defvar mastodon-profile--account-view-alist '((statuses . mastodon-profile-open-statuses) (no-boosts . mastodon-profile-open-statuses-no-reblogs) (no-replies . mastodon-profile-open-statuses-no-replies) (only-media . mastodon-profile-open-statuses-only-media) (followers . mastodon-profile-open-followers) (following . mastodon-profile-open-following) (tag . mastodon-profile-open-statuses-tagged))) (defun mastodon-profile--view-types () "Return the keys of `mastodon-profile--account-view-alist' as a list." (map-keys mastodon-profile--account-view-alist)) (defun mastodon-profile-account-view-cycle (&optional prefix) "Cycle through profile view: toots, toot sans boosts, followers, and following. If a PREFIX argument is provided, prompt for a view type and load." (interactive "P") (if prefix (let* ((choice (completing-read "Profile view:" mastodon-profile--account-view-alist)) (fun (alist-get choice mastodon-profile--account-view-alist))) (funcall fun)) (cond ((mastodon-tl--buffer-type-eq 'profile-statuses) (mastodon-profile-open-statuses-no-reblogs)) ((mastodon-tl--buffer-type-eq 'profile-statuses-no-boosts) (mastodon-profile-open-statuses-no-replies)) ((mastodon-tl--buffer-type-eq 'profile-statuses-no-replies) (mastodon-profile-open-statuses-only-media)) ((mastodon-tl--buffer-type-eq 'profile-statuses-only-media) (mastodon-profile-open-followers)) ((mastodon-tl--buffer-type-eq 'profile-followers) (mastodon-profile-open-following)) ((mastodon-tl--buffer-type-eq 'profile-following) (mastodon-profile-open-statuses))))) (defun mastodon-profile-open-statuses () "Open a profile showing statuses." (interactive) (if mastodon-profile--account (mastodon-profile--make-author-buffer mastodon-profile--account) (user-error "Not in a mastodon profile"))) (defun mastodon-profile-open-statuses-no-replies () "Open a profile buffer showing statuses without replies." (interactive) (if mastodon-profile--account (mastodon-profile--make-author-buffer mastodon-profile--account nil :no-replies) (user-error "Not in a mastodon profile"))) (defun mastodon-profile-open-statuses-no-reblogs () "Open a profile buffer showing statuses without reblogs." (interactive) (if mastodon-profile--account (mastodon-profile--make-author-buffer mastodon-profile--account :no-reblogs) (user-error "Not in a mastodon profile"))) (defun mastodon-profile-open-statuses-only-media () "Open a profile buffer showing only statuses with media." (interactive) (if mastodon-profile--account (mastodon-profile--make-author-buffer mastodon-profile--account nil nil :only-media) (user-error "Not in a mastodon profile"))) (defun mastodon-profile-open-statuses-tagged () "Prompt for a hashtag and display a profile with only statuses containing it." (interactive) (let ((tag (read-string "Statuses containing tag: "))) (if mastodon-profile--account (mastodon-profile--make-author-buffer mastodon-profile--account nil nil nil tag) (user-error "Not in a mastodon profile")))) (defun mastodon-profile-open-following () "Open a profile buffer showing the accounts that current profile follows." (interactive) (if mastodon-profile--account (mastodon-profile--make-profile-buffer-for mastodon-profile--account "following" #'mastodon-profile--format-user nil :headers) (user-error "Not in a mastodon profile"))) (defun mastodon-profile-open-followers () "Open a profile buffer showing the accounts following the current profile." (interactive) (if mastodon-profile--account (mastodon-profile--make-profile-buffer-for mastodon-profile--account "followers" #'mastodon-profile--format-user nil :headers) (user-error "Not in a mastodon profile"))) (defun mastodon-profile-view-favourites () "Open a new buffer displaying the user's favourites." (interactive) (message "Loading your favourited toots...") (mastodon-tl--init "favourites" "favourites" 'mastodon-tl--timeline :headers)) (defun mastodon-profile-view-bookmarks () "Open a new buffer displaying the user's bookmarks." (interactive) (message "Loading your bookmarked toots...") (mastodon-tl--init "bookmarks" "bookmarks" 'mastodon-tl--timeline :headers)) (defun mastodon-profile-add-account-to-list () "Add account of current profile buffer to a list." (interactive) (if (not mastodon-profile--account) (user-error "No profile to add?") (let-alist mastodon-profile--account (mastodon-views-add-account-to-list nil .id .acct)))) (defun mastodon-profile-account-search (query) "Run a statuses search QUERY for the currently viewed account." (interactive "sSearch account for: ") (let* ((ep (mastodon-tl--buffer-property 'endpoint)) (id (nth 1 (split-string ep "/")))) (mastodon-search-query query "statuses" nil nil id))) ;;; ACCOUNT PREFERENCES (defun mastodon-profile--get-account-value (key function) "Fetch KEY from data returned by FUNCTION. If value is :json-false, return nil." (let* ((response (funcall function)) (value (alist-get key response))) (if (eq value :json-false) nil value))) (defun mastodon-profile--get-json-value (key) "Fetch value for KEY from account. Account details are from `mastodon-return-credential-account'. If value is :json-false, return nil." (mastodon-profile--get-account-value key #'mastodon-return-credential-account)) (defun mastodon-profile--get-source-values () "Return the \"source\" preferences from the server." (mastodon-profile--get-json-value 'source)) (defun mastodon-profile--get-source-value (pref) "Return PREF erence from the account's \"source\" field." (mastodon-profile--get-account-value pref #'mastodon-profile--get-source-values)) (defun mastodon-profile-update-user-profile-note () "Fetch user's profile note and display for editing." (interactive) (let* ((source (mastodon-profile--get-source-values)) (note (alist-get 'note source)) (buffer (get-buffer-create "*mastodon-update-profile*")) (inhibit-read-only t) (msg-str (substitute-command-keys "Edit your profile note. \\`C-c C-c' to send, \\`C-c C-k' to cancel."))) (switch-to-buffer-other-window buffer) (text-mode) (mastodon-tl--set-buffer-spec (buffer-name buffer) "accounts/verify_credentials" nil) (setq-local header-line-format msg-str) (mastodon-profile-update-mode t) (insert (propertize (concat (propertize "0" 'note-counter t 'display nil) "/500 characters") 'read-only t 'face 'mastodon-toot-docs-face 'note-header t) "\n") (make-local-variable 'after-change-functions) (cl-pushnew #'mastodon-profile--update-note-count after-change-functions) (let ((start-point (point))) (insert note) (goto-char start-point)) (delete-trailing-whitespace) ; remove all ^M's (message msg-str))) (defun mastodon-profile--update-note-count (&rest _args) "Display the character count of the profile note buffer." (let* ((inhibit-read-only t) (header-region (mastodon-tl--find-property-range 'note-header (point-min))) (count-region (mastodon-tl--find-property-range 'note-counter (point-min))) (count (number-to-string (mastodon-toot--count-toot-chars (buffer-substring-no-properties (cdr header-region) (point-max)))))) (add-text-properties (car count-region) (cdr count-region) (list 'display count)))) (defun mastodon-profile-update-profile-note-cancel () "Cancel updating user profile and kill buffer and window." (interactive) (when (y-or-n-p "Cancel updating your profile note?") (mastodon-kill-window))) (defun mastodon-profile--note-remove-header () "Get the profile note, without the buffer header." (let ((header-region (mastodon-tl--find-property-range 'note-header (point-min)))) (buffer-substring (cdr header-region) (point-max)))) (defun mastodon-profile-user-profile-send-updated () "Send PATCH request with the updated profile note. Ask for confirmation if length > 500 characters." (interactive) (let* ((note (mastodon-profile--note-remove-header)) (url (mastodon-http--api "accounts/update_credentials"))) (when (or (not (> (mastodon-toot--count-toot-chars note) 500)) (y-or-n-p "Note is over mastodon's max for profile notes (500). Proceed?")) (quit-window 'kill) (mastodon-profile--user-profile-send-updated-do url note)))) (defun mastodon-profile--user-profile-send-updated-do (url note) "Send PATCH request with the updated profile NOTE to URL." (let ((response (mastodon-http--patch url `(("note" . ,note))))) (mastodon-http--triage response (lambda (_) (message "Profile note updated!"))))) (defun mastodon-profile--update-preference (pref val &optional source) "Update account PREF erence to setting VAL. Both args are strings. SOURCE means that the preference is in the `source' part of the account JSON." (let* ((url (mastodon-http--api "accounts/update_credentials")) (pref-formatted (if source (concat "source[" pref "]") pref)) (response (mastodon-http--patch url `((,pref-formatted . ,val))))) (mastodon-http--triage response (lambda (_) (mastodon-profile--fetch-server-account-settings) (message "Account setting %s updated to %s!" pref val))))) (defun mastodon-profile--get-pref (pref) "Return PREF from `mastodon-profile-account-settings'." (plist-get mastodon-profile-account-settings pref)) (defun mastodon-profile--update-preference-plist (pref val) "Set local account preference plist preference PREF to VAL. This is done after changing the setting on the server." (setq mastodon-profile-account-settings (plist-put mastodon-profile-account-settings pref val))) ;; used in toot.el (defun mastodon-profile--fetch-server-account-settings-maybe () "Fetch account settings from the server. Only do so if `mastodon-profile-account-settings' is nil." (mastodon-profile--fetch-server-account-settings :no-force)) ;; FIXME: this does one request per setting! should just do one request then ;; parse (defun mastodon-profile--fetch-server-account-settings (&optional no-force) "Fetch basic account settings from the server. Store the values in `mastodon-profile-account-settings'. Run in `mastodon-mode-hook'. If NO-FORCE, only fetch if `mastodon-profile-account-settings' is nil." (unless (and no-force mastodon-profile-account-settings) (let ((keys '(locked discoverable display_name bot)) (source-keys '(privacy sensitive language))) (mapc (lambda (k) (mastodon-profile--update-preference-plist k (mastodon-profile--get-json-value k))) keys) (mapc (lambda (sk) (mastodon-profile--update-preference-plist sk (mastodon-profile--get-source-value sk))) source-keys) ;; hack for max toot chars: (mastodon-toot--get-max-toot-chars :no-toot) (mastodon-profile--update-preference-plist 'max_toot_chars mastodon-toot--max-toot-chars) ;; TODO: remove now redundant vars, replace with fetchers from the plist (setq mastodon-toot--visibility (mastodon-profile--get-pref 'privacy) mastodon-toot--content-nsfw (mastodon-profile--get-pref 'sensitive)) mastodon-profile-account-settings))) (defun mastodon-profile-account-locked-toggle () "Toggle the locked status of your account. Locked means follow requests have to be approved." (interactive) (mastodon-profile--toggle-account-key 'locked)) (defun mastodon-profile-account-discoverable-toggle () "Toggle the discoverable status of your account. Discoverable means the account is listed in the server directory." (interactive) (mastodon-profile--toggle-account-key 'discoverable)) (defun mastodon-profile-account-bot-toggle () "Toggle the bot status of your account." (interactive) (mastodon-profile--toggle-account-key 'bot)) (defun mastodon-profile-account-sensitive-toggle () "Toggle the sensitive status of your account. When enabled, statuses are marked as sensitive by default." (interactive) (mastodon-profile--toggle-account-key 'sensitive :source)) (defun mastodon-profile--toggle-account-key (key &optional source) "Toggle the boolean account setting KEY. SOURCE means the setting is located under \"source\" in the account JSON. Current settings are fetched from the server." (let* ((val (if source (mastodon-profile--get-source-value key) (mastodon-profile--get-json-value key))) (prompt (format "Account setting %s is %s. Toggle?" key val))) (when (y-or-n-p prompt) (mastodon-profile--update-preference (symbol-name key) (if val "false" "true") source)))) (defun mastodon-profile--edit-string-value (key) "Edit the string for account preference KEY." (let* ((val (mastodon-profile--get-json-value key)) (new-val (read-string (format "Edit account setting %s: " key) val))) (mastodon-profile--update-preference (symbol-name key) new-val))) (defun mastodon-profile-update-display-name () "Update display name for your account." (interactive) (mastodon-profile--edit-string-value 'display_name)) (defun mastodon-profile--make-meta-fields-params (fields) "Construct a parameter query string from metadata alist FIELDS. Returns an alist." (let ((keys (cl-loop for count from 1 to 5 collect (cons (format "fields_attributes[%s][name]" count) (format "fields_attributes[%s][value]" count))))) (cl-loop for a-pair in keys for b-pair in fields append (list (cons (car a-pair) (car b-pair)) (cons (cdr a-pair) (cdr b-pair)))))) (defun mastodon-profile-update-meta-fields () "Prompt for new metadata fields information and PATCH the server." (interactive) (let* ((url (mastodon-http--api "accounts/update_credentials")) (fields-updated (mastodon-profile--update-meta-fields-alist)) (params (mastodon-profile--make-meta-fields-params fields-updated)) (response (mastodon-http--patch url params))) (mastodon-http--triage response (lambda (_) (mastodon-profile--fetch-server-account-settings) (message "Metadata fields updated to %s!" fields-updated))))) (defun mastodon-profile--update-meta-fields-alist () "Prompt for new metadata fields information. Returns the results as an alist." (let ((fields-old (mastodon-profile--fields-get nil ;; we must fetch the plaintext version: (mastodon-profile--get-source-value 'fields)))) ;; offer empty fields if user currently has less than four filled: (while (< (length fields-old) 4) (setq fields-old (append fields-old '(("" . ""))))) (let* ((f-str "Metadata %s [%s/4] (max. 255 chars): ") (alist (cl-loop for f in fields-old for x from 1 to 5 collect (cons (read-string (format f-str "key" x) (car f)) (read-string (format f-str "value" x) (cdr f)))))) (mapcar (lambda (x) (cons (mastodon-profile--limit-to-255 (car x)) (mastodon-profile--limit-to-255 (cdr x)))) alist)))) (defun mastodon-profile--limit-to-255 (x) "Limit string X to 255 chars max." (if (> (length x) 255) (substring x 0 255) x)) ;; used in tl.el and toot.el: (defun mastodon-profile--get-preferences-pref (pref) "Fetch PREF from the endpoint \"/preferences\". If `mastodon-profile-acccount-preferences-data' is set, fetch from that instead. The endpoint only holds a few preferences. For others, see `mastodon-profile--update-preference' and its endpoint, \"/accounts/update_credentials.\"" (alist-get pref (or mastodon-profile-acccount-preferences-data (setq mastodon-profile-acccount-preferences-data (mastodon-http--get-json (mastodon-http--api "preferences")))))) (defun mastodon-profile-view-preferences () "View user preferences in another window." (interactive) (let* ((url (mastodon-http--api "preferences")) (response (mastodon-http--get-json url)) (buf (get-buffer-create "*mastodon-preferences*"))) (with-mastodon-buffer buf #'special-mode :other-window (mastodon-tl--set-buffer-spec (buffer-name buf) "preferences" nil) (while-let ((el (pop response))) (insert (format "%-30s %s" (prin1-to-string (car el)) (prin1-to-string (cdr el))) "\n\n")) (goto-char (point-min))))) ;;; PROFILE VIEW DETAILS (defun mastodon-profile--relationships-get (id) "Fetch info about logged-in user's relationship to user with id ID." (let* ((args `(("id[]" . ,id))) (url (mastodon-http--api "accounts/relationships"))) ;; FIXME: API takes array, we just get 1st (car (mastodon-http--get-json url args)))) (defun mastodon-profile--fields-get (&optional account fields) "Fetch the fields vector (aka profile metadata) from profile of ACCOUNT. Returns an alist. FIELDS means provide a fields vector fetched by other means." (let ((fields (or fields (alist-get 'fields account)))) (when fields (mastodon-tl--map-alist-vals-to-alist 'name 'value fields)))) (defun mastodon-profile--fields-insert (fields) "Format and insert field pairs (a.k.a profile metadata) in FIELDS." (let* ((car-fields (mapcar #'car fields)) (left-width (apply #'max (mapcar #'length car-fields)))) (mapconcat (lambda (field) (mastodon-tl--render-text (concat (format "_ %s " (car field)) (make-string (- (+ 1 left-width) (length (car field))) ?_) (format " :: %s" (cdr field))) field)) ; hack to make links tabstops fields ""))) (defun mastodon-profile--get-statuses-pinned (account) "Fetch the pinned toots for ACCOUNT." (let* ((id (alist-get 'id account)) (args `(("pinned" . "true"))) (url (mastodon-http--api (format "accounts/%s/statuses" id)))) (mastodon-http--get-json url args))) (defun mastodon-profile--insert-statuses-pinned (pinned-statuses) "Insert each of the PINNED-STATUSES for a given account." (cl-loop for s in pinned-statuses do (progn (insert (concat "\n " (propertize " pinned " 'face '(:inherit success :box t)) " ")) (mastodon-tl--toot s)))) (defun mastodon-profile--follows-p (list) "T if you have any relationship with the accounts in LIST." (let (result) (dolist (x list result) (when (not (eq :json-false x)) (setq result x))))) (defun mastodon-profile--render-roles (roles) "Return a propertized string of badges for ROLES." (mapconcat (lambda (role) (propertize (alist-get 'name role) 'face `(:box t :foreground ,(alist-get 'color role)))) roles)) (defun mastodon-profile--make-profile-buffer-for (account endpoint-type update-function &optional no-reblogs headers no-replies only-media tag max-id) "Display profile of ACCOUNT, using ENDPOINT-TYPE and UPDATE-FUNCTION. NO-REBLOGS means do not display boosts in statuses. HEADERS means also fetch link headers for pagination. NO-REPLIES means to exlude replies. ONLY-MEDIA means show only posts containing attachments. TAG is a hashtag to restrict posts to. MAX-ID is a flag to include the max_id pagination parameter." (let-alist account (let* ((max-id-str (when max-id (mastodon-tl--buffer-property 'max-id))) (args `(("limit" . ,mastodon-tl--timeline-posts-count) ,(when max-id `("max_id" . ,max-id-str)))) (args (cond (no-reblogs (push '("exclude_reblogs" . "t") args)) (no-replies (push '("exclude_replies" . "t") args)) (only-media (push '("only_media" . "t") args)) (tag (push `("tagged" . ,tag) args)) (t args))) (endpoint (format "accounts/%s/%s" .id endpoint-type)) (url (mastodon-http--api endpoint)) (buffer (concat "*mastodon-" .acct "-" (concat endpoint-type (cond (no-reblogs "-no-boosts") (no-replies "-no-replies") (only-media "-only-media") (tag (format "-tagged-%s" tag)) (t ""))) "*")) (response (if headers (mastodon-http--get-response url args) (mastodon-http--get-json url args))) (json (if headers (car response) response)) (link-header (when headers (mastodon-tl--get-link-header-from-response (cdr response)))) (fields (mastodon-profile--fields-get account)) (pinned (mastodon-profile--get-statuses-pinned account)) (relationships (mastodon-profile--relationships-get .id))) (with-mastodon-buffer buffer #'mastodon-mode nil (mastodon-profile-mode) (setq mastodon-profile--account account) (mastodon-tl--set-buffer-spec buffer endpoint update-function link-header args nil max-id-str) (let* ((inhibit-read-only t)) (insert (propertize (concat "\n" (mastodon-profile--image-from-account account 'avatar_static) (mastodon-profile--image-from-account account 'header_static) "\n" (when .display_name (propertize .display_name 'face 'mastodon-display-name-face)) ;; roles (when .roles (concat " " (mastodon-profile--render-roles .roles))) "\n" (propertize (concat "@" .acct) 'face 'default) (when (eq .locked t) (concat " " (mastodon-tl--symbol 'locked))) "\n " mastodon-tl--horiz-bar "\n" ;; profile note: (mastodon-tl--render-text .note account) ; account = tab-stops in profile ;; meta fields: (when fields (concat "\n" (mastodon-tl--set-face (mastodon-profile--fields-insert fields) 'success))) "\n" ;; Joined date: (propertize (mastodon-profile--format-joined-date-string .created_at) 'face 'success) "\n\n") 'profile-json account) ;; insert counts (mastodon-tl--set-face (concat " " mastodon-tl--horiz-bar "\n" " TOOTS: " (mastodon-tl--as-string .statuses_count) " | " "FOLLOWERS: " (mastodon-tl--as-string .followers_count) " | " "FOLLOWING: " (mastodon-tl--as-string .following_count) "\n" " " mastodon-tl--horiz-bar "\n\n") 'success) ;; insert relationship (follows) (let-alist relationships (if (not .id) ;; sharkey has no relationships endpoint, returns 500. ;; or poss it has a different endpoint "" (let* ((followsp (mastodon-profile--follows-p (list .requested_by .following .followed_by .blocked_by))) (rels (mastodon-profile--relationships-get .id)) (langs-filtered (if-let* ((langs (alist-get 'languages rels))) (concat " (" (mapconcat #'identity langs " ") ")") ""))) (if followsp (mastodon-tl--set-face (concat (when (eq .following t) (format " | FOLLOWED BY YOU%s" langs-filtered)) (when (eq .followed_by t) " | FOLLOWS YOU") (when (eq .requested_by t) " | REQUESTED TO FOLLOW YOU") (when (eq .blocked_by t) " | BLOCKS YOU") "\n\n") 'success) ""))))) ; for insert call (mastodon-media--inline-images (point-min) (point)) ;; widget items description (mastodon-widget--create "View" (mastodon-profile--view-types) (or (mastodon-profile--current-view-type endpoint-type no-reblogs no-replies only-media tag) 'statuses) (lambda (widget &rest _ignore) (let ((value (widget-value widget))) (funcall (alist-get value mastodon-profile--account-view-alist))))) (insert "\n") (setq mastodon-tl--update-point (point)))) ;; split insert of items from insert of profile: (with-current-buffer buffer (let* ((inhibit-read-only t)) ;; insert pinned toots first (when (and pinned (string= endpoint-type "statuses")) (let ((beg (point))) (mastodon-profile--insert-statuses-pinned pinned) (setq mastodon-tl--update-point (point)) (mastodon-media--inline-images beg (point)))) ; updates after pinned toots ;; insert items (funcall update-function json) (goto-char (point-min)) (message (substitute-command-keys ;; "\\[mastodon-profile-account-view-cycle]" ; not always bound? "\\`C-c C-c' to cycle profile views: toots, no replies, no boosts,\ only media, followers, following. \\`C-c C-s' to search user's toots, \\`C-c \#' to search user's posts for a hashtag."))))))) (defun mastodon-profile--current-view-type (type no-reblogs no-replies only-media tag) "Return the type of current profile view. Return a member of `mastodon-profile--view-types', based on TYPE, NO-REBLOGS, NO-REPLIES, ONLY-MEDIA and TAG." (cond (no-reblogs 'no-boosts) (no-replies 'no-replies) (only-media 'only-media) (tag 'tag) (t (if (stringp type) (intern type) type)))) (defun mastodon-profile--format-joined-date-string (joined) "Format a human-readable Joined string from timestamp JOINED. JOINED is the `created_at' field in profile account JSON, and of the format \"2000-01-31T00:00:00.000Z\"." (format-time-string "Joined: %d %B %Y" (parse-iso8601-time-string joined))) (defun mastodon-profile-get-toot-author (&optional max-id) "Open profile of author of toot under point. If toot is a boost, load the profile of the author of the original item. MAX-ID is a flag to include the max_id pagination parameter." (interactive) (mastodon-tl--do-if-item (let ((json (mastodon-tl--toot-or-base (mastodon-profile--item-json)))) (mastodon-profile--make-author-buffer (alist-get 'account json) nil nil nil nil max-id)))) (defun mastodon-profile--image-from-account (account img-type) "Return a avatar image from ACCOUNT. IMG-TYPE is the JSON key from the account data." (let ((img (alist-get img-type account))) (unless (string= img "/avatars/original/missing.png") (mastodon-media--get-media-link-rendering img)))) (defun mastodon-profile-show-user (user-handle) "Query for USER-HANDLE from current status and show that user's profile." (interactive (list (if (and (not (mastodon-tl--profile-buffer-p)) (not (mastodon-tl--property 'item-json :no-move))) (user-error "Looks like there's no toot or user at point?") (let ((user-handles (mastodon-profile--extract-users-handles (mastodon-profile--item-json)))) (completing-read "View profile of user [choose or enter any handle]: " user-handles nil ; predicate 'confirm))))) (if (not (or ; own profile has no need for item-json test: (string= user-handle (mastodon-auth--get-account-name)) (mastodon-tl--profile-buffer-p) (mastodon-tl--property 'item-json :no-move))) (user-error "Looks like there's no toot or user at point?") (let ((account (mastodon-profile--lookup-account-in-status user-handle (mastodon-profile--item-json)))) (if (not account) (user-error "Cannot find a user with handle %S" user-handle) (progn (message "Loading profile of user %s..." user-handle) (mastodon-profile--make-author-buffer account)))))) (defun mastodon-profile-my-profile () "Show the profile of the currently signed in user." (interactive) (message "Loading your profile...") (let ((account (mastodon-profile--account-from-id (mastodon-auth--get-account-id)))) (mastodon-profile--make-author-buffer account))) (defun mastodon-profile--format-user (tootv) "Convert TOOTV into author-bylines and insert. Also insert their profile note. Used to view a user's followers and those they're following." (let ((inhibit-read-only t)) (unless (seq-empty-p tootv) (mapc (lambda (toot) (let ((start-pos (point))) (insert "\n" (propertize (mastodon-tl--byline-author `((account . ,toot)) :avatar) 'byline 't 'item-id (alist-get 'id toot) 'base-item-id (mastodon-tl--item-id toot) 'item-json toot)) (mastodon-media--inline-images start-pos (point)) (insert "\n" (propertize (mastodon-tl--render-text (alist-get 'note toot) nil) 'item-json toot) "\n"))) tootv)))) (defun mastodon-profile--search-account-by-handle (handle) "Return an account based on a user's HANDLE. If the handle does not match a search return then retun NIL." (let* ((handle (if (string= "@" (substring handle 0 1)) (substring handle 1 (length handle)) handle)) (args `(("q" . ,handle) ("type" . "accounts"))) (result (mastodon-http--get-json (mastodon-http--api-v2 "search") args)) (matching-account (seq-remove (lambda (x) (not (string= handle (alist-get 'acct x)))) (alist-get 'accounts result)))) (when (eq 1 (length matching-account)) (elt matching-account 0)))) (defun mastodon-profile--account-from-id (user-id) "Request an account object relating to a USER-ID." (mastodon-http--get-json (mastodon-http--api (format "accounts/%s" user-id)))) (defun mastodon-profile--extract-users-handles (status) "Return all user handles found in STATUS. These include the author, author of reblogged entries and any user mentioned." (when status (let ((this-account (or (alist-get 'account status) ; status is a toot status)) ; status is a user listing (mentions (mastodon-tl--field-status 'mentions status)) (reblog (mastodon-tl--field-status 'reblog status))) (seq-remove (lambda (x) (string= x mastodon-active-user)) (seq-filter #'stringp (seq-uniq (seq-concatenate 'list (list (alist-get 'acct this-account)) (mastodon-profile--extract-users-handles reblog) (mastodon-tl--map-alist 'acct mentions)))))))) (defun mastodon-profile--lookup-account-in-status (handle status) "Return account for HANDLE using hints in STATUS if possible." (let* ((this-account (alist-get 'account status)) (reblog-account (alist-get 'account (alist-get 'reblog status))) (mention-id (seq-some (lambda (mention) (when (string= handle (alist-get 'acct mention)) (alist-get 'id mention))) (alist-get 'mentions status)))) (cond ((string= handle (alist-get 'acct this-account)) this-account) ((string= handle (alist-get 'acct reblog-account)) reblog-account) (mention-id (mastodon-profile--account-from-id mention-id)) (t (mastodon-profile--search-account-by-handle handle))))) ;;; REMOVE (defun mastodon-profile-remove-user-from-followers (&optional id) "Remove a user from your followers. Optionally provide the ID of the account to remove." (interactive) (let* ((account (unless id (mastodon-tl--property 'item-json :no-move))) (id (or id (alist-get 'id account))) (handle (let ((account (or account (mastodon-profile--account-from-id id)))) (alist-get 'acct account))) (url (mastodon-http--api (format "accounts/%s/remove_from_followers" id)))) (when (y-or-n-p (format "Remove follower %s? " handle)) (let ((response (mastodon-http--post url))) (mastodon-http--triage response (lambda (_) (message "Follower %s removed!" handle))))))) (defun mastodon-profile-remove-from-followers-at-point () "Prompt for a user in the item at point and remove from followers." (interactive) (let* ((handles (mastodon-profile--extract-users-handles (mastodon-profile--item-json))) (handle (completing-read "Remove from followers: " handles)) (account (mastodon-profile--lookup-account-in-status handle (mastodon-profile--item-json))) (id (alist-get 'id account))) (mastodon-profile-remove-user-from-followers id))) (defun mastodon-profile-remove-from-followers-list () "Select a user from your followers and remove from followers. Currently limited to 100 handles. If not found, try `mastodon-search-query'." (interactive) (let* ((endpoint (format "accounts/%s/followers" (mastodon-auth--get-account-id))) (url (mastodon-http--api endpoint)) (response (mastodon-http--get-json url `(("limit" . "100")))) (handles (mastodon-tl--map-alist-vals-to-alist 'acct 'id response)) (choice (completing-read "Remove from followers: " handles)) (id (alist-get choice handles))) (mastodon-profile-remove-user-from-followers id))) ;;; PRIVATE NOTES (defun mastodon-profile-add-private-note-to-account () "Add a private note to an account. Can be called from a profile page or normal timeline. Send an empty note to clear an existing one." (interactive) (mastodon-profile--add-or-view-private-note 'mastodon-profile--post-private-note-to-account "add a note to")) (defun mastodon-profile--post-private-note-to-account (id handle note-old) "POST a private note onto an account ID with user HANDLE on the server. NOTE-OLD is the text of any existing note." (let* ((note (read-string (format "Add private note to account %s: " handle) note-old)) (params `(("comment" . ,note))) (url (mastodon-http--api (format "accounts/%s/note" id))) (response (mastodon-http--post url params))) (mastodon-http--triage response (lambda (_) (message "Private note on %s added!" handle))))) (defun mastodon-profile-view-account-private-note () "Display the private note about a user." (interactive) (mastodon-profile--add-or-view-private-note 'mastodon-profile--display-private-note "view private note of" :view)) (defun mastodon-profile--display-private-note (note) "Display private NOTE in a temporary buffer." (with-output-to-temp-buffer "*mastodon-profile-private-note*" (let ((inhibit-read-only t)) (princ note)))) (defun mastodon-profile--profile-json () "Return the profile-json property if we are in a profile buffer." (if (not (mastodon-tl--profile-buffer-p)) (error "Not viewing a profile") (save-excursion (goto-char (point-min)) (or (mastodon-tl--property 'profile-json :no-move) (error "No profile data found"))))) (defun mastodon-profile--add-or-view-private-note (action-fun &optional message view) "Add or view a private note for an account. ACTION-FUN does the adding or viewing, MESSAGE is a prompt for `mastodon-tl--user-handles-get', VIEW is a flag." (let* ((profile-json (mastodon-profile--profile-json)) (handle (if (mastodon-tl--profile-buffer-p) (alist-get 'acct profile-json) (mastodon-tl--user-handles-get message))) (account (if (mastodon-tl--profile-buffer-p) profile-json (mastodon-profile--search-account-by-handle handle))) (id (alist-get 'id account)) (relationships (mastodon-profile--relationships-get id)) (note (alist-get 'note relationships))) (if view (if (string-empty-p note) (user-error "No private note for %s" handle) ;; `mastodon-profile--display-private-note' takes 1 arg: (funcall action-fun note)) ;; `mastodon-profile--post-private-note-to-account' takes 3 args: (funcall action-fun id handle note)))) ;;; FAMILIAR FOLLOWERS (defun mastodon-profile-show-familiar-followers () "Show a list of familiar followers. Familiar followers are accounts that you follow, and that follow the given account." (interactive) (let* ((profile-json (mastodon-profile--profile-json)) (handle (if (mastodon-tl--profile-buffer-p) (alist-get 'acct profile-json) (mastodon-tl--user-handles-get "show familiar followers of"))) (account (if (mastodon-tl--profile-buffer-p) profile-json (mastodon-profile--search-account-by-handle handle))) (id (alist-get 'id account))) (mastodon-profile--get-familiar-followers id))) (defun mastodon-profile--get-familiar-followers (id) "Return JSON data of familiar followers for account ID." ;; the server handles multiple IDs, but we just handle one. (let* ((params `(("id" . ,id))) (url (mastodon-http--api "accounts/familiar_followers")) (json (mastodon-http--get-json url params)) (accounts (alist-get 'accounts (car json))) ; first id (handles (mastodon-tl--map-alist 'acct accounts))) (if (null handles) (user-error "Looks like there are no familiar followers for this account") (let ((choice (completing-read "Show profile of user: " handles))) (mastodon-profile-show-user choice))))) (provide 'mastodon-profile) ;;; mastodon-profile.el ends here mastodon.el/lisp/mastodon-search.el000066400000000000000000000366671501733112700177030ustar00rootroot00000000000000;;; mastodon-search.el --- Search functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Marty Hiatt ;; Author: Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; A basic search function for mastodon.el ;;; Code: (require 'json) (require 'mastodon-tl) (require 'mastodon-widget) (autoload 'mastodon-auth--access-token "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-http--get-search-json "mastodon-http") (autoload 'mastodon-mode "mastodon") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--render-text "mastodon-tl") (autoload 'mastodon-tl--set-buffer-spec "mastodon-tl") (autoload 'mastodon-tl--set-face "mastodon-tl") (autoload 'mastodon-tl--timeline "mastodon-tl") (autoload 'mastodon-tl--toot "mastodon-tl") (autoload 'mastodon-tl--buffer-property "mastodon-tl") (autoload 'mastodon-http--api-v2 "mastodon-http") (defvar mastodon-toot--completion-style-for-mentions) (defvar mastodon-instance-url) (defvar mastodon-tl--link-keymap) (defvar mastodon-tl--horiz-bar) ;; functions for completion of mentions in mastodon-toot (defun mastodon-search--get-user-info-@ (account) "Get user handle, display name and account URL from ACCOUNT." (list (concat "@" (cdr (assoc 'acct account))) (cdr (assoc 'url account)) (cdr (assoc 'display_name account)))) (defun mastodon-search--search-accounts-query (query) "Prompt for a search QUERY and return accounts synchronously. Returns a nested list containing user handle, display name, and URL." (let* ((url (mastodon-http--api "accounts/search")) (response (mastodon-http--get-json url `(("q" . ,query) ;; NB: nil can break params (but works for me) ,(when (string= "following" mastodon-toot--completion-style-for-mentions) '("following" . "true"))) :silent))) (mapcar #'mastodon-search--get-user-info-@ response))) ;; functions for tags completion: (defun mastodon-search--search-tags-query (query) "Return an alist containing tag strings plus their URLs. QUERY is the string to search." (let* ((url (mastodon-http--api-v2 "search")) (params `(("q" . ,query) ("type" . "hashtags"))) (response (mastodon-http--get-json url params :silent)) (tags (alist-get 'hashtags response))) (mapcar #'mastodon-search--get-hashtag-info tags))) ;; trending tags (defun mastodon-search-trending-tags () "Display a list of tags trending on your instance." (interactive) (mastodon-search--view-trending "tags" #'mastodon-search--print-tags)) (defun mastodon-search-trending-statuses () "Display a list of statuses trending on your instance." (interactive) (mastodon-search--view-trending "statuses" #'mastodon-tl--timeline)) (defun mastodon-search-trending-links () "Display a list of links trending on your instance." (interactive) (mastodon-search--view-trending "links" #'mastodon-search--render-links)) (defun mastodon-search--render-links (links) "Render trending LINKS." (cl-loop for l in links do (mastodon-search--render-link l))) (defun mastodon-search--render-link (link) "Render a trending LINK." (let-alist link (insert (propertize (mastodon-tl--render-text (concat "" .url "\n" .title) link) 'item-type 'link 'item-json link 'shr-url .url 'byline t ;; nav 'help-echo (substitute-command-keys "\\[`mastodon-search-load-link-posts'] to view a link's timeline")) ;; TODO: display card link author here "\n\n"))) (defun mastodon-search-load-link-posts () "Load timeline of posts containing link at point." (interactive) (let* ((url (mastodon-tl--property 'shr-url))) (mastodon-tl--link-timeline url))) (defun mastodon-search--view-trending (type print-fun) "Display a list of tags trending on your instance. TYPE is a string, either tags, statuses, or links. PRINT-FUN is the function used to print the data from the response." (let* ((url (mastodon-http--api (format "trends/%s" type))) ;; max for statuses = 40, for others = 20 (limit (if (string= type "statuses") '("limit" . "40") '("limit" . "20"))) (offset '(("offset" . "0"))) (params (push limit offset)) (data (mastodon-http--get-json url params)) (buffer (get-buffer-create (format "*mastodon-trending-%s*" type)))) (with-mastodon-buffer buffer #'mastodon-mode nil (mastodon-tl--set-buffer-spec (buffer-name buffer) (format "trends/%s" type) print-fun nil params) (mastodon-search--insert-heading "trending" type) (funcall print-fun data) (unless (string= type "statuses") (goto-char (point-min)))))) ;; functions for mastodon search (defun mastodon-search--insert-heading (str &optional type) "Insert STR as a heading. Optionally add string TYPE after HEADING." (insert (mastodon-search--format-heading str type))) (defun mastodon-search--format-heading (str &optional type no-newline) "Format STR as a heading. Optionally add string TYPE after HEADING. NO-NEWLINE means don't add add a newline at end." (mastodon-tl--set-face (concat "\n " mastodon-tl--horiz-bar "\n " (upcase str) " " (when type (upcase type)) "\n" " " mastodon-tl--horiz-bar (unless no-newline "\n")) 'success)) (defvar mastodon-search-types '("statuses" "accounts" "hashtags")) (defun mastodon-search-query (query &optional type limit following account-id offset) "Prompt for a search QUERY and return accounts, statuses, and hashtags. TYPE is a member of `mastodon-search-types'. LIMIT is a number as string, up to 40, with 40 the default. FOLLOWING means limit to accounts followed, for \"accounts\" type only. A single prefix arg also sets FOLLOWING to true. ACCOUNT-ID means limit search to that account, for \"statuses\" type only. OFFSET is a number as string, means to skip that many results. It is used for pagination." ;; TODO: handle no results (interactive "sSearch mastodon for: ") (let* ((url (mastodon-http--api-v2 "search")) (following (when (or following (equal current-prefix-arg '(4))) "true")) (type (or type (if (equal current-prefix-arg '(4)) "accounts" ; if FOLLOWING, must be "accounts" (completing-read "Search type: " mastodon-search-types nil :match)))) (limit (or limit "40")) (offset (or offset "0")) (buffer (format "*mastodon-search-%s-%s*" type query)) (params `(("q" . ,query) ,@(when type `(("type" . ,type))) ,@(when limit `(("limit" . ,limit))) ,@(when offset `(("offset" . ,offset))) ,@(when following `(("following" . ,following))) ,@(when account-id `(("account_id" . ,account-id))))) (response (mastodon-http--get-json url params)) (items (alist-get (intern type) response))) (with-mastodon-buffer buffer #'mastodon-mode nil (mastodon-search-mode) (mastodon-search--insert-heading "search") (mastodon-widget--create "Results" '(accounts hashtags statuses) (intern type) (lambda (widget &rest _ignore) (let ((value (widget-value widget))) (mastodon-search-query query (symbol-name value))))) (insert "\n\n") (cond ((string= type "accounts") (mastodon-search--render-response items type buffer params 'mastodon-views--insert-users-propertized-note 'mastodon-views--insert-users-propertized-note)) ((string= type "hashtags") (mastodon-search--render-response items type buffer params 'mastodon-search--print-tags 'mastodon-search--print-tags)) ((string= type "statuses") (mastodon-search--render-response items type buffer params #'mastodon-tl--timeline #'mastodon-tl--timeline))) (goto-char (point-min)) (message (substitute-command-keys "\\[mastodon-search-query-cycle] to cycle result types."))))) (defun mastodon-search-insert-no-results (&optional thing) "Insert a no results message for object THING." (let ((thing (or thing "items"))) (insert (propertize (format "Looks like search returned no %s." thing) 'face 'mastodon-toot-docs-face)))) (defun mastodon-search--render-response (data type buffer params insert-fun update-fun) "Call INSERT-FUN on DATA of result TYPE if non-nil. BUFFER, PARAMS, and UPDATE-FUN are for `mastodon-tl--buffer-spec'." (if (not data) (mastodon-search-insert-no-results type) (funcall insert-fun data)) (mastodon-tl--set-buffer-spec buffer "search" update-fun nil params)) (defun mastodon-search--buf-type () "Return search buffer type, a member of `mastodon-search-types'." ;; called in `mastodon-tl--get-buffer-type' (let* ((spec (mastodon-tl--buffer-property 'update-params))) (alist-get "type" spec nil nil #'string=))) (defun mastodon-search-query-cycle () "Cycle through search types: accounts, hashtags, and statuses." (interactive) (let* ((spec (mastodon-tl--buffer-property 'update-params)) (type (alist-get "type" spec nil nil #'string=)) (query (alist-get "q" spec nil nil #'string=))) (cond ((string= type "hashtags") (mastodon-search-query query "accounts")) ((string= type "accounts") (mastodon-search-query query "statuses")) ((string= type "statuses") (mastodon-search-query query "hashtags"))))) (defun mastodon-search-query-accounts-followed (query) "Run an accounts search QUERY, limited to your followers." (interactive "sSearch mastodon for: ") (mastodon-search-query query "accounts" :following)) (defun mastodon-search--insert-users-propertized (json &optional note) "Insert users list into the buffer. JSON is the data from the server. If NOTE is non-nil, include user's profile note. This is also called by `mastodon-tl--get-follow-suggestions' and `mastodon-profile--insert-follow-requests'." (cl-loop for acct in json do (insert (concat (mastodon-search--propertize-user acct note) mastodon-tl--horiz-bar "\n\n")))) (defun mastodon-search--propertize-user (acct &optional note) "Propertize display string for ACCT, optionally including profile NOTE." (let* ((user (mastodon-search--get-user-info acct)) (id (alist-get 'id acct))) (propertize (concat (propertize (car user) 'face 'mastodon-display-name-face 'byline t 'item-type 'user 'item-id id) ; for prev/next nav " : \n : " (propertize (concat "@" (cadr user)) 'face 'mastodon-handle-face 'mouse-face 'highlight 'mastodon-tab-stop 'user-handle 'keymap mastodon-tl--link-keymap 'mastodon-handle (concat "@" (cadr user)) 'help-echo (concat "Browse user profile of @" (cadr user))) " : \n" (when note (mastodon-tl--render-text (cadddr user) acct)) "\n") 'item-json acct))) ; for compat w other processing functions (defun mastodon-search--print-tags (tags) "Print TAGS data as returned from a \"hashtags\" search query." (let ((tags-list (mapcar #'mastodon-search--get-hashtag-info tags))) (mastodon-search--print-tags-list tags-list))) (defun mastodon-search--print-tags-list (tags-list) "Insert a propertized list of TAGS-LIST." (cl-loop for el in tags-list do (insert " : " (propertize (concat "#" (car el)) 'face '(:box t) 'mouse-face 'highlight 'mastodon-tag (car el) 'mastodon-tab-stop 'hashtag 'item-type 'tag ; for next/prev nav 'byline t ; for next/prev nav 'help-echo (concat "Browse tag #" (car el)) 'keymap mastodon-tl--link-keymap) " : \n\n"))) (defun mastodon-search--get-user-info (account) "Get user handle, display name, account URL and profile note from ACCOUNT." (list (mastodon-tl--display-or-uname account) (alist-get 'acct account) (alist-get 'url account) (alist-get 'note account))) (defun mastodon-search--get-hashtag-info (tag) "Get hashtag name and URL from TAG." (list (alist-get 'name tag) (alist-get 'url tag))) ;; These functions are all unused! ;; (defun mastodon-search--get-status-info (status) ;; "Get ID, timestamp, content, and spoiler from STATUS." ;; (list (alist-get 'id status) ;; (alist-get 'created_at status) ;; (alist-get 'spoiler_text status) ;; (alist-get 'content status))) ;; (defun mastodon-search--id-from-status (status) ;; "Fetch the id from a STATUS returned by a search call to the server. ;; We use this to fetch the complete status from the server." ;; (alist-get 'id status)) ;; (defun mastodon-search--full-status-from-id (id) ;; "Fetch the full status with id ID from the server. ;; This allows us to access the full account etc. details and to ;; render them properly." ;; (let* ((url (mastodon-http--api (format "statuses/%s" id))) ;; ;; (concat mastodon-instance-url "/api/v1/statuses/" ;; ;; (mastodon-tl--as-string id))) ;; (json (mastodon-http--get-json url))) ;; json)) (defvar mastodon-search-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'mastodon-search-query-cycle) map) "Keymap for `mastodon-search-mode'.") (define-minor-mode mastodon-search-mode "Toggle mastodon search minor mode. This minor mode is used for mastodon search pages to adds a keybinding." :init-value nil :lighter " Search" :keymap mastodon-search-mode-map :group 'mastodon :global nil) (provide 'mastodon-search) ;;; mastodon-search.el ends here mastodon.el/lisp/mastodon-tl.el000066400000000000000000005135451501733112700170500ustar00rootroot00000000000000;;; mastodon-tl.el --- Timeline functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-tl.el provides timeline functions. ;;; Code: (require 'shr) (require 'thingatpt) ; for word-at-point (require 'time-date) (require 'cl-lib) (require 'mastodon-iso) (require 'mpv nil :no-error) (require 'url-cache) (autoload 'mastodon-mode "mastodon") (autoload 'mastodon-notifications-get "mastodon") (autoload 'mastodon-url-lookup "mastodon") (autoload 'mastodon-auth--get-account-id "mastodon-auth") (autoload 'mastodon-auth--get-account-name "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--build-array-params-alist "mastodon-http") (autoload 'mastodon-http--build-params-string "mastodon-http") (autoload 'mastodon-http--delete "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-http--get-json-async "mastodon-http") (autoload 'mastodon-http--get-response-async "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-http--process-json "mastodon-http") (autoload 'mastodon-http--put "mastodon-http") (autoload 'mastodon-http--triage "mastodon-http") (autoload 'mastodon-media--get-avatar-rendering "mastodon-media") (autoload 'mastodon-media--get-media-link-rendering "mastodon-media") (autoload 'mastodon-media--inline-images "mastodon-media") (autoload 'mastodon-notifications--filter-types-list "mastodon-notifications") (autoload 'mastodon-notifications-get-mentions "mastodon-notifications") (autoload 'mastodon-profile--account-from-id "mastodon-profile") (autoload 'mastodon-profile--extract-users-handles "mastodon-profile") (autoload 'mastodon-profile--get-preferences-pref "mastodon-profile") (autoload 'mastodon-profile-get-toot-author "mastodon-profile") (autoload 'mastodon-profile--lookup-account-in-status "mastodon-profile") (autoload 'mastodon-profile--make-author-buffer "mastodon-profile") (autoload 'mastodon-profile-my-profile "mastodon-profile") (autoload 'mastodon-profile-open-statuses-no-reblogs "mastodon-profile") (autoload 'mastodon-profile--profile-json "mastodon-profile") (autoload 'mastodon-profile--search-account-by-handle "mastodon-profile") (autoload 'mastodon-profile--item-json "mastodon-profile") (autoload 'mastodon-profile--view-author-profile "mastodon-profile") (autoload 'mastodon-profile-mode "mastodon-profile") (autoload 'mastodon-search--get-user-info "mastodon-search") (autoload 'mastodon-search--insert-users-propertized "mastodon-search") (autoload 'mastodon-search--propertize-user "mastodon-search") (autoload 'mastodon-toot--compose-buffer "mastodon-toot") (autoload 'mastodon-toot-delete-toot "mastodon-toot") (autoload 'mastodon-toot--get-toot-edits "mastodon-toot") (autoload 'mastodon-toot--iso-to-human "mastodon-toot") (autoload 'mastodon-toot-schedule-toot "mastodon-toot") (autoload 'mastodon-toot--set-toot-properties "mastodon-toot") (autoload 'mastodon-toot--update-status-fields "mastodon-toot") (autoload 'mastodon-search--buf-type "mastodon-search") (autoload 'mastodon-views--insert-users-propertized-note "mastodon-views") ; for search pagination (autoload 'mastodon-http--get-response "mastodon-http") (autoload 'mastodon-search--insert-heading "mastodon-search") (autoload 'mastodon-media--process-full-sized-image-response "mastodon-media") (autoload 'mastodon-search-trending-statuses "mastodon-search") (autoload 'mastodon-search--format-heading "mastodon-search") (autoload 'mastodon-media--image-or-cached "mastodon-media") (autoload 'mastodon-toot--base-toot-or-item-json "mastodon-toot") (autoload 'mastodon-search-load-link-posts "mastodon-search") (autoload 'mastodon-notifications--current-type "mastodon-notifications") (autoload 'mastodon-notifications--timeline "mastodon-notifications") (autoload 'mastodon-notifications--empty-group-json-p "mastodon-notifications") (autoload 'mastodon-search--print-tags "mastodon-search") (autoload 'mastodon-profile-show-user "mastodon-profile") (defvar mastodon-toot--visibility) (defvar mastodon-toot-mode) (defvar mastodon-active-user) (defvar mastodon-images-in-notifs) (defvar mastodon-group-notifications) (when (require 'mpv nil :no-error) (declare-function mpv-start "mpv")) (defvar mastodon-mode-map) (defvar mastodon-instance-url) (defvar mastodon-toot-timestamp-format) (defvar shr-use-fonts) ;; declare it since Emacs24 didn't have this (defvar mastodon-media--enable-image-caching) (defvar mastodon-media--generic-broken-image-data) (defvar mastodon-media--sensitive-image-data) (defvar mastodon-media--attachments) ;;; CUSTOMIZES (defgroup mastodon-tl nil "Timelines in Mastodon." :prefix "mastodon-tl-" :group 'mastodon) (defcustom mastodon-tl--enable-relative-timestamps t "Whether to show relative (to the current time) timestamps. This will require periodic updates of a timeline buffer to keep the timestamps current as time progresses." :type '(boolean :tag "Enable relative timestamps and background updater task")) (defcustom mastodon-tl--enable-proportional-fonts nil "Nonnil to enable using proportional fonts when rendering HTML. By default fixed width fonts are used." :type '(boolean :tag "Enable using proportional rather than fixed \ width fonts when rendering HTML text")) (defcustom mastodon-tl--no-fill-on-render nil "Non-nil to disable filling by shr.el while rendering toot body. Use this if your setup isn't compatible with shr's window width filling." :type '(boolean)) (defcustom mastodon-tl--display-media-p t "A boolean value stating whether to show media in timelines." :type 'boolean) (defcustom mastodon-tl--display-caption-not-url-when-no-media t "Display an image's caption rather than URL. Only has an effect when `mastodon-tl--display-media-p' is set to nil." :type 'boolean) (defcustom mastodon-tl--show-avatars nil "Whether to enable display of user avatars in timelines." :type '(boolean :tag "Whether to display user avatars in timelines")) (defcustom mastodon-tl--show-stats t "Whether to show toot stats (faves, boosts, replies counts)." :type 'boolean) (defcustom mastodon-tl--symbols '((reply . ("💬" . "R")) (boost . ("🔁" . "B")) (reblog . ("🔁" . "B")) ;; server compat (favourite . ("⭐" . "F")) (bookmark . ("🔖" . "K")) (media . ("📹" . "[media]")) (verified . ("✓" . "V")) (locked . ("🔒" . "[locked]")) (private . ("🔒" . "[followers]")) (mention . ("@" . "[mention]")) (direct . ("✉" . "[direct]")) (edited . ("✍" . "[edited]")) (update . ("✍" . "[edited]")) ;; server compat (status . ("✍" . "[posted]")) (replied . ("⬇" . "↓")) (reply-bar . ("┃" . "|")) (poll . ("📊" . "[poll]")) (follow . ("👤" . "+")) (follow_request . ("👤" . "+")) (severed_relationships . ("🔗" . "//")) (moderation_warning . ("⚠" . "!!"))) "A set of symbols (and fallback strings) to be used in timeline. If a symbol does not look right (tofu), it means your font settings do not support it." :type '(alist :key-type symbol :value-type string)) (defcustom mastodon-tl-position-after-update nil "Defines where `point' should be located after a timeline update. Valid values are: - nil Top/bottom depending on timeline type - keep-point Keep original position of point - last-old-toot The last toot before the new ones" :type '(choice (const :tag "Top/bottom depending on timeline type" nil) (const :tag "Keep original position of point" keep-point) (const :tag "The last toot before the new ones" last-old-toot))) (defcustom mastodon-tl--timeline-posts-count "20" "Number of posts to display when loading a timeline. Must be an integer between 20 and 40 inclusive." :type '(string)) (defcustom mastodon-tl--hide-replies nil "Whether to hide replies from the timelines. Note that you can hide replies on a one-off basis by loading a timeline with a simple prefix argument, `C-u'." :type '(boolean :tag "Whether to hide replies from the timelines.")) (defcustom mastodon-tl--highlight-current-toot nil "Whether to highlight the toot at point. Uses `cursor-face' special property." :type '(boolean)) (defcustom mastodon-tl--expand-content-warnings 'server "Whether to expand content warnings by default. The API returns data about this setting on the server, but no means to set it, so we roll our own option here to override the server setting if desired. If you change the server setting and want it to be respected by mastodon.el, you'll likely need to either unset `mastodon-profile-acccount-preferences-data' and re-load mastodon.el, or restart Emacs." :type '(choice (const :tag "true" t) (const :tag "false" nil) (const :tag "follow server setting" server))) (defcustom mastodon-tl--tag-timeline-tags nil "A list of up to four tags for use with `mastodon-tl-followed-tags-timeline'." :type '(repeat string)) (defcustom mastodon-tl--load-full-sized-images-in-emacs t "Whether to load full-sized images inside Emacs. Full-sized images are loaded when you hit return on or click on an image in a timeline. If nil, mastodon.el will instead call `shr-browse-image', which respects the user's `browse-url' settings." :type '(boolean)) (defcustom mastodon-tl--remote-local-domains nil "A list of domains to view the local timelines of. See `mastodon-tl-get-remote-local-timeline' for view remote local domains." :type '(repeat string)) (defcustom mastodon-tl--fold-toots-at-length 1200 "Length, in characters, to fold a toot at. Longer toots will be folded and the remainder replaced by a \"read more\" button. If the value is nil, don't fold at all." :type '(integer)) ;;; VARIABLES (defvar-local mastodon-tl--buffer-spec nil "A unique identifier and functions for each mastodon buffer.") (defvar-local mastodon-tl--update-point nil "When updating a mastodon buffer this is where new toots will be inserted. If nil `(point-min)' is used instead.") (defvar-local mastodon-tl--after-update-marker nil "Marker defining the position of point after the update is done.") (defvar-local mastodon-tl--timestamp-next-update nil "The timestamp when the buffer should next be scanned to update the timestamps.") (defvar-local mastodon-tl--timestamp-update-timer nil "The timer that, when set will scan the buffer to update the timestamps.") (defvar mastodon-tl--horiz-bar (make-string 12 (if (char-displayable-p ?―) ?― ?-))) ;;; KEYMAPS (defvar mastodon-tl--link-keymap (let ((map (make-sparse-keymap))) (define-key map [return] #'mastodon-tl-do-link-action-at-point) (define-key map [mouse-2] #'mastodon-tl-do-link-action) (define-key map [follow-link] 'mouse-face) map) "The keymap for link-like things in buffer (except for shr.el generate links). This will make the region of text act like like a link with mouse highlighting, mouse click action tabbing to next/previous link etc.") (defvar mastodon-tl--shr-map-replacement (let ((map (make-sparse-keymap))) (set-keymap-parent map shr-map) ;; Replace the move to next/previous link bindings with our ;; version that knows about more types of links. (define-key map [remap shr-next-link] #'mastodon-tl-next-tab-item) (define-key map [remap shr-previous-link] #'mastodon-tl-previous-tab-item) ;; keep new my-profile binding; shr 'O' doesn't work here anyway (define-key map (kbd "O") #'mastodon-profile-my-profile) ;; remove shr's u binding, as it the maybe-probe-and-copy-url ;; is already bound to w also (define-key map (kbd "u") #'mastodon-tl-update) (define-key map [remap shr-browse-url] #'mastodon-url-lookup) (define-key map (kbd "M-RET") #'mastodon-search-load-link-posts) map) "The keymap to be set for shr.el generated links that are not images. We need to override the keymap so tabbing will navigate to all types of mastodon links and not just shr.el-generated ones.") (defvar mastodon-tl--shr-image-map-replacement (let ((map (make-sparse-keymap))) (set-keymap-parent map (if (boundp 'shr-image-map) shr-image-map shr-map)) ;; Replace the move to next/previous link bindings with our ;; version that knows about more types of links. (define-key map [remap shr-next-link] #'mastodon-tl-next-tab-item) (define-key map [remap shr-previous-link] #'mastodon-tl-previous-tab-item) ;; browse-url loads the preview only, we want browse-image ;; on RET to browse full sized image URL (define-key map [remap shr-browse-url] #'mastodon-tl-view-full-image-or-play-video) ;; remove shr's u binding, as it the maybe-probe-and-copy-url ;; is already bound to w also (define-key map (kbd "u") #'mastodon-tl-update) ;; keep new my-profile binding; shr 'O' doesn't work here anyway (define-key map (kbd "O") #'mastodon-profile-my-profile) (define-key map (kbd "C") #'mastodon-tl-copy-image-caption) (define-key map (kbd "S") #'mastodon-tl-toggle-sensitive-image) (define-key map (kbd "") #'mastodon-tl-mpv-play-video-at-point) (define-key map (kbd "") #'mastodon-tl-click-image-or-video) map) "The keymap to be set for shr.el generated image links. We need to override the keymap so tabbing will navigate to all types of mastodon links and not just shr.el-generated ones.") (defvar mastodon-tl--byline-link-keymap (when (require 'mpv nil :no-error) (let ((map (make-sparse-keymap))) (define-key map (kbd "") #'mastodon-tl-mpv-play-video-from-byline) (define-key map (kbd "RET") #'mastodon-profile-get-toot-author) (define-key map (kbd "S") #'mastodon-tl-toggle-sensitive-image) map)) "The keymap to be set for the author byline. It is active where point is placed by `mastodon-tl-goto-next-item.'") (require 'image-mode) (defvar mastodon-image-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map image-mode-map) (define-key map (kbd ">") #'mastodon-tl-next-full-image) (define-key map (kbd "<") #'mastodon-tl-prev-full-image) (define-key map (kbd ".") #'mastodon-tl-next-full-image) (define-key map (kbd ",") #'mastodon-tl-prev-full-image) ;; matches view full image binding in main keymap: (define-key map (kbd "=") #'mastodon-tl-next-full-image) (define-key map (kbd "-") #'mastodon-tl-prev-full-image) (define-key map (kbd "") #'mastodon-tl-next-full-image) (define-key map (kbd "") #'mastodon-tl-prev-full-image) map)) ;;; MACROS (defmacro with-mastodon-buffer (buffer mode-fun other-window &rest body) "Evaluate BODY in a new or existing buffer called BUFFER. MODE-FUN is called to set the major mode. OTHER-WINDOW means call `switch-to-buffer-other-window' rather than `pop-to-buffer'." (declare (debug t) (indent 3)) `(with-current-buffer (get-buffer-create ,buffer) (let ((inhibit-read-only t)) (erase-buffer) (funcall ,mode-fun) (remove-overlays) ; video overlays ,@body ;; return result of switching buffer: (if ,other-window (switch-to-buffer-other-window ,buffer) (pop-to-buffer ,buffer '(display-buffer-same-window)))))) (defmacro mastodon-tl--do-if-item (&rest body) "Execute BODY if we have an item at point." (declare (debug t)) `(if (and (not (mastodon-tl--profile-buffer-p)) (not (mastodon-tl--property 'item-json))) ; includes users but not tags (user-error "Looks like there's no item at point?") ,@body)) ;;; NAV (defun mastodon-tl-scroll-up-command () "Call `scroll-up-command', loading more toots if necessary. If we hit `point-max', call `mastodon-tl--more' then `scroll-up-command'." (interactive) (if (not (eq (point) (point-max))) (scroll-up-command) (mastodon-tl--more) (scroll-up-command))) (defun mastodon-tl-next-tab-item (&optional previous) "Move to the next interesting item. This could be the next toot, link, or image; whichever comes first. Don't move if nothing to move to is found, i.e. near the end of the buffer. This also skips tab items in invisible text, i.e. hidden spoiler text. PREVIOUS means move to previous item." (interactive) (let (next-range (search-pos (point))) (while (and (setq next-range (mastodon-tl--find-next-or-previous-property-range 'mastodon-tab-stop search-pos previous)) (get-text-property (car next-range) 'invisible) (setq search-pos (if previous (1- (car next-range)) (1+ (cdr next-range))))) ;; do nothing, all the action is in the while condition ) (if (null next-range) (user-error "Nothing else here") (goto-char (car next-range)) (message "%s" (mastodon-tl--property 'help-echo :no-move))))) (defun mastodon-tl-previous-tab-item () "Move to the previous interesting item. This could be the previous toot, link, or image; whichever comes first. Don't move if nothing else to move to is found, i.e. near the start of the buffer. This also skips tab items in invisible text, i.e. hidden spoiler text." (interactive) (mastodon-tl-next-tab-item :previous)) (defun mastodon-tl--goto-item-pos (find-pos refresh &optional pos) "Search for item with function FIND-POS. If search returns nil, execute REFRESH function. Optionally start from POS." (let* ((npos ; toot/user items have byline: (funcall find-pos (or pos (point)) ;; FIXME: we need to fix item-type? ;; 'item-type ; breaks nav to last item in a view? 'byline (current-buffer))) (max-lisp-eval-depth 4)) ;; clamp down on endless loops (if npos (if (not (get-text-property npos 'item-type)) ; generic ;; FIXME let's make refresh &optional and only call refresh/recur ;; if non-nil: (mastodon-tl--goto-item-pos find-pos refresh npos) (goto-char npos) ;; force display of help-echo on moving to a toot byline: (mastodon-tl--message-help-echo)) (condition-case nil (funcall refresh) (error "No more items"))))) (defun mastodon-tl-goto-next-item (&optional no-refresh) "Jump to next item. Load more items it no next item. NO-REFRESH means do no not try to load more items if no next item found." (interactive) (condition-case nil (mastodon-tl--goto-item-pos 'next-single-property-change (unless no-refresh 'mastodon-tl--more)) (t (error "No more items")))) (defun mastodon-tl-goto-prev-item (&optional no-refresh) "Jump to previous item. Update if no previous items. NO-REFRESH means do no not try to load more items if no next item found." (interactive) (condition-case nil (mastodon-tl--goto-item-pos 'previous-single-property-change (unless no-refresh 'mastodon-tl-update)) (t (error "No more items")))) (defun mastodon-tl--goto-first-item () "Jump to first toot or item in buffer. Used on initializing a timeline or thread." (goto-char (point-min)) (condition-case nil (mastodon-tl--goto-item-pos 'next-single-property-change 'next-line) (t (error "No item")))) ;;; TIMELINES (defun mastodon-tl-get-federated-timeline (&optional prefix local max-id) "Open federated timeline. If LOCAL, get only local timeline. With a single PREFIX arg, hide-replies. With a double PREFIX arg, only show posts with media." (interactive "p") (let ((params `(("limit" . ,mastodon-tl--timeline-posts-count) ,@(when (eq prefix 16) '(("only_media" . "true"))) ,@(when local '(("local" . "true"))) ,@(when max-id `(("max_id" . ,(mastodon-tl--buffer-property 'max-id))))))) (message "Loading federated timeline...") (mastodon-tl--init (if local "local" "federated") "timelines/public" 'mastodon-tl--timeline nil params (when (eq prefix 4) t)))) (defun mastodon-tl-get-home-timeline (&optional arg max-id) "Open home timeline. With a single prefix ARG, hide replies. MAX-ID is a flag to add the max_id pagination parameter." (interactive "p") (let* ((params `(("limit" . ,mastodon-tl--timeline-posts-count) ,@(when max-id `(("max_id" . ,(mastodon-tl--buffer-property 'max-id))))))) (message "Loading home timeline...") (mastodon-tl--init "home" "timelines/home" 'mastodon-tl--timeline nil params (when (eq arg 4) t)))) (defun mastodon-tl-get-remote-local-timeline (&optional endpoint) "Prompt for an instance domain and try to display its local timeline. You can enter any working instance domain. Domains that you want to regularly load can be stored in `mastodon-tl--remote-local-domains' for easy access with completion. Note that some instances do not make their local timelines public, in which case this will not work. To interact with any item, you must view it from your own instance, which you can do with `mastodon-tl-view-item-on-own-instance'. Optionally, provide API ENDPOINT." (interactive) (let* ((domain (completing-read "Domain for remote local tl: " mastodon-tl--remote-local-domains)) (params `(("limit" . ,mastodon-tl--timeline-posts-count) ("local" . "true"))) (buf (concat "remote-local-" domain)) (known (member domain (mastodon-http--get-json (mastodon-http--api "instance/peers"))))) ;; condition-case doesn't work here, so i added basic error handling to ;; `mastodon-tl--init*' instead (when (or known (y-or-n-p "Domain appears unknown to your instance. Proceed?")) (mastodon-tl--init buf (or endpoint "timelines/public") 'mastodon-tl--timeline nil params nil domain)))) (defun mastodon-tl-remote-tag-timeline (&optional tag) "Call `mastodon-tl-get-remote-local-timeline' but for a TAG timeline." (interactive) (let* ((tag (or tag (read-string "Tag: "))) (endpoint (format "timelines/tag/%s" tag))) (mastodon-tl-get-remote-local-timeline endpoint))) (defun mastodon-tl-view-item-on-own-instance () "Load current toot on your own instance. Use this to re-load remote-local items in order to interact with them." (interactive) (mastodon-tl--do-if-item (let* ((toot (mastodon-tl--property 'item-json)) (uri (mastodon-tl--field 'uri toot))) (mastodon-url-lookup uri)))) (defun mastodon-tl-get-local-timeline (&optional prefix max-id) "Open local timeline. With a single PREFIX arg, hide-replies. With a double PREFIX arg, only show posts with media. MAX-ID is a flag to add the max_id pagination parameter." (interactive "p") (message "Loading local timeline...") (mastodon-tl-get-federated-timeline prefix :local max-id)) (defun mastodon-tl-get-tag-timeline (&optional prefix tag) "Prompt for tag and opens its timeline. Optionally load TAG timeline directly. With a single PREFIX arg, only show posts with media. With a double PREFIX arg, limit results to your own instance." (interactive "p") (let* ((word (or (word-at-point) "")) (input (or tag (read-string (format "Load timeline for tag (%s): " word)))) (tag (or tag (if (string-empty-p input) word input)))) (message "Loading timeline for #%s..." tag) (mastodon-tl--show-tag-timeline prefix tag))) (defun mastodon-tl--show-tag-timeline (&optional prefix tag) "Opens a new buffer showing the timeline of posts with hastag TAG. If TAG is a list, show a timeline for all tags. With a single PREFIX arg, only show posts with media. With a double PREFIX arg, limit results to your own instance." (let ((params `(("limit" . ,mastodon-tl--timeline-posts-count) ,@(when (eq prefix 4) '(("only_media" . "true"))) ,@(when (eq prefix 16) '(("local" . "true")))))) (when (listp tag) (let ((list (mastodon-http--build-array-params-alist "any[]" (cdr tag)))) (while list (push (pop list) params)))) (mastodon-tl--init (if (listp tag) "tags-multiple" (concat "tag-" tag)) (concat "timelines/tag/" (if (listp tag) (car tag) tag)) ; must be /tag/:sth 'mastodon-tl--timeline nil params))) (defun mastodon-tl--link-timeline (url) "Load a link timeline, displaying posts containing URL." (let ((params `(("url" . ,url)))) (mastodon-tl--init "links" "timelines/link" 'mastodon-tl--timeline nil params))) (defun mastodon-tl-announcements () "Display announcements from your instance." (interactive) (mastodon-tl--init "announcements" "announcements" 'mastodon-tl--timeline nil nil nil nil :no-byline)) ;;; BYLINES, etc. (defun mastodon-tl--message-help-echo () "Call message on `help-echo' property at point. Do so if type of status at poins is not follow_request/follow." (let ((type (alist-get 'type (mastodon-tl--property 'item-json :no-move))) (echo (mastodon-tl--property 'help-echo :no-move))) (when (not (string= "" echo)) ; not for followers/following in profile (unless (or (string= type "follow_request") (string= type "follow")) ; no counts for these (message "%s" echo))))) (defun mastodon-tl--byline-username (toot) "Format a byline username from account in TOOT. TOOT may be account data, or toot data, in which case acount data is extracted from it." (let ((data (or (alist-get 'account toot) toot))) ;; grouped nofifs use account data directly (let-alist data (propertize (if (and .display_name (not (string-empty-p .display_name))) .display_name .username) 'face 'mastodon-display-name-face ;; enable playing of videos when point is on byline: ;; 'attachments (mastodon-tl--get-attachments-for-byline toot) 'keymap mastodon-tl--byline-link-keymap ;; echo faves count when point on post author name: ;; which is where --goto-next-toot puts point. 'help-echo ;; but don't add it to "following"/"follows" on ;; profile views: we don't have a tl--buffer-spec ;; yet: (unless (or (string-suffix-p "-followers*" (buffer-name)) (string-suffix-p "-following*" (buffer-name))) (mastodon-tl--format-byline-help-echo data)))))) (defun mastodon-tl--byline-handle (toot &optional domain string face) "Format a byline handle from account in TOOT. DOMAIN is optionally added to the handle. ACCOUNT is optionally acccount data to use. STRING is optionally the string to propertize, it is used to make username rather than handle buttons. FACE is optionally the face to use. The last two args allow for display a username as a clickable handle." (let-alist (or (alist-get 'account toot) toot) ;; grouped notifs (mastodon-tl--buttonify-link (or string (concat "@" .acct (when domain (concat "@" (url-host (url-generic-parse-url .url)))))) 'face (or face 'mastodon-handle-face) 'mastodon-tab-stop 'user-handle 'shr-url .url 'mastodon-handle (concat "@" .acct) 'help-echo (concat "Browse user profile of @" .acct)))) (defun mastodon-tl--byline-uname-+-handle (data &optional domain) "Concatenate a byline username and handle. DATA is the (toot) data to use. DOMAIN is optionally a domain for the handle. ACCOUNT is optionally acccount data to use." (concat (mastodon-tl--byline-username data) " (" (mastodon-tl--byline-handle data domain) ")")) (defun mastodon-tl--display-or-uname (account) "Return display name or username from ACCOUNT data." (if (not (string-empty-p (alist-get 'display_name account))) (alist-get 'display_name account) (alist-get 'username account))) (defun mastodon-tl--byline-author (toot &optional avatar domain base) "Propertize author of TOOT. With arg AVATAR, include the account's avatar image. When DOMAIN, force inclusion of user's domain in their handle. BASE means to use data from the base item (reblog slot) if possible. If BASE is nil, we are a boosted byline, so show less info. ACCOUNT is optionally acccount data to use." (let* ((data (if base (mastodon-tl--toot-or-base toot) toot)) (account (alist-get 'account data)) (uname (mastodon-tl--display-or-uname account))) (concat ;; avatar insertion moved up to `mastodon-tl--byline' by default to ;; be outside 'byline propt. (when (and avatar ; used by `mastodon-profile--format-user' mastodon-tl--show-avatars mastodon-tl--display-media-p (mastodon-tl--image-trans-check)) (mastodon-media--get-avatar-rendering (map-nested-elt data '(account avatar)))) (if (not base) ;; boost symbol: (concat (mastodon-tl--symbol 'boost) " " ;; username as button: (mastodon-tl--byline-handle data domain ;; display uname not handle (for boosts): uname 'mastodon-display-name-face)) ;; normal combo author byline: (mastodon-tl--byline-uname-+-handle data domain))))) (defun mastodon-tl--format-byline-help-echo (toot) "Format a help-echo for byline of TOOT. Displays a toot's media types and optionally the binding to play moving image media from the byline. Used when point is at the start of a byline, i.e. where `mastodon-tl-goto-next-item' leaves point." (let* ((toot-to-count (or ; simply praying this order works (alist-get 'status toot) ; notifications timeline ;; fol-req notif, has 'type placed before boosts coz fol-reqs have ;; a (useless) reblog entry: (when (and (or (mastodon-tl--buffer-type-eq 'notifications) (mastodon-tl--buffer-type-eq 'mentions)) (alist-get 'type toot)) toot) (alist-get 'reblog toot) ; boosts toot)) ; everything else (fol-req-p (let ((type (alist-get 'type toot-to-count))) (or (string= type "follow") (string= type "follow_request"))))) (unless fol-req-p (let* ((media-types (mastodon-tl--get-media-types toot)) (format-media (when media-types (format "media: %s" (mapconcat #'identity media-types " ")))) (format-media-binding (when (and (or (member "video" media-types) (member "gifv" media-types)) (require 'mpv nil :no-error)) " | C-RET to view with mpv"))) (concat format-media format-media-binding))))) (defun mastodon-tl--get-media-types (toot) "Return a list of the media attachment types of the TOOT at point." (let* ((attachments (mastodon-tl--field 'media_attachments toot))) (mastodon-tl--map-alist 'type attachments))) (defun mastodon-tl--get-attachments-for-byline (toot) "Return a list of attachment URLs and types for TOOT. The result is added as an attachments property to author-byline." (let ((media (mastodon-tl--field 'media_attachments toot))) (mapcar (lambda (attachment) (let-alist attachment (list :id .id :type .type ;; fallback for notifications: :url (or .remote_url .url)))) media))) (defun mastodon-tl--byline-booster (toot) "Add author byline for booster from TOOT. Only return something if TOOT contains a reblog." (let ((reblog (alist-get 'reblog toot))) (if reblog (mastodon-tl--byline-author toot) ""))) (defun mastodon-tl--byline-booster-str (toot) "Format boosted string for action byline. Only return string if TOOT contains a reblog." (let ((reblog (alist-get 'reblog toot))) (if reblog (concat " " (propertize "boosted" 'face 'mastodon-boosted-face) "\n") ""))) (defun mastodon-tl--byline-boost (toot) "Format a boost action-byline element for TOOT." (concat (mastodon-tl--byline-booster toot) (mastodon-tl--byline-booster-str toot))) (defun mastodon-tl--format-faved-or-boosted-byline (letter) "Format the byline marker for a boosted or favourited status. LETTER is a string, F for favourited, B for boosted, or K for bookmarked." (let ((help-string (cond ((string= letter "F") "favourited") ((string= letter "B") "boosted") ((string= letter (or "🔖" "K")) "bookmarked")))) (format "(%s) " (propertize letter 'face 'mastodon-boost-fave-face ;; emojify breaks this for 🔖: 'help-echo (format "You have %s this status." help-string))))) (defun mastodon-tl--image-trans-check () "Call `image-transforms-p', or `image-type-available-p' imagemagick." (if (version< emacs-version "27.1") (image-type-available-p 'imagemagick) (image-transforms-p))) (defun mastodon-tl--byline (toot &optional detailed-p domain base-toot group ts) "Generate (bottom) byline for TOOT. AUTHOR-BYLINE is a function for adding the author portion of the byline that takes one variable. DETAILED-P means display more detailed info. For now this just means displaying toot client. When DOMAIN, force inclusion of user's domain in their handle. BASE-TOOT is JSON for the base toot, if any. GROUP is the notification group if any. ACCOUNT is the notification account if any. TS is a timestamp from the server, if any." (let* ((type (alist-get 'type (or group toot))) (created-time (or ts ;; mentions, statuses, folls/foll-reqs ;; bosts, faves, edits, polls in notifs view use base item ;; timestamp: (mastodon-tl--field 'created_at (mastodon-tl--field 'status toot)) ;; all other toots, inc. boosts/faves in timelines: ;; (mastodon-tl--field auto fetches from reblogs if needed): (mastodon-tl--field 'created_at toot))) (parsed-time (when created-time (date-to-time created-time))) ;; non-grouped notifs now need to pull the following data from ;; base toot: (base-maybe (or base-toot ;; show edits for notifs (mastodon-tl--toot-or-base toot))) ;; for boosts (faved (eq t (mastodon-tl--field 'favourited base-maybe))) (boosted (eq t (mastodon-tl--field 'reblogged base-maybe))) (bookmarked (eq t (mastodon-tl--field 'bookmarked base-maybe))) (visibility (mastodon-tl--field 'visibility base-maybe)) (account (alist-get 'account base-maybe)) (avatar-url (alist-get 'avatar account)) (edited-time (alist-get 'edited_at base-maybe)) (edited-parsed (when edited-time (date-to-time edited-time)))) (concat ;; Boosted/favourited markers are not technically part of the byline, so ;; we don't propertize them with 'byline t', as per the rest. This ;; ensures that `mastodon-tl-goto-next-item' puts point on ;; author-byline, not before the (F) or (B) marker. Not propertizing like ;; this makes the behaviour of these markers consistent whether they are ;; displayed for an already boosted/favourited toot or as the result of ;; the toot having just been favourited/boosted. (concat (when boosted (mastodon-tl--format-faved-or-boosted-byline (mastodon-tl--symbol 'boost))) (when faved (mastodon-tl--format-faved-or-boosted-byline (mastodon-tl--symbol 'favourite))) (when bookmarked (mastodon-tl--format-faved-or-boosted-byline (mastodon-tl--symbol 'bookmark)))) ;; we remove avatars from the byline also, so that they also do not ;; mess with `mastodon-tl-goto-next-item': (when (and mastodon-tl--show-avatars mastodon-tl--display-media-p (mastodon-tl--image-trans-check)) (mastodon-media--get-avatar-rendering avatar-url)) (propertize (concat ;; NB: action-byline (boost) is now added in insert-status, so no ;; longer part of the byline. ;; (base) author byline: ;; we use base-toot if poss for fave/boost notifs that need to show ;; base item in author byline (mastodon-tl--byline-author (or base-toot toot) nil domain :base) ;; visibility: (cond ((string= visibility "direct") (propertize (concat " " (mastodon-tl--symbol 'direct)) 'help-echo visibility)) ((string= visibility "private") (propertize (concat " " (mastodon-tl--symbol 'private)) 'help-echo visibility))) " " ;; timestamp: (let ((ts (format-time-string mastodon-toot-timestamp-format parsed-time))) (propertize ts 'timestamp parsed-time 'display (if mastodon-tl--enable-relative-timestamps (mastodon-tl--relative-time-description parsed-time) parsed-time) 'help-echo ts)) ;; detailed: (when detailed-p (let* ((app-name (map-nested-elt toot '(application name))) (app-url (map-nested-elt toot '(application website)))) (when app-name (concat (propertize " via " 'face 'default) (propertize app-name 'face 'mastodon-display-name-face 'follow-link t 'mouse-face 'highlight 'mastodon-tab-stop 'shr-url 'shr-url app-url 'help-echo app-url 'keymap mastodon-tl--shr-map-replacement))))) ;; edited: (when edited-time (concat " " (mastodon-tl--symbol 'edited) " " (propertize (format-time-string mastodon-toot-timestamp-format edited-parsed) 'face 'mastodon-toot-docs-face 'timestamp edited-parsed 'display (if mastodon-tl--enable-relative-timestamps (mastodon-tl--relative-time-description edited-parsed) edited-parsed)))) (propertize (concat "\n " mastodon-tl--horiz-bar) 'face 'default) ;; stats: (when (and mastodon-tl--show-stats (not (member type '("follow" "follow_request")))) (mastodon-tl--toot-stats toot)) "\n") 'favourited-p faved 'boosted-p boosted 'bookmarked-p bookmarked ;; enable playing of videos when point is on byline: 'attachments (mastodon-tl--get-attachments-for-byline toot) 'edited edited-time 'edit-history (when edited-time (mastodon-toot--get-toot-edits (alist-get 'id base-maybe))) 'byline t)))) ;;; TIMESTAMPS (defun mastodon-tl--relative-time-details (timestamp &optional current-time) "Return cons of (DESCRIPTIVE STRING . NEXT-CHANGE) for the TIMESTAMP. Use the optional CURRENT-TIME as the current time (only used for reliable testing). The descriptive string is a human readable version relative to the current time while the next change timestamp give the first time that this description will change in the future. TIMESTAMP is assumed to be in the past." (let* ((time-difference (time-subtract current-time timestamp)) (seconds-difference (float-time time-difference)) (tmp (mastodon-tl--human-duration (max 0 seconds-difference)))) ;; revert to old just now style for < 1 min (cons (concat (car tmp) (if (string= "just now" (car tmp)) "" " ago")) (time-add current-time (cdr tmp))))) (defun mastodon-tl--relative-time-description (timestamp &optional current-time) "Return a string with a human readable TIMESTAMP relative to the current time. Use the optional CURRENT-TIME as the current time (only used for reliable testing). E.g. this could return something like \"1 min ago\", \"yesterday\", etc. TIME-STAMP is assumed to be in the past." (car (mastodon-tl--relative-time-details timestamp current-time))) ;;; RENDERING HTML, LINKS, HASHTAGS, HANDLES (defun mastodon-tl--render-text (string &optional toot) "Return a propertized text rendering the given HTML string STRING. The contents comes from the given TOOT which is used in parsing links in the text. If TOOT is nil no parsing occurs." (when string ; handle rare empty notif server bug (with-temp-buffer (insert string) (let ((shr-use-fonts mastodon-tl--enable-proportional-fonts) (shr-width (when mastodon-tl--enable-proportional-fonts (if mastodon-tl--no-fill-on-render 0 (- (window-width) 3)))) (cat (get 'mastodon-tl-link 'button-category-symbol))) (shr-render-region (point-min) (point-max)) (alter-text-property (point-min) (point-max) 'category (lambda (type) (when type cat)))) ;; Make all links a tab stop recognized by our own logic, make ;; things point to our own logic (e.g. hashtags), and update keymaps ;; where needed: (when toot (let (region) (while (setq region (mastodon-tl--find-property-range 'shr-url (or (cdr region) (point-min)))) (mastodon-tl--process-link toot (car region) (cdr region) (get-text-property (car region) 'shr-url)) (when (proper-list-p toot) ;; not on profile fields cons cells ;; render card author maybe: (let* ((card-url (map-nested-elt toot '(card url))) (authors (map-nested-elt toot '(card authors))) (url (buffer-substring (car region) (cdr region))) (url-no-query (car (split-string url "?")))) (when (and (string= url-no-query card-url) ;; only if we have an account's data: (alist-get 'account (car authors))) (goto-char (point-max)) (mastodon-tl--insert-card-authors authors))))))) (buffer-string)))) (defun mastodon-tl--insert-card-authors (authors) "Insert a string of card AUTHORS." (let ((authors-str (format "Author%s: " (if (< 1 (length authors)) "s" "")))) (insert (concat "\n(" authors-str (mapconcat #'mastodon-tl--format-card-author authors "\n") ")\n")))) (defun mastodon-tl--format-card-author (data) "Render card author DATA." (when-let* ((account (alist-get 'account data))) ;.account (let-alist account ;.account ;; FIXME: replace with refactored handle render fun ;; in byline refactor branch: (concat (propertize (or .display_name .username) 'face 'mastodon-display-name-face 'item-type 'user 'item-id .id) " " (propertize (concat "@" .acct) 'face 'mastodon-handle-face 'mouse-face 'highlight 'mastodon-tab-stop 'user-handle 'keymap mastodon-tl--link-keymap 'mastodon-handle (concat "@" .acct) 'help-echo (concat "Browse user profile of @" .acct)))))) (defun mastodon-tl--process-link (toot start end url) "Process link URL in TOOT as hashtag, userhandle, or normal link. START and END are the boundaries of the link in the toot." (let* (mastodon-tab-stop-type keymap (help-echo (get-text-property start 'help-echo)) extra-properties ;; handle calling this on non-toots, e.g. for profiles: (toot-url (when (proper-list-p toot) (mastodon-tl--field 'url toot))) (toot-url (when toot-url (url-generic-parse-url toot-url))) (toot-instance-url (if toot-url (concat (url-type toot-url) "://" (url-host toot-url)) mastodon-instance-url)) (link-str (buffer-substring-no-properties start end)) (maybe-hashtag (mastodon-tl--hashtag-from-url url toot-instance-url)) (maybe-userhandle (if (proper-list-p toot) ; fails for profile buffers? (or (mastodon-tl--userhandle-from-mentions toot link-str) (mastodon-tl--userhandle-from-url url link-str)) (mastodon-tl--userhandle-from-url url link-str)))) (cond (maybe-hashtag (setq mastodon-tab-stop-type 'hashtag keymap mastodon-tl--link-keymap help-echo (concat "Browse tag #" maybe-hashtag) extra-properties (list 'mastodon-tag maybe-hashtag))) (maybe-userhandle ;; fails on mentions in profile notes: (let ((maybe-userid (when (proper-list-p toot) (mastodon-tl--extract-userid-toot toot link-str)))) (setq mastodon-tab-stop-type 'user-handle keymap mastodon-tl--link-keymap help-echo (concat "Browse user profile of " maybe-userhandle) extra-properties (append (list 'mastodon-handle maybe-userhandle) (when maybe-userid (list 'account-id maybe-userid)))))) (t ;; Anything else (leave it as a url handled by shr.el): (setq keymap (if (eq shr-map (get-text-property start 'keymap)) mastodon-tl--shr-map-replacement mastodon-tl--shr-image-map-replacement) mastodon-tab-stop-type 'shr-url))) (add-text-properties start end (append (list 'mastodon-tab-stop mastodon-tab-stop-type 'keymap keymap 'help-echo help-echo) extra-properties)))) (defun mastodon-tl--userhandle-from-mentions (toot link) "Extract a user handle from mentions in json TOOT. LINK is maybe the `@handle' to search for." (mastodon-tl--el-from-mentions 'acct toot link)) (defun mastodon-tl--extract-userid-toot (toot link) "Extract a user id for an ACCT from mentions in a TOOT. LINK is maybe the `@handle' to search for." (mastodon-tl--el-from-mentions 'id toot link)) (defun mastodon-tl--el-from-mentions (el toot link) "Extract element EL from TOOT mentions that matches LINK. LINK should be a simple handle string with no domain, i.e. \"@user\". Return nil if no matching element." (let ((mentions (alist-get 'mentions toot))) (when mentions (let* ((mention (pop mentions)) (name (substring-no-properties link 1 (length link))) ; cull @ return) (while mention (when (string= name (alist-get 'username mention)) (setq return (alist-get el mention))) (setq mention (pop mentions))) return)))) (defun mastodon-tl--userhandle-from-url (url &optional buffer-text) "Return the user hande the URL points to or nil if it is not a profile link. BUFFER-TEXT is the text covered by the link with URL, for a user profile this should be of the form , e.g. \"@Gargon\". This is called on all post URLs, so needs to handle non profile URLs gracefully." (let* ((parsed-url (url-generic-parse-url url)) (host (url-host parsed-url)) (local-p (string= (url-host (url-generic-parse-url mastodon-instance-url)) host)) (path-raw (url-filename parsed-url))) (unless (string-empty-p path-raw) (let ((path (substring path-raw 1))) ;; remove "/" prefix (if (not buffer-text) (when (string-prefix-p "@" path) (if local-p path (concat "@" host))) (when (and (string= "@" (substring buffer-text 0 1)) ;; don't error on domain only url (rare): (string= (downcase buffer-text) (downcase path))) (if local-p buffer-text ; no instance suffix for local mention (concat buffer-text "@" host)))))))) (defun mastodon-tl--hashtag-from-url (url instance-url) "Return the hashtag that URL points to or nil if URL is not a tag link. INSTANCE-URL is the url of the instance for the toot that the link came from (tag links always point to a page on the instance publishing the toot)." ;; TODO: do we rly need to check it against instance-url? ;; test suggests we might (let* ((instance-host (url-host (url-generic-parse-url instance-url))) (parsed (url-generic-parse-url url)) (path (url-filename parsed)) (split (split-string path "/"))) (when (and (string= instance-host (url-host parsed)) (string-prefix-p "/tag" path)) ;; "/tag/" or "/tags/" (nth 2 split)))) (defun mastodon-tl--base-tags (tags body-tags) "Return a string of all tags not in BODY-TAGS, linkified. TAGS is a list of tag alists, from a post's JSON." (when (mastodon-tl--base-tags-print-p tags body-tags) (concat "\n" (cl-loop for tag in tags concat (concat (mastodon-tl--render-base-tag tag body-tags) " "))))) (defun mastodon-tl--base-tags-print-p (tags body-tags) "Non-nil if we need to print base tags. We need to do so if TAGS contains any elements not in BODY-TAGS." (cl-remove-if (lambda (tag) (member (alist-get 'name tag) body-tags)) tags)) (defun mastodon-tl--render-base-tag (tag body-tags) "Return TAG as a linkified string, provided it is not in BODY-TAGS." (let ((name (alist-get 'name tag))) (unless (member (downcase name) body-tags) (mastodon-tl--buttonify-link (concat "#" name) 'mastodon-tab-stop 'hashtag 'mastodon-tag name 'mouse-face '(highlight) 'keymap mastodon-tl--link-keymap 'face '(shr-text shr-link) 'follow-link t 'shr-tab-stop t 'shr-url (alist-get 'url tag) 'help-echo (concat "Browse tag #" name))))) ;;; HYPERLINKS (define-button-type 'mastodon-tl-link 'action #'mastodon-tl--push-button 'keymap mastodon-tl--link-keymap 'mouse-face 'highlight) (defun mastodon-tl--push-button (button) "Do the appropriate action for BUTTON." (mastodon-tl-do-link-action-at-point (button-start button))) (defun mastodon-tl--buttonify-link (string &rest properties) "Make STRING a `mastodon-tl-link' type button. PROPERTIES are additional properties to attach to string." (apply #'propertize string 'button t 'category (get 'mastodon-tl-link 'button-category-symbol) properties)) (defun mastodon-tl--make-link (string link-type) "Return a propertized version of STRING that will act like link. LINK-TYPE is the type of link to produce." (let ((help-text (cond ((eq link-type 'content-warning) "Toggle hidden text") ((or (eq link-type 'read-more) (eq link-type 'read-less)) "Toggle full post") (t (error "Unknown link type %s" link-type))))) (mastodon-tl--buttonify-link string 'mastodon-tab-stop link-type 'help-echo help-text))) (defun mastodon-tl-do-link-action-at-point (pos) "Do the action of the link at POS. Used for hitting RET on a given link." (interactive "d") (let ((link-type (get-text-property pos 'mastodon-tab-stop))) (cond ((eq link-type 'content-warning) (mastodon-tl--toggle-spoiler-text pos)) ((eq link-type 'hashtag) (mastodon-tl--show-tag-timeline nil (get-text-property pos 'mastodon-tag))) ;; 'account / 'account-id is not set for mentions, only bylines ((eq link-type 'user-handle) (let ((account-json (get-text-property pos 'account)) (account-id (get-text-property pos 'account-id))) (cond (account-json (mastodon-profile--make-author-buffer account-json)) (account-id (mastodon-profile--make-author-buffer (mastodon-profile--account-from-id account-id))) (t (let ((account (mastodon-profile--search-account-by-handle (get-text-property pos 'mastodon-handle)))) ;; never call make-author-buffer on nil account: (cond (account (mastodon-profile--make-author-buffer account)) ;; optional webfinger lookup: ((y-or-n-p "Search for account returned nothing. Perform URL lookup?") (mastodon-url-lookup (get-text-property pos 'shr-url))) (t (error "Unable to find account")))))))) ((eq link-type 'shr-url) (mastodon-url-lookup (get-text-property pos 'shr-url))) ((eq link-type 'read-more) (mastodon-tl-unfold-post)) ((eq link-type 'read-less) (mastodon-tl-fold-post)) (t (error "Unknown link type %s" link-type))))) (defun mastodon-tl-do-link-action (event) "Do the action of the link at point. Used for a mouse-click EVENT on a link." (interactive "@e") (mastodon-tl-do-link-action-at-point (posn-point (event-end event)))) ;;; CONTENT WARNINGS (defun mastodon-tl--has-spoiler (toot) "Check if the given TOOT has a spoiler text. Spoiler text should initially be shown only while the main content should be hidden." (let ((spoiler (mastodon-tl--field 'spoiler_text toot))) (and spoiler (> (length spoiler) 0)))) (defun mastodon-tl--toggle-spoiler-text (position) "Toggle the visibility of the spoiler text at/after POSITION." (let* ((inhibit-read-only t) (spoiler-region (mastodon-tl--find-property-range 'mastodon-content-warning-body position nil)) (new-state (not (get-text-property (car spoiler-region) 'invisible)))) (if (not spoiler-region) (user-error "No spoiler text here") (add-text-properties (car spoiler-region) (cdr spoiler-region) (list 'invisible new-state)) new-state))) ;; return what we set invisibility to (defun mastodon-tl-toggle-spoiler-text-in-toot () "Toggle the visibility of the spoiler text in the current toot." (interactive) (let* ((toot-range (or (mastodon-tl--find-property-range 'item-json (point)) (mastodon-tl--find-property-range 'item-json (point) t))) (spoiler-range (when toot-range (mastodon-tl--find-property-range 'mastodon-content-warning-body (car toot-range))))) (cond ((null toot-range) (user-error "No toot here")) ((or (null spoiler-range) (> (car spoiler-range) (cdr toot-range))) (user-error "No content warning text here")) (t (mastodon-tl--toggle-spoiler-text (car spoiler-range)))))) (defun mastodon-tl-toggle-spoiler-in-thread () "Toggler content warning for all posts in current thread." (interactive) (let ((thread-p (eq (mastodon-tl--buffer-property 'update-function) 'mastodon-tl--thread-do))) (if (not thread-p) (user-error "Not in a thread") (save-excursion (goto-char (point-min)) (while (not (string= "No more items" ; improve this hack test! (mastodon-tl-goto-next-item :no-refresh))) (let* ((json (mastodon-tl--property 'item-json :no-move)) (cw (alist-get 'spoiler_text json))) (when (not (string= "" cw)) (let ((new-state (pcase (mastodon-tl-toggle-spoiler-text-in-toot) ('t 'folded) ('nil 'unfolded)))) (plist-put mastodon-tl--buffer-spec 'thread-unfolded new-state))))))))) (defun mastodon-tl--spoiler (toot &optional filter) "Render TOOT with spoiler message. This assumes TOOT is a toot with a spoiler message. The main body gets hidden and only the spoiler text and the content warning message are displayed. The content warning message is a link which unhides/hides the main body. FILTER is a string to use as a filter warning spoiler instead." (let* ((spoiler (mastodon-tl--field 'spoiler_text toot)) (string (mastodon-tl--set-face (mastodon-tl--clean-tabs-and-nl (mastodon-tl--render-text spoiler toot)) 'default)) (message (concat " " mastodon-tl--horiz-bar "\n " (mastodon-tl--make-link (if filter (concat "Filtered: " filter) (concat "CW: " string)) 'content-warning) "\n " mastodon-tl--horiz-bar "\n")) (cw (mastodon-tl--set-face message 'mastodon-cw-face))) (concat cw (propertize (mastodon-tl--content toot) 'invisible (or filter ;; filters = invis (let ((cust mastodon-tl--expand-content-warnings)) (if (not (eq 'server cust)) (not cust) ;; opp to setting ;; respect server setting: ;; If something goes wrong reading prefs, ;; just return t so CWs fold by default. (condition-case nil (if (eq :json-false (mastodon-profile--get-preferences-pref 'reading:expand:spoilers)) t nil) (error t))))) 'mastodon-content-warning-body t)))) ;;; MEDIA (defun mastodon-tl--media (toot) "Retrieve a media attachment link for TOOT if one exists. Else return an empty string." (let* ((attachments (mastodon-tl--field 'media_attachments toot)) (sensitive (mastodon-tl--field 'sensitive toot)) (media-string (mapconcat (lambda (x) (mastodon-tl--media-attachment x sensitive)) attachments ""))) (if (not (and mastodon-tl--display-media-p (string-empty-p media-string))) (concat "\n" media-string) ""))) (defun mastodon-tl--media-attachment (attachment sensitive) "Return a propertized string for ATTACHMENT. SENSITIVE is a flag from the item's JSON data." (let-alist attachment (let ((display-str (concat "Media:: " (if (and mastodon-tl--display-caption-not-url-when-no-media .description) .description .preview_url))) (remote-url (or .remote_url .url))) (if (and mastodon-tl--display-media-p ;; if in notifs, also check notifs images custom: (if (or (mastodon-tl--buffer-type-eq 'notifications) (mastodon-tl--buffer-type-eq 'mentions)) mastodon-images-in-notifs t)) (mastodon-media--get-media-link-rendering ; placeholder: "[img]" .preview_url remote-url ; for shr-browse-url .type .description sensitive) ;; return URL/caption: (concat (mastodon-tl--propertize-img-str-or-url (concat "Media:: " .preview_url) ; string .preview_url remote-url .type .description display-str 'shr-link .description sensitive) "\n"))))) (defun mastodon-tl--propertize-img-str-or-url (str media-url full-remote-url type help-echo &optional display face caption sensitive) "Propertize an media placeholder string \"[img]\" or media URL. STR is the string to propertize, MEDIA-URL is the preview link, FULL-REMOTE-URL is the link to the full resolution image on the server, TYPE is the media type. HELP-ECHO, DISPLAY, and FACE are the text properties to add. CAPTION is the image caption, added as a text property. SENSITIVE is a flag from the item's JSON data." (propertize str 'media-url media-url 'media-state (when (string= str "[img]") 'needs-loading) 'media-type 'media-link 'mastodon-media-type type 'display display 'face face 'mouse-face 'highlight 'mastodon-tab-stop 'image ; for do-link-action-at-point 'image-url (or full-remote-url media-url) ; for shr-browse-image 'keymap mastodon-tl--shr-image-map-replacement 'image-description caption 'sensitive sensitive 'help-echo (if (or (string= type "image") (string= type nil) (string= type "unknown")) ; handle borked images help-echo (concat help-echo "\nC-RET: play " type " with mpv")))) ;;; FULL IMAGE VIEW (define-derived-mode mastodon-image-mode image-mode "mastodon-image" :group 'mastodon) ;; patch `shr-browse-image' to accept url arg: (defun mastodon-tl-shr-browse-image (&optional image-url copy-url) "Browse the image under point. If COPY-URL (the prefix if called interactively) is non-nil, copy the URL of the image to the kill buffer instead. Optionally use IMAGE-URL rather than the image-url property at point." (interactive "sP") (let ((url (or image-url (get-text-property (point) 'image-url)))) (cond ((not url) (message "No image under point")) (copy-url (with-temp-buffer (insert url) (copy-region-as-kill (point-min) (point-max)) (message "Copied %s" url))) (t (message "Browsing %s..." url) (browse-url url))))) (defun mastodon-tl--view-image-url (url attachments) "View image URL. Set ATTACHMENTS metadata in image buffer." (if (not url) (user-error "No url found") (if (not mastodon-tl--load-full-sized-images-in-emacs) (mastodon-tl-shr-browse-image url) (mastodon-media--image-or-cached url #'mastodon-media--process-full-sized-image-response `(nil ,url ,attachments ,(buffer-name)))))) (defun mastodon-tl-view-full-image-at-point () "Browse full-sized version of image at point in a new window." (interactive) (if (not (eq (mastodon-tl--property 'mastodon-tab-stop) 'image)) (user-error "No image at point?") (let* ((url (mastodon-tl--property 'image-url)) (attachments (mastodon-tl--property 'attachments))) (mastodon-tl--view-image-url url attachments)))) (defun mastodon-tl-view-first-full-image () "From item byline, fetch load its first full image." (interactive) (let* ((attachments (mastodon-tl--property 'attachments)) (url (plist-get (car attachments) :url))) (if (not attachments) (user-error "Toot has no attachments") (mastodon-tl--view-image-url url attachments)))) (defun mastodon-tl--get-next-image-url () "Return the url for the next image to load. Cycles through values in `mastodon-media--attachments'." (let* ((url (car mastodon-media--attachments)) ;; match url against our plists: (current (mastodon-tl--current-image-url url))) ;; fetch from next item in current or use first item if current has ;; only 1 item: (plist-get (if (= 1 (length current)) (cadr mastodon-media--attachments) (cadr current)) :url))) (defun mastodon-tl--current-image-url (url) "Try to fetch URL from `mastodon-media--attachments'. The return value is that of `cl-member-if', ie if a match is found, it returns the match and the list of which it is the car." (cl-member-if (lambda (attachment) (equal url (plist-get attachment :url))) (cdr mastodon-media--attachments))) (defun mastodon-tl--get-prev-image-url () "Return the URL of the previous item in `mastodon-media--attachments'." (let* ((url (car mastodon-media--attachments)) (current (mastodon-tl--current-image-url url))) (plist-get (nth (1- (length current)) (cdr mastodon-media--attachments)) :url))) (defun mastodon-tl-next-full-image () "From full image view buffer, load the toot's next image." (interactive) (let* ((next-url (mastodon-tl--get-next-image-url))) (mastodon-tl--view-image-url next-url (cdr mastodon-media--attachments)))) (defun mastodon-tl-prev-full-image () "From full image view buffer, load the toot's prev image." (interactive) (let* ((prev-url (mastodon-tl--get-prev-image-url))) (mastodon-tl--view-image-url prev-url (cdr mastodon-media--attachments)))) (defun mastodon-tl-toggle-sensitive-image () "Toggle dislay of sensitive image at point." (interactive) (if (not (eq t (mastodon-tl--property 'sensitive))) (user-error "No sensitive media at point?") (let ((data (mastodon-tl--property 'image-data :no-move)) (inhibit-read-only t) (end (next-single-property-change (point) 'sensitive-state))) (add-text-properties (point) end (if (eq 'hidden (mastodon-tl--property 'sensitive-state :no-move)) ;; display: `( display ,data sensitive-state showing) ;; hide: `( sensitive-state hidden display ,(create-image mastodon-media--sensitive-image-data nil t))))))) ;; POLLS (defun mastodon-tl--format-poll-option (option counter length) "Format poll OPTION. COUNTER is a counter. LENGTH is of the longest option, for formatting." (format "%s: %s%s%s\n" counter (propertize (alist-get 'title option) 'face 'success) (make-string (1+ (- length (length (alist-get 'title option)))) ?\ ) ;; TODO: disambiguate no votes from hidden votes (format "[%s votes]" (or (alist-get 'votes_count option) "0")))) (defun mastodon-tl--format-poll (poll) "From json poll data POLL, return a display string." (let-alist poll (let* ((options (mastodon-tl--map-alist 'title .options)) (longest (car (sort (mapcar #'length options ) #'>))) (counter 0)) (concat "\n" (mastodon-tl--symbol 'poll) "\n\n" (mapconcat (lambda (option) (setq counter (1+ counter)) (mastodon-tl--format-poll-option option counter longest)) .options "\n") "\n" (propertize (cond (.voters_count ; sometimes it is nil (format "%s %s | " .voters_count (if (= .voters_count 1) "person" "people"))) (.vote_count (format "%s votes | " .vote_count)) (t "")) 'face 'mastodon-toot-docs-face) (let ((str (if (eq .expired :json-false) (if (eq .expires_at nil) "" (mastodon-tl--format-poll-expiry .expires_at)) "Poll expired."))) (propertize str 'face 'mastodon-toot-docs-face)) "\n")))) (defconst mastodon-tl--time-units '("sec" 60.0 ;; Use a float to convert `n' to float. "min" 60 "hour" 24 "day" 7 "week" 4.345 "month" 12 "year")) (defun mastodon-tl--format-poll-expiry (timestamp) "Convert poll expiry TIMESTAMP into a descriptive string. TIMESTAMP is from the expires_at field of a poll's JSON data, and is in ISO 8601 Datetime format." (let* ((ts (encode-time (parse-time-string timestamp))) (seconds (time-to-seconds (time-subtract ts nil)))) ;; FIXME: Use the `cdr' to update poll expiry times? (concat (car (mastodon-tl--human-duration (max 0 seconds))) " left"))) (defun mastodon-tl--human-duration (seconds &optional resolution) "Return a string describing SECONDS in a more human-friendly way. The return format is (STRING . RES) where RES is the resolution of this string, in seconds. RESOLUTION is the finest resolution, in seconds, to use for the second part of the output (defaults to 60, so that seconds are only displayed when the duration is smaller than a minute)." (cl-assert (>= seconds 0)) (unless resolution (setq resolution 60)) (let* ((units mastodon-tl--time-units) (n1 seconds) (unit1 (pop units)) (res1 1) n2 unit2 res2 next) (while (and units (> (truncate (setq next (/ n1 (car units)))) 0)) (setq unit2 unit1) (setq res2 res1) (setq n2 (- n1 (* (car units) (truncate n1 (car units))))) (setq n1 next) (setq res1 (truncate (* res1 (car units)))) (pop units) (setq unit1 (pop units))) (setq n1 (truncate n1)) (if n2 (setq n2 (truncate n2))) (cond ((null n2) ;; revert to old just now style for < 1 min: (cons "just now" 60)) ;; (cons (format "%d %s%s" n1 unit1 (if (> n1 1) "s" "")) ;; (max resolution res1))) ((< (* res2 n2) resolution) (cons (format "%d %s%s" n1 unit1 (if (> n1 1) "s" "")) (max resolution res2))) ((< res2 resolution) (let ((n2 (/ (* resolution (/ (* n2 res2) resolution)) res2))) (cons (format "%d %s%s, %d %s%s" n1 unit1 (if (> n1 1) "s" "") n2 unit2 (if (> n2 1) "s" "")) resolution))) (t (cons (format "%d %s%s, %d %s%s" n1 unit1 (if (> n1 1) "s" "") n2 unit2 (if (> n2 1) "s" "")) (max res2 resolution)))))) (defun mastodon-tl--format-read-poll-option (options) "Format poll OPTIONS for `completing-read'. OPTIONS is an alist." ;; we display option number and the option title ;; but also store both as a cons cell as the cdr, as we need it later (cl-loop for cell in options collect (cons (format "%s | %s" (car cell) (cdr cell)) cell))) (defun mastodon-tl--read-poll-option () "Read a poll option to vote on a poll." (let* ((toot (mastodon-tl--property 'item-json)) (poll (mastodon-tl--field 'poll toot))) (if (null poll) (user-error "No poll here") (let* ((options (mastodon-tl--field 'options poll)) (titles (mastodon-tl--map-alist 'title options)) (number-seq (number-sequence 1 (length options))) (numbers (mapcar #'number-to-string number-seq)) (options-alist (cl-mapcar #'cons numbers titles)) (candidates (mastodon-tl--format-read-poll-option options-alist)) (choice (completing-read "Poll option to vote for: " candidates nil :match))) (list (cdr (assoc choice candidates))))))) (defun mastodon-tl-poll-vote (option) "If there is a poll at point, prompt user for OPTION to vote on it." (interactive (mastodon-tl--read-poll-option)) (let ((toot (mastodon-tl--property 'item-json))) (if (null (mastodon-tl--field 'poll toot)) (user-error "No poll here") (let* ((poll (mastodon-tl--field 'poll toot)) (id (alist-get 'id poll)) (url (mastodon-http--api (format "polls/%s/votes" id))) ;; zero-index our option: (option-arg (number-to-string (1- (string-to-number (car option))))) (arg `(("choices[]" . ,option-arg))) (response (mastodon-http--post url arg))) (mastodon-http--triage response (lambda (_) (message "You voted for option %s: %s!" (car option) (cdr option)))))))) ;; VIDEOS / MPV (defun mastodon-tl--find-first-video-in-attachments () "Return the first media attachment that is a moving image." (let ((attachments (mastodon-tl--property 'attachments)) vids) (cl-loop for x in attachments do (let ((att-type (plist-get x :type))) (when (or (string= "video" att-type) (string= "gifv" att-type)) (push x vids)))) (car vids))) (defun mastodon-tl-mpv-play-video-from-byline () "Run `mastodon-tl-mpv-play-video-at-point' on first moving image in post." (interactive) (let* ((video (mastodon-tl--find-first-video-in-attachments)) (url (plist-get video :url)) (type (plist-get video :type))) (mastodon-tl-mpv-play-video-at-point url type))) (defun mastodon-tl-view-full-image-or-play-video (_pos) "View full sized version of image at point, or try to play video." (interactive "d") (if (mastodon-tl--media-video-p) (mastodon-tl-mpv-play-video-at-point) (mastodon-tl-view-full-image-at-point))) (defun mastodon-tl-click-image-or-video (event) "Click to play video with `mpv.el'. EVENT is a mouse-click arg." (interactive "@e") (mastodon-tl-view-full-image-or-play-video (posn-point (event-end event)))) (defun mastodon-tl--media-video-p (&optional type) "T if mastodon-media-type prop is \"gifv\" or \"video\". TYPE is a mastodon media type." (let ((type (or type (mastodon-tl--property 'mastodon-media-type :no-move)))) (or (string= type "gifv") (string= type "video")))) (defun mastodon-tl-mpv-play-video-at-point (&optional url type) "Play the video or gif at point with an mpv process. URL and TYPE are provided when called while point is on byline, in which case play first video or gif from current toot." (interactive) (let ((url (or url ; point in byline: (mastodon-tl--property 'image-url :no-move)))) ; point in toot (if (or (not url) (not (mastodon-tl--media-video-p type))) (user-error "No moving image here?") (message "'q' to kill mpv.") (condition-case x (mpv-start "--loop" url) (void-function (message "Looks like mpv.el not installed. Error: %s" (error-message-string x))))))) (defun mastodon-tl-copy-image-caption () "Copy the caption of the image at point." (interactive) (if-let* ((desc (get-text-property (point) 'image-description))) (progn (kill-new desc) (message "Image caption copied.")) (message "No image caption."))) ;;; INSERT TOOTS (defun mastodon-tl--content (toot) "Retrieve text content from TOOT. Runs `mastodon-tl--render-text' and fetches poll or media." (let* ((content (mastodon-tl--field 'content toot)) (poll-p (mastodon-tl--field 'poll toot)) (media-p (mastodon-tl--field 'media_attachments toot))) (concat (mastodon-tl--render-text content toot) (when poll-p (mastodon-tl--format-poll (mastodon-tl--field 'poll toot))) ;; toot or reblog (when media-p (mastodon-tl--media toot))))) (defun mastodon-tl--prev-item-id () "Return the id of the last toot inserted into the buffer." (let* ((prev-change (save-excursion (previous-single-property-change (point) 'base-item-id))) (prev-pos (when prev-change (1- prev-change)))) (when prev-pos (get-text-property prev-pos 'base-item-id)))) (defun mastodon-tl--after-reply-status (reply-to-id) "T if REPLY-TO-ID is equal to that of the last toot inserted in the bufer." (let ((prev-id (mastodon-tl--prev-item-id))) (string= reply-to-id prev-id))) (defun mastodon-tl--body-tags (body) "Return a plain string list of the tags in BODY." ;; NB: replies on text props 'mastodon-tab-stop and 'shr-url ;; FIXME: snac tags fail our prop test, not sure about others. (let (list prop) (with-temp-buffer (insert body) (goto-char (point-min)) (save-match-data (while (setq prop (text-property-search-forward 'mastodon-tab-stop 'hashtag t)) (goto-char (prop-match-beginning prop)) (let ((tag (mastodon-tl--property 'mastodon-tag))) (when tag (push (downcase tag) list))) (goto-char (prop-match-end prop))))) list)) (defun mastodon-tl--insert-status (toot body &optional detailed-p thread domain unfolded no-byline cw-expanded) "Display the content and byline of timeline element TOOT. BODY will form the section of the toot above the byline. DETAILED-P means display more detailed info. For now this just means displaying toot client. THREAD means the status will be displayed in a thread view. When DOMAIN, force inclusion of user's domain in their handle. UNFOLDED is a boolean meaning whether to unfold or fold item if foldable. NO-BYLINE means just insert toot body, used for folding. CW-EXPANDED means treat content warnings as unfolded." (let* ((reply-to-id (alist-get 'in_reply_to_id toot)) (after-reply-status-p (when (and thread reply-to-id) (mastodon-tl--after-reply-status reply-to-id))) ;; (type (alist-get 'type toot)) (toot-foldable (and mastodon-tl--fold-toots-at-length (length> body mastodon-tl--fold-toots-at-length))) (cw-p (not (string-empty-p (alist-get 'spoiler_text toot)))) (body-tags (mastodon-tl--body-tags body))) (insert (propertize ;; body + byline: (concat (propertize ;; body only: (concat "\n" (mastodon-tl--byline-boost toot) ;; top byline (boost) ;; relpy symbol: (when (and after-reply-status-p thread) (concat (mastodon-tl--symbol 'replied) "\n")) ;; actual body: (let ((bar (mastodon-tl--symbol 'reply-bar)) (body (if (and toot-foldable (not unfolded)) (mastodon-tl--fold-body body) body))) (if (and after-reply-status-p thread) (propertize body 'line-prefix bar 'wrap-prefix bar) body)) (if (and toot-foldable unfolded cw-expanded) (mastodon-tl--read-more-or-less "LESS" cw-p (not cw-expanded)) "")) 'toot-body t) ;; includes newlines etc. for folding ;; post tags: (let ((tags (alist-get 'tags toot))) ;; FIXME: we also need to test here for normal body tags, and if ;; so, don't go ahead: (if tags (concat (mastodon-tl--base-tags tags body-tags)) "")) ;; byline: "\n" (if no-byline "" (mastodon-tl--byline toot detailed-p domain))) 'item-type 'toot 'item-id (alist-get 'id toot) ; toot id 'base-item-id (mastodon-tl--item-id toot) ; with reblog check 'item-json toot 'cursor-face 'mastodon-cursor-highlight-face 'toot-foldable toot-foldable 'toot-folded (and toot-foldable (not unfolded))) (if no-byline "" "\n")))) (defun mastodon-tl--is-reply (toot) "Check if the TOOT is a reply to another one (and not boosted). Used as a predicate in `mastodon-tl--timeline'." (and (mastodon-tl--field 'in_reply_to_id toot) (eq :json-false (mastodon-tl--field 'reblogged toot)))) (defun mastodon-tl--filters-alist (filters) "Parse filter data for FILTERS. For each filter, return a list of action (warn or hide), filter title, and context." (cl-loop for x in filters ;; includes non filter elts! for f = (alist-get 'filter x) collect (list (alist-get 'filter_action f) (alist-get 'title f) (alist-get 'context f)))) (defun mastodon-tl--filter-by-context (context filters) "Remove FILTERS that don't apply to the current CONTEXT." (cl-remove-if-not (lambda (x) (member context (nth 2 x))) filters)) (defun mastodon-tl--filters-context () "Return a string of the current buffer's filter context. Returns a member of `mastodon-views--filter-types'." (let ((buf (mastodon-tl--get-buffer-type))) (cond ((or (eq buf 'local) (eq buf 'federated)) "public") ((mastodon-tl--profile-buffer-p) "profile") ((eq buf 'list-timeline) "home") ;; lists are "home" filter (t ;; thread, notifs, home: (symbol-name buf))))) (defun mastodon-tl--current-filters (filters) "Return the filters from FILTERS data that apply in the current context. For each filter, return a list of action (warn or hide), filter title, and context." (let ((context (mastodon-tl--filters-context)) (filters-no-context (mastodon-tl--filters-alist filters))) (mastodon-tl--filter-by-context context filters-no-context))) (defun mastodon-tl--toot (toot &optional detailed-p thread domain unfolded no-byline cw-expanded) "Format TOOT and insert it into the buffer. DETAILED-P means display more detailed info. For now this just means displaying toot client. THREAD means the status will be displayed in a thread view. When DOMAIN, force inclusion of user's domain in their handle. UNFOLDED is a boolean meaning whether to unfold or fold item if foldable. NO-BYLINE means just insert toot body, used for folding. CW-EXPANDED means treat content warnings as unfolded." (let* ((mastodon-tl--expand-content-warnings (or cw-expanded mastodon-tl--expand-content-warnings)) (filtered (mastodon-tl--field 'filtered toot)) (filters (when filtered (mastodon-tl--current-filters filtered))) (spoiler-or-content (if-let* ((match (assoc "warn" filters))) (mastodon-tl--spoiler toot (cadr match)) (if (mastodon-tl--has-spoiler toot) (mastodon-tl--spoiler toot) (mastodon-tl--content toot))))) ;; If any filters are "hide", then we hide, ;; even though item may also have a "warn" filter: (unless (and filtered (assoc "hide" filters)) ;; no insert (mastodon-tl--insert-status toot (mastodon-tl--clean-tabs-and-nl spoiler-or-content) detailed-p thread domain unfolded no-byline cw-expanded)))) (defun mastodon-tl--timeline (toots &optional thread domain no-byline) "Display each toot in TOOTS. This function removes replies if user required. THREAD means the status will be displayed in a thread view. When DOMAIN, force inclusion of user's domain in their handle. NO-BYLINE means just insert toot body, used for folding." (let ((start-pos (point)) (toots ;; hack to *not* filter replies on profiles: (if (eq (mastodon-tl--get-buffer-type) 'profile-statuses) toots (if (or ; we were called via --more*: (mastodon-tl--buffer-property 'hide-replies nil :no-error) ;; loading a tl with a prefix arg: (mastodon-tl--hide-replies-p current-prefix-arg)) (cl-remove-if-not #'mastodon-tl--is-reply toots) toots)))) (cl-loop for toot in toots do (mastodon-tl--toot toot nil thread domain nil no-byline)) ;; media: (when mastodon-tl--display-media-p (mastodon-media--inline-images start-pos (point))) (goto-char (point-min)))) ;;; FOLDING (defun mastodon-tl--read-more-or-less (str cw invis) "Return a read more or read less heading. STR is an uppercase string, either MORE or LESS. The heading is a link to toggle the fold status of the toot. CW and INVIS are boolean values for the properties invisible and mastodon-content-warning-body." (let ((type (if (string= str "MORE") 'read-more 'read-less))) (propertize (mastodon-search--format-heading (mastodon-tl--make-link (format "READ %s" str) type) nil :no-newline) 'mastodon-content-warning-body cw 'invisible invis))) (defun mastodon-tl--fold-body (body) "Fold toot BODY if it is very long. Folding decided by `mastodon-tl--fold-toots-at-length'." (let* ((invis (get-text-property (1- (length body)) 'invisible body)) (cw (get-text-property (1- (length body)) 'mastodon-content-warning-body body)) (heading (mastodon-tl--read-more-or-less "MORE" cw invis)) (display (concat (substring body 0 mastodon-tl--fold-toots-at-length) heading))) (propertize display 'read-more body))) (defun mastodon-tl-unfold-post (&optional fold) "Unfold the toot at point if it is folded (read-more). FOLD means to fold it instead." (interactive) (let ((at-byline (mastodon-tl--property 'byline :no-move))) (if (save-excursion (when (not at-byline) (mastodon-tl-goto-next-item)) (not (mastodon-tl--property 'toot-foldable :no-move))) (user-error "No foldable item at point?") (let* ((inhibit-read-only t) (body-range (mastodon-tl--find-property-range 'toot-body (point) :backward)) (cw-range (mastodon-tl--find-property-range 'mastodon-content-warning-body (point) :backward)) (cw-invis (when cw-range (get-text-property (car cw-range) 'invisible))) (toot (mastodon-tl--property 'item-json :no-move)) ;; `replace-region-contents' is much too slow, our hack from ;; fedi.el is much simpler and much faster: (beg (car body-range)) (end (cdr body-range)) (last-point (point)) (point-after-fold (> last-point (+ beg mastodon-tl--fold-toots-at-length)))) ;; save-excursion here useless actually: ;; FIXME: because point goes to top of item, the screen gets scrolled ;; by insertion (goto-char beg) (delete-region beg end) (delete-char 1) ;; prevent newlines accumulating ;; insert toot body: (mastodon-tl--toot toot nil nil nil (not fold) :no-byline (unless cw-invis :cw-expanded)) ;; respect CW state ;; set toot-folded prop on entire toot (not just body): (let ((toot-range ;; post fold action range: (mastodon-tl--find-property-range 'item-json (point) :backward))) (add-text-properties (car toot-range) (cdr toot-range) `(toot-folded ,fold))) ;; try to leave point somewhere sane: (cond ((or at-byline (and fold point-after-fold)) ;; point was in area now folded (ignore-errors (forward-line -1)) ;; in case we are between (mastodon-tl-goto-next-item)) ;; goto byline (t (goto-char last-point) (when point-after-fold ;; point was in READ MORE heading: (beginning-of-line)))) (message (format "%s toot" (if fold "Fold" "Unfold"))))))) (defun mastodon-tl-fold-post () "Fold post at point, if it is too long." (interactive) (mastodon-tl-unfold-post :fold)) (defun mastodon-tl-fold-post-toggle () "Toggle the folding status of the toot at point." (interactive) (let* ((folded (mastodon-tl--property 'toot-folded :no-move))) (mastodon-tl-unfold-post (not folded)))) ;;; TOOT STATS ;; calqued off mastodon-alt.el: (defun mastodon-tl--toot-for-stats (&optional toot) "Return the TOOT on which we want to extract stats. If no TOOT is given, the one at point is considered." (let* ((original-toot (or toot (get-text-property (point) 'item-json))) (toot (or (alist-get 'status original-toot) (when (alist-get 'type original-toot) original-toot) (alist-get 'reblog original-toot) original-toot)) (type (alist-get 'type (or toot)))) (unless (member type '("follow" "follow_request")) toot))) (defun mastodon-tl--toot-stats (toot) "Return a right aligned string (using display align-to). String is filled with TOOT statistics (boosts, favs, replies). When the TOOT is a reblog (boost), statistics from reblogged toots are returned. To disable showing the stats, customize `mastodon-tl--show-stats'." (let-alist (mastodon-tl--toot-for-stats toot) (let* ((faves-prop (propertize (format "%s" .favourites_count) 'favourites-count .favourites_count)) (boosts-prop (propertize (format "%s" .reblogs_count) 'boosts-count .reblogs_count)) (faves (format "%s %s" faves-prop (mastodon-tl--symbol 'favourite))) (boosts (format "%s %s" boosts-prop (mastodon-tl--symbol 'boost))) (replies (format "%s %s" .replies_count (mastodon-tl--symbol 'reply))) (stats (concat (propertize faves 'favourited-p (eq t .favourited) 'favourites-field t 'help-echo (format "%s favourites" .favourites_count) 'face 'mastodon-toot-docs-face) (propertize " | " 'face 'mastodon-toot-docs-face) (propertize boosts 'boosted-p (eq t .reblogged) 'boosts-field t 'help-echo (format "%s boosts" .reblogs_count) 'face 'mastodon-toot-docs-face) (propertize " | " 'face 'mastodon-toot-docs-face) (propertize replies 'replies-field t 'replies-count .replies_count 'help-echo (format "%s replies" .replies_count) 'face 'mastodon-toot-docs-face))) (right-spacing (propertize " " 'display `(space :align-to (- right ,(+ (length stats) 7)))))) (concat right-spacing stats)))) ;;; BUFFER SPEC (defun mastodon-tl--update-function (&optional buffer) "Get the UPDATE-FUNCTION stored in `mastodon-tl--buffer-spec'. Optionally get it for BUFFER." (mastodon-tl--buffer-property 'update-function buffer)) (defun mastodon-tl--endpoint (&optional buffer no-error) "Get the ENDPOINT stored in `mastodon-tl--buffer-spec'. Optionally set it for BUFFER. NO-ERROR means to fail silently." (mastodon-tl--buffer-property 'endpoint buffer no-error)) (defun mastodon-tl--buffer-name (&optional buffer no-error) "Get the BUFFER-NAME stored in `mastodon-tl--buffer-spec'. Optionally get it for BUFFER. NO-ERROR means to fail silently." (mastodon-tl--buffer-property 'buffer-name buffer no-error)) (defun mastodon-tl--link-header (&optional buffer) "Get the LINK HEADER stored in `mastodon-tl--buffer-spec'. Optionally get it for BUFFER." (mastodon-tl--buffer-property 'link-header buffer :no-error)) (defun mastodon-tl--update-params (&optional buffer) "Get the UPDATE PARAMS stored in `mastodon-tl--buffer-spec'. Optionally get it for BUFFER." (mastodon-tl--buffer-property 'update-params buffer :no-error)) (defun mastodon-tl--buffer-property (property &optional buffer no-error) "Get PROPERTY from `mastodon-tl--buffer-spec' in BUFFER or `current-buffer'. If NO-ERROR is non-nil, do not error when property is empty." (with-current-buffer (or buffer (current-buffer)) (if no-error (plist-get mastodon-tl--buffer-spec property) (or (plist-get mastodon-tl--buffer-spec property) (error "Mastodon-tl--buffer-spec not defined for buffer %s, prop %s" (or buffer (current-buffer)) property))))) (defun mastodon-tl--set-buffer-spec (buffer endpoint update-fun &optional link-header update-params hide-replies max-id thread-item-id) "Set `mastodon-tl--buffer-spec' for the current buffer. BUFFER is buffer name, ENDPOINT is buffer's enpoint, UPDATE-FUN is its update function. LINK-HEADER is the http Link header if present. UPDATE-PARAMS is any http parameters needed for the update function. HIDE-REPLIES is a flag indicating if replies are hidden in the current buffer. MAX-ID is the pagination parameter. THREAD-ITEM-ID is the ID of the item in thread that we opened the thread with." (setq mastodon-tl--buffer-spec `( account ,(cons mastodon-active-user mastodon-instance-url) buffer-name ,buffer endpoint ,endpoint update-function ,update-fun link-header ,link-header update-params ,update-params hide-replies ,hide-replies max-id ,max-id thread-item-id ,thread-item-id))) ;;; BUFFERS (defun mastodon-tl--endpoint-str-= (str &optional type) "Return T if STR is equal to the current buffer's endpoint. TYPE may be :prefix or :suffix, in which case, T if STR is a prefix or suffix." (let ((endpoint-fun (mastodon-tl--endpoint nil :no-error))) (cond ((eq type :prefix) (string-prefix-p str endpoint-fun)) ((eq type :suffix) (string-suffix-p str endpoint-fun)) (t (string= str endpoint-fun))))) (defun mastodon-tl--get-buffer-type () "Return a symbol descriptive of current mastodon buffer type. Should work in all mastodon buffers. Note that for many buffers, this requires `mastodon-tl--buffer-spec' to be set. It is set for almost all buffers, but you still have to call this function after it is set or use something else." (let ((buffer-name (mastodon-tl--buffer-name nil :no-error))) (cond (mastodon-toot-mode ;; composing/editing (no buffer spec): (if (string= "*edit toot*" (buffer-name)) 'edit-toot 'new-toot)) ;; main timelines: ((mastodon-tl--endpoint-str-= "timelines/home") 'home) ((string= "*mastodon-local*" buffer-name) 'local) ((mastodon-tl--endpoint-str-= "timelines/public") 'federated) ((mastodon-tl--endpoint-str-= "timelines/tag/" :prefix) 'tag-timeline) ((mastodon-tl--endpoint-str-= "timelines/list/" :prefix) 'list-timeline) ;; notifs: ((string-suffix-p "mentions*" buffer-name) 'mentions) ((mastodon-tl--endpoint-str-= "notifications") 'notifications) ((mastodon-tl--endpoint-str-= "notifications/requests") 'notification-requests) ;; threads: ((mastodon-tl--endpoint-str-= "context" :suffix) 'thread) ((mastodon-tl--endpoint-str-= "statuses" :prefix) 'single-status) ;; profiles: ((mastodon-tl--profile-buffer-p) (cond ;; an own profile option is needlessly confusing e.g. for ;; `mastodon-profile-account-view-cycle' ;; profile note: ((string-suffix-p "update-profile*" buffer-name) 'update-profile-note) ;; posts inc. boosts: ((string-suffix-p "no-boosts*" buffer-name) 'profile-statuses-no-boosts) ((string-suffix-p "no-replies*" buffer-name) 'profile-statuses-no-replies) ((string-suffix-p "only-media*" buffer-name) 'profile-statuses-only-media) ((string-match-p "-tagged-" buffer-name) 'profile-statuses-tagged) ((mastodon-tl--endpoint-str-= "statuses" :suffix) 'profile-statuses) ;; profile followers ((mastodon-tl--endpoint-str-= "followers" :suffix) 'profile-followers) ;; profile following ((mastodon-tl--endpoint-str-= "following" :suffix) 'profile-following))) ((mastodon-tl--endpoint-str-= "preferences") 'preferences) ;; search ((mastodon-tl--search-buffer-p) (cond ((string= "accounts" (mastodon-search--buf-type)) 'search-accounts) ((string= "hashtags" (mastodon-search--buf-type)) 'search-hashtags) ((string= "statuses" (mastodon-search--buf-type)) 'search-statuses))) ;; trends ((mastodon-tl--endpoint-str-= "trends/statuses") 'trending-statuses) ((mastodon-tl--endpoint-str-= "trends/tags") 'trending-tags) ((mastodon-tl--endpoint-str-= "trends/links") 'trending-links) ;; User's views: ((mastodon-tl--endpoint-str-= "filters") 'filters) ((mastodon-tl--endpoint-str-= "lists") 'lists) ((mastodon-tl--endpoint-str-= "suggestions") 'follow-suggestions) ((mastodon-tl--endpoint-str-= "favourites") 'favourites) ((mastodon-tl--endpoint-str-= "bookmarks") 'bookmarks) ((mastodon-tl--endpoint-str-= "follow_requests") 'follow-requests) ((mastodon-tl--endpoint-str-= "scheduled_statuses") 'scheduled-statuses) ;; instance description ((mastodon-tl--endpoint-str-= "instance") 'instance-description) ((string= "*mastodon-toot-edits*" buffer-name) 'toot-edits) ((string= "*masto-image*" (buffer-name)) 'mastodon-image) ((mastodon-tl--endpoint-str-= "timelines/link") 'link-timeline) ((mastodon-tl--endpoint-str-= "announcements") 'announcements) ;; followed hashtags ((mastodon-tl--endpoint-str-= "followed_tags") 'followed-hashtags)))) (defun mastodon-tl--buffer-type-eq (type) "Return t if current buffer type is equal to symbol TYPE." (eq (mastodon-tl--get-buffer-type) type)) (defun mastodon-tl--profile-buffer-p () "Return t if current buffer is a profile buffer of any kind. This includes the update profile note buffer, but not the preferences one." (string-prefix-p "accounts" (mastodon-tl--endpoint nil :no-error))) (defun mastodon-tl--own-profile-buffer-p () "Return t if we are viewing our own profile buffer. We check that our account credientials id matches the endpoint id in the buffer spec, which if in a profile buffer is of the form \"accounts/$id/statuses\"." (and (mastodon-tl--profile-buffer-p) (let ((endpoint-id (nth 1 (split-string (mastodon-tl--endpoint) "/")))) (string= (mastodon-auth--get-account-id) endpoint-id)))) (defun mastodon-tl--search-buffer-p () "T if current buffer is a search buffer." (string-suffix-p "search" (mastodon-tl--endpoint nil :no-error))) (defun mastodon-tl--timeline-proper-p () "Return non-nil if the current buffer is a \"proper\" timeline. A proper timeline excludes notifications, threads, profiles, and other toot buffers that aren't strictly mastodon timelines." (let ((timeline-buffers '(home federated local tag-timeline list-timeline profile-statuses))) (member (mastodon-tl--get-buffer-type) timeline-buffers))) (defun mastodon-tl--hide-replies-p (&optional prefix) "Return non-nil if replies should be hidden in the timeline. We hide replies if user explictly set the `mastodon-tl--hide-replies' or used PREFIX combination to open a timeline." (and (mastodon-tl--timeline-proper-p) ; Only if we are in a proper timeline (or (mastodon-tl--buffer-property 'hide-replies nil :noerror) mastodon-tl--hide-replies ; User configured to hide replies (equal '(4) prefix)))) ; Timeline called with C-u prefix ;;; UTILITIES (defun mastodon-tl--clean-tabs-and-nl (string) "Remove tabs and newlines from STRING." (replace-regexp-in-string "[\t\n ]*\\'" "" string)) (defun mastodon-tl--map-alist (key alists &optional testfn) "Return a list of values extracted from ALISTS with KEY. Key is a symbol, as with `alist-get', or else compatible with TESTFN. ALISTS is a list of alists." ;; this actually for a list of alists, right? so change the arg? (cl-loop for x in alists collect (alist-get key x nil nil testfn))) (defun mastodon-tl--map-alist-vals-to-alist (key1 key2 alist) "From ALIST, return an alist consisting of (val1 . val2) elements. Values are accessed by `alist-get', using KEY1 and KEY2." (cl-loop for x in alist collect (cons (alist-get key1 x) (alist-get key2 x)))) (defun mastodon-tl--symbol (name) "Return the unicode symbol (as a string) corresponding to NAME. If symbol is not displayable, an ASCII equivalent is returned. If NAME is not part of the symbol table, '?' is returned." (if-let* ((symbol (alist-get name mastodon-tl--symbols))) (if (char-displayable-p (string-to-char (car symbol))) (car symbol) (cdr symbol)) "?")) (defun mastodon-tl--set-face (string face) "Return the propertized STRING with the face property set to FACE." (propertize string 'face face)) (defun mastodon-tl--field (field toot) "Return FIELD from TOOT. Return value from boosted content if available." (or (alist-get field (alist-get 'reblog toot)) (alist-get field toot))) (defun mastodon-tl--field-status (field toot) "Return FIELD from TOOT. Return value from status field if available." (or (alist-get field (alist-get 'status toot)) (alist-get field toot))) (defun mastodon-tl--remove-html (toot) "Remove unrendered tags from TOOT." (let* ((t1 (replace-regexp-in-string "<\/p>" "\n\n" toot)) (t2 (replace-regexp-in-string "<\/?span>" "" t1))) (replace-regexp-in-string "" "" t2))) (defun mastodon-tl--property (prop &optional no-move backward) "Get property PROP for toot at point. Move forward (down) the timeline unless NO-MOVE is non-nil. BACKWARD means move backward (up) the timeline." (if no-move (get-text-property (point) prop) ;; NB: this doesn't differentiate absence of property from ;; property set to zero, making flag props fraught: (or (get-text-property (point) prop) (save-excursion (if backward (mastodon-tl-goto-prev-item) (mastodon-tl-goto-next-item)) (get-text-property (point) prop))))) (defun mastodon-tl--newest-id () "Return item-id from the top of the buffer. If we are in a notifications view, return `notifications-max-id'." (save-excursion (goto-char (point-min)) (mastodon-tl--property (if (eq (mastodon-tl--get-buffer-type) (member (mastodon-tl--get-buffer-type) '(mentions notifications))) 'notifications-max-id 'item-id)))) (defun mastodon-tl--oldest-id () "Return item-id from the bottom of the buffer. If we are in a notifications view, return `notifications-min-id'." (save-excursion (goto-char (point-max)) (mastodon-tl--property (if (and mastodon-group-notifications (member (mastodon-tl--get-buffer-type) '(mentions notifications))) 'notifications-min-id 'item-id) nil :backward))) (defun mastodon-tl--as-string (numeric) "Convert NUMERIC to string." (cond ((numberp numeric) (number-to-string numeric)) ((stringp numeric) numeric) (t (error "Numeric: %s must be either a string or a number" numeric)))) (defun mastodon-tl--item-id (json) "Find approproiate toot id in JSON. If the toot has been boosted use the id found in the reblog portion of the toot. Otherwise, use the body of the toot. This is the same behaviour as the mastodon.social webapp" (let-alist json (if .reblog .reblog.id .id))) (defun mastodon-tl--toot-or-base (json) "Return the base toot or just the toot from toot JSON." (or (alist-get 'reblog json) json)) ;;; THREADS (defun mastodon-tl-view-single-toot () "View toot at point in a separate buffer." (interactive) (let ((id (mastodon-tl--property 'base-item-id))) (mastodon-tl--single-toot id))) (defun mastodon-tl--single-toot (id) "View toot in separate buffer. ID is that of the toot to view." (let* ((buffer (format "*mastodon-toot-%s*" id)) (toot (mastodon-http--get-json (mastodon-http--api (concat "statuses/" id))))) (if (eq (caar toot) 'error) (user-error "Error: %s" (cdar toot)) (with-mastodon-buffer buffer #'mastodon-mode nil (mastodon-tl--set-buffer-spec buffer (format "statuses/%s" id) #'mastodon-tl--update-toot ;; id for reload on reply: nil nil nil nil id) (mastodon-tl--toot toot :detailed-p) (goto-char (point-min)) (when mastodon-tl--display-media-p (mastodon-media--inline-images (point-min) (point-max))) (mastodon-tl-goto-next-item :no-refresh))))) (defun mastodon-tl--update-toot (json) "Call `mastodon-tl-single-toot' on id found in JSON." (let ((id (alist-get 'id json))) (mastodon-tl--single-toot id))) (defun mastodon-tl-view-whole-thread () "From a thread view, view entire thread. If you load a thread from a toot, only the branches containing are displayed by default. Call this if you subsequently want to view all branches of a thread." (interactive) (if (not (eq (mastodon-tl--get-buffer-type) 'thread)) (user-error "You need to be viewing a thread to call this") (goto-char (point-min)) (let ((id (mastodon-tl--property 'base-item-id))) (mastodon-tl--thread-do id)))) (defun mastodon-tl-return () "Load user profile or thread of item at point. If item at point is a follow or follow request, load user profile. Else load thread." (interactive) (let ((notif (mastodon-tl--property 'notification-type))) (if (or (equal "follow" notif) (equal "follow_request" notif)) (let* ((json (mastodon-tl--property 'item-json)) (handle (alist-get 'acct json))) (mastodon-profile-show-user handle)) (mastodon-tl-thread)))) (defun mastodon-tl-thread () "Open thread buffer for toot at point." (interactive) (if (not (eq 'toot (mastodon-tl--property 'item-type :no-move))) (user-error "Looks like there's no toot at point?") (mastodon-tl--thread-do))) (defun mastodon-tl--thread-do (&optional thread-id) "Open thread buffer for toot at point or with THREAD-ID. This is the non-interactive version, so we can call it programmatically and not crash into `mastodon-toot--with-toot-item'." ;; this function's var must not be id as the above macro binds id and ;; even if we provide the arg (e.g. url-lookup), the macro definition ;; overrides it, making the optional arg unusable! (let* ((id (or thread-id (mastodon-tl--property 'base-item-id :no-move))) (type (if (and (mastodon-tl--buffer-type-eq 'notifications) mastodon-group-notifications) (mastodon-tl--property 'notification-type) (mastodon-tl--field 'type (mastodon-tl--property 'item-json :no-move)))) (unfolded-state (mastodon-tl--buffer-property 'thread-unfolded (current-buffer) :noerror)) (mastodon-tl--expand-content-warnings ;; if reloading and thread was explicitly (un)folded, respect it: (or (pcase unfolded-state ('folded nil) ('unfolded t) (_ mastodon-tl--expand-content-warnings))))) (if (or (string= type "follow_request") (string= type "follow")) ; no can thread these (user-error "No thread") (let* ((endpoint (format "statuses/%s/context" id)) (url (mastodon-http--api endpoint)) (buffer (format "*mastodon-thread-%s*" id)) (toot (mastodon-http--get-json ; refetch in case we just faved/boosted: (mastodon-http--api (concat "statuses/" id)) nil :silent)) (context (mastodon-http--get-json url nil :silent))) (if (eq (caar toot) 'error) (user-error "Error: %s" (cdar toot)) (when (member (alist-get 'type toot) '("reblog" "favourite")) (setq toot (alist-get 'status toot))) (if (not (< 0 (+ (length (alist-get 'ancestors context)) (length (alist-get 'descendants context))))) ;; just print the lone toot: (mastodon-tl--single-toot id) ;; we have a thread: (with-mastodon-buffer buffer #'mastodon-mode nil (let ((marker (make-marker))) (mastodon-tl--set-buffer-spec buffer endpoint #'mastodon-tl--thread-do nil nil nil nil id) (when unfolded-state (plist-put mastodon-tl--buffer-spec 'thread-unfolded unfolded-state)) (when-let* ((ancestors (alist-get 'ancestors context))) (mastodon-tl--timeline ancestors :thread)) (goto-char (point-max)) (move-marker marker (point)) ;; print re-fetched toot: (mastodon-tl--toot toot :detailed-p :thread) ;; inline images only for the toot ;; (`mastodon-tl--timeline' handles the rest): (when mastodon-tl--display-media-p (mastodon-media--inline-images marker ;start-pos (point))) (when-let* ((descendants (alist-get 'descendants context))) (mastodon-tl--timeline descendants :thread)) ;; put point at the toot: (goto-char (marker-position marker)) (mastodon-tl-goto-next-item :no-refresh))))))))) (defun mastodon-tl-mute-thread () "Mute the thread displayed in the current buffer. Note that you can only (un)mute threads you have posted in." (interactive) (mastodon-tl--mute-or-unmute-thread)) (defun mastodon-tl-unmute-thread () "Unmute the thread displayed in the current buffer. Note that you can only (un)mute threads you have posted in." (interactive) (mastodon-tl--mute-or-unmute-thread :unmute)) (defun mastodon-tl--thread-parent-id () "Return the ID of the top item in a thread." (save-excursion (mastodon-tl--goto-first-item) (mastodon-tl--property 'base-item-id :no-move))) (defun mastodon-tl--mute-or-unmute-thread (&optional unmute) "Mute a thread. If UNMUTE, unmute it." (let ((mute-str (if unmute "unmute" "mute"))) (when (or (mastodon-tl--buffer-type-eq 'thread) (mastodon-tl--buffer-type-eq 'notifications)) (let* ((id ;; the id for `mastodon-tl--user-in-thread-p' ought to be the ;; top-level item: (if (mastodon-tl--buffer-type-eq 'notifications) (mastodon-tl--property 'base-item-id :no-move) (mastodon-tl--thread-parent-id))) (we-posted-p (mastodon-tl--user-in-thread-p id)) (url (mastodon-http--api (format "statuses/%s/%s" id mute-str)))) (if (not we-posted-p) (user-error "You can only (un)mute a thread you have posted in") (when (y-or-n-p (format "%s this thread? " (capitalize mute-str))) (let ((response (mastodon-http--post url))) (mastodon-http--triage response (lambda (_) (message (format "Thread %sd!" mute-str))))))))))) (defun mastodon-tl--map-account-id-from-toot (statuses) "Return a list of the account IDs of the author of each toot in STATUSES." (mapcar (lambda (status) (map-nested-elt status '(account id))) statuses)) (defun mastodon-tl--user-in-thread-p (id) "Return non-nil if the logged-in user has posted to the current thread. ID is that of the post the context is currently displayed for." (let* ((context-json (mastodon-http--get-json (mastodon-http--api (format "statuses/%s/context" id)) nil :silent)) (ancestors (alist-get 'ancestors context-json)) (descendants (alist-get 'descendants context-json)) (a-ids (mastodon-tl--map-account-id-from-toot ancestors)) (d-ids (mastodon-tl--map-account-id-from-toot descendants))) (or (member (mastodon-auth--get-account-id) a-ids) (member (mastodon-auth--get-account-id) d-ids)))) ;;; FOLLOW/BLOCK/MUTE, ETC (defun mastodon-tl-follow-user (user-handle &optional notify langs reblogs json) "Query for USER-HANDLE from current status and follow that user. If NOTIFY is \"true\", enable notifications when that user posts. If NOTIFY is \"false\", disable notifications when that user posts. Can be called to toggle NOTIFY on users already being followed. LANGS is an array parameters alist of languages to filer user's posts by. REBLOGS is a boolean string like NOTIFY, enabling or disabling display of the user's boosts in your timeline. JSON is a flag arg for `mastodon-http--post'." (interactive (list (mastodon-tl--user-handles-get "follow"))) (mastodon-tl--do-if-item (mastodon-tl--do-user-action-and-response user-handle "follow" nil notify langs reblogs json))) (defun mastodon-tl-follow-user-by-handle (user-handle) "Prompt for a USER-HANDLE and follow that user. USER-HANDLE can also be a URL to a user profile page." ;; code adapted from sachac: ;; https://sachachua.com/dotemacs/index.html#mastodon. thanks sachac! (interactive "MHandle: ") (when (string-match "https?://\\(.+?\\)/\\(@.+\\)" user-handle) (setq user-handle ;; sachac's model doesn't work with local user handles in URL, ;; meaning the search below will fail, so we use our own ;; URL-to-handle function, modified for the purpose: ;; (concat (match-string 2 user-handle) "@" (match-string 1 user-handle)))) (mastodon-tl--userhandle-from-url user-handle))) (let* ((account (mastodon-profile--search-account-by-handle user-handle)) (user-id (alist-get 'id account)) (name (if (not (string-empty-p (alist-get 'display_name account))) (alist-get 'display_name account) (alist-get 'username account))) (url (mastodon-http--api (format "accounts/%s/%s" user-id "follow")))) (if account (mastodon-tl--do-user-action-function url name (substring user-handle 1) "follow") (user-error "Cannot find a user with handle %S" user-handle)))) ;; TODO: make this action "enable/disable notifications" (defun mastodon-tl-enable-notify-user-posts (user-handle) "Query for USER-HANDLE and enable notifications when they post." (interactive (list (mastodon-tl--user-handles-get "enable"))) (mastodon-tl--do-if-item (mastodon-tl-follow-user user-handle "true"))) (defun mastodon-tl-disable-notify-user-posts (user-handle) "Query for USER-HANDLE and disable notifications when they post." (interactive (list (mastodon-tl--user-handles-get "disable"))) (mastodon-tl-follow-user user-handle "false")) (defun mastodon-tl-follow-user-disable-boosts (user-handle) "Prompt for a USER-HANDLE, and disable display of boosts in home timeline. If they are also not yet followed, follow them." (interactive (list (mastodon-tl--user-handles-get "disable boosts"))) (mastodon-tl-follow-user user-handle nil nil "false")) (defun mastodon-tl-follow-user-enable-boosts (user-handle) "Prompt for a USER-HANDLE, and enable display of boosts in home timeline. If they are also not yet followed, follow them. You only need to call this if you have previously disabled display of boosts." (interactive (list (mastodon-tl--user-handles-get "enable boosts"))) (mastodon-tl-follow-user user-handle nil nil "true")) (defun mastodon-tl-filter-user-user-posts-by-language (user-handle) "Query for USER-HANDLE and filter display of their posts by language. If they are not already followed, they will be too. To be filtered, a post has to be marked as in the language given. This may mean that you will not see posts that are in your desired language if they are not marked as such (or as anything)." (interactive (list (mastodon-tl--user-handles-get "filter by language"))) (let ((langs (mastodon-tl--read-filter-langs))) (mastodon-tl--do-if-item (if (string= "" (cdar langs)) (mastodon-tl-unfilter-user-languages user-handle) (mastodon-tl-follow-user user-handle nil langs))))) (defun mastodon-tl-unfilter-user-languages (user-handle) "Remove any language filters for USER-HANDLE. This means you will receive posts of theirs marked as being in any or no language." (interactive (list (mastodon-tl--user-handles-get "filter by language"))) (let ((langs "languages[]")) (mastodon-tl--do-if-item ;; we need "languages[]" as a param, with no "=" and not json-encoded as ;; a string (mastodon-tl-follow-user user-handle nil langs nil :raw)))) (defun mastodon-tl--read-filter-langs (&optional langs) "Read language choices and return an alist array parameter. LANGS is the accumulated array param alist if we re-run recursively." (let* ((iso-const mastodon-iso-639-1) (iso (cons '("None (all)" . "") iso-const)) (langs-alist langs) (choice (completing-read "Filter user's posts by language: " iso))) (when choice (setq langs-alist (push `("languages[]" . ,(alist-get choice iso nil nil #'string=)) langs-alist)) (if (y-or-n-p "Filter by another language? ") (mastodon-tl--read-filter-langs langs-alist) langs-alist)))) (defun mastodon-tl-unfollow-user (user-handle) "Query for USER-HANDLE from current status and unfollow that user." (interactive (list (mastodon-tl--user-handles-get "unfollow"))) (mastodon-tl--do-if-item (mastodon-tl--do-user-action-and-response user-handle "unfollow" t))) (defun mastodon-tl-block-user (user-handle) "Query for USER-HANDLE from current status and block that user." (interactive (list (mastodon-tl--user-handles-get "block"))) (mastodon-tl--do-if-item (mastodon-tl--do-user-action-and-response user-handle "block"))) (defun mastodon-tl-unblock-user (user-handle) "Query for USER-HANDLE from list of blocked users and unblock that user." (interactive (list (mastodon-tl--get-blocks-or-mutes-list "unblock"))) (if (not user-handle) (user-error "Looks like you have no blocks to unblock!") (mastodon-tl--do-user-action-and-response user-handle "unblock" t))) (defun mastodon-tl-mute-user (user-handle) "Query for USER-HANDLE from current status and mute that user." (interactive (list (mastodon-tl--user-handles-get "mute"))) (mastodon-tl--do-if-item (mastodon-tl--do-user-action-and-response user-handle "mute"))) (defun mastodon-tl-unmute-user (user-handle) "Query for USER-HANDLE from list of muted users and unmute that user." (interactive (list (mastodon-tl--get-blocks-or-mutes-list "unmute"))) (if (not user-handle) (user-error "Looks like you have no mutes to unmute!") (mastodon-tl--do-user-action-and-response user-handle "unmute" t))) (defun mastodon-tl-dm-user (user-handle) "Query for USER-HANDLE from current status and compose a message to that user." (interactive (list (mastodon-tl--user-handles-get "message"))) (mastodon-tl--do-if-item (mastodon-toot--compose-buffer (concat "@" user-handle)) (setq mastodon-toot--visibility "direct") (mastodon-toot--update-status-fields))) (defun mastodon-tl--user-handles-get (action) "Get the list of user-handles for ACTION from the current toot." (mastodon-tl--do-if-item (let ((user-handles (cond ((or ; follow suggests / search / foll requests compat: (member (mastodon-tl--get-buffer-type) '( follow-suggestions search follow-requests ;; profile follows/followers but not statuses: profile-followers profile-following))) ;; fetch 'item-json: (list (alist-get 'acct (mastodon-tl--property 'item-json :no-move)))) ;; profile view, point in profile details, poss no toots ;; needed for e.g. gup.pe groups which show no toots publically: ((and (mastodon-tl--profile-buffer-p) (get-text-property (point) 'profile-json)) (list (alist-get 'acct (mastodon-profile--profile-json)))) ;; (grouped) notifications: ((member (mastodon-tl--get-buffer-type) '(mentions notifications)) (append ;; those acting on item: (cl-remove-duplicates (cl-loop for a in (mastodon-tl--property 'notification-accounts :no-move) collect (alist-get 'acct a))) ;; mentions in item: (mastodon-profile--extract-users-handles (mastodon-profile--item-json)))) (t (mastodon-profile--extract-users-handles (mastodon-profile--item-json)))))) (completing-read (cond ((or ; TODO: make this "enable/disable notifications" (string= action "disable") (string= action "enable")) (format "%s notifications when user posts: " action)) ((string-suffix-p "boosts" action) (format "%s by user: " action)) (t (format "Handle of user to %s: " action))) user-handles nil ; predicate 'confirm)))) (defun mastodon-tl--get-blocks-or-mutes-list (action) "Fetch the list of accounts for ACTION from the server. Action must be either \"unblock\" or \"unmute\"." (let* ((endpoint (cond ((string= action "unblock") "blocks") ((string= action "unmute") "mutes"))) (url (mastodon-http--api endpoint)) (json (mastodon-http--get-json url)) (accts (mastodon-tl--map-alist 'acct json))) (when accts (completing-read (format "Handle of user to %s: " action) accts nil :match)))) (defun mastodon-tl--do-user-action-and-response (user-handle action &optional negp notify langs reblogs json) "Do ACTION on user USER-HANDLE. NEGP is whether the action involves un-doing something. If NOTIFY is \"true\", enable notifications when that user posts. If NOTIFY is \"false\", disable notifications when that user posts. NOTIFY is only non-nil when called by `mastodon-tl-follow-user'. LANGS is an array parameters alist of languages to filer user's posts by. REBLOGS is a boolean string like NOTIFY, enabling or disabling display of the user's boosts in your timeline." (let* ((account (cond (negp ;; unmuting/unblocking, use mute/block list (mastodon-profile--search-account-by-handle user-handle)) ;; (grouped) notifications: ((member (mastodon-tl--get-buffer-type) '(mentions notifications)) (let ((accounts (mastodon-tl--property 'notification-accounts))) (or (cl-some (lambda (x) (when (string= user-handle (alist-get 'acct x)) x)) accounts) (mastodon-profile--lookup-account-in-status user-handle (mastodon-profile--item-json))))) (t (mastodon-profile--lookup-account-in-status user-handle (if (mastodon-tl--profile-buffer-p) ;; profile view, use 'profile-json as status: (mastodon-profile--profile-json) ;; muting/blocking, select from handles in current status (mastodon-profile--item-json)))))) (user-id (alist-get 'id account)) (name (mastodon-tl--display-or-uname account)) (args (cond (notify `(("notify" . ,notify))) (langs langs) (reblogs `(("reblogs" . ,reblogs))) (t nil))) (url (mastodon-http--api (format "accounts/%s/%s" user-id action)))) (if (not account) (user-error "Cannot find a user with handle %S" user-handle) (when (or (string= action "follow") ;; y-or-n for all but follow (y-or-n-p (format "%s user %s? " action name))) (mastodon-tl--do-user-action-function url name user-handle action notify args reblogs json))))) (defun mastodon-tl--do-user-action-function (url name user-handle action &optional notify args reblogs json) "Post ACTION on user NAME/USER-HANDLE to URL. NOTIFY is either \"true\" or \"false\", and used when we have been called by `mastodon-tl-follow-user' to enable or disable notifications. ARGS is an alist of any parameters to send with the request." (let ((response (mastodon-http--post url args nil nil json))) (mastodon-http--triage response (lambda (response) (let ((json (with-current-buffer response (mastodon-http--process-json)))) ;; TODO: when > if, with failure msg (cond ((string= notify "true") (when (eq t (alist-get 'notifying json)) (message "Receiving notifications for user %s (@%s)!" name user-handle))) ((string= notify "false") (when (eq :json-false (alist-get 'notifying json)) (message "Not receiving notifications for user %s (@%s)!" name user-handle))) ((string= reblogs "true") (when (eq t (alist-get 'showing_reblogs json)) (message "Receiving boosts by user %s (@%s)!" name user-handle))) ((string= reblogs "false") (when (eq :json-false (alist-get 'showing_reblogs json)) (message "Not receiving boosts by user %s (@%s)!" name user-handle))) ((or (string= action "mute") (string= action "unmute")) (message "User %s (@%s) %sd!" name user-handle action)) ((string= args "languages[]") (message "User %s language filters removed!" name)) ((assoc "languages[]" args #'string=) (message "User %s filtered by language(s): %s" name (mapconcat #'cdr args " "))) ((not (or notify reblogs)) (if (and (string= action "follow") (eq t (alist-get 'requested json))) (message "Follow requested for user %s (@%s)!" name user-handle) (message "User %s (@%s) %sed!" name user-handle action))))))))) (defun mastodon-tl--get-domain-blocks () "Return a list of current domain blocks." (mastodon-http--get-json (mastodon-http--api "domain_blocks"))) (defun mastodon-tl-block-domain () "Read a domain and block it." (interactive) (let* ((domain (read-string "Block domain: ")) (params `(("domain" . ,domain))) (url (mastodon-http--api "domain_blocks")) (resp (mastodon-http--post url params))) (mastodon-http--triage resp (lambda (_) (message "Domain blocked!"))))) (defun mastodon-tl-unblock-domain () "Read a blocked domain and unblock it." (interactive) (let ((blocks (mastodon-tl--get-domain-blocks))) (if (not blocks) (user-error "No blocked domains?") (let* ((domain (completing-read "Unblock domain: " blocks)) (params `(("domain" . ,domain))) (url (mastodon-http--api "domain_blocks")) (resp (mastodon-http--delete url params))) (mastodon-http--triage resp (lambda (_) (message "Domain unblocked!"))))))) ;; FOLLOW TAGS (defun mastodon-tl--get-tags-list () "Return the list of tags of the toot at point." (let* ((toot (mastodon-toot--base-toot-or-item-json)) (tags (mastodon-tl--field 'tags toot))) (mastodon-tl--map-alist 'name tags))) (defun mastodon-tl-follow-tag (&optional tag) "Prompt for a tag (from post at point) and follow it. If TAG provided, follow it." (interactive) (let* ((tags (unless tag (mastodon-tl--get-tags-list))) (tag-at-point (unless tag (when (eq 'hashtag (mastodon-tl--property 'mastodon-tab-stop :no-move)) (mastodon-tl--property 'mastodon-tag :no-move)))) (tag (or tag (completing-read (format "Tag to follow [%s]: " tag-at-point) tags nil nil nil nil tag-at-point))) (url (mastodon-http--api (format "tags/%s/follow" tag))) (response (mastodon-http--post url))) (mastodon-http--triage response (lambda (_) (message "tag #%s followed!" tag))))) (defun mastodon-tl--followed-tags () "Return JSON of tags followed." (let ((url (mastodon-http--api (format "followed_tags")))) (mastodon-http--get-json url))) (defun mastodon-tl-unfollow-tag (&optional tag) "Prompt for a followed tag, and unfollow it. If TAG is provided, unfollow it." (interactive) (let* ((followed-tags-json (unless tag (mastodon-tl--followed-tags))) (tags (unless tag (mastodon-tl--map-alist 'name followed-tags-json))) (tag (or tag (completing-read "Unfollow tag: " tags))) (url (mastodon-http--api (format "tags/%s/unfollow" tag))) (response (mastodon-http--post url))) (mastodon-http--triage response (lambda (_) (message "tag #%s unfollowed!" tag))))) (defun mastodon-tl-jump-to-followed-tag (&optional prefix) "Prompt for a followed tag and view its timeline. PREFIX is sent to `mastodon-tl-get-tag-timeline', which see." (interactive "p") (let* ((followed-tags-json (mastodon-tl--followed-tags)) (tags (mastodon-tl--map-alist 'name followed-tags-json)) (tag (completing-read "Tag: " tags nil))) (if (null tag) (user-error "You have to follow some tags first") (mastodon-tl-get-tag-timeline prefix tag)))) (defun mastodon-tl-list-followed-tags () "List followed tags. View timeline of tag user choses. PREFIX is sent to `mastodon-tl-get-tag-timeline', which see." (interactive) (let* ((json (mastodon-tl--followed-tags)) (sorted (sort json :key (lambda (x) (downcase (alist-get 'name x))))) (buf "*mastodon-followed-tags*")) (if (null sorted) (user-error "You have to follow some tags first") (with-mastodon-buffer (get-buffer-create buf) #'mastodon-mode nil (mastodon-tl--set-buffer-spec buf "followed_tags" #'mastodon-tl-list-followed-tags) (mastodon-search--insert-heading "followed tags") (insert "\n") (mastodon-search--print-tags sorted) (goto-char (point-min)))))) (defun mastodon-tl-followed-tags-timeline (&optional prefix) "Open a timeline of multiple tags. With a single PREFIX arg, only show posts with media. With a double PREFIX arg, limit results to your own instance. If `mastodon-tl--tag-timeline-tags' is set, use its tags, else fetch followed tags and load the first four of them." (interactive "p") (let* ((followed-tags-json (mastodon-tl--followed-tags)) (tags (or mastodon-tl--tag-timeline-tags (mastodon-tl--map-alist 'name followed-tags-json)))) (mastodon-tl--show-tag-timeline prefix tags))) (defun mastodon-tl-some-followed-tags-timeline (&optional prefix) "Prompt for some tags, and open a timeline for them. The suggestions are from followed tags, but any other tags are also allowed. PREFIX is for `mastodon-tl--show-tag-timeline', which see." (interactive "p") (let* ((followed-tags-json (mastodon-tl--followed-tags)) (tags (mastodon-tl--map-alist 'name followed-tags-json)) (selection (completing-read-multiple "Tags' timelines to view [TAB to view, comma to separate]: " tags))) (mastodon-tl--show-tag-timeline prefix selection))) (defcustom mastodon-tl--tags-groups nil "A list containing lists of up to four tags each. You can load a tag timeline list with one of these by calling `mastodon-tl-tag-group-timeline'." :group 'mastodon-tl :type '(repeat (list string string string string))) (defun mastodon-tl-tag-group-timeline (&optional prefix) "Load a timeline of a tag group from `mastodon-tl--tags-groups'. PREFIX is for `mastodon-tl--show-tag-timeline', which see." (interactive "P") (if (not mastodon-tl--tags-groups) (user-error "Set `mastodon-tl--tags-groups' to view tag group timelines") (let* ((list-strs (mapcar (lambda (x) ;; cons of list-as-string and list: (cons (prin1-to-string x) x)) mastodon-tl--tags-groups)) (choice (completing-read "Tag group: " list-strs)) (choice-list (cdr (assoc choice list-strs #'equal)))) (mastodon-tl--show-tag-timeline prefix choice-list)))) ;;; REPORT TO MODERATORS (defun mastodon-tl--instance-rules () "Return the rules of the user's instance." (let ((url (mastodon-http--api "instance/rules"))) (mastodon-http--get-json url nil :silent))) (defun mastodon-tl--report-params (account toot) "Query user and return report params alist. ACCOUNT and TOOT are the data to use." (let* ((account-id (alist-get 'id account)) (comment (read-string "Add comment [optional]: ")) (item-id (when (y-or-n-p "Also report status at point? ") (mastodon-tl--item-id toot))) ; base toot if poss (forward-p (when (y-or-n-p "Forward to remote admin? ") "true")) (rules (when (y-or-n-p "Cite a rule broken? ") (mastodon-tl--read-rules-ids))) (cat (unless rules (if (y-or-n-p "Spam? ") "spam" "other")))) (mastodon-tl--report-build-params account-id comment item-id forward-p cat rules))) (defun mastodon-tl--report-build-params (account-id comment item-id forward-p cat &optional rules) "Build the parameters alist based on user responses. ACCOUNT-ID, COMMENT, ITEM-ID, FORWARD-P, CAT, and RULES are all from `mastodon-tl--report-params', which see." (let ((params `(("account_id" . ,account-id) ,@(when comment `(("comment" . ,comment))) ,@(when item-id `(("status_ids[]" . ,item-id))) ,@(when forward-p `(("forward" . ,forward-p))) ,@(when cat `(("category" . ,cat)))))) (if (not rules) params (let ((alist (mastodon-http--build-array-params-alist "rule_ids[]" rules))) (append alist params))))) (defun mastodon-tl-report-to-mods () "Report the author of the toot at point to your instance moderators. Optionally report the toot at point, add a comment, cite rules that have been broken, forward the report to the remove admin, report the account for spam." (interactive) (mastodon-tl--do-if-item (when (y-or-n-p "Report author of toot at point?") (let* ((url (mastodon-http--api "reports")) (toot (mastodon-tl--toot-or-base (mastodon-tl--property 'item-json :no-move))) (account (alist-get 'account toot)) (handle (alist-get 'acct account)) (params (mastodon-tl--report-params account toot)) (response (mastodon-http--post url params))) (mastodon-http--triage response (lambda (_) (message "User %s reported!" handle))))))) (defvar crm-separator) (defun mastodon-tl--map-rules-alist (rules) "Convert RULES text and id fields into an alist." (mastodon-tl--map-alist-vals-to-alist 'text 'id rules)) (defun mastodon-tl--read-rules-ids () "Prompt for a list of instance rules and return a list of selected ids." (let* ((rules (mastodon-tl--instance-rules)) (alist (mastodon-tl--map-rules-alist rules)) (crm-separator (replace-regexp-in-string "," "|" crm-separator)) (choices (completing-read-multiple "rules [TAB for options, | to separate]: " alist nil t))) (mapcar (lambda (x) (alist-get x alist nil nil #'string=)) choices))) ;;; UPDATING, etc. (defun mastodon-tl--no-json (json) "Nil if JSON is nil or empty group notif data." (if (and (mastodon-tl--buffer-type-eq 'notifications) mastodon-group-notifications) (mastodon-notifications--empty-group-json-p json) (not json))) (defun mastodon-tl--more-json (endpoint id) "Return JSON for timeline ENDPOINT before ID." (let* ((args `(("max_id" . ,(mastodon-tl--as-string id)))) (url (mastodon-http--api endpoint))) (mastodon-http--get-json url args))) (defun mastodon-tl--more-json-async (endpoint id &optional params callback &rest cbargs) "Return JSON for timeline ENDPOINT before ID. Then run CALLBACK with arguments CBARGS. PARAMS is used to send any parameters needed to correctly update the current view." (let* ((args `(("max_id" . ,(mastodon-tl--as-string id)))) (args (append args params)) (url (mastodon-http--api endpoint (when (or (and mastodon-group-notifications (string= endpoint "notifications")) (string-suffix-p "search" endpoint)) "v2")))) (apply #'mastodon-http--get-json-async url args callback cbargs))) (defun mastodon-tl--more-json-async-offset (endpoint &optional params callback &rest cbargs) "Return JSON for ENDPOINT, using the \"offset\" query param. This is used for pagination with endpoints that implement the \"offset\" parameter, rather than using link-headers or \"max_id\". PARAMS are the update parameters, see `mastodon-tl--update-params'. These (\"limit\" and \"offset\") must be set in `mastodon-tl--buffer-spec' for pagination to work. Then run CALLBACK with arguments CBARGS." (let* ((params (or params (mastodon-tl--update-params))) (limit (string-to-number (alist-get "limit" params nil nil #'string=))) (offset (number-to-string (+ limit ; limit + old offset = new offset (string-to-number (alist-get "offset" params nil nil #'string=))))) (url (mastodon-http--api endpoint (when (string-suffix-p "search" endpoint) "v2")))) ;; increment: (setf (alist-get "offset" params nil nil #'string=) offset) (apply #'mastodon-http--get-json-async url params callback cbargs))) (defun mastodon-tl--updated-json (endpoint id &optional params version) "Return JSON for timeline ENDPOINT since ID. PARAMS is used to send any parameters needed to correctly update the current view. VERSION is the API version to use, as grouped notifs use v2." (let* ((args `(("since_id" . ,(mastodon-tl--as-string id)))) (args (append args params)) (url (mastodon-http--api endpoint version))) (mastodon-http--get-json url args))) ;; TODO: add this to new posts in some cases, e.g. in thread view. (defun mastodon-tl--reload-timeline-or-profile (&optional pos) "Reload the current timeline or profile page. For use after e.g. deleting a toot. POS is a number, where point will be placed. Aims to respect any pagination in effect." (let ((type (mastodon-tl--get-buffer-type)) (max-id (mastodon-tl--buffer-property 'max-id nil :no-error))) (cond ((eq type 'home) (mastodon-tl-get-home-timeline nil max-id)) ((eq type 'federated) (mastodon-tl-get-federated-timeline nil nil max-id)) ((eq type 'local) (mastodon-tl-get-local-timeline nil max-id)) ((eq type 'mentions) (mastodon-notifications-get-mentions)) ((eq type 'notifications) (mastodon-notifications-get nil nil max-id)) ((eq type 'profile-statuses-no-boosts) ;; TODO: max-id arg needed here also (mastodon-profile-open-statuses-no-reblogs)) ((eq type 'profile-statuses) (save-excursion (goto-char (point-min)) (mastodon-profile--make-author-buffer ;; (mastodon-profile-get-toot-author max-id))) (mastodon-profile--profile-json)))) ((or (eq type 'single-status) (eq type 'thread)) (let ((id (mastodon-tl--buffer-property 'thread-item-id (current-buffer) :no-error))) (mastodon-tl--thread-do id)))) ;; TODO: sends point to where point was in buffer. This is very rough; we ;; may have removed an item , so the buffer will be smaller, point will ;; end up past where we were, etc. (when pos (goto-char pos) (mastodon-tl-goto-prev-item :no-refresh)))) (defun mastodon-tl--build-link-header-url (str) "Return a URL from STR, an http Link header." (let* ((split (split-string str "; ")) (url-base (string-trim (car split) "<" ">")) (param (cadr split))) (concat url-base "&" param))) (defun mastodon-tl--use-link-header-p () "Return t if we are in a view needing Link header pagination. Currently this includes favourites, bookmarks, follow requests, and profile pages when showing followers or accounts followed." (or (mastodon-tl--buffer-type-eq 'favourites) (mastodon-tl--buffer-type-eq 'bookmarks) (mastodon-tl--buffer-type-eq 'profile-followers) (mastodon-tl--buffer-type-eq 'profile-following) (mastodon-tl--buffer-type-eq 'follow-requests))) (defun mastodon-tl--get-link-header-from-response (headers) "Get http Link header from list of http HEADERS." ;; pleroma uses "link", so case-insensitive match required: (when-let* ((link-headers (alist-get "Link" headers nil nil #'cl-equalp))) (split-string link-headers ", "))) (defun mastodon-tl--more () "Append older toots to timeline, asynchronously." (message "Loading...") (if (mastodon-tl--use-link-header-p) ;; link-header paginate: ;; can't build a URL with --more-json-async, endpoint/id: ;; ensure we have a "next" type here, otherwise the CAR will be the ;; "prev" type! (let ((link-header (mastodon-tl--link-header))) (if (> 2 (length link-header)) (user-error "No next page") (let* ((next (car link-header)) ;;(prev (cadr (mastodon-tl--link-header))) (url (mastodon-tl--build-link-header-url next))) (mastodon-http--get-response-async url nil 'mastodon-tl--more* (current-buffer) (point) :headers)))) (cond (;; no paginate (or (mastodon-tl--buffer-type-eq 'follow-suggestions) (mastodon-tl--buffer-type-eq 'filters) (mastodon-tl--buffer-type-eq 'lists)) (user-error "No more results")) ;; offset paginate (search, trending, user lists, ...?): ((or (string-prefix-p "*mastodon-trending-" (buffer-name)) (mastodon-tl--search-buffer-p)) (mastodon-tl--more-json-async-offset (mastodon-tl--endpoint) (mastodon-tl--update-params) 'mastodon-tl--more* (current-buffer) (point))) (t ;; max_id paginate (timelines, items with ids/timestamps): (let ((max-id (mastodon-tl--oldest-id)) (params (mastodon-tl--update-params))) (mastodon-tl--more-json-async (mastodon-tl--endpoint) max-id params 'mastodon-tl--more* (current-buffer) (point) nil max-id)))))) (defun mastodon-tl--more* (response buffer point-before &optional headers max-id) "Append older toots to timeline, asynchronously. Runs the timeline's update function on RESPONSE, in BUFFER. When done, places point at POINT-BEFORE. HEADERS is the http headers returned in the response, if any. MAX-ID is the pagination parameter, a string. UPDATE-PARAMS is from prev buffer spec, added to the new one." (with-current-buffer buffer (if (not response) (user-error "No more results") (let* ((inhibit-read-only t) (json (if headers (car response) response)) ;; FIXME: max-id pagination works for statuses only, not other ;; search results pages: (json (if (not (mastodon-tl--search-buffer-p)) json (let ((type (mastodon-search--buf-type))) (cond ((string= "statuses" type) (cdr ; avoid repeat of last status (alist-get 'statuses response))) ((string= "hashtags" type) (alist-get 'hashtags response)) ((string= "accounts" type) (alist-get 'accounts response)))))) (headers (when headers (cdr response))) (link-header (mastodon-tl--get-link-header-from-response headers)) (buf-type (mastodon-tl--get-buffer-type)) (notifs-p (or (eq buf-type 'notifications) (eq buf-type 'mentions))) (notif-type (when notifs-p (mastodon-notifications--current-type)))) (goto-char (point-max)) (if (eq 'thread buf-type) ;; if thread fully unfolded, respect it: ;; if thread view, call --thread-do with parent ID (progn (goto-char (point-min)) (mastodon-tl-goto-next-item) (mastodon-tl--thread-do) (goto-char point-before) (message "Loaded full thread.")) (if (mastodon-tl--no-json json) (user-error "No more results") (if notifs-p (mastodon-notifications--timeline json notif-type :update) (funcall (mastodon-tl--update-function) json)) (goto-char point-before) ;; update buffer spec to new link-header or max-id: ;; (other values should just remain as they were) (mastodon-tl--set-buffer-spec (mastodon-tl--buffer-name) (mastodon-tl--endpoint) (mastodon-tl--update-function) link-header (mastodon-tl--update-params) (mastodon-tl--hide-replies-p) max-id) (message "Loading... done."))))))) (defun mastodon-tl--find-property-range (property start-point &optional search-backwards) "Return nil if no such range is found. If PROPERTY is set at START-POINT returns a range around START-POINT otherwise before/after START-POINT. SEARCH-BACKWARDS determines whether we pick point before (non-nil) or after (nil)" (if (get-text-property start-point property) ;; We are within a range, so look backwards for the start: (cons (previous-single-property-change (if (eq start-point (point-max)) start-point (1+ start-point)) property nil (point-min)) (next-single-property-change start-point property nil (point-max))) (if search-backwards (let* ((end (or (previous-single-property-change (if (eq start-point (point-max)) start-point (1+ start-point)) property) ;; we may either be just before the range or there ;; is nothing at all (and (not (eq start-point (point-min))) (get-text-property (1- start-point) property) start-point))) (start (and end (previous-single-property-change end property nil (point-min))))) (when end (cons start end))) (let* ((start (next-single-property-change start-point property)) (end (and start (next-single-property-change start property nil (point-max))))) (when start (cons start end)))))) (defun mastodon-tl--find-next-or-previous-property-range (property start-point search-backwards) "Find (start . end) property range after/before START-POINT. Does so while PROPERTY is set to a consistent value (different from the value at START-POINT if that is set). Return nil if no such range exists. If SEARCH-BACKWARDS is non-nil it find a region before START-POINT otherwise after START-POINT." (if (not (get-text-property start-point property)) ;; If we are not within a range, we can just defer to ;; mastodon-tl--find-property-range directly. (mastodon-tl--find-property-range property start-point search-backwards) ;; We are within a range, we need to start the search from ;; before/after this range: (let ((current-range (mastodon-tl--find-property-range property start-point))) (if search-backwards (unless (eq (car current-range) (point-min)) (mastodon-tl--find-property-range property (1- (car current-range)) search-backwards)) (unless (eq (cdr current-range) (point-max)) (mastodon-tl--find-property-range property (1+ (cdr current-range)) search-backwards)))))) (defun mastodon-tl--consider-timestamp-for-updates (timestamp) "Take note that TIMESTAMP is used in buffer and ajust timers as needed. This calculates the next time the text for TIMESTAMP will change and may adjust existing or future timer runs should that time before current plans to run the update function. The adjustment is only made if it is significantly (a few seconds) before the currently scheduled time. This helps reduce the number of occasions where we schedule an update only to schedule the next one on completion to be within a few seconds. If relative timestamps are disabled (i.e. if `mastodon-tl--enable-relative-timestamps' is nil), this is a no-op." (when mastodon-tl--enable-relative-timestamps (let ((this-update (cdr (mastodon-tl--relative-time-details timestamp)))) (when (time-less-p this-update (time-subtract mastodon-tl--timestamp-next-update (seconds-to-time 10))) (setq mastodon-tl--timestamp-next-update this-update) (when mastodon-tl--timestamp-update-timer ;; We need to re-schedule for an earlier time (cancel-timer mastodon-tl--timestamp-update-timer) (setq mastodon-tl--timestamp-update-timer (run-at-time (time-to-seconds (time-subtract this-update (current-time))) nil ;; don't repeat #'mastodon-tl--update-timestamps-callback (current-buffer) nil))))))) (defun mastodon-tl--update-timestamps-callback (buffer previous-marker) "Update the next few timestamp displays in BUFFER. Start searching for more timestamps from PREVIOUS-MARKER or from the start if it is nil." ;; only do things if the buffer hasn't been killed in the meantime (when (and mastodon-tl--enable-relative-timestamps ; just in case (buffer-live-p buffer)) (save-excursion (with-current-buffer buffer (let ((previous-timestamp (if previous-marker (marker-position previous-marker) (point-min))) (iteration 0) next-timestamp-range) (if previous-marker ;; a follow-up call to process the next batch of timestamps. ;; Release the marker to not slow things down. (set-marker previous-marker nil) ;; Otherwise this is a rew run, so let's initialize the next-run time. (setq mastodon-tl--timestamp-next-update (time-add (current-time) (seconds-to-time 300)) mastodon-tl--timestamp-update-timer nil)) (while (and (< iteration 5) (setq next-timestamp-range (mastodon-tl--find-property-range 'timestamp previous-timestamp))) (let* ((start (car next-timestamp-range)) (end (cdr next-timestamp-range)) (timestamp (get-text-property start 'timestamp)) (current-display (get-text-property start 'display)) (new-display (mastodon-tl--relative-time-description timestamp))) (unless (string= current-display new-display) (let ((inhibit-read-only t)) (add-text-properties start end (list 'display (mastodon-tl--relative-time-description timestamp))))) (mastodon-tl--consider-timestamp-for-updates timestamp) (setq iteration (1+ iteration) previous-timestamp (1+ (cdr next-timestamp-range))))) (if next-timestamp-range ;; schedule the next batch from the previous location to ;; start very soon in the future: (run-at-time 0.1 nil #'mastodon-tl--update-timestamps-callback buffer (copy-marker previous-timestamp)) ;; otherwise we are done for now; schedule a new run for when needed (setq mastodon-tl--timestamp-update-timer (run-at-time (time-to-seconds (time-subtract mastodon-tl--timestamp-next-update (current-time))) nil ;; don't repeat #'mastodon-tl--update-timestamps-callback buffer nil)))))))) (defun mastodon-tl--set-after-update-marker () "Set `mastodon-tl--after-update-marker' to the after-update location. This location is defined by a non-nil value of `mastodon-tl-position-after-update'." (if (not mastodon-tl-position-after-update) (setq mastodon-tl--after-update-marker nil) (let ((marker (make-marker))) (set-marker marker (cond ((eq 'keep-point mastodon-tl-position-after-update) (point)) ((eq 'last-old-toot mastodon-tl-position-after-update) (next-single-property-change (or mastodon-tl--update-point (point-min)) 'byline)) (t (error "Unknown mastodon-tl-position-after-update value %S" mastodon-tl-position-after-update)))) ;; Make the marker advance if text gets inserted there. (set-marker-insertion-type marker t) (setq mastodon-tl--after-update-marker marker)))) (defun mastodon-tl-update () "Update timeline with new toots." (interactive) ;; FIXME: actually these buffers should just reload by calling their own ;; load function (actually g is mostly mapped as such) ;; well actually, g should be for reload, update is different. (if (or (member (mastodon-tl--get-buffer-type) '(trending-statuses trending-tags follow-suggestions lists filters scheduled-statuses)) (mastodon-tl--search-buffer-p)) (user-error "Update not available in this view") ;; FIXME: handle update for search and trending buffers (let* ((endpoint (mastodon-tl--endpoint)) (update-fun (mastodon-tl--update-function)) (id (mastodon-tl--newest-id))) ;; update a thread, without calling `mastodon-tl--updated-json': (if (mastodon-tl--buffer-type-eq 'thread) ;; load whole thread: (progn (mastodon-tl--thread-do id) (message "Loaded full thread.")) (if (not id) ;; if e.g. notifs all cleared: (user-error "No last id") ;; update other timelines: (let* ((params (mastodon-tl--update-params)) (notifs-p (eq update-fun 'mastodon-notifications--timeline)) (json (mastodon-tl--updated-json endpoint id params (when (and notifs-p mastodon-group-notifications) "v2")))) (if (mastodon-tl--no-json json) (user-error "Nothing to update") (let ((inhibit-read-only t)) (mastodon-tl--set-after-update-marker) (goto-char (or mastodon-tl--update-point (point-min))) (if notifs-p (funcall update-fun json nil :update) (funcall update-fun json)) (if mastodon-tl--after-update-marker (goto-char mastodon-tl--after-update-marker) (mastodon-tl-goto-next-item)))))))))) ;;; LOADING TIMELINES (defun mastodon-tl--init (buffer-name endpoint update-function &optional headers params hide-replies instance no-byline) "Initialize BUFFER-NAME with timeline targeted by ENDPOINT asynchronously. UPDATE-FUNCTION is used to recieve more toots. HEADERS means to also collect the response headers. Used for paginating favourites and bookmarks. PARAMS is any parameters to send with the request. HIDE-REPLIES is a flag indicating if replies are hidden in the current buffer. INSTANCE is a string of another instance domain we are displaying a timeline from. NO-BYLINE means just insert toot body, used for announcements." (let ((url (if instance (concat "https://" instance "/api/v1/" endpoint) (mastodon-http--api endpoint))) (buffer (concat "*mastodon-" buffer-name "*"))) (funcall (if headers #'mastodon-http--get-response-async #'mastodon-http--get-json-async) url params 'mastodon-tl--init* buffer endpoint update-function headers params hide-replies instance no-byline))) (defun mastodon-tl--init* (response buffer endpoint update-function &optional headers update-params hide-replies instance no-byline) "Initialize BUFFER with timeline targeted by ENDPOINT. UPDATE-FUNCTION is used to recieve more toots. RESPONSE is the data returned from the server by `mastodon-http--process-json', with arg HEADERS a cons cell of JSON and http headers, without it just the JSON. NO-BYLINE means just insert toot body, used for announcements." (let ((json (if headers (car response) response))) (cond ((not json) ; praying this is right here, else try "\n[]" ;; this means that whatever tl was inited won't load, which is not ;; always wanted, as sometimes you still need the page to load so ;; you can be in eg mastodon-mode, have keymap, search etc. (message "Looks like nothing returned from endpoint: %s" endpoint) ;; if we are a new account, home tl may have nothing, but then ;; this clause means we can never load mastodon.el at all! ;; so as a fallback, load trending statuses: ;; FIXME: this could possibly be a fallback for all timelines not ;; just home? (when (string= endpoint "timelines/home") (mastodon-search-trending-statuses))) ((eq (caar json) 'error) (user-error "Looks like the server bugged out: \"%s\"" (cdar json))) (t (let* ((headers (when headers (cdr response))) (link-header (mastodon-tl--get-link-header-from-response headers))) (with-mastodon-buffer buffer #'mastodon-mode nil (mastodon-tl--set-buffer-spec buffer endpoint update-function link-header update-params hide-replies ;; awful hack to fix multiple reloads: (alist-get "max_id" update-params nil nil #'string=)) (mastodon-tl--do-init json update-function instance no-byline))))))) (defun mastodon-tl--init-sync (buffer-name endpoint update-function &optional note-type params headers view-name binding-str endpoint-version) "Initialize BUFFER-NAME with timeline targeted by ENDPOINT. UPDATE-FUNCTION is used to receive more toots. Runs synchronously. Optional arg NOTE-TYPE means only get that type of notification. PARAMS is an alist of any params to include in the request. HEADERS are any headers to send in the request. VIEW-NAME is a string, to be used as a heading for the view. BINDING-STR is a string explaining any bindins in the view, it can have formatting for `substitute-command-keys'. ENDPOINT-VERSION is a string, format Vx, e.g. V2." ;; Used by `mastodon-notifications-get' and in views.el (let* ((notes-params (when note-type (mastodon-http--build-array-params-alist "types[]" (list note-type)))) (params (append notes-params params)) (url (mastodon-http--api endpoint endpoint-version)) (buffer (concat "*mastodon-" buffer-name "*")) (response (mastodon-http--get-response url params)) (json (car response)) (headers (when headers (cdr response))) (link-header (when headers (mastodon-tl--get-link-header-from-response headers)))) (with-mastodon-buffer buffer #'mastodon-mode nil ;; insert view-name/ heading-str (when view-name (mastodon-search--insert-heading view-name)) (when binding-str (insert (substitute-command-keys (mastodon-tl--set-face (concat "[" binding-str "]\n\n") 'mastodon-toot-docs-face)))) (mastodon-tl--set-buffer-spec buffer endpoint update-function link-header params nil ;; awful hack to fix multiple reloads: (alist-get "max_id" params nil nil #'string=)) (mastodon-tl--do-init json update-function nil nil note-type) buffer))) (defun mastodon-tl--do-init (json update-fun &optional domain no-byline type) "Utility function for `mastodon-tl--init*' and `mastodon-tl--init-sync'. JSON is the data to call UPDATE-FUN on. When DOMAIN, force inclusion of user's domain in their handle. NO-BYLINE means just insert toot body, used for announcements. TYPE is a notification type." (remove-overlays) ; video overlays (cond (domain ;; maybe our update-fun doesn't always have 3 args...: (funcall update-fun json nil domain)) (type (funcall update-fun json type)) ;; notif types (no-byline (funcall update-fun json nil nil no-byline)) (t (funcall update-fun json))) (setq ;; Initialize with a minimal interval; we re-scan at least once ;; every 5 minutes to catch any timestamps we may have missed mastodon-tl--timestamp-next-update (time-add (current-time) (seconds-to-time 300))) (setq mastodon-tl--timestamp-update-timer (when mastodon-tl--enable-relative-timestamps (run-at-time (time-to-seconds (time-subtract mastodon-tl--timestamp-next-update (current-time))) nil ;; don't repeat #'mastodon-tl--update-timestamps-callback (current-buffer) nil))) (unless (mastodon-tl--profile-buffer-p) (mastodon-tl--goto-first-item))) ;;; BOOKMARKS (require 'bookmark) (defun mastodon-tl--bookmark-handler (record) "Jump to a bookmarked location in mastodon.el. RECORD is the bookmark record." (let ((id (bookmark-prop-get record 'id))) ;; we need to handle thread and single toot for starters (pop-to-buffer (mastodon-tl--thread-do id)))) (defun mastodon-tl--bookmark-make-record () "Return a bookmark record for the current mastodon buffer." (let ((id (mastodon-tl--property 'item-id :no-move)) (name (buffer-name))) `(,name (buf . ,name) (id . ,id) (handler . mastodon-tl--bookmark-handler)))) (add-hook 'mastodon-mode-hook (lambda () (setq-local bookmark-make-record-function #'mastodon-tl--bookmark-make-record))) (provide 'mastodon-tl) ;;; mastodon-tl.el ends here mastodon.el/lisp/mastodon-toot.el000066400000000000000000002634521501733112700174150ustar00rootroot00000000000000;;; mastodon-toot.el --- Minor mode for sending Mastodon toots -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-toot.el supports POSTing status data to Mastodon. ;;; Code: (eval-when-compile (require 'subr-x)) (defvar mastodon-use-emojify) (require 'emojify nil :noerror) (declare-function emojify-insert-emoji "emojify") (declare-function emojify-set-emoji-data "emojify") (declare-function emojify-mode "emojify") (declare-function emojify-emojis-each "emojify") (defvar emojify-emojis-dir) (defvar emojify-user-emojis) (defvar emojify-emoji-styles) (require 'cl-lib) (require 'persist) (require 'mastodon-iso) (require 'facemenu) (require 'text-property-search) (eval-when-compile (require 'mastodon-tl)) (defvar mastodon-instance-url) (defvar mastodon-tl--buffer-spec) (defvar mastodon-tl--enable-proportional-fonts) (defvar mastodon-profile-account-settings) (defvar mastodon-profile-acccount-preferences-data) (autoload 'iso8601-parse "iso8601") (autoload 'ht-get "ht") (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--build-array-params-alist "mastodon-http") (autoload 'mastodon-http--delete "mastodon-http") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-http--get-json-async "mastodon-http") (autoload 'mastodon-http--post "mastodon-http") (autoload 'mastodon-http--post-media-attachment "mastodon-http") (autoload 'mastodon-http--process-json "mastodon-http") (autoload 'mastodon-http--put "mastodon-http") (autoload 'mastodon-http--read-file-as-string "mastodon-http") (autoload 'mastodon-http--triage "mastodon-http") (autoload 'mastodon-kill-window "mastodon") (autoload 'mastodon-profile--fetch-server-account-settings "mastodon-profile") (autoload 'mastodon-profile--fetch-server-account-settings-maybe "mastodon-profile") (autoload 'mastodon-profile--get-source-pref "mastodon-profile") (autoload 'mastodon-profile-show-user "mastodon-profile") (autoload 'mastodon-profile--update-preference "mastodon-profile") (autoload 'mastodon-search--search-accounts-query "mastodon-search") (autoload 'mastodon-search--search-tags-query "mastodon-search") (autoload 'mastodon-tl--as-string "mastodon-tl") (autoload 'mastodon-tl--buffer-type-eq "mastodon-tl") (autoload 'mastodon-tl--clean-tabs-and-nl "mastodon-tl") (autoload 'mastodon-tl--field "mastodon-tl") (autoload 'mastodon-tl--find-property-range "mastodon-tl") (autoload 'mastodon-tl--find-property-range "mastodon-tl") (autoload 'mastodon-tl-goto-next-item "mastodon-tl") (autoload 'mastodon-tl--map-alist "mastodon-tl") (autoload 'mastodon-tl--property "mastodon-tl") (autoload 'mastodon-tl--reload-timeline-or-profile "mastodon-tl") (autoload 'mastodon-tl--render-text "mastodon-tl") (autoload 'mastodon-tl--set-buffer-spec "mastodon-tl") (autoload 'mastodon-tl--symbol "mastodon-tl") (autoload 'mastodon-tl--item-id "mastodon-tl") (autoload 'mastodon-toot "mastodon") (autoload 'mastodon-views-cancel-scheduled-toot "mastodon-views") (autoload 'mastodon-views-view-scheduled-toots "mastodon-views") (autoload 'org-read-date "org") (autoload 'mastodon-tl--toot-or-base "mastodon-tl") (autoload 'mastodon-profile--get-source-value "mastodon-toot") (autoload 'mastodon-tl--get-buffer-type "mastodon-tl") (autoload 'mastodon-tl--human-duration "mastodon-tl") (autoload 'mastodon-profile--get-preferences-pref "mastodon-profile") (autoload 'mastodon-views--get-own-instance "mastodon-views") (autoload 'mastodon-tl--image-trans-check "mastodon-tl") (autoload 'mastodon-instance-data "mastodon") (autoload 'mastodon-create-poll "mastodon-transient") (autoload 'mastodon-tl--own-profile-buffer-p "mastodon-tl") ;; for mastodon-toot-translate-toot-text (autoload 'mastodon-tl--content "mastodon-tl") (when (require 'lingva nil :no-error) (declare-function lingva-translate "lingva")) (defgroup mastodon-toot nil "Tooting in Mastodon." :prefix "mastodon-toot-" :group 'mastodon) (defcustom mastodon-toot--default-media-directory "~/" "The default directory when prompting for a media file to upload." :type 'string) (defcustom mastodon-toot--attachment-height 80 "Height of the attached images preview in the toot draft buffer." :type 'integer) (defcustom mastodon-toot--enable-completion t "Whether to enable completion of mentions and hashtags. Used for completion in toot compose buffer." :type 'boolean) (defcustom mastodon-toot--use-company-for-completion nil "Whether to enable company for completion. When non-nil, `company-mode' is enabled in the toot compose buffer, and mastodon completion backends are added to `company-capf'. You need to install company yourself to use this." :type 'boolean) (defcustom mastodon-toot--completion-style-for-mentions "all" "The company completion style to use for mentions." :type '(choice (const :tag "off" nil) (const :tag "following only" "following") (const :tag "all users" "all"))) (defcustom mastodon-toot-display-orig-in-reply-buffer nil "Display a copy of the toot replied to in the compose buffer." :type 'boolean) (defcustom mastodon-toot-orig-in-reply-length 191 ;; three lines of divider width: (- (* 3 67) (length " Reply to: ")) "Length to crop toot replied to in the compose buffer to." :type 'integer) (defcustom mastodon-toot--default-reply-visibility "public" "Default visibility settings when replying. If the original toot visibility is different we use the more restricted one." :type '(choice (const :tag "public" "public") (const :tag "unlisted" "unlisted") (const :tag "followers only" "private") (const :tag "direct" "direct"))) (defcustom mastodon-toot--enable-custom-instance-emoji nil "Whether to enable your instance's custom emoji by default." :type 'boolean) (defcustom mastodon-toot--proportional-fonts-compose nil "Nonnil to enable using proportional fonts in the compose buffer. By default fixed width fonts are used." :type '(boolean :tag "Enable using proportional rather than fixed \ width fonts")) (defcustom mastodon-toot-poll-use-transient t "Whether to use the transient menu to create a poll." :type '(boolean)) (defvar-local mastodon-toot--content-warning nil "The content warning of the current toot.") (defvar-local mastodon-toot--content-nsfw nil "A flag indicating whether the toot should be marked as NSFW.") (defvar mastodon-toot-visibility-list '(public unlisted private direct) "A list of the available toot visibility settings.") (defvar mastodon-toot-visibility-settings-list '("public" "unlisted" "private") "A list of the available default toot visibility settings. Like `mastodon-toot-visibility-list' but without direct.") (defvar-local mastodon-toot--visibility nil "A string indicating the visibility of the toot being composed. Valid values are \"direct\", \"private\" (followers-only), \"unlisted\", and \"public\". This is determined by the account setting on the server. To change the setting on the server, see `mastodon-toot-set-default-visibility'.") (defvar-local mastodon-toot--media-attachments nil "A list of the media attachments of the toot being composed.") (defvar-local mastodon-toot--media-attachment-ids nil "A list of any media attachment ids of the toot being composed.") (defvar mastodon-toot-poll nil "A plist of poll options for the toot being composed.") (defvar-local mastodon-toot--language nil "The language of the toot being composed, in ISO 639 (two-letter).") (defvar-local mastodon-toot--scheduled-for nil "An ISO 8601 timestamp that specifying when the post should be published. Should be at least 5 minutes into the future.") (defvar-local mastodon-toot--scheduled-id nil "The id of the scheduled post that we are now editing.") (defvar-local mastodon-toot--reply-to-id nil "Buffer-local variable to hold the id of the toot being replied to.") (defvar-local mastodon-toot--edit-item-id nil "The id of the toot being edited.") (defvar-local mastodon-toot-previous-window-config nil "A list of window configuration prior to composing a toot. Takes its form from `window-configuration-to-register'.") (defvar mastodon-toot--max-toot-chars nil "The maximum allowed characters count for a single toot.") (defvar-local mastodon-toot-completions nil "The data of completion candidates for the current completion at point.") (defvar mastodon-toot-current-toot-text nil "The text of the toot being composed.") (persist-defvar mastodon-toot-draft-toots-list nil "A list of toots that have been saved as drafts. For the moment we just put all composed toots in here, as we want to also capture toots that are \"sent\" but that don't successfully send.") ;;; REGEXES (defvar mastodon-toot-handle-regex (rx (| (any ?\( "\n" "\t "" ") bol) ; preceding things (group-n 2 (+ ?@ (* (any ?- ?_ ?. "A-Z" "a-z" "0-9" ))) ; handle (? ?@ (* (not (any "\n" "\t" " "))))) ; optional domain (| "'" word-boundary))) ; boundary or possessive (defvar mastodon-toot-tag-regex (rx (| (any ?\( "\n" "\t" " ") bol) (group-n 2 ?# (+ (any "_" "A-Z" "a-z" "0-9"))) (| "'" word-boundary))) ; boundary or possessive (defvar mastodon-toot-emoji-regex (rx (| (any ?\( "\n" "\t" " ") bol) (group-n 2 ?: ; opening : (+ (any "A-Z" "a-z" "0-9" "_")) (? ?:)) ; closing : word-boundary)) ; boundary (defvar mastodon-toot-url-regex ;; adapted from ffap-url-regexp (concat "\\(?2:\\(news\\(post\\)?:\\|mailto:\\|file:\\|\\(ftp\\|https?\\|telnet\\|gopher\\|www\\|wais\\)://\\)" ; uri prefix "[^ \n\t]*\\)" ; any old thing, that is, i.e. we allow invalid/unwise chars ;; "[ .,:;!?]\\b")) ;; "/" ; poss an ending slash? incompat with boundary end: "\\>")) ; boundary end ;;; UTILS (defun mastodon-toot--base-toot-or-item-json () "Return the JSON data of either base-toot or item-json property. The former is for boost or favourite notifications, returning data about the item boosted or favourited." (or (mastodon-tl--property 'base-toot :no-move) ; fave/boost notifs (mastodon-tl--property 'item-json))) (defun mastodon-toot--inc-or-dec (count subtract) "If SUBTRACT, decrement COUNT, else increment." (if subtract (1- count) (1+ count))) ;;; MACRO (defmacro mastodon-toot--with-toot-item (&rest body) "Execute BODY if we have a toot object at point. Includes boosts, and notifications that display toots. This macro makes the local variable ID available." (declare (debug t)) `(if (or (not (eq 'toot (mastodon-tl--property 'item-type :no-move))) (member (mastodon-tl--property 'notification-type :no-move) '("follow" "follow_request"))) (user-error "Looks like there's no toot at point?") (mastodon-tl--with-toot-helper (lambda (id) ,@body)))) (defun mastodon-tl--with-toot-helper (body-fun) "Helper function for `mastodon-tl--with-toot-item'. Extract any common variables needed, such as base-item-id property, and call BODY-FUN on them." (let ((id (mastodon-tl--property 'base-item-id))) (funcall body-fun id))) ;;; MODE MAP (defvar mastodon-toot-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-c") #'mastodon-toot-send) (define-key map (kbd "C-c C-k") #'mastodon-toot-cancel) (define-key map (kbd "C-c C-w") #'mastodon-toot-set-content-warning) (define-key map (kbd "C-c C-n") #'mastodon-toot-toggle-nsfw) (define-key map (kbd "C-c C-v") #'mastodon-toot-change-visibility) (define-key map (kbd "C-c C-e") #'mastodon-toot-insert-emoji) (define-key map (kbd "C-c C-a") #'mastodon-toot-attach-media) (define-key map (kbd "C-c !") #'mastodon-toot-clear-all-attachments) (define-key map (kbd "C-c C-p") #'mastodon-toot-create-poll) (define-key map (kbd "C-c C-o") #'mastodon-toot-clear-poll) (define-key map (kbd "C-c C-l") #'mastodon-toot-set-toot-language) (define-key map (kbd "C-c C-s") #'mastodon-toot-schedule-toot) map) "Keymap for `mastodon-toot'.") (defun mastodon-toot-set-default-visibility () "Set the default visibility for toots on the server." (interactive) (let ((vis (completing-read "Set default visibility to:" mastodon-toot-visibility-list nil t))) (mastodon-profile--update-preference "privacy" vis :source))) (defun mastodon-toot--get-max-toot-chars (&optional no-toot) "Fetch max_toot_chars from `mastodon-instance-url' asynchronously. NO-TOOT means we are not calling from a toot buffer." (mastodon-http--get-json-async (mastodon-http--api "instance") nil 'mastodon-toot--get-max-toot-chars-callback no-toot)) (defun mastodon-toot--get-max-toot-chars-callback (json-response &optional no-toot) "Set max_toot_chars returned in JSON-RESPONSE and display in new toot buffer. NO-TOOT means we are not calling from a toot buffer." (let ((max-chars (or (alist-get 'max_toot_chars json-response) (alist-get 'max_characters ; some servers have this instead (alist-get 'statuses (alist-get 'configuration json-response)))))) (setq mastodon-toot--max-toot-chars max-chars) (unless no-toot (with-current-buffer "*new toot*" (mastodon-toot--update-status-fields))))) (defun mastodon-toot--action-success (marker byline-region remove &optional json) "Insert/remove the text MARKER with `success' face in byline. BYLINE-REGION is a cons of start and end pos of the byline to be modified. Remove MARKER if REMOVE is non-nil, otherwise add it. JSON is added to the string as its item-json." (let ((inhibit-read-only t) (bol (car byline-region)) (eol (cdr byline-region)) (at-byline-p (eq t (mastodon-tl--property 'byline :no-move)))) (save-excursion (when remove (goto-char bol) (beginning-of-line) ;; The marker is not part of the byline (if (search-forward (format "(%s) " marker) eol :no-error) (replace-match "") (user-error "Oops: could not find marker '(%s)'" marker))) (unless remove (goto-char bol) (insert (propertize (format "(%s) " (propertize marker 'face 'success)) 'cursor-face 'mastodon-cursor-highlight-face 'item-json json)))) ;; for (un)folding items (when at-byline-p ;; leave point after the marker: (unless remove ;; if point is inside the byline, back up first so ;; we don't move to the following toot: (beginning-of-line) (forward-line -1) (mastodon-tl-goto-next-item))))) (defun mastodon-toot--action (action callback) "Take ACTION, a string, on toot at point, then execute CALLBACK. Makes a POST request to the server. Used for favouriting, boosting, or bookmarking toots." (let* ((id (mastodon-tl--property 'base-item-id)) (url (mastodon-http--api (concat "statuses/" (mastodon-tl--as-string id) "/" action))) (response (mastodon-http--post url))) (mastodon-http--triage response callback))) (defun mastodon-toot--toggle-boost-or-favourite (action) "Toggle boost or favourite of toot at point. ACTION is a symbol, either `favourite' or `boost.'" (mastodon-toot--with-toot-item (let* ((n-type (mastodon-tl--property 'notification-type :no-move)) (byline-region (mastodon-tl--find-property-range 'byline (point))) (boost-p (eq action 'boost)) (action-str (symbol-name action)) (item-json (mastodon-tl--property 'item-json)) (vis (mastodon-tl--field 'visibility item-json))) (cond ((not byline-region) (user-error "Nothing to %s here?!?" action-str)) ;; there's nothing wrong with faving/boosting own toots ;; & nothing wrong with faving/boosting own toots from notifs, ;; it boosts/faves the base toot, not the notif status ((or (string= n-type "follow") (string= n-type "follow_request")) (user-error "Can't %s %s notifications" action n-type)) ((and boost-p (or (string= vis "direct") (string= vis "private"))) (user-error "Can't boost posts with visibility: %s" vis)) (t (let* ((boosted (when byline-region (get-text-property (car byline-region) 'boosted-p))) (faved (when byline-region (get-text-property (car byline-region) 'favourited-p))) (str-api (if boost-p "reblog" action-str)) (action-str-api (mastodon-toot--str-negify str-api faved boosted action)) (action-pp (concat (mastodon-toot--str-negify action-str faved boosted action) (if boost-p "ed" "d"))) (remove-p (if boost-p boosted faved))) (mastodon-toot--action action-str-api (lambda (_) (let ((inhibit-read-only t)) (add-text-properties (car byline-region) (cdr byline-region) (if boost-p (list 'boosted-p (not boosted)) (list 'favourited-p (not faved)))) (mastodon-toot--update-stats-on-action action remove-p) (mastodon-toot--action-success (mastodon-tl--symbol action) byline-region remove-p item-json)) (message "%s #%s" action-pp id))))))))) (defun mastodon-toot--str-negify (str faved boosted action) "Add \"un\" to STR if item is already FAVED or BOOSTED. ACTION is the action currently being taken." (if (eq action 'boost) (if boosted (concat "un" str) str) (if faved (concat "un" str) str))) (defun mastodon-toot--update-stats-on-action (action &optional subtract) "Increment the toot stats display upon ACTION. ACTION is a symbol, either `favourite' or `boost'. SUBTRACT means we are un-favouriting or unboosting, so we decrement." (if (not (symbolp action)) (error "Invalid argument: symbolp %s" action) (let* ((count-prop (if (eq action 'favourite) 'favourites-count 'boosts-count)) (count-range (mastodon-tl--find-property-range count-prop (point))) (count (get-text-property (car count-range) count-prop)) (inhibit-read-only 1)) ;; TODO another way to implement this would be to async fetch counts again ;; and re-display from count-properties (add-text-properties (car count-range) (cdr count-range) (list 'display (number-to-string (mastodon-toot--inc-or-dec count subtract)) ;; update the count prop ;; we rely on this for any subsequent actions: count-prop (mastodon-toot--inc-or-dec count subtract)))))) (defun mastodon-toot-toggle-boost () "Boost/unboost toot at `point'." (interactive) (mastodon-toot--toggle-boost-or-favourite 'boost)) (defun mastodon-toot-toggle-favourite () "Favourite/unfavourite toot at `point'." (interactive) (mastodon-toot--toggle-boost-or-favourite 'favourite)) ;; TODO maybe refactor into boost/fave fun (defun mastodon-toot-toggle-bookmark () "Bookmark or unbookmark toot at point." (interactive) (mastodon-toot--with-toot-item (let* ((n-type (mastodon-tl--property 'notification-type :no-move)) (byline-region (mastodon-tl--find-property-range 'byline (point))) (bookmarked-p (when byline-region (get-text-property (car byline-region) 'bookmarked-p))) (action (if bookmarked-p "unbookmark" "bookmark"))) (cond ((or (string= n-type "follow") (string= n-type "follow_request")) (user-error "Can't bookmark %s notifications" n-type)) ((not byline-region) (user-error "Nothing to %s here?!?" action)) (t (let* ((bookmark-str (mastodon-tl--symbol 'bookmark)) (message (if bookmarked-p "Bookmark removed!" "Toot bookmarked!")) (item-json (mastodon-tl--property 'item-json))) (mastodon-toot--action action (lambda (_) (let ((inhibit-read-only t)) (add-text-properties (car byline-region) (cdr byline-region) (list 'bookmarked-p (not bookmarked-p))) (mastodon-toot--action-success bookmark-str byline-region bookmarked-p item-json) (message "%s #%s" message id)))))))))) (defun mastodon-toot-list-boosters () "List the boosters of toot at point." (interactive) ;; use grouped notifs data if present: ;; only send accounts as arg if type matches notif type we are acting ;; on, to prevent showing accounts for a boost notif when asking for ;; favers, and vice versa. (let* ((type (mastodon-tl--property 'notification-type :no-move)) (accounts (when (string= type "reblog") (mastodon-tl--property 'notification-accounts :no-move)))) (mastodon-toot--list-boosters-or-favers nil accounts))) (defun mastodon-toot-list-favouriters () "List the favouriters of toot at point." (interactive) (let* ((type (mastodon-tl--property 'notification-type :no-move)) (accounts (when (string= type "favourite") (mastodon-tl--property 'notification-accounts :no-move)))) (mastodon-toot--list-boosters-or-favers :favourite accounts))) (defun mastodon-toot--list-boosters-or-favers (&optional favourite accounts) "List the favouriters or boosters of toot at point. With FAVOURITE, list favouriters, else list boosters. ACCOUNTS is notfications accounts if any." (mastodon-toot--with-toot-item (let* ((endpoint (unless accounts (if favourite "favourited_by" "reblogged_by"))) (url (unless accounts (mastodon-http--api (format "statuses/%s/%s" id endpoint)))) (params (unless accounts '(("limit" . "80")))) (json (or accounts (mastodon-http--get-json url params)))) (if (eq (caar json) 'error) (user-error "%s (Status does not exist or is private)" (alist-get 'error json)) (let ((handles (mastodon-tl--map-alist 'acct json)) (type-string (if favourite "Favouriters" "Boosters"))) (if (not handles) (user-error "Looks like this toot has no %s" type-string) (let ((choice (completing-read (format "%s (enter to view profile): " type-string) handles nil t))) (mastodon-profile-show-user choice)))))))) (defun mastodon-toot-copy-toot-url () "Copy URL of toot at point. If the toot is a fave/boost notification, copy the URL of the base toot." (interactive) (let* ((url (mastodon-toot--toot-url))) (kill-new url) (message "Toot URL copied to the clipboard."))) (defun mastodon-toot-browse-toot-url () "Browse URL of toot at point. Calls `browse-url'." (interactive) (browse-url (mastodon-toot--toot-url))) (defun mastodon-toot--toot-url () "Return the URL of the base toot at point." (let* ((toot (mastodon-toot--base-toot-or-item-json))) (if (mastodon-tl--field 'reblog toot) (alist-get 'url (alist-get 'reblog toot)) (alist-get 'url toot)))) (defun mastodon-toot-copy-toot-text () "Copy text of toot at point. If the toot is a fave/boost notification, copy the text of the base toot." (interactive) (let* ((toot (mastodon-toot--base-toot-or-item-json))) (kill-new (mastodon-tl--content toot)) (message "Toot content copied to the clipboard."))) (defun mastodon-toot-translate-toot-text () "Translate text of toot at point. Uses `lingva.el'." (interactive) (if mastodon-tl--buffer-spec (if-let* ((toot (mastodon-tl--property 'item-json))) (condition-case x (lingva-translate nil (mastodon-tl--content toot) (when mastodon-tl--enable-proportional-fonts t)) (void-function (user-error "Looks like you need to install lingva.el. Error: %s" (error-message-string x)))) (user-error "No toot to translate?")) (user-error "No mastodon buffer?"))) (defun mastodon-toot--own-toot-p (toot) "Check if TOOT is user's own, for deleting, editing, or pinning it." ;; this check needs to allow acting on own toots displayed as boosts, so we ;; call `mastodon-tl--toot-or-base'. (let ((json (mastodon-tl--toot-or-base toot))) (string= (alist-get 'acct (alist-get 'account json)) (mastodon-auth--user-acct)))) (defun mastodon-toot-pin-toot-toggle () "Pin or unpin user's toot at point." (interactive) (let* ((toot (mastodon-toot--base-toot-or-item-json)) (pinnable-p (mastodon-toot--own-toot-p toot)) (pinned-p (eq t (alist-get 'pinned toot))) (action (if pinned-p "unpin" "pin")) (msg (if pinned-p "unpinned" "pinned"))) (if (not pinnable-p) (user-error "You can only pin your own toots") (when (y-or-n-p (format "%s this toot? " (capitalize action))) (mastodon-toot--action action (lambda (_) ;; let's only reload when in own profile view: (when (mastodon-tl--own-profile-buffer-p) (mastodon-tl--reload-timeline-or-profile)) (message "Toot %s!" msg))))))) ;;; DELETE, DRAFT, REDRAFT (defun mastodon-toot-delete-toot () "Delete user's toot at point synchronously." (interactive) (mastodon-toot-delete-and-redraft-toot t)) ;; TODO: handle media/poll for redrafting toots (defun mastodon-toot-delete-and-redraft-toot (&optional no-redraft) "Delete and redraft user's toot at point synchronously. NO-REDRAFT means delete toot only." (interactive) (let* ((toot (mastodon-toot--base-toot-or-item-json)) (id (mastodon-tl--as-string (mastodon-tl--item-id toot))) (url (mastodon-http--api (format "statuses/%s" id))) (pos (point))) (let-alist toot (if (not (mastodon-toot--own-toot-p toot)) (user-error "You can only delete (and redraft) your own toots") (when (y-or-n-p (if no-redraft (format "Delete this toot? ") (format "Delete and redraft this toot? "))) (let* ((response (mastodon-http--delete url))) (mastodon-http--triage response (lambda (_) (if no-redraft (progn (when mastodon-tl--buffer-spec (mastodon-tl--reload-timeline-or-profile pos)) (message "Toot deleted!")) (mastodon-toot--redraft response .in_reply_to_id .visibility .spoiler_text)))))))))) (defun mastodon-toot--set-cw (&optional cw) "Set content warning to CW if it is non-nil." (unless (or (null cw) ; cw is nil for `mastodon-tl-dm-user' (string-empty-p cw)) (setq mastodon-toot--content-warning cw))) ;;; REDRAFT (defun mastodon-toot--redraft (response &optional reply-id toot-visibility toot-cw) "Opens a new toot compose buffer using values from RESPONSE buffer. REPLY-ID, TOOT-VISIBILITY, and TOOT-CW of deleted toot are preseved." (with-current-buffer response (let* ((response (mastodon-http--process-json)) (content (alist-get 'text response))) (mastodon-toot--compose-buffer) (goto-char (point-max)) (insert content) ;; adopt reply-to-id, visibility and CW from deleted toot: (mastodon-toot--set-toot-properties reply-id toot-visibility toot-cw ;; TODO set new lang/scheduled props here nil)))) (defun mastodon-toot--set-toot-media-attachments (media) "Set the media attachments variables. MEDIA is the media_attachments data for a status from the server." (mapcar (lambda (x) (cl-pushnew (alist-get 'id x) mastodon-toot--media-attachment-ids) (cl-pushnew `((:contents . ,(mastodon-http--read-file-as-string (alist-get 'url x) :url)) (:description . ,(alist-get 'description x))) mastodon-toot--media-attachments)) media)) (defun mastodon-toot--set-toot-properties (reply-id visibility cw lang &optional scheduled scheduled-id media poll) "Set the toot properties for the current redrafted or edited toot. REPLY-ID, VISIBILITY, CW, SCHEDULED, and LANG are the properties to set. MEDIA is the media_attachments data for a status from the server." (with-current-buffer "*edit toot*" (when reply-id (setq mastodon-toot--reply-to-id reply-id)) (setq mastodon-toot--visibility visibility) (setq mastodon-toot--scheduled-for scheduled) (setq mastodon-toot--scheduled-id scheduled-id) (when (not (string-empty-p lang)) (setq mastodon-toot--language lang)) (mastodon-toot--set-cw cw) (when media (mastodon-toot--set-toot-media-attachments media)) (when poll (mastodon-toot--server-poll-to-local poll)) (mastodon-toot--refresh-attachments-display) (mastodon-toot--update-status-fields))) (defun mastodon-toot--kill (&optional cancel) "Kill `mastodon-toot-mode' buffer and window. CANCEL means the toot was not sent, so we save the toot text as a draft." (let ((prev-window-config mastodon-toot-previous-window-config)) (unless (eq mastodon-toot-current-toot-text nil) (when cancel (cl-pushnew mastodon-toot-current-toot-text mastodon-toot-draft-toots-list :test #'string=))) ;; prevent some weird bug when cancelling a non-empty toot: (delete #'mastodon-toot--save-toot-text after-change-functions) (quit-window 'kill) (mastodon-toot--restore-previous-window-config prev-window-config))) (defun mastodon-toot-cancel () "Kill new-toot buffer/window. Does not POST content. If toot is not empty, prompt to save text as a draft." (interactive) (when (and (not (mastodon-toot--empty-p)) (y-or-n-p "Save draft toot?")) (mastodon-toot-save-draft)) (mastodon-toot--kill)) (defun mastodon-toot-save-draft () "Save the current compose toot text as a draft. Pushes `mastodon-toot-current-toot-text' to `mastodon-toot-draft-toots-list'." (interactive) (unless (string= mastodon-toot-current-toot-text nil) (cl-pushnew mastodon-toot-current-toot-text mastodon-toot-draft-toots-list :test 'string=) (message "Draft saved!"))) (defun mastodon-toot--empty-p (&optional text-only) "Return t if toot has no text, attachments, or polls. TEXT-ONLY means don't check for attachments or polls." (and (if text-only t (and (not mastodon-toot--media-attachments) (not mastodon-toot-poll))) (string-empty-p (mastodon-tl--clean-tabs-and-nl (mastodon-toot--remove-docs))))) ;;; EMOJIS (defun mastodon-toot-insert-emoji () "Prompt to insert an emoji." (interactive) (if mastodon-use-emojify (emojify-insert-emoji) (emoji-search))) ;; 29.1 (defun mastodon-toot--emoji-dir () "Return the file path for the mastodon custom emojis directory." (concat (expand-file-name emojify-emojis-dir) "/mastodon-custom-emojis/")) (defun mastodon-toot-download-custom-emoji () "Download `mastodon-instance-url's custom emoji. Emoji images are stored in a subdir of `emojify-emojis-dir'. To use the downloaded emoji, run `mastodon-toot-enable-custom-emoji'." (interactive) (let* ((url (mastodon-http--api "custom_emojis")) (custom-emoji (mastodon-http--get-json url)) (mastodon-custom-emoji-dir (mastodon-toot--emoji-dir))) (if (not (file-directory-p emojify-emojis-dir)) (user-error "Looks like you need to set up emojify first") (unless (file-directory-p mastodon-custom-emoji-dir) (make-directory mastodon-custom-emoji-dir nil)) ; no add parent (cl-loop for x in custom-emoji do (let ((url (alist-get 'url x)) (shortcode (alist-get 'shortcode x))) ;; skip anything that contains unexpected characters (when (and url shortcode (string-match-p "^[a-zA-Z0-9-_]+$" shortcode) (string-match-p "^[a-zA-Z]+$" (file-name-extension url))) (url-copy-file url (concat mastodon-custom-emoji-dir shortcode "." (file-name-extension url)) t)))) (message "Custom emoji for %s downloaded to %s" mastodon-instance-url mastodon-custom-emoji-dir)))) (defun mastodon-toot--collect-custom-emoji () "Return a list of `mastodon-instance-url's custom emoji. The list is formatted for `emojify-user-emojis', which see." (let* ((mastodon-custom-emojis-dir (mastodon-toot--emoji-dir)) (custom-emoji-files (directory-files mastodon-custom-emojis-dir nil ; not full path "^[^.]")) ; no dot files mastodon-emojify-user-emojis) (cl-loop for x in custom-emoji-files do (push `(,(concat ":" (file-name-base x) ":") . (("name" . ,(file-name-base x)) ("image" . ,(concat mastodon-custom-emojis-dir x)) ("style" . "github"))) mastodon-emojify-user-emojis)) (reverse mastodon-emojify-user-emojis))) (defun mastodon-toot-enable-custom-emoji () "Add `mastodon-instance-url's custom emoji to `emojify'. Custom emoji must first be downloaded with `mastodon-toot-download-custom-emoji'. Custom emoji are appended to `emojify-user-emojis', and the emoji data is updated." (interactive) (unless (file-exists-p (mastodon-toot--emoji-dir)) (when (y-or-n-p "Looks like you haven't downloaded your instance's custom emoji yet. Download now? ") (mastodon-toot-download-custom-emoji))) (let ((masto-emojis (mastodon-toot--collect-custom-emoji))) (unless (cl-find (car masto-emojis) emojify-user-emojis :test #'equal) (setq emojify-user-emojis (append masto-emojis emojify-user-emojis)) ;; if already loaded, reload (when (featurep 'emojify) ;; we now only do this within the unless test above, as it is extremely ;; slow and runs in `mastodon-mode-hook'. (emojify-set-emoji-data))))) (defun mastodon-toot--remove-docs () "Get the body of a toot from the current compose buffer." (let ((header-region (mastodon-tl--find-property-range 'toot-post-header (point-min)))) (string-trim-left (buffer-substring (cdr header-region) (point-max))))) (defun mastodon-toot--build-poll-params () "Return an alist of parameters for POSTing a poll status." (if mastodon-toot-poll-use-transient (let-alist mastodon-toot-poll (append (mastodon-http--build-array-params-alist "poll[options][]" (list .one .two .three .four)) (list (cons "poll[expires_in]" .expiry) (cons "poll[multiple]" .multi) (cons "poll[hide_totals]" .hide)))) (append (mastodon-http--build-array-params-alist "poll[options][]" (plist-get mastodon-toot-poll :options)) `(("poll[expires_in]" . ,(plist-get mastodon-toot-poll :expiry))) `(("poll[multiple]" . ,(symbol-name (plist-get mastodon-toot-poll :multi)))) `(("poll[hide_totals]" . ,(symbol-name (plist-get mastodon-toot-poll :hide))))))) ;;; SEND TOOT FUNCTION (defun mastodon-toot-send () "POST contents of new-toot buffer to fediverse instance and kill buffer. If media items have been attached and uploaded with `mastodon-toot-attach-media', they are attached to the toot. If `mastodon-toot--edit-item-id' is non-nil, PUT contents to instance to edit a toot." (interactive) (let* ((toot (mastodon-toot--remove-docs)) (scheduled mastodon-toot--scheduled-for) (scheduled-id mastodon-toot--scheduled-id) (edit-id mastodon-toot--edit-item-id) (endpoint (mastodon-http--api (if edit-id ; we are sending an edit: (format "statuses/%s" edit-id) "statuses"))) (args-no-media (append `(("status" . ,toot) ("in_reply_to_id" . ,mastodon-toot--reply-to-id) ("visibility" . ,mastodon-toot--visibility) ("sensitive" . ,(when mastodon-toot--content-nsfw (symbol-name t))) ("spoiler_text" . ,mastodon-toot--content-warning) ("language" . ,mastodon-toot--language)) ;; Pleroma instances can't handle null-valued ;; scheduled_at args, so only add if non-nil (when scheduled `(("scheduled_at" . ,scheduled))))) (args-media (when mastodon-toot--media-attachment-ids (mastodon-http--build-array-params-alist "media_ids[]" mastodon-toot--media-attachment-ids))) (args-poll (when mastodon-toot-poll (mastodon-toot--build-poll-params))) ;; media || polls: (args (if mastodon-toot--media-attachment-ids (append args-media args-no-media) (if mastodon-toot-poll (append args-no-media args-poll) args-no-media))) (prev-window-config mastodon-toot-previous-window-config)) (cond ((and mastodon-toot--media-attachment-ids ;; make sure we have media args ;; and the same num of ids as attachments (or (not args-media) (not (= (length mastodon-toot--media-attachments) (length mastodon-toot--media-attachment-ids))))) (user-error "Something is wrong with your uploads. Wait for them to complete or try again")) ((and mastodon-toot--max-toot-chars (> (mastodon-toot--count-toot-chars toot mastodon-toot--content-warning) mastodon-toot--max-toot-chars)) (user-error "Looks like your toot (inc. CW) is longer than that maximum allowed length")) ;; polls must have text, so we use poll as flag for text-only ;; check here: ((mastodon-toot--empty-p mastodon-toot-poll) (user-error "Empty toot. Cowardly refusing to post this")) (t (let ((response (funcall (if edit-id ; we are sending an edit: #'mastodon-http--put #'mastodon-http--post) endpoint args))) (mastodon-http--triage response (lambda (_) ;; kill buffer: (mastodon-toot--kill) ;; nil our poll var: (setq mastodon-toot-poll nil) (message "Toot %s!" (if scheduled "scheduled" "toot")) ;; cancel scheduled toot if we were editing it: (when scheduled-id (mastodon-views-cancel-scheduled-toot scheduled-id :no-confirm)) ;; window config: (mastodon-toot--restore-previous-window-config prev-window-config) ;; reload: - when we have been editing ;; - when we are in thread view ;; (we don't reload in every case as it can be slow and we ;; may lose our place in a timeline.) (let ((type (mastodon-tl--get-buffer-type))) (when (or edit-id (eq 'single-status type) (eq 'thread type)) (let ((pos (marker-position (cadr prev-window-config)))) (mastodon-tl--reload-timeline-or-profile pos))))))))))) ;;; EDITING TOOTS: (defun mastodon-toot-edit-toot-at-point () "Edit the user's toot at point." (interactive) (mastodon-toot--with-toot-item (let ((toot (mastodon-toot--base-toot-or-item-json))) (if (not (mastodon-toot--own-toot-p toot)) (user-error "You can only edit your own toots") (let* ((source (mastodon-toot--get-toot-source id)) (content (alist-get 'text source)) (source-cw (alist-get 'spoiler_text source))) (let-alist toot (when (y-or-n-p "Edit this toot? ") (mastodon-toot--compose-buffer nil .in_reply_to_id nil content :edit) (goto-char (point-max)) ;; adopt reply-to-id, visibility, CW, language, and media: (mastodon-toot--set-toot-properties .in_reply_to_id .visibility source-cw .language nil nil ;; maintain media order: (reverse .media_attachments) .poll) (setq mastodon-toot--edit-item-id id)))))))) (defun mastodon-toot--get-toot-source (id) "Fetch the source JSON of toot with ID." (let ((url (mastodon-http--api (format "/statuses/%s/source" id)))) (mastodon-http--get-json url nil :silent))) (defun mastodon-toot--get-toot-edits (id) "Return the edit history of toot with ID." (let* ((url (mastodon-http--api (format "statuses/%s/history" id)))) (mastodon-http--get-json url))) (defun mastodon-toot-view-toot-edits () "View editing history of the toot at point in a popup buffer." (interactive) (let ((id (mastodon-tl--property 'base-item-id)) (history (mastodon-tl--property 'edit-history)) ;; at byline (buf "*mastodon-toot-edits*")) (if (not history) (user-error "No editing history for this toot") (with-mastodon-buffer buf #'special-mode :other-window (cl-loop for count from 1 for x in history do (insert (propertize (if (= count 1) (format "%s [original]:\n" count) (format "%s:\n" count)) 'face 'mastodon-toot-docs-face) (mastodon-toot--insert-toot-iter x) "\n")) (goto-char (point-min)) (setq-local header-line-format (propertize (format "Edits to toot by %s:" (alist-get 'username (alist-get 'account (car history)))) 'face 'mastodon-toot-docs-face)) (mastodon-tl--set-buffer-spec (buffer-name (current-buffer)) (format "statuses/%s/history" id) nil))))) (defun mastodon-toot--insert-toot-iter (it) "Insert iteration IT of toot." (let ((content (alist-get 'content it))) ;; TODO: handle polls, media (mastodon-tl--render-text content))) (defun mastodon-toot--restore-previous-window-config (config) "Restore the window CONFIG after killing the toot compose buffer. Buffer-local variable `mastodon-toot-previous-window-config' holds the config." (set-window-configuration (car config)) (goto-char (cadr config))) (defun mastodon-toot--mentions-to-string (mentions) "Apply `mastodon-toot--process-local' function to each mention in MENTIONS. Remove empty string (self) from result and joins the sequence with whitespace." (let ((mentions (remove "" (mapcar #'mastodon-toot--process-local mentions)))) (mapconcat #'identity mentions " "))) (defun mastodon-toot--process-local (acct) "Add domain to local ACCT and replace the curent user name with \"\". Mastodon requires the full @user@domain, even in the case of local accts. eg. \"user\" -> \"@user@local.social\" (when local.social is the domain of the `mastodon-instance-url'). eg. \"yourusername\" -> \"\" eg. \"feduser@fed.social\" -> \"@feduser@fed.social\"." (cond ((string-match-p "@" acct) (concat "@" acct)) ; federated acct ((string= (mastodon-auth--user-acct) acct) "") ; your acct (t (concat "@" acct "@" ; local acct (cadr (split-string mastodon-instance-url "/" :omit-nulls)))))) ;;; COMPLETION (TAGS, MENTIONS) (defun mastodon-toot--mentions (status) "Extract mentions (not the reply-to author or booster) from STATUS. The mentioned users look like this: Local user (including the logged in): `username`. Federated user: `username@host.co`." (let* ((mentions (mastodon-tl--field 'mentions status))) ;; reverse does not work on vectors in 24.5 (mastodon-tl--map-alist 'acct (reverse mentions)))) (defun mastodon-toot--get-bounds (regex) "Get bounds of tag or handle before point using REGEX." ;; # and @ are not part of any existing thing at point (save-match-data (save-excursion ;; match full handle inc. domain, or tag including # ;; (see the regexes for subexp 2) (when (re-search-backward regex (save-excursion (forward-whitespace -1) (point)) :no-error) (cons (match-beginning 2) (match-end 2)))))) (defun mastodon-toot--fetch-emojify-candidates () "Get the candidates to be used for emojis completion. The candidates are calculated according to currently active `emojify-emoji-styles'. Hacked off `emojify--get-completing-read-candidates'." (let ((styles (mapcar #'symbol-name emojify-emoji-styles))) (let ((emojis '())) (emojify-emojis-each (lambda (key value) (when (seq-position styles (ht-get value "style")) (push (cons key (format "%s (%s)" (ht-get value "name") (ht-get value "style"))) emojis)))) emojis))) (defun mastodon-toot--fetch-candidates (start end &optional type) "Search for a completion prefix from buffer positions START to END. Return a list of candidates. TYPE is the candidate type, it may be :tags, :handles, or :emoji." ;; we can't save the first two-letter search then only filter the ;; resulting list, as max results returned is 40. (setq mastodon-toot-completions (cond ((eq type :tags) (let ((tags-list (mastodon-search--search-tags-query (buffer-substring-no-properties start end)))) (cl-loop for tag in tags-list collect (cons (concat "#" (car tag)) (cdr tag))))) ((eq type :emoji) (when (bound-and-true-p emojify-mode) (mastodon-toot--fetch-emojify-candidates))) (t (mastodon-search--search-accounts-query (buffer-substring-no-properties start end)))))) (defun mastodon-toot--make-capf (regex annot-fun type) "Build a completion backend for `completion-at-point-functions'. REGEX is the regex to match preceding text. TYPE is a keyword symbol for `mastodon-toot--fetch-candidates'. ANNOT-FUN is a function returning an annotatation from a single arg, a candidate." (let* ((bounds (mastodon-toot--get-bounds regex)) (start (car bounds)) (end (cdr bounds))) (when bounds (list start end (completion-table-dynamic ; only search when necessary (lambda (_) ;; Interruptible candidate computation, from minad/d mendler, thanks! (let ((result (while-no-input (mastodon-toot--fetch-candidates start end type)))) (and (consp result) result)))) :exclusive 'no :annotation-function (lambda (cand) (concat " " (funcall annot-fun cand))))))) (defun mastodon-toot--mentions-capf () "Build a mentions completion backend for `completion-at-point-functions'." (mastodon-toot--make-capf mastodon-toot-handle-regex #'mastodon-toot--mentions-annotation-fun :handles)) (defun mastodon-toot--tags-capf () "Build a tags completion backend for `completion-at-point-functions'." (mastodon-toot--make-capf mastodon-toot-tag-regex #'mastodon-toot--tags-annotation-fun :tags)) (defun mastodon-toot--emoji-capf () "Build an emoji completion backend for `completion-at-point-functions'." (mastodon-toot--make-capf mastodon-toot-emoji-regex #'mastodon-toot--emoji-annotation-fun :emoji)) (defun mastodon-toot--mentions-annotation-fun (candidate) "Given a handle completion CANDIDATE, return its annotation string, a username." (caddr (assoc candidate mastodon-toot-completions))) (defun mastodon-toot--tags-annotation-fun (candidate) "Given a tag string CANDIDATE, return an annotation, the tag's URL." ;; TODO: check the list returned here? should be cadr ;; or make it an alist and use cdr (cadr (assoc candidate mastodon-toot-completions))) (defun mastodon-toot--emoji-annotation-fun (candidate) "CANDIDATE." ;; TODO: emoji image as annot (cdr (assoc candidate mastodon-toot-completions))) ;;; REPLY (defun mastodon-toot-reply () "Reply to toot at `point'. Customize `mastodon-toot-display-orig-in-reply-buffer' to display text of the toot being replied to in the compose buffer. If the region is active, inject it into the reply buffer, prefixed by >." (interactive) (mastodon-toot--with-toot-item (let* ((quote (when (region-active-p) (buffer-substring (region-beginning) (region-end)))) (toot (mastodon-toot--base-toot-or-item-json)) (account (mastodon-tl--field 'account toot)) (user (alist-get 'acct account)) (mentions (mastodon-toot--mentions toot)) (boosted (mastodon-tl--field 'reblog toot)) (booster (when boosted (alist-get 'acct (alist-get 'account toot)))) (mentions (cond ((and booster ;; different booster, user and mentions: (and (not (string= user booster)) (not (member booster mentions)))) (mastodon-toot--mentions-to-string (append (list user booster) mentions nil))) ((not (member user mentions)) ;; user not in mentions: (mastodon-toot--mentions-to-string (append (list user) mentions nil))) (t ;; user already in mentions: (mastodon-toot--mentions-to-string (copy-sequence mentions)))))) (mastodon-toot--compose-buffer mentions id toot quote)))) ;;; COMPOSE TOOT SETTINGS (defun mastodon-toot-set-content-warning () "Set a content warning for the current toot." (interactive) (setq mastodon-toot--content-warning (read-string "Warning: " mastodon-toot--content-warning)) (mastodon-toot--update-status-fields)) (defun mastodon-toot-toggle-nsfw () "Toggle `mastodon-toot--content-nsfw'." (interactive) (setq mastodon-toot--content-nsfw (not mastodon-toot--content-nsfw)) (message "NSFW flag is now %s" (if mastodon-toot--content-nsfw "on" "off")) (mastodon-toot--update-status-fields)) (defun mastodon-toot-change-visibility (&optional arg) "Change the current visibility to the next valid value. With prefix ARG, read a visibility type in the minibuffer." (interactive "P") (if (mastodon-tl--buffer-type-eq 'edit-toot) (user-error "You can't change visibility when editing toots") (setq mastodon-toot--visibility (if arg (completing-read "Visibility: " mastodon-toot-visibility-list) (cond ((string= mastodon-toot--visibility "public") "unlisted") ((string= mastodon-toot--visibility "unlisted") "private") ((string= mastodon-toot--visibility "private") "direct") (t "public")))) (mastodon-toot--update-status-fields))) (defun mastodon-toot-set-toot-language () "Prompt for a language and set `mastodon-toot--language'. Return its two letter ISO 639 1 code." (interactive) (let* ((choice (completing-read "Language for this toot: " mastodon-iso-639-1))) (setq mastodon-toot--language (alist-get choice mastodon-iso-639-1 nil nil #'string=)) (message "Language set to %s" choice) (mastodon-toot--update-status-fields))) ;;; ATTACHMENTS (defun mastodon-toot-clear-all-attachments () "Remove all attachments from a toot draft." (interactive) (setq mastodon-toot--media-attachments nil) (setq mastodon-toot--media-attachment-ids nil) (mastodon-toot--refresh-attachments-display) (mastodon-toot--update-status-fields)) (defun mastodon-toot--get-instance-max-attachments () "Return the maximum attachments from `mastodon-active-user's instance. If that fails, return 4 as a fallback" ;; FIXME: this likely various for other server types: ;; pleroma doesn't advertise this on "api/v1/instance" (checked ;; fe.disroot.org) (or (let ((config (alist-get 'statuses (alist-get 'configuration (mastodon-views--get-own-instance))))) (alist-get 'max_media_attachments config)) 4)) ; mastodon default as fallback (defun mastodon-toot-attach-media (file description) "Prompt for an attachment FILE with DESCRIPTION. A preview is displayed in the new toot buffer, and the file is uploaded asynchronously using `mastodon-toot--upload-attached-media'. File is actually attached to the toot upon posting." (interactive "fFilename: \nsDescription: ") (let ((max-attachments (mastodon-toot--get-instance-max-attachments))) (when (>= (length mastodon-toot--media-attachments) max-attachments) ;; warn + pop the oldest one: (when (y-or-n-p (format "Maximum attachments (%s) reached: remove first one?" max-attachments)) (pop mastodon-toot--media-attachments))) (if (file-directory-p file) (user-error "Looks like you chose a directory not a file") (setq mastodon-toot--media-attachments (nconc mastodon-toot--media-attachments `(((:contents . ,(mastodon-http--read-file-as-string file)) (:description . ,description) (:filename . ,file))))) (mastodon-toot--refresh-attachments-display) ;; upload only most recent attachment: (mastodon-toot--upload-attached-media (car (last mastodon-toot--media-attachments)))))) (defun mastodon-toot--attachment-descriptions () "Return a list of image descriptions for current attachments." (mastodon-tl--map-alist :description mastodon-toot--media-attachments)) (defun mastodon-toot--attachment-from-desc (desc) "Return an attachment based on its description DESC." (car (cl-member-if (lambda (x) (rassoc desc x)) mastodon-toot--media-attachments))) (defun mastodon-toot-edit-media-description () "Prompt for an attachment, and update its description." (interactive) (let* ((descs (mastodon-toot--attachment-descriptions)) (choice (completing-read "Attachment: " descs nil :match)) (attachment (mastodon-toot--attachment-from-desc choice)) (desc-new (read-string "Description: " choice))) (setf (alist-get :description attachment) desc-new) (mastodon-toot--refresh-attachments-display))) (defun mastodon-toot--upload-attached-media (attachment) "Upload a single ATTACHMENT using `mastodon-http--post-media-attachment'. The item's id is added to `mastodon-toot--media-attachment-ids', which is used to attach it to a toot when posting." (let* ((filename (expand-file-name (alist-get :filename attachment))) (caption (alist-get :description attachment)) (url (concat mastodon-instance-url "/api/v2/media"))) (message "Uploading %s... (please wait before starting further uploads)" (file-name-nondirectory filename)) (mastodon-http--post-media-attachment url filename caption))) (defun mastodon-toot--refresh-attachments-display () "Update the display attachment previews in toot draft buffer." (let ((inhibit-read-only t) (attachments-region (mastodon-tl--find-property-range 'toot-attachments (point-min))) (display-specs (mastodon-toot--format-attachments))) (dotimes (i (- (cdr attachments-region) (car attachments-region))) (add-text-properties (+ i (car attachments-region)) (+ i 1 (car attachments-region)) (list 'display (or (nth i display-specs) "")))))) (defun mastodon-toot--format-attachments () "Format the attachment previews for display in toot draft buffer." (or (let ((image-options (when (mastodon-tl--image-trans-check) `(:height ,mastodon-toot--attachment-height)))) (cl-loop for count from 1 for att in mastodon-toot--media-attachments nconc (let* ((data (alist-get :contents att)) (image (apply #'create-image data (if (version< emacs-version "27.1") (when image-options 'imagemagick) nil) ; inbuilt scaling in 27.1 t image-options)) (desc (alist-get :description att))) (list (format "\n %d: " count) image (format " \"%s\"" desc))))) (list "None"))) ;;; POLL (defun mastodon-toot--fetch-max-poll-options (instance) "Return the maximum number of poll options from JSON data INSTANCE." (mastodon-toot--fetch-poll-field 'max_options instance)) (defun mastodon-toot--fetch-max-poll-option-chars (instance) "Return the maximum number of characters a poll option may have. INSTANCE is JSON." (if (alist-get 'pleroma instance) (mastodon-toot--fetch-poll-field 'max_option_chars instance) (or (mastodon-toot--fetch-poll-field 'max_characters_per_option instance) 50))) ; masto default (defun mastodon-toot--fetch-poll-field (field instance) "Return FIELD from the poll settings from JSON data INSTANCE." (let* ((polls (if (alist-get 'pleroma instance) (alist-get 'poll_limits instance) (alist-get 'polls (alist-get 'configuration instance))))) (alist-get field polls))) (defun mastodon-toot--read-poll-options-count (max) "Read the user's choice of the number of options the poll should have. MAX is the maximum number set by their instance." (let ((number (read-number (format "Number of options [2-%s]: " max) 2))) (if (> number max) (user-error "You need to choose a number between 2 and %s" max) number))) (defun mastodon-toot-create-poll () "Prompt for new poll options and return as a list." (interactive) (if mastodon-toot-poll-use-transient (call-interactively #'mastodon-create-poll) (mastodon-toot--read-poll))) (defun mastodon-toot--read-poll () "Read poll options." (let* ((instance (mastodon-instance-data)) (max-options (mastodon-toot--fetch-max-poll-options instance)) (count (mastodon-toot--read-poll-options-count max-options)) (length (mastodon-toot--fetch-max-poll-option-chars instance)) (multiple-p (y-or-n-p "Multiple choice? ")) (options (mastodon-toot--read-poll-options count length)) (hide-totals (y-or-n-p "Hide votes until poll ends? ")) (expiry (mastodon-toot--read-poll-expiry)) (expiry-str (cdr expiry)) (expiry-human (car expiry))) (setq mastodon-toot-poll `( :options ,options :length ,length :expiry-readable ,expiry-human :expiry ,expiry-str :multi ,multiple-p :hide ,hide-totals)) (message "poll created!") (mastodon-toot--update-status-fields))) (defun mastodon-toot--read-poll-options (count length) "Read a list of options for poll with COUNT options. LENGTH is the maximum character length allowed for a poll option." (let* ((choices (cl-loop for x from 1 to count collect (read-string (format "Poll option [%s/%s] [max %s chars]: " x count length)))) (longest (apply #'max (mapcar #'length choices)))) (if (not (> longest length)) choices (user-error "Looks like you went over the max length. Try again") (sleep-for 2) (mastodon-toot--read-poll-options count length)))) (defun mastodon-toot--read-poll-expiry () "Prompt for a poll expiry time. Return a cons of a human readable string, and a seconds-from-now string." ;; API requires this in seconds (let* ((options (mastodon-toot--poll-expiry-options-alist)) (response (completing-read "poll ends in [or enter seconds]: " options nil 'confirm))) (or (assoc response options #'string=) (if (< (string-to-number response) 300) (cons "5 minutes" (number-to-string (* 60 5))) ;; min 5 mins (cons (format "%s seconds" response) response))))) (defun mastodon-toot--poll-expiry-options-alist () "Return an alist of expiry options options in seconds." `(("5 minutes" . ,(number-to-string (* 60 5))) ("30 minutes" . ,(number-to-string (* 60 30))) ("1 hour" . ,(number-to-string (* 60 60))) ("6 hours" . ,(number-to-string (* 60 60 6))) ("1 day" . ,(number-to-string (* 60 60 24))) ("3 days" . ,(number-to-string (* 60 60 24 3))) ("7 days" . ,(number-to-string (* 60 60 24 7))) ("14 days" . ,(number-to-string (* 60 60 24 14))) ("30 days" . ,(number-to-string (* 60 60 24 30))))) (defun mastodon-toot-clear-poll (&optional transient) "Remove poll from toot compose buffer. Sets `mastodon-toot-poll' to nil. If TRANSIENT, we are called from a transient, so nil `tp-transient-settings' too." (interactive) (let ((var (if transient 'tp-transient-settings 'mastodon-toot-poll))) (if (not (symbol-value var)) (user-error "No poll?") (set var nil) (when transient (setq mastodon-toot-poll nil)) (mastodon-toot--update-status-fields)))) (defun mastodon-toot--server-poll-to-local (json) "Convert server poll data JSON to a `mastodon-toot-poll' plist." (let-alist json (let* ((expiry-seconds-rel (time-to-seconds (time-subtract (encode-time (parse-time-string .expires_at)) (current-time)))) (expiry-str (format-time-string "%s" expiry-seconds-rel)) (expiry-human (car (mastodon-tl--human-duration expiry-seconds-rel))) (options (mastodon-tl--map-alist 'title .options)) (multiple (if (eq :json-false .multiple) nil t))) (if mastodon-toot-poll-use-transient (setq mastodon-toot-poll `((multi . ,multiple) (expiry . ,expiry-str) ;; (hide . ,hide) (one . ,(nth 0 options)) (two . ,(nth 1 options)) (three . ,(nth 2 options)) (four . ,(nth 3 options)))) (setq mastodon-toot-poll `( :options ,options :expiry-readable ,expiry-human :expiry ,expiry-str :multi ,multiple)))))) ;;; SCHEDULE (defun mastodon-toot-schedule-toot (&optional reschedule) "Read a date (+ time) in the minibuffer and schedule the current toot. With RESCHEDULE, reschedule the scheduled toot at point without editing." ;; original idea by christian tietze, thanks! ;; https://codeberg.org/martianh/mastodon.el/issues/285 (interactive) (cond ((mastodon-tl--buffer-type-eq 'edit-toot) (user-error "You can't schedule toots you're editing")) ((not (or (mastodon-tl--buffer-type-eq 'new-toot) (mastodon-tl--buffer-type-eq 'scheduled-statuses))) (user-error "You can only schedule toots from the compose buffer or scheduled toots view")) (t (let* ((id (when reschedule (mastodon-tl--property 'id :no-move))) (ts (when reschedule (alist-get 'scheduled_at (mastodon-tl--property 'scheduled-json :no-move)))) (time-value (org-read-date t t nil "Schedule toot:" ;; default to scheduled timestamp if already set: (mastodon-toot--iso-to-org ;; we are rescheduling without editing: (or ts ;; we are maybe editing the scheduled toot: mastodon-toot--scheduled-for)))) (iso8601-str (format-time-string "%FT%T%z" time-value)) (msg-str (format-time-string "%d-%m-%y at %H:%M[%z]" time-value))) (if (not reschedule) (progn (setq-local mastodon-toot--scheduled-for iso8601-str) (message "Toot scheduled for %s." msg-str)) (let* ((args `(("scheduled_at" . ,iso8601-str))) (url (mastodon-http--api (format "scheduled_statuses/%s" id))) (response (mastodon-http--put url args))) (mastodon-http--triage response (lambda (_) ;; reschedule means we are in scheduled toots view: (mastodon-views-view-scheduled-toots) (message "Toot rescheduled for %s." msg-str))))))))) (defun mastodon-toot--iso-to-human (ts) "Format an ISO8601 timestamp TS to be more human-readable." (let* ((decoded (iso8601-parse ts)) (encoded (encode-time decoded))) (format-time-string "%d-%m-%y, %H:%M[%z]" encoded))) (defun mastodon-toot--iso-to-org (ts) "Convert ISO8601 timestamp TS to something `org-read-date' can handle." (when ts (let* ((decoded (iso8601-parse ts))) (encode-time decoded)))) ;;; DISPLAY KEYBINDINGS (defun mastodon-toot--get-kbinds () "Get a list of the keybindings in the `mastodon-toot-mode'." (let* ((binds (copy-tree mastodon-toot-mode-map)) (prefix (car (cadr binds))) (bindings (remove nil (mapcar (lambda (i) (when (listp i) i)) (cadr binds))))) (mapcar (lambda (b) (setf (car b) (vector prefix (car b))) b) bindings))) (defun mastodon-toot--format-kbind-command (cmd) "Format CMD to be more readable. e.g. `mastodon-toot-send' -> Send." (let* ((str (symbol-name cmd)) (re "mastodon-toot-\\(.*\\)$") (str2 (save-match-data (string-match re str) (match-string 1 str)))) (capitalize (replace-regexp-in-string "-" " " str2)))) (defun mastodon-toot--format-kbind (kbind) "Format a single keybinding, KBIND, for display in documentation." (let ((key (concat "\\`" (help-key-description (car kbind) nil) "'")) (command (mastodon-toot--format-kbind-command (cdr kbind)))) (substitute-command-keys (format (concat (mastodon-toot--comment " ") "%-10s" (mastodon-toot--comment " - %s")) key command)))) (defun mastodon-toot--comment (str) "Propertize STR with `mastodon-toot-docs-face'." (propertize str 'face 'mastodon-toot-docs-face)) (defun mastodon-toot--format-kbinds (kbinds) "Format a list of keybindings, KBINDS, for display in documentation." (mapcar #'mastodon-toot--format-kbind kbinds)) (defvar-local mastodon-toot--kbinds-pairs nil "Contains a list of paired toot compose buffer keybindings for inserting.") (defun mastodon-toot--formatted-kbinds-pairs (kbinds-list longest) "Return a list of strings each containing two formatted kbinds. KBINDS-LIST is the list of formatted bindings to pair. LONGEST is the length of the longest binding." (when kbinds-list (push (concat "\n" (car kbinds-list) (make-string (- (1+ longest) (length (car kbinds-list))) ?\ ) (cadr kbinds-list)) mastodon-toot--kbinds-pairs) (mastodon-toot--formatted-kbinds-pairs (cddr kbinds-list) longest)) (reverse mastodon-toot--kbinds-pairs)) (defun mastodon-toot--kbinds-longest (kbinds-list) "Return the length of the longest item in KBINDS-LIST." (let ((lengths (mapcar #'length kbinds-list))) (car (sort lengths #'>)))) ;;; DISPLAY DOCS (defun mastodon-toot--make-mode-docs () "Create formatted documentation text for `mastodon-toot-mode'." (let* ((kbinds (mastodon-toot--get-kbinds)) (formatted (mastodon-toot--format-kbinds kbinds)) (longest-kbind (mastodon-toot--kbinds-longest formatted))) (concat (mastodon-toot--comment " Compose a new toot here. The following keybindings are available:") (mapconcat #'identity (mastodon-toot--formatted-kbinds-pairs formatted longest-kbind) nil)))) (defun mastodon-toot--format-reply-in-compose (reply-text) "Format a REPLY-TEXT for display in compose buffer docs." (let* ((rendered (mastodon-tl--render-text reply-text)) (no-props (substring-no-properties rendered)) ;; FIXME: this replaces \n at end of every post, so we have to trim: (no-newlines (string-trim (replace-regexp-in-string "[\n]+" " " no-props))) (reply-to (concat " Reply to: \"" no-newlines "\"")) (crop (truncate-string-to-width reply-to mastodon-toot-orig-in-reply-length))) (if (> (length no-newlines) (length crop)) ; we cropped: (concat crop "\n") (concat reply-to "\n")))) (defun mastodon-toot--display-docs-and-status-fields (&optional reply-text) "Insert propertized text with documentation about `mastodon-toot-mode'. Also includes and the status fields which will get updated based on the status of NSFW, content warning flags, media attachments, etc. REPLY-TEXT is the text of the toot being replied to." (let ((divider "|=================================================================|")) (insert (concat (mastodon-toot--make-mode-docs) "\n" (mastodon-toot--comment divider) "\n" (propertize (concat " " (propertize "Count" 'toot-post-counter t) " ⋅ " (propertize "Visibility" 'toot-post-visibility t) " ⋅ " (propertize "Language" 'toot-post-language t) " " (propertize "Scheduled" 'toot-post-scheduled t) " " (propertize "CW" 'toot-post-cw-flag t) " " (propertize "POLL" 'toot-post-poll-flag t) " " (propertize "NSFW" 'toot-post-nsfw-flag t) "\n" " Attachments: " (propertize "None " 'toot-attachments t) "\n" (when reply-text (propertize (mastodon-toot--format-reply-in-compose reply-text) 'toot-reply t)) divider) 'face 'mastodon-toot-docs-face 'read-only "Edit your message below." 'toot-post-header t)) ;; allow us to enter text after read-only header: (propertize "\n\n" 'rear-nonsticky t)))) (defun mastodon-toot--most-restrictive-visibility (reply-visibility) "Return REPLY-VISIBILITY or default visibility, whichever is more restrictive. The default is given by `mastodon-toot--default-reply-visibility'." (unless (null reply-visibility) (let ((less-restrictive (member (intern mastodon-toot--default-reply-visibility) mastodon-toot-visibility-list))) (if (member (intern reply-visibility) less-restrictive) reply-visibility mastodon-toot--default-reply-visibility)))) (defun mastodon-toot--render-reply-region-str (str) "Refill STR and prefix all lines with >, as reply-quote text." (with-temp-buffer (insert str) ;; unfill first: (let ((fill-column (point-max))) (fill-region (point-min) (point-max))) ;; then fill: (fill-region (point-min) (point-max)) ;; add our own prefix, pauschal: (goto-char (point-min)) (save-match-data (while (re-search-forward "^" nil t) (replace-match " > "))) (buffer-substring-no-properties (point-min) (point-max)))) (defun mastodon-toot--setup-as-reply (reply-to-user reply-to-id reply-json reply-region) "If REPLY-TO-USER is provided, inject their handle into the message. If REPLY-TO-ID is provided, set `mastodon-toot--reply-to-id'. REPLY-JSON is the full JSON of the toot being replied to. REPLY-REGION is a string to be injected into the buffer." (let ((reply-visibility (mastodon-toot--most-restrictive-visibility (alist-get 'visibility reply-json))) (reply-cw (alist-get 'spoiler_text reply-json))) (when reply-to-user (when (> (length reply-to-user) 0) ; self is "" unforch (insert (format "%s " reply-to-user))) (when reply-region (insert "\n" (mastodon-toot--render-reply-region-str reply-region) "\n")) (setq mastodon-toot--reply-to-id reply-to-id) (unless (string= mastodon-toot--visibility reply-visibility) (setq mastodon-toot--visibility reply-visibility)) (mastodon-toot--set-cw reply-cw)))) (defun mastodon-toot--update-status-fields (&rest _args) "Update the status fields in the header based on the current state." (ignore-errors ;; called from after-change-functions so let's not leak errors (let* ((inhibit-read-only t) (header-region (mastodon-tl--find-property-range 'toot-post-header (point-min))) (count-region (mastodon-tl--find-property-range 'toot-post-counter (point-min))) (vis-region (mastodon-tl--find-property-range 'toot-post-visibility (point-min))) (nsfw-region (mastodon-tl--find-property-range 'toot-post-nsfw-flag (point-min))) (cw-region (mastodon-tl--find-property-range 'toot-post-cw-flag (point-min))) (lang-region (mastodon-tl--find-property-range 'toot-post-language (point-min))) (sched-region (mastodon-tl--find-property-range 'toot-post-scheduled (point-min))) (poll-region (mastodon-tl--find-property-range 'toot-post-poll-flag (point-min))) (toot-string (buffer-substring-no-properties (cdr header-region) (point-max)))) (mastodon-toot--apply-fields-props count-region (format "%s/%s chars" (mastodon-toot--count-toot-chars toot-string) (number-to-string mastodon-toot--max-toot-chars))) (mastodon-toot--apply-fields-props vis-region (format "%s" (if (string= "private" mastodon-toot--visibility) "followers-only" mastodon-toot--visibility))) ;; WHEN clauses don't work here, we need "" as display arg: (mastodon-toot--apply-fields-props lang-region (if mastodon-toot--language (format "Lang: %s ⋅" mastodon-toot--language) "")) (mastodon-toot--apply-fields-props sched-region (if mastodon-toot--scheduled-for (format "Scheduled: %s ⋅" (mastodon-toot--iso-to-human mastodon-toot--scheduled-for)) "")) (mastodon-toot--apply-fields-props nsfw-region (if mastodon-toot--content-nsfw (if mastodon-toot--media-attachments "NSFW" "NSFW (attachments only)") "") 'mastodon-cw-face) (mastodon-toot--apply-fields-props poll-region (if mastodon-toot-poll "POLL" "") 'mastodon-cw-face (prin1-to-string mastodon-toot-poll)) (mastodon-toot--apply-fields-props cw-region (if (and mastodon-toot--content-warning (not (string= "" mastodon-toot--content-warning))) (format "CW: %s" mastodon-toot--content-warning) " ") ;; hold the blank space 'mastodon-cw-face)))) (defun mastodon-toot--apply-fields-props (region display &optional face help-echo) "Apply DISPLAY props FACE and HELP-ECHO to REGION, a cons of beg and end." (add-text-properties (car region) (cdr region) `(display ,display ,@(when face `(face ,face)) ,@(when help-echo `(help-echo ,help-echo))))) (defun mastodon-toot--count-toot-chars (toot-string &optional cw) "Count the characters in TOOT-STRING. URLs always = 23, and domain names of handles are not counted. This is how mastodon does it. CW is the content warning, which contributes to the character count." ;; FIXME: URL chars is avail at /api/v1/instance ;; for masto, it's .statuses.characters_reserved_per_url (let* ((url-replacement (make-string 23 ?x)) (count-str (replace-regexp-in-string ; handle @handles mastodon-toot-handle-regex "\2" (replace-regexp-in-string ; handle URLs mastodon-toot-url-regex url-replacement toot-string)))) (+ (length cw) (length count-str)))) ;;; DRAFTS (defun mastodon-toot--save-toot-text (&rest _args) "Save the current toot text in `mastodon-toot-current-toot-text'. Added to `after-change-functions' in new toot buffers." (let ((text (mastodon-toot--remove-docs))) (unless (string-empty-p text) (setq mastodon-toot-current-toot-text text)))) (defun mastodon-toot-open-draft-toot () "Prompt for a draft and compose a toot with it." (interactive) (if mastodon-toot-draft-toots-list (let ((text (completing-read "Select draft toot: " mastodon-toot-draft-toots-list nil t))) (if (not (mastodon-toot--compose-buffer-p)) (mastodon-toot--compose-buffer nil nil nil text) (when (and (not (mastodon-toot--empty-p :text-only)) (y-or-n-p "Replace current text with draft?")) (cl-pushnew mastodon-toot-current-toot-text mastodon-toot-draft-toots-list) (goto-char (cdr (mastodon-tl--find-property-range 'toot-post-header (point-min)))) (kill-region (point) (point-max)) ;; to not save to kill-ring: ;; (delete-region (point) (point-max)) (insert text)))) (unless (mastodon-toot--compose-buffer-p) (mastodon-toot--compose-buffer)) (message "No drafts available."))) (defun mastodon-toot-delete-draft-toot () "Prompt for a draft toot and delete it." (interactive) (if (not mastodon-toot-draft-toots-list) (user-error "No drafts to delete") (let ((draft (completing-read "Select draft to delete: " mastodon-toot-draft-toots-list nil t))) (setq mastodon-toot-draft-toots-list (cl-delete draft mastodon-toot-draft-toots-list :test #'equal)) (message "Draft deleted!")))) (defun mastodon-toot-delete-all-drafts () "Delete all drafts." (interactive) (setq mastodon-toot-draft-toots-list nil) (message "All drafts deleted!")) ;;; PROPERTIZE TAGS AND HANDLES (defun mastodon-toot--propertize-tags-and-handles (&rest _args) "Propertize tags and handles in toot compose buffer. Added to `after-change-functions'." (when (mastodon-toot--compose-buffer-p) (let ((header-region (mastodon-tl--find-property-range 'toot-post-header (point-min))) (face (when mastodon-toot--proportional-fonts-compose 'variable-pitch))) ;; cull any prev props: ;; stops all text after a handle or mention being propertized: (set-text-properties (cdr header-region) (point-max) `(face ,face)) (mastodon-toot--propertize-item mastodon-toot-tag-regex 'success (cdr header-region)) (mastodon-toot--propertize-item mastodon-toot-handle-regex 'mastodon-display-name-face (cdr header-region)) (mastodon-toot--propertize-item mastodon-toot-url-regex 'link (cdr header-region))))) (defun mastodon-toot--propertize-item (regex face start) "Propertize item matching REGEX with FACE starting from START." (save-excursion (goto-char start) (cl-loop while (search-forward-regexp regex nil :noerror) do (add-text-properties (match-beginning 2) (match-end 2) `(face ,face))))) (defun mastodon-toot--compose-buffer-p () "Return t if compose buffer is current." (or (mastodon-tl--buffer-type-eq 'edit-toot) (mastodon-tl--buffer-type-eq 'new-toot))) (defun mastodon-toot--fill-reply-in-compose () "Fill reply text in compose buffer to the width of the divider." (save-excursion (save-match-data (let* ((fill-column 67)) (goto-char (point-min)) (when-let* ((prop (text-property-search-forward 'toot-reply))) (fill-region (prop-match-beginning prop) (point))))))) ;;; COMPOSE BUFFER FUNCTION (defun mastodon-toot--compose-buffer (&optional reply-to-user reply-to-id reply-json initial-text edit) "Create a new buffer to capture text for a new toot. If REPLY-TO-USER is provided, inject their handle into the message. If REPLY-TO-ID is provided, set the `mastodon-toot--reply-to-id' var. REPLY-JSON is the full JSON of the toot being replied to. INITIAL-TEXT is used by `mastodon-toot-insert-draft-toot' to add a draft into the buffer. EDIT means we are editing an existing toot, not composing a new one." (let* ((buffer-name (if edit "*edit toot*" "*new toot*")) (buffer-exists (get-buffer buffer-name)) (buffer (if (not buffer-exists) (get-buffer-create buffer-name) ;; if a user hits reply while a compose buffer is already ;; open, we really ought to wipe it all and start over. (switch-to-buffer-other-window buffer-exists) (if (not (y-or-n-p "Overwrite existing compose buffer?")) (user-error "Aborting") (kill-buffer-and-window) (get-buffer-create buffer-name)))) (inhibit-read-only t) (reply-text (alist-get 'content (or (alist-get 'reblog reply-json) reply-json))) (previous-window-config (list (current-window-configuration) (point-marker)))) (switch-to-buffer-other-window buffer) (text-mode) (mastodon-toot-mode t) ;; set visibility: (setq mastodon-toot--visibility (or (plist-get mastodon-profile-account-settings 'privacy) ;; use toot visibility setting from the server: (mastodon-profile--get-source-value 'privacy) "public")) ; fallback ;; default language: ;; NB: this is not necessarily set in ;; `mastodon-profile-credential-account' nor in ;; `mastodon-profile-account-settings'! (setq mastodon-toot--language (mastodon-profile--get-preferences-pref 'posting:default:language)) ;; display original toot: (if mastodon-toot-display-orig-in-reply-buffer (progn (mastodon-toot--display-docs-and-status-fields reply-text) (mastodon-toot--fill-reply-in-compose)) (mastodon-toot--display-docs-and-status-fields)) ;; `reply-to-user' (alone) is also used by `mastodon-tl-dm-user', so ;; perhaps we should not always call --setup-as-reply, or make its ;; workings conditional on reply-to-id. currently it only checks for ;; reply-to-user. (mastodon-toot--setup-as-reply reply-to-user reply-to-id reply-json ;; only initial-text if reply (not edit): (when reply-json initial-text)) (unless mastodon-toot--max-toot-chars ;; no need to fetch from `mastodon-profile-account-settings' as ;; `mastodon-toot--max-toot-chars' is set when we set it (mastodon-toot--get-max-toot-chars)) ;; set up completion: (setq-local completion-ignore-case t) (when mastodon-toot--enable-completion (set (make-local-variable 'completion-at-point-functions) (add-to-list 'completion-at-point-functions #'mastodon-toot--mentions-capf)) (add-to-list 'completion-at-point-functions #'mastodon-toot--tags-capf) (add-to-list 'completion-at-point-functions #'mastodon-toot--emoji-capf) ;; company (when (and mastodon-toot--use-company-for-completion (require 'company nil :no-error)) (declare-function company-mode-on "company") (set (make-local-variable 'company-backends) (add-to-list 'company-backends 'company-capf)) (company-mode-on))) ;; after-change: (make-local-variable 'after-change-functions) (cl-pushnew #'mastodon-toot--save-toot-text after-change-functions) (cl-pushnew #'mastodon-toot--update-status-fields after-change-functions) (mastodon-toot--update-status-fields) (cl-pushnew #'mastodon-toot--propertize-tags-and-handles after-change-functions) (mastodon-toot--propertize-tags-and-handles) (mastodon-toot--refresh-attachments-display) ;; draft toot text saving: (setq mastodon-toot-current-toot-text nil) ;; if we set this before changing modes, it gets nuked: (setq mastodon-toot-previous-window-config previous-window-config) (when mastodon-toot--proportional-fonts-compose (facemenu-set-face 'variable-pitch)) (when (and mastodon-use-emojify ;; emojify loaded but poss not enabled in our buffer: (boundp 'emojify-mode)) (emojify-mode)) (when (and initial-text (not reply-json)) (insert initial-text)))) ;; flyspell ignore masto toot regexes: (defvar flyspell-generic-check-word-predicate) (defun mastodon-toot-mode-flyspell-verify () "A predicate function for `flyspell'. Only text that is not one of these faces will be spell-checked." (let ((faces '(mastodon-display-name-face mastodon-toot-docs-face font-lock-comment-face success link))) (unless (eql (point) (point-min)) ;; (point) is next char after the word. Must check one char before. (let ((f (get-text-property (1- (point)) 'face))) (not (memq f faces)))))) (defun mastodon-toot-mode-hook-fun () "Function for code to run in `mastodon-toot-mode-hook'." ;; disable auto-fill-mode: (auto-fill-mode -1) ;; add flyspell predicate function: (setq flyspell-generic-check-word-predicate #'mastodon-toot-mode-flyspell-verify)) (add-hook 'mastodon-toot-mode-hook #'mastodon-toot-mode-hook-fun) ;;;###autoload (add-hook 'mastodon-toot-mode-hook #'mastodon-profile--fetch-server-account-settings-maybe) (define-minor-mode mastodon-toot-mode "Minor mode for composing toots." :keymap mastodon-toot-mode-map :global nil) (provide 'mastodon-toot) ;;; mastodon-toot.el ends here mastodon.el/lisp/mastodon-transient.el000066400000000000000000000500061501733112700204240ustar00rootroot00000000000000;;; mastodon-transient.el --- transient menus for mastodon.el -*- lexical-binding: t; -*- ;; Copyright (C) 2024 martian hiatus ;; Author: martian hiatus ;; Keywords: convenience ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; ;;; Code: (require 'transient) (require 'tp) (defvar mastodon-active-user) (defvar mastodon-toot-visibility-settings-list) (defvar mastodon-iso-639-regional) (defvar mastodon-toot-poll) (autoload 'mastodon-toot-visibility-settings-list "mastodon-toot") (autoload 'mastodon-http--get-json "mastodon-http") (autoload 'mastodon-http--api "mastodon-http") (autoload 'mastodon-http--triage "mastodon-http") (autoload 'mastodon-http--patch "mastodon-http") (autoload 'mastodon-profile-update-user-profile-note "mastodon-profile") (autoload 'mastodon-toot--fetch-max-poll-options "mastodon-toot") (autoload 'mastodon-toot--fetch-max-poll-option-chars "mastodon-toot") (autoload 'mastodon-instance-data "mastodon") (autoload 'mastodon-toot--update-status-fields "mastodon-toot") (autoload 'mastodon-toot--read-poll-expiry "mastodon-toot") (autoload 'mastodon-toot--poll-expiry-options-alist "mastodon-toot") (autoload 'mastodon-toot-clear-poll "mastodon-toot") (autoload 'mastodon-notifications-get-policy "mastodon-notifications") ;;; UTILS (transient-define-suffix mastodon-transient--prefix-inspect () "Inspect a transient prefix's arguments and scope." (interactive) :transient 'transient--do-return (let ((args (transient-args (oref transient-current-prefix command))) (scope (oref transient-current-prefix scope))) (message "prefix's scope: %s \ntransient-args: %s\n last: %s" scope args (length (cl-member-if (lambda (x) (equal (car x) 'one)) args))))) ;; some JSON fields that are returned under the "source" field need to be ;; sent back in the format source[key], while some others are sent kust as ;; key: (defun mastodon-transient-parse-source-key (key) "Parse mastodon source KEY. If KEY needs to be source[key], format like so, else just return the inner key part." (let* ((split (split-string key "[][]")) (array-key (cadr split))) (if (or (= 1 (length split)) ;; no split (member array-key '("privacy" "sensitive" "language"))) key array-key))) (defun mastodon-transient-parse-source-keys (alist) "Parse ALIST containing source[key] keys." (cl-loop for a in alist collect (cons (mastodon-transient-parse-source-key (car a)) (cdr a)))) (defun mastodon-transient-get-creds () "Fetch account data." (mastodon-http--get-json (mastodon-http--api "accounts/verify_credentials") nil :silent)) ;; fields utils: ;; to PATCH fields, we just need fields[x][name] and fields[x][value] (defun mastodon-transient--fields-alist (fields) "Convert fields in FIELDS to numbered conses. The keys in the data are not numbered, so we convert the key into the format fields.X.keyname." (cl-loop for f in fields for count from 1 to 5 collect (cl-loop for x in f collect (cons (concat "fields." (number-to-string count) "." (symbol-name (car x))) (cdr x))))) (defun mastodon-transient-field-dot-to-array (key) "Convert KEY from tp dot annotation to array[key] annotation." (tp-dot-to-array (symbol-name key) nil "_attributes")) (defun mastodon-transient-dot-fields-to-arrays (alist) "Parse fields ALIST in dot notation to array notation." (cl-loop for y in alist collect (cons (mastodon-transient-field-dot-to-array (car y)) (cdr y)))) ;;; TRANSIENTS ;; FIXME: PATCHing source vals as JSON request body doesn't work! existing ;; `mastodon-profile--update-preference' doesn't use it! it just uses ;; query params! strange thing is it works for non-source params (transient-define-suffix mastodon-user-settings-update (&optional args) "Update current user settings on the server." :transient 'transient--do-exit (interactive (list (transient-args 'mastodon-user-settings))) (let* ((parsed (tp-parse-args-for-send args :strings)) (strs (mastodon-transient-parse-source-keys parsed)) (url (mastodon-http--api "accounts/update_credentials")) (resp (mastodon-http--patch url strs))) ;; :json fails (mastodon-http--triage resp (lambda (_resp) (message "Settings updated!\n%s" (pp-to-string strs)))))) (transient-define-prefix mastodon-user-settings () "A transient for setting current user settings." :value (lambda () (tp-return-data #'mastodon-transient-get-creds)) [:description (lambda () (format "User settings for %s" mastodon-active-user)) (:info "Note: use the empty string (\"\") to remove a value from an option.")] ;; strings ["Account info" ("n" "display name" "display_name" :alist-key display_name :class tp-option-str) ("t" "update profile note" mastodon-update-profile-note) ("f" "update profile fields" mastodon-profile-fields)] ;; "choice" booleans (so we can PATCH :json-false explicitly): ["Account options" ("l" "locked" "locked" :alist-key locked :class tp-bool) ("b" "bot" "bot" :alist-key bot :class tp-bool) ("d" "discoverable" "discoverable" :alist-key discoverable :class tp-bool) ("c" "hide follower/following lists" "source.hide_collections" :alist-key source.hide_collections :class tp-bool) ("i" "indexable" "source.indexable" :alist-key source.indexable :class tp-bool)] ["Tooting options" ("p" "default privacy" "source.privacy" :alist-key source.privacy :class tp-option :choices (lambda () mastodon-toot-visibility-settings-list)) ("s" "mark sensitive" "source.sensitive" :alist-key source.sensitive :class tp-bool) ("g" "default language" "source.language" :alist-key source.language :class tp-option :choices (lambda () mastodon-iso-639-regional))] ["Update" ("C-c C-c" "Save settings" mastodon-user-settings-update) ("C-x C-k" :info "Revert all changes")] (interactive) (if (or (not (boundp 'mastodon-active-user)) (not mastodon-active-user)) (user-error "User not set") (transient-setup 'mastodon-user-settings))) (transient-define-suffix mastodon-update-profile-note () "Update current user profile note." :transient 'transient--do-exit (interactive) (mastodon-profile-update-user-profile-note)) (transient-define-suffix mastodon-profile-fields-update (args) "Update current user profile fields." :transient 'transient--do-return (interactive (list (transient-args 'mastodon-profile-fields))) (let* (;; FIXME: maybe only changed also won't work with fields, as ;; perhaps what is PATCHed overwrites whatever is on the server? ;; (only-changed (tp-only-changed-args alist)) (arrays (mastodon-transient-dot-fields-to-arrays args)) (endpoint "accounts/update_credentials") (url (mastodon-http--api endpoint)) (resp (mastodon-http--patch url arrays))) ; :json))) (mastodon-http--triage resp (lambda (_resp) (message "Fields updated!"))))) (defun mastodon-transient-fetch-fields () "Fetch profile fields (metadata)." (tp-return-data #'mastodon-transient-get-creds nil 'fields) (setq tp-transient-settings (mastodon-transient--fields-alist tp-transient-settings))) (transient-define-prefix mastodon-profile-fields () "A transient for setting profile fields." :value (lambda () (mastodon-transient-fetch-fields)) [:description "Fields" ["Name" ("1 n" "" "fields.1.name" :alist-key fields.1.name :class mastodon-transient-field) ("2 n" "" "fields.2.name" :alist-key fields.2.name :class mastodon-transient-field) ("3 n" "" "fields.3.name" :alist-key fields.3.name :class mastodon-transient-field) ("4 n" "" "fields.4.name" :alist-key fields.4.name :class mastodon-transient-field)] ["Value" ("1 v" "" "fields.1.value" :alist-key fields.1.value :class mastodon-transient-field) ("2 v" "" "fields.2.value" :alist-key fields.2.value :class mastodon-transient-field) ("3 v" "" "fields.3.value" :alist-key fields.3.value :class mastodon-transient-field) ("4 v" "" "fields.4.value" :alist-key fields.4.value :class mastodon-transient-field)]] ["Update" ("C-c C-c" "Save settings" mastodon-profile-fields-update) ("C-x C-k" :info "Revert all changes")] (interactive) (if (not mastodon-active-user) (user-error "User not set") (transient-setup 'mastodon-profile-fields))) (defun mastodon-transient-max-poll-opts () "Return max poll options of user's instance." (let ((instance (mastodon-instance-data))) (mastodon-toot--fetch-max-poll-options instance))) (defun mastodon-transient-max-poll-opt-chars () "Return max poll option characters of user's instance." (let ((instance (mastodon-instance-data))) (mastodon-toot--fetch-max-poll-option-chars instance))) (transient-define-suffix mastodon-transient-choice-add () "Add another poll choice if possible. Do not add more than 9 choices. Do not add more than the server's maximum setting." (interactive) :transient 'transient--do-stay (let* ((args (transient-args (oref transient-current-prefix command))) (choice-count (length (cl-member-if (lambda (x) (equal (car x) 'one)) args))) (inc (1+ choice-count)) (next (number-to-string inc)) (next-symbol (pcase inc (5 'five) (6 'six) (7 'seven) (8 'eight) (9 'nine)))) (if (or (>= choice-count (mastodon-transient-max-poll-opts)) (= choice-count 9)) ;; FIXME when we hit '10', we get a binding clash with '1'. :/ (message "Max choices reached") (transient-append-suffix 'mastodon-create-poll '(2 -1) `(,next "" ,next :class mastodon-transient-poll-choice :alist-key ,next-symbol :transient t)))) (transient-setup 'mastodon-create-poll)) (transient-define-prefix mastodon-create-poll () "A transient for creating a poll." :value (lambda () ;; we set `tp-transient-settings' here to the poll value poss ;; pulled from the server by ;; `mastodon-toot--server-poll-to-local'. when we are done with ;; the transient, we set `mastodon-toot-poll' again (setq tp-transient-settings mastodon-toot-poll)) ["Create poll" (:info (lambda () (format "Max options: %s" (mastodon-transient-max-poll-opts)))) (:info (lambda () (format "Max option length: %s" (mastodon-transient-max-poll-opt-chars))))] ["Options" ("m" "Multiple choice?" "multi" :alist-key multi :class mastodon-transient-poll-bool) ("h" "Hide vote count till expiry?" "hide" :alist-key hide :class mastodon-transient-poll-bool) ("e" "Expiry" "expiry" :alist-key expiry :class mastodon-transient-expiry)] ["Choices" ("1" "" "1" :alist-key one :class mastodon-transient-poll-choice) ("2" "" "2" :alist-key two :class mastodon-transient-poll-choice) ("3" "" "3" :alist-key three :class mastodon-transient-poll-choice) ("4" "" "4" :alist-key four :class mastodon-transient-poll-choice)] ;; TODO: display the max number of options or add options cmd ["Update" ("C-c C-s" "Add another poll choice" mastodon-transient-choice-add :if (lambda () (< 4 (mastodon-transient-max-poll-opts)))) ("C-c C-c" "Save and done" mastodon-create-poll-done) ("C-x C-k" :info "Revert all") ("C-c C-k" "Delete all" mastodon-clear-poll)] (interactive) (if (not mastodon-active-user) (user-error "User not set") (transient-setup 'mastodon-create-poll))) (transient-define-suffix mastodon-clear-poll () "Clear current poll data." :transient 'transient--do-stay (interactive) (mastodon-toot-clear-poll :transient) (transient-reset)) (transient-define-suffix mastodon-create-poll-done (args) "Finish setting poll details." :transient 'transient--do-exit (interactive (list (transient-args 'mastodon-create-poll))) (let* ((options (cl-member-if (lambda (x) (eq (car x) 'one)) args)) (opt-vals (cl-loop for x in options collect (cdr x))) (lengths (mapcar #'length opt-vals)) (vals (cl-remove 'nil (cl-loop for x in args collect (cdr x)))) (opts-count (length (cl-remove 'nil opt-vals)))) ;; this way of checking gets annoying if we want to just cancel out of ;; the poll (but to actually cancel user should C-g, not C-c C-c): (if (or (and (< 50 (apply #'max lengths)) (not (y-or-n-p "Options longer than server max. Proceed? "))) (and (not (alist-get 'expiry args)) (not (y-or-n-p "No expiry. Proceed? "))) (and (not (< 1 opts-count)) (not (y-or-n-p "Need more than one option. Proceed? "))) (and (> opts-count (mastodon-transient-max-poll-opts)) (not (y-or-n-p "More options than server max. Proceed? ")))) (call-interactively #'mastodon-create-poll) ;; if we are called with no poll data, do not set: (unless (not vals) ;; we set `mastodon-toot-poll' here not `tp-transient-settings' ;; as that is our var outside of our transient: (setq mastodon-toot-poll (tp-bools-to-strs args))) (mastodon-toot--update-status-fields)))) (defvar mastodon-notifications-policy-vals) (declare-function mastodon-notifications-get-policy "mastodon-notifications") (declare-function mastodon-notifications--update-policy "mastodon-notifications") (transient-define-prefix mastodon-notifications-policy () "A transient to set notifications policy options." ;; https://docs.joinmastodon.org/methods/notifications/#get-policy :value (lambda () (tp-return-data #'mastodon-notifications-get-policy)) ["Notification policy options" ("f" "people you don't follow" "for_not_following" :alist-key for_not_following :class mastodon-transient-policy) ("F" "people not following you" "for_not_followers" :alist-key for_not_followers :class mastodon-transient-policy) ("n" "New accounts" "for_new_accounts" :alist-key for_new_accounts :class mastodon-transient-policy) ("p" "Unsolicited private mentions" "for_private_mentions" :alist-key for_private_mentions :class mastodon-transient-policy) ("l" "Moderated accounts" "for_limited_accounts" :alist-key for_limited_accounts :class mastodon-transient-policy) (:info "") (:info "\"accept\" = receive notifications") (:info "\"filter\" = mark as filtered") (:info "\"drop\" = do not receive any notifications")] ["Notification requests" (:info #'mastodon-notifications-requests-count) (:info #'mastodon-notifications-filtered-count)] ["Update" ("C-c C-c" "Save settings" mastodon-notifications-policy-update) ("C-x C-k" :info "Revert all changes")]) (defun mastodon-notifications-requests-count () "Format a string for pending requests." (let ((val (oref transient--prefix value))) (format "Pending requests: %d" (or (map-nested-elt val '(summary pending_requests_count)) 0)))) (defun mastodon-notifications-filtered-count () "Format a string for pending notifications." (let ((val (oref transient--prefix value))) (format "Pending notifications: %d" (or (map-nested-elt val '(summary pending_notifications_count)) 0)))) (transient-define-suffix mastodon-notifications-policy-update (args) "Send updated notification policy settings." :transient 'transient--do-exit ;; TODO: (interactive (list (transient-args 'mastodon-notifications-policy))) (let* ((parsed (tp-parse-args-for-send args)) (resp (mastodon-notifications--update-policy parsed))) (mastodon-http--triage resp (lambda (_resp) (message "Settings updated!\n%s" (pp-to-string parsed)))))) ;;; CLASSES (defclass mastodon-transient-policy (tp-cycle) ((choices :initarg :choices :initform 'mastodon-notifications-policy-vals)) "An option class for mastodon notification policy options.") (defclass mastodon-transient-field (tp-option-str) ((always-read :initarg :always-read :initform t)) "An infix option class for our options. We always read.") (cl-defmethod transient-init-value ((obj mastodon-transient-field)) "Initialize value of OBJ." (let* ((prefix-val (oref transient--prefix value))) ;; (arg (oref obj alist-key))) (oset obj value (tp-get-server-val obj prefix-val)))) (cl-defmethod tp-get-server-val ((obj mastodon-transient-field) data) "Return the server value for OBJ from DATA. If OBJ's key has dotted notation, drill down into the alist. Currently only one level of nesting is supported." ;; TODO: handle nested alist keys (let* ((key (oref obj alist-key)) (split (split-string (symbol-name key) "\\.")) (num (string-to-number (cadr split)))) (alist-get key (nth (1- num) data) nil nil #'string=))) (cl-defmethod tp-arg-changed-p ((_obj mastodon-transient-field) cons) "T if value of OBJ is changed from the server value. CONS is a cons of the form \"(fields.1.name . val)\"." (let* ((key-split (split-string (symbol-name (car cons)) "\\.")) (num (1- (string-to-number (nth 1 key-split)))) (server-key (symbol-name (car cons))) (server-elt (nth num tp-transient-settings))) (not (equal (cdr cons) (alist-get server-key server-elt nil nil #'string=))))) (defclass mastodon-transient-opt (tp-option tp-option-var) (())) (defclass mastodon-transient-poll-bool (tp-bool tp-option-var) ()) (defclass mastodon-transient-poll-choice (tp-option-str tp-option-var) ()) (cl-defmethod transient-infix-read ((obj mastodon-transient-poll-choice)) "Reader function for OBJ, a poll expiry." (let* ((value (transient-infix-value obj)) (prompt (transient-prompt obj)) (str (read-string prompt (cdr value))) (max (mastodon-transient-max-poll-opt-chars))) (if (not (> (length str) max)) str (if (not (y-or-n-p (format "Poll option too long for server (%s/%s chars), retry?" (length str) max))) str (oset obj value str) (transient-infix-read obj))))) (defclass mastodon-transient-expiry (tp-option tp-option-var) ()) (cl-defmethod transient-infix-read ((_obj mastodon-transient-expiry)) "Reader function for OBJ, a poll expiry." (cdr (mastodon-toot--read-poll-expiry))) (cl-defmethod transient-format-value ((obj mastodon-transient-expiry)) "Format function for OBJ, a poll expiry." (let* ((cons (transient-infix-value obj)) (value (when cons (cdr cons)))) (if (not value) "" (let ((readable (or (car (rassoc value (mastodon-toot--poll-expiry-options-alist))) (concat value " secs")))) ;; editing a poll wont match expiry list (propertize readable 'face (if (tp-arg-changed-p obj cons) 'transient-value 'transient-inactive-value)))))) (provide 'mastodon-transient) ;;; mastodon-transient.el ends here mastodon.el/lisp/mastodon-views.el000066400000000000000000001312151501733112700175540ustar00rootroot00000000000000;;; mastodon-views.el --- Minor views functions for mastodon.el -*- lexical-binding: t -*- ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon-views.el provides minor views functions. ;; These are currently lists, follow suggestions, filters, scheduled toots, ;; follow requests, and instance descriptions. ;; It doesn't include favourites, bookmarks, preferences, trending tags, followed tags, toot edits, ;;; Code: (require 'cl-lib) (require 'mastodon-http) (eval-when-compile (require 'mastodon-tl)) (defvar mastodon-mode-map) (defvar mastodon-tl--horiz-bar) (defvar mastodon-tl--timeline-posts-count) (autoload 'mastodon-mode "mastodon") (autoload 'mastodon-tl--init "mastodon-tl") (autoload 'mastodon-tl--init-sync "mastodon-tl") (autoload 'mastodon-tl--field "mastodon-tl") (autoload 'mastodon-tl--property "mastodon-tl") (autoload 'mastodon-tl--set-face "mastodon-tl") (autoload 'mastodon-tl--buffer-type-eq "mastodon-tl") (autoload 'mastodon-tl--profile-buffer-p "mastodon-tl") (autoload 'mastodon-tl--goto-first-item "mastodon-tl") (autoload 'mastodon-tl--do-if-item "mastodon-tl") (autoload 'mastodon-tl--set-buffer-spec "mastodon-tl") (autoload 'mastodon-tl--render-text "mastodon-tl") (autoload 'mastodon-notifications-follow-request-accept "mastodon-notifications") (autoload 'mastodon-notifications-follow-request-reject "mastodon-notifications") (autoload 'mastodon-auth--get-account-id "mastodon-auth") (autoload 'mastodon-toot--iso-to-human "mastodon-toot") (autoload 'mastodon-toot-schedule-toot "mastodon-toot") (autoload 'mastodon-toot--compose-buffer "mastodon-toot") (autoload 'mastodon-toot--set-toot-properties "mastodon-toot") (autoload 'mastodon-search--propertize-user "mastodon-search") (autoload 'mastodon-search--insert-users-propertized "mastodon-search") (autoload 'mastodon-tl--map-alist "mastodon-tl") (autoload 'mastodon-tl--map-alist-vals-to-alist "mastodon-tl") ;;; KEYMAPS ;; we copy `mastodon-mode-map', as then all timeline functions are ;; available. this is helpful because if a minor view is the only buffer left ;; open, calling `mastodon' will switch to it, but then we will be unable to ;; switch to timlines without closing the minor view. ;; copying the mode map however means we need to avoid/unbind/override any ;; functions that might interfere with the minor view. ;; this is not redundant, as while the buffer -init function calls ;; `mastodon-mode', it gets overridden in some but not all cases. (defvar mastodon-views-map (let ((map (make-sparse-keymap))) (set-keymap-parent map mastodon-mode-map) map) "Base keymap for minor mastodon views.") (defvar mastodon-views--view-filters-keymap (let ((map (make-sparse-keymap))) (set-keymap-parent map mastodon-views-map) (define-key map (kbd "d") #'mastodon-views-delete-filter) (define-key map (kbd "c") #'mastodon-views-create-filter) (define-key map (kbd "g") #'mastodon-views-view-filters) (define-key map (kbd "u") #'mastodon-views-update-filter) (define-key map (kbd "k") #'mastodon-views-delete-filter) (define-key map (kbd "a") #'mastodon-views-add-filter-kw) (define-key map (kbd "r") #'mastodon-views-remove-filter-kw) (define-key map (kbd "U") #'mastodon-views-update-filter-kw) map) "Keymap for viewing filters.") (defvar mastodon-views--follow-suggestions-map (let ((map (make-sparse-keymap))) (set-keymap-parent map mastodon-views-map) (define-key map (kbd "g") #'mastodon-views-view-follow-suggestions) map) "Keymap for viewing follow suggestions.") (defvar mastodon-views--view-lists-keymap (let ((map (make-sparse-keymap))) (set-keymap-parent map mastodon-views-map) (define-key map (kbd "D") #'mastodon-views-delete-list) (define-key map (kbd "C") #'mastodon-views-create-list) (define-key map (kbd "A") #'mastodon-views-add-account-to-list) (define-key map (kbd "R") #'mastodon-views-remove-account-from-list) (define-key map (kbd "E") #'mastodon-views-edit-list) (define-key map (kbd "g") #'mastodon-views-view-lists) map) "Keymap for viewing lists.") (defvar mastodon-views--list-name-keymap (let ((map (make-sparse-keymap))) (define-key map (kbd "RET") #'mastodon-views-view-timeline-list-at-point) (define-key map (kbd "d") #'mastodon-views-delete-list-at-point) (define-key map (kbd "a") #'mastodon-views-add-account-to-list-at-point) (define-key map (kbd "r") #'mastodon-views-remove-account-from-list-at-point) (define-key map (kbd "e") #'mastodon-views-edit-list-at-point) (define-key map (kbd "g") #'mastodon-views-view-lists) map) "Keymap for when point is on list name.") (defvar mastodon-views--scheduled-map (let ((map (make-sparse-keymap))) (set-keymap-parent map mastodon-views-map) (define-key map (kbd "r") #'mastodon-views-reschedule-toot) (define-key map (kbd "c") #'mastodon-views-cancel-scheduled-toot) (define-key map (kbd "e") #'mastodon-views-edit-scheduled-as-new) (define-key map (kbd "RET") #'mastodon-views-edit-scheduled-as-new) (define-key map (kbd "g") #'mastodon-views-view-scheduled-toots) map) "Keymap for when point is on a scheduled toot.") (defvar mastodon-views--view-follow-requests-keymap (let ((map (make-sparse-keymap))) (set-keymap-parent map mastodon-views-map) ;; make reject binding match the binding in notifs view ;; 'r' is then reserved for replying, even tho it is not avail ;; in foll-reqs view (define-key map (kbd "j") #'mastodon-notifications-follow-request-reject) (define-key map (kbd "a") #'mastodon-notifications-follow-request-accept) (define-key map (kbd "g") #'mastodon-views-view-follow-requests) map) "Keymap for viewing follow requests.") ;;; GENERAL FUNCTION (defun mastodon-views--minor-view (view-name insert-fun data) "Load a minor view named VIEW-NAME. BINDINGS-STRING is a string explaining the view's local bindings. INSERT-FUN is the function to call to insert the view's elements. DATA is the argument to insert-fun, usually JSON returned in a request. This function is used as the update-function to `mastodon-tl--init-sync', which initializes a buffer for us and provides the JSON data." ;; FIXME not tecnically an update-fun for init-sync, but just a simple way ;; to set up the empty buffer or else call the insert-fun. not sure if we cd ;; improve by eg calling init-sync in here, making this a real view function. (if (seq-empty-p data) (insert (propertize (format "Looks like you have no %s for now." view-name) 'face 'mastodon-toot-docs-face 'byline t 'item-type 'no-item ; for nav 'item-id "0")) ; so point can move here when no item (funcall insert-fun data) (goto-char (point-min))) ;; (when data ;; FIXME: this seems to trigger a new request, but ideally would run. ;; (mastodon-tl-goto-next-item)) ) ;;; LISTS (defun mastodon-views-view-lists () "Show the user's lists in a new buffer." (interactive) (mastodon-tl--init-sync "lists" "lists" 'mastodon-views--insert-lists nil nil nil "your lists" "C - create a list\n D - delete a list\ \n A/R - add/remove account from a list\ \n E - edit a list\n n/p - go to next/prev item") (with-current-buffer "*mastodon-lists*" (use-local-map mastodon-views--view-lists-keymap))) (defun mastodon-views--insert-lists (json) "Insert the user's lists from JSON." (mastodon-views--minor-view "lists" #'mastodon-views--print-list-set json)) (defun mastodon-views--print-list-set (lists) "Print each account plus a separator for each list in LISTS." (cl-loop for x in lists do (progn (mastodon-views--print-list-accounts x) (insert (propertize (concat " " mastodon-tl--horiz-bar "\n\n") 'face 'success))))) (defun mastodon-views--print-list-accounts (list) "Insert the accounts in list named LIST, an alist." (let-alist list (let* ((accounts (mastodon-views--accounts-in-list .id))) (insert (propertize .title 'byline t ; so we nav here 'item-id "0" ; so we nav here 'item-type 'list 'help-echo "RET: view list timeline, d: delete this list, \ a: add account to this list, r: remove account from this list" 'list t 'face 'link 'keymap mastodon-views--list-name-keymap 'list-name .title 'list-id .id) (propertize (format " [replies: %s, exclusive %s]" .replies_policy (when (eq t .exclusive) "true")) 'face 'mastodon-toot-docs-face) (propertize "\n\n" 'list t 'keymap mastodon-views--list-name-keymap 'list-name .title 'list-id .id) (propertize (mapconcat #'mastodon-search--propertize-user accounts " ") 'list t 'keymap mastodon-views--list-name-keymap 'list-name .title 'list-id .id))))) (defun mastodon-views--get-users-lists () "Get the list of the user's lists from the server." (let ((url (mastodon-http--api "lists"))) (mastodon-http--get-json url))) (defun mastodon-views--get-lists-names () "Return a list of the user's lists' names." (let ((lists (mastodon-views--get-users-lists))) (mastodon-tl--map-alist 'title lists))) (defun mastodon-views--get-list-by-name (name) "Return the list data for list with NAME." (let* ((lists (mastodon-views--get-users-lists))) (cl-loop for list in lists if (string= (alist-get 'title list) name) return list))) (defun mastodon-views--get-list-id (name) "Return id for list with NAME." (let ((list (mastodon-views--get-list-by-name name))) (alist-get 'id list))) (defun mastodon-views--get-list-name (id) "Return name of list with ID." (let* ((url (mastodon-http--api (format "lists/%s" id))) (response (mastodon-http--get-json url))) (alist-get 'title response))) (defun mastodon-views-edit-list-at-point () "Edit list at point." (interactive) (let ((id (mastodon-tl--property 'list-id :no-move))) (mastodon-views-edit-list id))) (defun mastodon-views-edit-list (&optional id) "Prompt for a list and edit the name and replies policy. If ID is provided, use that list." (interactive) (let* ((list-names (unless id (mastodon-views--get-lists-names))) (name-old (if id (mastodon-tl--property 'list-name :no-move) (completing-read "Edit list: " list-names))) (id (or id (mastodon-views--get-list-id name-old))) (name-choice (read-string "List name: " name-old)) (replies-policy (completing-read "Replies policy: " ; give this a proper name '("followed" "list" "none") nil t nil nil "list")) (exclusive (if (y-or-n-p "Exclude items from home timeline? ") "true" "false")) (url (mastodon-http--api (format "lists/%s" id))) (response (mastodon-http--put url `(("title" . ,name-choice) ("replies_policy" . ,replies-policy) ("exclusive" . ,exclusive))))) (mastodon-http--triage response (lambda (_) (with-current-buffer response (let* ((json (mastodon-http--process-json)) (name-new (alist-get 'title json))) (message "list %s edited to %s!" name-old name-new))) (when (mastodon-tl--buffer-type-eq 'lists) (mastodon-views-view-lists)))))) (defun mastodon-views-view-timeline-list-at-point () "View timeline of list at point." (interactive) (let ((list-id (mastodon-tl--property 'list-id :no-move))) (mastodon-views-view-list-timeline list-id))) (defun mastodon-views-view-list-timeline (&optional id) "Prompt for a list and view its timeline. If ID is provided, use that list." (interactive) (let* ((list-names (unless id (mastodon-views--get-lists-names))) (list-name (unless id (completing-read "View list: " list-names))) (id (or id (mastodon-views--get-list-id list-name))) (endpoint (format "timelines/list/%s" id)) (name (mastodon-views--get-list-name id)) (buffer-name (format "list-%s" name))) (mastodon-tl--init buffer-name endpoint 'mastodon-tl--timeline nil `(("limit" . ,mastodon-tl--timeline-posts-count))))) (defun mastodon-views-create-list () "Create a new list. Prompt for name and replies policy." (interactive) (let* ((title (read-string "New list name: ")) (replies-policy (completing-read "Replies policy: " ; give this a proper name '("followed" "list" "none") nil t nil nil "list")) ; default (exclusive (when (y-or-n-p "Exclude items from home timeline? ") "true")) (response (mastodon-http--post (mastodon-http--api "lists") `(("title" . ,title) ("replies_policy" . ,replies-policy) ("exclusive" . ,exclusive))))) (mastodon-views--list-action-triage response "list %s created!" title))) (defun mastodon-views-delete-list-at-point () "Delete list at point." (interactive) (let ((id (mastodon-tl--property 'list-id :no-move))) (mastodon-views-delete-list id))) (defun mastodon-views-delete-list (&optional id) "Prompt for a list and delete it. If ID is provided, delete that list." (interactive) (let* ((list-names (unless id (mastodon-views--get-lists-names))) (name (if id (mastodon-views--get-list-name id) (completing-read "Delete list: " list-names))) (id (or id (mastodon-views--get-list-id name))) (url (mastodon-http--api (format "lists/%s" id)))) (when (y-or-n-p (format "Delete list %s?" name)) (let ((response (mastodon-http--delete url))) (mastodon-views--list-action-triage response "list %s deleted!" name))))) (defun mastodon-views--get-users-followings () "Return the list of followers of the logged in account." (let* ((id (mastodon-auth--get-account-id)) (url (mastodon-http--api (format "accounts/%s/following" id)))) (mastodon-http--get-json url '(("limit" . "80"))))) ; max 80 accounts (defun mastodon-views-add-account-to-list-at-point () "Prompt for account and add to list at point." (interactive) (let ((id (mastodon-tl--property 'list-id :no-move))) (mastodon-views-add-account-to-list id))) (defun mastodon-views-add-account-to-list (&optional id account-id handle) "Prompt for a list and for an account, add account to list. If ID is provided, use that list. If ACCOUNT-ID and HANDLE are provided use them rather than prompting." (interactive) (let* ((list-prompt (if handle (format "Add %s to list: " handle) "Add account to list: ")) (list-name (if id (mastodon-tl--property 'list-name :no-move) (completing-read list-prompt (mastodon-views--get-lists-names) nil t))) (list-id (or id (mastodon-views--get-list-id list-name))) (followings (unless handle (mastodon-views--get-users-followings))) (handles (unless handle (mastodon-tl--map-alist-vals-to-alist 'acct 'id followings))) (account (or handle (completing-read "Account to add: " handles nil t))) (account-id (or account-id (alist-get account handles))) (url (mastodon-http--api (format "lists/%s/accounts" list-id))) (response (mastodon-http--post url `(("account_ids[]" . ,account-id))))) (mastodon-views--list-action-triage response "%s added to list %s!" account list-name))) (defun mastodon-views-add-toot-account-at-point-to-list () "Prompt for a list, and add the account of the toot at point to it." (interactive) (let* ((toot (mastodon-tl--property 'item-json)) (account (mastodon-tl--field 'account toot)) (account-id (mastodon-tl--field 'id account)) (handle (mastodon-tl--field 'acct account))) (mastodon-views-add-account-to-list nil account-id handle))) (defun mastodon-views-remove-account-from-list-at-point () "Prompt for account and remove from list at point." (interactive) (let ((id (mastodon-tl--property 'list-id :no-move))) (mastodon-views-remove-account-from-list id))) (defun mastodon-views-remove-account-from-list (&optional id) "Prompt for a list, select an account and remove from list. If ID is provided, use that list." (interactive) (let* ((list-name (if id (mastodon-tl--property 'list-name :no-move) (completing-read "Remove account from list: " (mastodon-views--get-lists-names) nil t))) (list-id (or id (mastodon-views--get-list-id list-name))) (accounts (mastodon-views--accounts-in-list list-id)) (handles (mastodon-tl--map-alist-vals-to-alist 'acct 'id accounts)) (account (completing-read "Account to remove: " handles nil t)) (account-id (alist-get account handles)) (url (mastodon-http--api (format "lists/%s/accounts" list-id))) (args (mastodon-http--build-array-params-alist "account_ids[]" `(,account-id))) (response (mastodon-http--delete url args))) (mastodon-views--list-action-triage response "%s removed from list %s!" account list-name))) (defun mastodon-views--list-action-triage (response &rest args) "Call `mastodon-http--triage' on RESPONSE and call message on ARGS." (mastodon-http--triage response (lambda (_) (when (mastodon-tl--buffer-type-eq 'lists) (mastodon-views-view-lists)) (apply #'message args)))) (defun mastodon-views--accounts-in-list (list-id) "Return the JSON of the accounts in list with LIST-ID." (let* ((url (mastodon-http--api (format "lists/%s/accounts" list-id)))) (mastodon-http--get-json url))) ;;; FOLLOW REQUESTS (defun mastodon-views--insert-follow-requests (json) "Insert the user's current follow requests. JSON is the data returned by the server." (mastodon-views--minor-view "follow requests" #'mastodon-views--insert-users-propertized-note json)) (defun mastodon-views-view-follow-requests () "Open a new buffer displaying the user's follow requests." (interactive) (mastodon-tl--init-sync "follow-requests" "follow_requests" 'mastodon-views--insert-follow-requests nil '(("limit" . "40")) ; server max is 80 :headers "follow requests" "a/j - accept/reject request at point\n\ n/p - go to next/prev request") (mastodon-tl--goto-first-item) (with-current-buffer "*mastodon-follow-requests*" (use-local-map mastodon-views--view-follow-requests-keymap))) ;;; SCHEDULED TOOTS ;;;###autoload (defun mastodon-views-view-scheduled-toots () "Show the user's scheduled toots in a new buffer." (interactive) (mastodon-tl--init-sync "scheduled-toots" "scheduled_statuses" 'mastodon-views--insert-scheduled-toots nil nil nil "your scheduled toots" "n/p - prev/next\n r - reschedule\n\ e/RET - edit toot\n c - cancel") (with-current-buffer "*mastodon-scheduled-toots*" (use-local-map mastodon-views--scheduled-map))) (defun mastodon-views--insert-scheduled-toots (json) "Insert the user's scheduled toots, from JSON." (mastodon-views--minor-view "scheduled toots" #'mastodon-views--insert-scheduled-toots-list json)) (defun mastodon-views--insert-scheduled-toots-list (scheduleds) "Insert scheduled toots in SCHEDULEDS." (mapc #'mastodon-views--insert-scheduled-toot scheduleds)) (defun mastodon-views--insert-scheduled-toot (toot) "Insert scheduled TOOT into the buffer." (let-alist toot (insert (propertize (concat (string-trim .params.text) " | " (mastodon-toot--iso-to-human .scheduled_at)) 'byline t ; so we nav here 'item-type 'scheduled ; so we nav here 'face 'mastodon-toot-docs-face 'keymap mastodon-views--scheduled-map 'item-json toot 'id .id) "\n"))) (defun mastodon-views--get-scheduled-toots (&optional id) "Get the user's currently scheduled toots. If ID, just return that toot." (let* ((endpoint (if id (format "scheduled_statuses/%s" id) "scheduled_statuses")) (url (mastodon-http--api endpoint))) (mastodon-http--get-json url))) (defun mastodon-views-reschedule-toot () "Reschedule the scheduled toot at point." (interactive) (mastodon-tl--do-if-item (mastodon-toot-schedule-toot :reschedule))) (defun mastodon-views-copy-scheduled-toot-text () "Copy the text of the scheduled toot at point." (interactive) (let* ((toot (mastodon-tl--property 'toot :no-move)) (params (alist-get 'params toot)) (text (alist-get 'text params))) (kill-new text))) (defun mastodon-views-cancel-scheduled-toot (&optional id no-confirm) "Cancel the scheduled toot at point. ID is that of the scheduled toot to cancel. NO-CONFIRM means there is no ask or message, there is only do." (interactive) (mastodon-tl--do-if-item (when (or no-confirm (y-or-n-p "Cancel scheduled toot?")) (let* ((id (or id (mastodon-tl--property 'id :no-move))) (url (mastodon-http--api (format "scheduled_statuses/%s" id))) (response (mastodon-http--delete url))) (mastodon-http--triage response (lambda (_) (mastodon-views-view-scheduled-toots) (unless no-confirm (message "Toot cancelled!")))))))) (defun mastodon-views-edit-scheduled-as-new () "Edit scheduled status as new toot." (interactive) (mastodon-tl--do-if-item (let* ((toot (mastodon-tl--property 'scheduled-json :no-move)) (id (mastodon-tl--property 'id :no-move)) (scheduled (alist-get 'scheduled_at toot))) (let-alist (alist-get 'params toot) ;; TODO: preserve polls ;; (poll (alist-get 'poll params)) (mastodon-toot--compose-buffer nil .in_reply_to_id nil .text :edit) (goto-char (point-max)) ;; adopt properties from scheduled toot: (mastodon-toot--set-toot-properties .in_reply_to_id .visibility .spoiler_text .language scheduled id (alist-get 'media_attachments toot)))))) ;;; FILTERS ;;;###autoload (defun mastodon-views-view-filters () "View the user's filters in a new buffer." (interactive) (mastodon-tl--init-sync "filters" "filters" 'mastodon-views--insert-filters nil nil nil "current filters" "c/u - create/update filter | d/k - delete filter\ at point\n a/r/U - add/remove/Update filter keyword\n\ n/p - next/prev filter" "v2") (with-current-buffer "*mastodon-filters*" (use-local-map mastodon-views--view-filters-keymap))) (defun mastodon-views--insert-filters (json) "Insert a filter string plus a blank line. JSON is the filters data." (mapc #'mastodon-views--insert-filter json)) (require 'table) (defun mastodon-views--insert-filter-kws (kws) "Insert filter keywords KWS." (insert "\n") (let ((beg (point)) (table-cell-horizontal-chars (if (char-displayable-p ?–) "–" "-")) (whole-str "whole words only:")) (insert (concat "Keywords: | " whole-str "\n")) (cl-loop for kw in kws do (let ((whole (if (eq :json-false (alist-get 'whole_word kw)) "nil" "t"))) (insert (propertize (concat (format "\"%s\" | %s\n" (alist-get 'keyword kw) whole)) 'kw-id (alist-get 'id kw) 'item-json kw 'mastodon-tab-stop t 'whole-word whole)))) ;; table display of kws: (table-capture beg (point) "|" "\n" nil (+ 2 (length whole-str))) (table-justify-column 'center) (table-forward-cell) ;; col 2 (table-justify-column 'center) (while (re-search-forward ;; goto end of table: (concat table-cell-horizontal-chars (make-string 1 table-cell-intersection-char) "\n") nil :no-error)))) (defun mastodon-views--insert-filter (filter) "Insert a single FILTER." (let-alist filter (insert ;; FIXME: awful hack to fix nav: exclude horiz-bar from propertize then ;; propertize rest of the filter text. if we add only byline prop to ;; title, point will move to end of title, because at that byline-prop ;; change, item-type prop is present. (mastodon-tl--set-face (concat "\n " mastodon-tl--horiz-bar "\n ") 'success) (propertize (concat ;; heading: (mastodon-tl--set-face (concat (upcase .title) " " "\n " mastodon-tl--horiz-bar "\n") 'success) ;; context: (concat "Context: " (mapconcat #'identity .context ", ")) ;; type (warn or hide): (concat "\nType: " .filter_action)) 'item-json filter 'byline t 'item-id .id 'filter-title .title 'item-type 'filter)) ;; terms list: (when .keywords ;; poss to have no keywords (mastodon-views--insert-filter-kws .keywords)))) (defvar mastodon-views--filter-types '("home" "notifications" "public" "thread" "profile")) (defun mastodon-views-create-filter (&optional id title context type terms) "Create a filter for a word. Prompt for a context, must be a list containting at least one of \"home\", \"notifications\", \"public\", \"thread\". Optionally, provide ID, TITLE, CONTEXT, TYPE, and TERMS to update a filter." (interactive) ;; ID non-nil = we are updating (let* ((url (mastodon-http--api-v2 (if id (format "filters/%s" id) "filters"))) (title (or title (read-string "Filter name: "))) (terms (or terms (read-string "Terms to filter (comma or space separated): "))) (terms-split (split-string terms "[, ]")) (terms-processed (if (not terms) ;; well actually it is poss to have no terms (user-error "You must select at least one term") (mastodon-http--build-array-params-alist "keywords_attributes[][keyword]" terms-split))) (warn-or-hide (or type (completing-read "Warn (like CW) or hide? " '("warn" "hide") nil :match))) ;; TODO: display "home (and lists)" but just use "home" for API (contexts (or context (completing-read-multiple "Filter contexts [TAB for options, comma separated]: " mastodon-views--filter-types nil :match))) (contexts-processed (if (not contexts) (user-error "You must select at least one context") (mastodon-http--build-array-params-alist "context[]" contexts))) (params (append `(("title" . ,title) ("filter_action" . ,warn-or-hide)) terms-processed contexts-processed)) (resp (if id (mastodon-http--put url params) (mastodon-http--post url params)))) (mastodon-views--filters-triage resp (message "Filter %s %s!" title (if id "updated" "created"))))) (defun mastodon-views-update-filter () "Update filter at point." (interactive) (if (not (eq 'filter (mastodon-tl--property 'item-type))) (user-error "No filter at point?") (let* ((filter (mastodon-tl--property 'item-json)) (id (mastodon-tl--property 'item-id)) (name (read-string "Name: " (alist-get 'title filter))) (contexts (completing-read-multiple "Filter contexts [TAB for options, comma separated]: " mastodon-views--filter-types nil :match (mapconcat #'identity (alist-get 'context filter) ","))) (type (completing-read "Warn (like CW) or hide? " '("warn" "hide") nil :match (alist-get 'type filter))) (terms (read-string "Terms to add (comma or space separated): "))) (mastodon-views-create-filter id name contexts type terms)))) (defun mastodon-views-delete-filter () "Delete filter at point." (interactive) (let* ((id (mastodon-tl--property 'item-id :no-move)) (title (mastodon-tl--property 'filter-title :no-move)) (url (mastodon-http--api-v2 (format "filters/%s" id)))) (if (not (eq 'filter (mastodon-tl--property 'item-type))) (user-error "No filter at point?") (when (y-or-n-p (format "Delete filter %s? " title)) (let ((resp (mastodon-http--delete url))) (mastodon-views--filters-triage resp (message "Filter \"%s\" deleted!" title))))))) (defun mastodon-views--get-filter-kw (&optional id) "GET filter with ID." (let* ((id (or id (mastodon-tl--property 'kw-id :no-move))) (url (mastodon-http--api-v2 (format "filters/keywords/%s" id))) (resp (mastodon-http--get-json url))) resp)) (defun mastodon-views-update-filter-kw () "Update filter keyword. Prmopt to change the term, and the whole words option. When t, whole words means only match whole words." (interactive) (if (not (eq 'filter (mastodon-tl--property 'item-type))) (user-error "No filter at point?") (let* ((kws (alist-get 'keywords (mastodon-tl--property 'item-json :no-move))) (alist (mastodon-tl--map-alist-vals-to-alist 'keyword 'id kws)) (choice (completing-read "Update keyword: " alist)) (updated (read-string "Keyword: " choice)) (whole-word (if (y-or-n-p "Match whole words only? ") "true" "false")) (params `(("keyword" . ,updated) ("whole_word" . ,whole-word))) (id (cdr (assoc choice alist #'string=))) (url (mastodon-http--api-v2 (format "filters/keywords/%s" id))) (resp (mastodon-http--put url params))) (mastodon-views--filters-triage resp (format "Keyword %s updated!" updated))))) (defun mastodon-views--filters-triage (resp msg-str) "Triage filter action response RESP, reload filters, message MSG-STR." (mastodon-http--triage resp (lambda (_resp) (when (mastodon-tl--buffer-type-eq 'filters) (mastodon-views-view-filters)) (message msg-str)))) (defun mastodon-views-add-filter-kw () "Add a keyword to filter at point." (interactive) (if (not (eq 'filter (mastodon-tl--property 'item-type))) (user-error "No filter at point?") (let* ((kw (read-string "Keyword: ")) (id (mastodon-tl--property 'item-id :no-move)) (whole-word (if (y-or-n-p "Match whole words only? ") "true" "false")) (params `(("keyword" . ,kw) ("whole_word" . ,whole-word))) (url (mastodon-http--api-v2 (format "filters/%s/keywords" id))) (resp (mastodon-http--post url params))) (mastodon-views--filters-triage resp (format "Keyword %s added!" kw))))) (defun mastodon-views-remove-filter-kw () "Remove keyword from filter at point." (interactive) (if (not (eq 'filter (mastodon-tl--property 'item-type))) (user-error "No filter at point?") (let* ((kws (alist-get 'keywords (mastodon-tl--property 'item-json :no-move))) (alist (mastodon-tl--map-alist-vals-to-alist 'keyword 'id kws)) (choice (completing-read "Remove keyword: " alist)) (id (cdr (assoc choice alist #'string=))) (url (mastodon-http--api-v2 (format "filters/keywords/%s" id))) (resp (mastodon-http--delete url))) (mastodon-views--filters-triage resp (format "Keyword %s removed!" choice))))) ;;; FOLLOW SUGGESTIONS ;; No pagination: max 80 results (defun mastodon-views-view-follow-suggestions () "Display a buffer of suggested accounts to follow." (interactive) (mastodon-tl--init-sync "follow-suggestions" "suggestions" 'mastodon-views--insert-follow-suggestions nil '(("limit" . "80")) ; server max nil "suggested accounts") (with-current-buffer "*mastodon-follow-suggestions*" (use-local-map mastodon-views--follow-suggestions-map))) (defun mastodon-views--insert-follow-suggestions (json) "Insert follow suggestions into buffer. JSON is the data returned by the server." (mastodon-views--minor-view "suggested accounts" #'mastodon-views--insert-users-propertized-note json)) (defun mastodon-views--insert-users-propertized-note (json) "Insert users list into the buffer, including profile note. JSON is the users list data." (mastodon-search--insert-users-propertized json :note)) ;;; INSTANCES (defun mastodon-views-view-own-instance (&optional brief) "View details of your own instance. BRIEF means show fewer details." (interactive) (mastodon-views-view-instance-description :user brief)) (defun mastodon-views-view-own-instance-brief () "View brief details of your own instance." (interactive) (mastodon-views-view-instance-description :user :brief)) (defun mastodon-views-view-instance-description-brief () "View brief details of the instance the current post's author is on." (interactive) (mastodon-views-view-instance-description nil :brief)) (defun mastodon-views--get-instance-url (url username &optional instance) "Return an instance base url from a user account URL. USERNAME is the name to cull. If INSTANCE is given, use that." (cond (instance (concat "https://" instance)) ;; pleroma URL is https://instance.com/users/username ((string-suffix-p "users/" (url-basepath url)) (string-remove-suffix "/users/" (url-basepath url))) ;; friendica is https://instance.com/profile/user ((string-suffix-p "profile/" (url-basepath url)) (string-remove-suffix "/profile/" (url-basepath url))) ;; snac is https://instance.com/user ((not (string-match-p "@" url)) ;; cull trailing slash: (string-trim-right (url-basepath url) "/")) ;; mastodon is https://instance.com/@user (t (string-remove-suffix (concat "/@" username) url)))) (defun mastodon-views--get-own-instance () "Return JSON of `mastodon-active-user's instance." (mastodon-http--get-json (mastodon-http--api "instance" "v2") nil nil :vector)) (defun mastodon-views-view-instance-description (&optional user brief instance misskey) "View the details of the instance the current post's author is on. USER means to show the instance details for the logged in user. BRIEF means to show fewer details. INSTANCE is an instance domain name. MISSKEY means the instance is a Misskey or derived server." (interactive) (if user (let ((response (mastodon-views--get-own-instance))) (mastodon-views--instance-response-fun response brief instance)) (mastodon-tl--do-if-item (let* ((toot (or (and (mastodon-tl--profile-buffer-p) (mastodon-tl--property 'profile-json)) ; either profile (mastodon-tl--property 'item-json))) ; or toot or user listing (reblog (alist-get 'reblog toot)) (account (or (alist-get 'account reblog) (alist-get 'account toot) toot)) ; else `toot' is already an account listing. ;; we may be at toots/boosts/users in a profile buffer. ;; profile-json is a defacto test for if point is on the profile ;; details at the top of a profile buffer. (profile-note-p (and (mastodon-tl--profile-buffer-p) ;; only call this in profile buffers: (mastodon-tl--property 'profile-json))) (url (if profile-note-p (alist-get 'url toot) ; profile description (alist-get 'url account))) (username (if profile-note-p (alist-get 'username toot) ;; profile (alist-get 'username account))) (instance (mastodon-views--get-instance-url url username instance))) (if misskey (let* ((params `(("detail" . ,(or brief t)))) (headers '(("Content-Type" . "application/json"))) (url (concat instance "/api/meta")) (response (with-current-buffer (mastodon-http--post url params headers t :json) (mastodon-http--process-response)))) (mastodon-views--instance-response-fun response brief instance :misskey)) (let ((response (mastodon-http--get-json (concat instance "/api/v1/instance") nil nil :vector))) ;; if non-misskey attempt errors, try misskey instance: ;; akkoma i guess should not error here. (if (eq 'error (caar response)) (mastodon-views-instance-desc-misskey) (mastodon-views--instance-response-fun response brief instance)))))))) (defun mastodon-views-instance-desc-misskey (&optional user brief instance) "Show instance description for a misskey/firefish server. USER, BRIEF, and INSTANCE are all for `mastodon-views-view-instance-description', which see." (interactive) (mastodon-views-view-instance-description user brief instance :miskey)) (defun mastodon-views--instance-response-fun (response brief instance &optional misskey) "Display instance description RESPONSE in a new buffer. BRIEF means to show fewer details. INSTANCE is the instance were are working with. MISSKEY means the instance is a Misskey or derived server." (when response (let* ((domain (url-file-nondirectory instance)) (buf (get-buffer-create (format "*mastodon-instance-%s*" domain)))) (with-mastodon-buffer buf #'special-mode :other-window (if misskey (mastodon-views--insert-json response) (condition-case nil (progn (when brief (setq response (list (assoc 'uri response) (assoc 'title response) (assoc 'short_description response) (assoc 'email response) (cons 'contact_account (list (assoc 'username (assoc 'contact_account response)))) (assoc 'rules response) (assoc 'stats response)))) (mastodon-views--print-json-keys response) (mastodon-tl--set-buffer-spec (buffer-name buf) "instance" nil) (goto-char (point-min))) (error ; just insert the raw response: (mastodon-views--insert-json response)))))))) (defun mastodon-views--insert-json (response) "Insert raw JSON RESPONSE in current buffer." (let ((inhibit-read-only t)) (erase-buffer) (insert (prin1-to-string response)) (pp-buffer) (goto-char (point-min)))) (defun mastodon-views--format-key (el pad) "Format a key of element EL, a cons, with PAD padding." (format (concat "%-" (number-to-string pad) "s: ") (propertize (prin1-to-string (car el)) 'face '(:underline t)))) (defun mastodon-views--print-json-keys (response &optional ind) "Print the JSON keys and values in RESPONSE. IND is the optional indentation level to print at." (let* ((cars (mapcar (lambda (x) (symbol-name (car x))) response)) (pad (1+ (apply #'max (mapcar #'length cars))))) (while response (let ((el (pop response))) (cond ((and (vectorp (cdr el)) ; vector of alists (fields, instance rules): (not (seq-empty-p (cdr el))) (consp (seq-elt (cdr el) 0))) (insert (mastodon-views--format-key el pad) "\n\n") (seq-do #'mastodon-views--print-instance-rules-or-fields (cdr el)) (insert "\n")) ((and (vectorp (cdr el)) ; vector of strings (media types): (not (seq-empty-p (cdr el))) (< 1 (seq-length (cdr el))) (stringp (seq-elt (cdr el) 0))) (when ind (indent-to ind)) (insert (mastodon-views--format-key el pad) "\n" (seq-mapcat (lambda (x) (concat x ", ")) (cdr el) 'string) "\n\n")) ((consp (cdr el)) ; basic nesting: (when ind (indent-to ind)) (insert (mastodon-views--format-key el pad) "\n\n") (mastodon-views--print-json-keys (cdr el) (if ind (+ ind 4) 4))) (t ; basic handling of raw booleans: (let ((val (cond ((eq (cdr el) :json-false) "no") ((eq (cdr el) t) "yes") (t (cdr el))))) (when ind (indent-to ind)) (insert (mastodon-views--format-key el pad) " " (mastodon-views--newline-if-long (cdr el)) ;; only send strings to --render-text (for hyperlinks): (mastodon-tl--render-text (if (stringp val) val (prin1-to-string val))) "\n")))))))) (defun mastodon-views--print-instance-rules-or-fields (alist) "Print ALIST of instance rules or contact account or emoji fields." (let-alist alist (let ((key (or .id .name .shortcode)) (value (or .text .value .url))) (indent-to 4) (insert (format "%-5s: " (propertize key 'face '(:underline t))) (mastodon-views--newline-if-long value) (format "%s" (mastodon-tl--render-text value)) "\n")))) (defun mastodon-views--newline-if-long (el) "Return a newline string if the cdr of EL is over 50 characters long." (let ((rend (if (stringp el) (mastodon-tl--render-text el) el))) (if (and (sequencep rend) (< 50 (length rend))) "\n" ""))) (provide 'mastodon-views) ;;; mastodon-views.el ends here mastodon.el/lisp/mastodon-widget.el000066400000000000000000000100271501733112700176770ustar00rootroot00000000000000;;; mastodon-widget.el --- Widget utilities -*- lexical-binding: t -*- ;; Copyright (C) 2020-2024 Marty Hiatt ;; Author: Marty Hiatt ;; Maintainer: Marty Hiatt ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; some widget utilities for mastodon.el ;;; Code: (require 'cl-lib) (defvar mastodon-widget-keymap (let ((map (make-sparse-keymap))) (define-key map [down-mouse-2] 'widget-button-click) (define-key map [down-mouse-1] 'widget-button-click) (define-key map [touchscreen-begin] 'widget-button-click) ;; The following definition needs to avoid using escape sequences that ;; might get converted to ^M when building loaddefs.el (define-key map [(control ?m)] 'widget-button-press) map) "Keymap containing useful binding for buffers containing widgets. Recommended as a parent keymap for modes using widgets. Note that such modes will need to require wid-edit.") (defface mastodon-widget-face '((t :inherit font-lock-function-name-face :weight bold :underline t)) "Face for widgets." :group 'mastodon) (defun mastodon-widget--return-item-widgets (list) "Return a list of item widgets for each item, a string, in LIST." (cl-loop for x in list collect `(choice-item :value ,x :format "%[%v%] " :keymap ,mastodon-widget-keymap))) (defun mastodon-widget--format (str &optional padding newline) "Return a widget format string for STR, its name. PADDING is an integer, for how much right-side padding to add." (concat "%[" (propertize str 'face 'mastodon-widget-face 'mastodon-tab-stop t) "%]: %v" (make-string padding ? ) (if newline "\n" ""))) (defun mastodon-widget--create (kind type value notify-fun &optional newline) "Return a widget of KIND, with TYPE elements, and default VALUE. KIND is a string, either Listing, Sort, Items, or Inbox, and will be used for the widget's tag. VALUE is a string, a member of TYPE. NOTIFY-FUN is the widget's notify function." (let* ((val-length (length (if (symbolp value) (symbol-name value) value))) (type-list (if (symbolp type) (symbol-value type) type)) (longest (apply #'max (mapcar #'length (if (symbolp (car type-list)) (mapcar #'symbol-name type-list) type-list)))) (padding (- longest val-length))) (if (not (member value type-list)) (user-error "%s is not a member of %s" value type-list) (widget-create 'menu-choice :tag kind :value value :args (mastodon-widget--return-item-widgets type-list) :help-echo (format "Select a %s kind" kind) :format (mastodon-widget--format kind padding newline) :notify notify-fun ;; eg format of notify-fun: ;; (lambda (widget &rest ignore) ;; (let ((value (widget-value widget)) ;; (tag (widget-get widget :tag))) ;; (notify-fun value))) :keymap mastodon-widget-keymap)))) (provide 'mastodon-widget) ;;; mastodon-widget.el ends here mastodon.el/lisp/mastodon.el000066400000000000000000000613271501733112700164270ustar00rootroot00000000000000;;; mastodon.el --- Client for fediverse services using the Mastodon API -*- lexical-binding: t -*- ;; Copyright (C) 2017-2019 Johnson Denen ;; Copyright (C) 2020-2022 Marty Hiatt ;; Copyright (C) 2021 Abhiseck Paira ;; Author: Johnson Denen ;; Marty Hiatt ;; Maintainer: Marty Hiatt ;; Version: 2.0.1 ;; Package-Requires: ((emacs "28.1") (persist "0.4") (tp "0.7")) ;; Homepage: https://codeberg.org/martianh/mastodon.el ;; This file is not part of GNU Emacs. ;; This file is part of mastodon.el. ;; mastodon.el is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; mastodon.el is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with mastodon.el. If not, see . ;;; Commentary: ;; mastodon.el is a client for fediverse services that implement the Mastodon ;; API. See . ;; For set up and usage details, see the Info documentation, or the readme ;; file at . ;;; Code: (require 'cl-lib) ; for `cl-some' call in `mastodon' (eval-when-compile (require 'subr-x)) (require 'url) (require 'thingatpt) (require 'shr) (require 'mastodon-http) (require 'mastodon-toot) (require 'mastodon-search) (require 'mastodon-transient) (require 'mastodon-tl) (declare-function discover-add-context-menu "discover") (declare-function emojify-mode "emojify") (declare-function request "request") (autoload 'mastodon-auth--get-account-name "mastodon-auth") (autoload 'mastodon-auth--user-acct "mastodon-auth") (autoload 'mastodon-discover "mastodon-discover") (autoload 'mastodon-notifications-follow-request-accept "mastodon-notifications") (autoload 'mastodon-notifications-follow-request-reject "mastodon-notifications") (autoload 'mastodon-notifications-get-mentions "mastodon-notifications") (autoload 'mastodon-notifications--timeline "mastodon-notifications") (autoload 'mastodon-notifications-policy "mastodon-notifications") (autoload 'mastodon-notifications-requests "mastodon-notifications") (autoload 'mastodon-profile--fetch-server-account-settings "mastodon-profile") (autoload 'mastodon-profile-get-toot-author "mastodon-profile") (autoload 'mastodon-profile--make-author-buffer "mastodon-profile") (autoload 'mastodon-profile-my-profile "mastodon-profile") (autoload 'mastodon-profile-show-user "mastodon-profile") (autoload 'mastodon-profile-update-user-profile-note "mastodon-profile") (autoload 'mastodon-profile-view-bookmarks "mastodon-profile") (autoload 'mastodon-profile-view-favourites "mastodon-profile") (autoload 'mastodon-toot-edit-toot-at-point "mastodon-toot") (when (require 'lingva nil :no-error) (autoload 'mastodon-toot-translate-toot-text "mastodon-toot")) (autoload 'mastodon-toot--view-toot-history "mastodon-tl") (autoload 'mastodon-tl-return "mastodon-tl") (autoload 'mastodon-tl-jump-to-followed-tag "mastodon-tl") ;; for M-x visibility ;; (views.el uses `mastodon-mode-map', so we can't easily require it) (autoload 'mastodon-views-view-follow-suggestions "mastodon-views" nil :interactive) (autoload 'mastodon-views-view-filters "mastodon-views" nil :interactive) (autoload 'mastodon-views-view-follow-requests "mastodon-views" nil :interactive) (autoload 'mastodon-views-view-own-instance "mastodon-views" nil :interactive) (autoload 'mastodon-views-view-instance-description "mastodon-views" nil :interactive) (autoload 'mastodon-views-view-lists "mastodon-views" nil :interactive) (autoload 'mastodon-views-view-scheduled-toots "mastodon-views" nil :interactive) (autoload 'mastodon-views-add-account-to-list "mastodon-views" nil :interactive) (autoload 'mastodon-views-add-toot-account-at-point-to-list "mastodon-views" nil :interactive) (autoload 'mastodon-views-create-list "mastodon-views" nil :interactive) (autoload 'mastodon-views-create-filter "mastodon-views" nil :interactive) (autoload 'mastodon-views-view-list-timeline "mastodon-views" nil :interactive) (autoload 'special-mode "simple") (defvar mastodon-tl--highlight-current-toot) (defvar mastodon-notifications--map) (defvar mastodon-client--token-file) (defvar mastodon-notifications-grouped-types '("reblog" "favourite") ;; TODO: implement follow! "List of notification types for which grouping is implemented. Used in `mastodon-notifications-get'") (defgroup mastodon nil "Interface with Mastodon." :prefix "mastodon-" :group 'external) (defcustom mastodon-instance-url "https://mastodon.social" "Base URL for the fediverse instance you want to be active. For example, if your username is \"example_user@social.instance.org\", and you want this account to be active, the value of this variable should be \"https://social.instance.org\". Also for completeness, the value of `mastodon-active-user' should be \"example_user\". After setting these variables you should restart Emacs for these changes to take effect." :type 'string) (defcustom mastodon-active-user nil "Username of the active user. For example, if your username is \"example_user@social.instance.org\", and you want this account to be active, the value of this variable should be \"example_user\". Also for completeness, the value of `mastodon-instance-url' should be \"https://social.instance.org\". After setting these variables you should restart Emacs for these changes to take effect." :type 'string) (defcustom mastodon-toot-timestamp-format "%F %T" "Format to use for timestamps. For valid formatting options see `format-time-string`. The default value \"%F %T\" prints ISO8601-style YYYY-mm-dd HH:MM:SS. Use. e.g. \"%c\" for your locale's date and time format." :type 'string) (defcustom mastodon-use-emojify nil "Whether to use emojify.el to display emojis. From version 28, Emacs can display emojis natively. But currently, it doesn't seem to have a way to handle custom emoji, while emojify,el has this feature and mastodon.el implements it." :type 'boolean) ;; notifications customizes ;; moved here because we can load notifs without first loading mastodon.el ;; or mastodon-notifications.el (defcustom mastodon-profile-note-in-foll-reqs t "If non-nil, show a user's profile note in follow request notifications." :type '(boolean)) (defcustom mastodon-profile-note-in-foll-reqs-max-length nil "The max character length for user profile note in follow requests. Profile notes are only displayed if `mastodon-profile-note-in-foll-reqs' is non-nil. If unset, profile notes of any size will be displayed, which may make them unweildy." :type '(integer)) (defcustom mastodon-images-in-notifs nil "Whether to display attached images in notifications." :type '(boolean)) (defcustom mastodon-group-notifications nil "Whether to use grouped notifications. Requires that your instance actually implements grouped notifications. Mastodon implemented them in 4.3." :type '(boolean)) (defcustom mastodon-notifications-grouped-names-count 2 "The number of notification authors to display. A count of 2 for example means to display like so: \"Bob, Jenny and X others...\"." :type '(integer)) (defun mastodon-kill-window () "Quit window and delete helper." (interactive) (quit-window 'kill)) (defvar mastodon-client--active-user-details-plist) (defvar mastodon-auth--token-alist) ;;;###autoload (defun mastodon-forget-all-logins () "Delete `mastodon-client--token-file'. Also nil `mastodon-auth--token-alist'." (interactive) (when (y-or-n-p "Remove all saved login data?") (if (not (file-exists-p mastodon-client--token-file)) (message "No plstore file") (delete-file mastodon-client--token-file) (message "File %s deleted." mastodon-client--token-file)) ;; nil some vars too: (setq mastodon-client--active-user-details-plist nil) (setq mastodon-auth--token-alist nil))) (defvar mastodon-mode-map (let ((map (make-sparse-keymap))) ;; navigation inside a timeline (define-key map (kbd "n") #'mastodon-tl-goto-next-item) (define-key map (kbd "p") #'mastodon-tl-goto-prev-item) (define-key map (kbd "M-n") #'mastodon-tl-next-tab-item) (define-key map (kbd "M-p") #'mastodon-tl-previous-tab-item) (define-key map [?\t] #'mastodon-tl-next-tab-item) (define-key map [backtab] #'mastodon-tl-previous-tab-item) (define-key map [?\S-\t] #'mastodon-tl-previous-tab-item) (define-key map [?\M-\t] #'mastodon-tl-previous-tab-item) (define-key map (kbd "l") #'recenter-top-bottom) ;; navigation between timelines (define-key map (kbd "#") #'mastodon-tl-get-tag-timeline) (define-key map (kbd "\"") #'mastodon-tl-list-followed-tags) (define-key map (kbd "C-\"") #'mastodon-tl-jump-to-followed-tag) (define-key map (kbd "'") #'mastodon-tl-followed-tags-timeline) (define-key map (kbd "C-'") #'mastodon-tl-tag-group-timeline) (define-key map (kbd "A") #'mastodon-profile-get-toot-author) (define-key map (kbd "F") #'mastodon-tl-get-federated-timeline) (define-key map (kbd "H") #'mastodon-tl-get-home-timeline) (define-key map (kbd "L") #'mastodon-tl-get-local-timeline) (define-key map (kbd "N") #'mastodon-notifications-get) (define-key map (kbd "S-C-n") #'mastodon-notifications-requests) (define-key map (kbd "@") #'mastodon-notifications-get-mentions) (define-key map (kbd "P") #'mastodon-profile-show-user) (define-key map (kbd "s") #'mastodon-search-query) (define-key map (kbd "/") #'mastodon-switch-to-buffer) (define-key map (kbd "\\") #'mastodon-tl-get-remote-local-timeline) ;; quitting mastodon (define-key map (kbd "q") #'kill-current-buffer) (define-key map (kbd "Q") #'mastodon-kill-window) (define-key map (kbd "M-C-q") #'mastodon-kill-all-buffers) ;; toot actions (define-key map (kbd "c") #'mastodon-tl-toggle-spoiler-text-in-toot) (define-key map (kbd "b") #'mastodon-toot-toggle-boost) (define-key map (kbd "f") #'mastodon-toot-toggle-favourite) (define-key map (kbd "k") #'mastodon-toot-toggle-bookmark) (define-key map (kbd "r") #'mastodon-toot-reply) (define-key map (kbd "C") #'mastodon-toot-copy-toot-url) (define-key map (kbd "o") #'mastodon-toot-browse-toot-url) (define-key map (kbd "v") #'mastodon-tl-poll-vote) (define-key map (kbd "E") #'mastodon-toot-view-toot-edits) (define-key map (kbd "T") #'mastodon-tl-thread) (define-key map (kbd "RET") #'mastodon-tl-return) (define-key map (kbd "m") #'mastodon-tl-dm-user) (define-key map (kbd "=") #'mastodon-tl-view-first-full-image) (when (require 'lingva nil :no-error) (define-key map (kbd "a") #'mastodon-toot-translate-toot-text)) (define-key map (kbd ",") #'mastodon-toot-list-favouriters) (define-key map (kbd ".") #'mastodon-toot-list-boosters) (define-key map (kbd ";") #'mastodon-views-view-instance-description) ;; override special mode binding (define-key map (kbd "g") #'undefined) (define-key map (kbd "g") #'mastodon-tl-update) ;; this is now duplicated by 'g', cd remove/use for else: (define-key map (kbd "u") #'mastodon-tl-update) ;; own toot actions: (define-key map (kbd "t") #'mastodon-toot) (define-key map (kbd "d") #'mastodon-toot-delete-toot) (define-key map (kbd "D") #'mastodon-toot-delete-and-redraft-toot) (define-key map (kbd "i") #'mastodon-toot-pin-toot-toggle) (define-key map (kbd "e") #'mastodon-toot-edit-toot-at-point) ;; user actions (define-key map (kbd "W") #'mastodon-tl-follow-user) (define-key map (kbd "C-S-W") #'mastodon-tl-unfollow-user) (define-key map (kbd "B") #'mastodon-tl-block-user) (define-key map (kbd "C-S-B") #'mastodon-tl-unblock-user) (define-key map (kbd "M") #'mastodon-tl-mute-user) (define-key map (kbd "C-S-M") #'mastodon-tl-unmute-user) (define-key map (kbd "Z") #'mastodon-tl-report-to-mods) ;; own profile (define-key map (kbd "O") #'mastodon-profile-my-profile) (define-key map (kbd "U") #'mastodon-profile-update-user-profile-note) (define-key map (kbd "V") #'mastodon-profile-view-favourites) (define-key map (kbd "K") #'mastodon-profile-view-bookmarks) (define-key map (kbd ":") #'mastodon-user-settings) (define-key map (kbd "C-:") #'mastodon-notifications-policy) ;; minor views (define-key map (kbd "R") #'mastodon-views-view-follow-requests) (define-key map (kbd "S") #'mastodon-views-view-scheduled-toots) (define-key map (kbd "I") #'mastodon-views-view-filters) (define-key map (kbd "G") #'mastodon-views-view-follow-suggestions) (define-key map (kbd "X") #'mastodon-views-view-lists) (define-key map (kbd "SPC") #'mastodon-tl-scroll-up-command) (define-key map (kbd "!") #'mastodon-tl-fold-post-toggle) (define-key map (kbd "z") #'bury-buffer) map) "Keymap for `mastodon-mode'.") (defcustom mastodon-mode-hook nil "Hook run when entering Mastodon mode." :type 'hook :options '(provide-discover-context-menu)) (defface mastodon-handle-face '((t :inherit default)) "Face used for user handles in bylines.") (defface mastodon-display-name-face '((t :inherit warning)) "Face used for user display names.") (defface mastodon-boosted-face '((t :inherit success :weight bold)) "Face to indicate that a toot is boosted.") (defface mastodon-boost-fave-face '((t :inherit success)) "Face to indicate that you have boosted or favourited a toot.") (defface mastodon-cw-face '((t :inherit success)) "Face used for content warning.") (defface mastodon-toot-docs-face `((t :inherit shadow)) "Face used for documentation in toot compose buffer. If `mastodon-tl--enable-proportional-fonts' is changed, mastodon.el needs to be re-loaded for this to be correctly set.") (defface mastodon-toot-docs-reply-text-face `((t :inherit font-lock-comment-face :family ,(face-attribute 'variable-pitch :family))) "Face used for reply text in toot compose buffer. See `mastodon-toot-display-orig-in-reply-buffer'.") (defface mastodon-cursor-highlight-face `((t :inherit highlight :extend t)) "Face for `mastodon-tl--highlight-current-toot'.") ;;;###autoload (defun mastodon () "Connect client to `mastodon-instance-url' instance. If there are any open mastodon.el buffers, switch to one instead. Prority in switching is given to timeline views." (interactive) (let* ((tls (list "home" "local" "federated" (concat (mastodon-auth--user-acct) "-statuses") ; own profile "favourites" "search")) (buffer (or (cl-some (lambda (el) (get-buffer (concat "*mastodon-" el "*"))) tls) ; return first buff that exists (cl-some (lambda (x) (when (string-prefix-p "*mastodon-" (buffer-name x)) (get-buffer x))) (buffer-list))))) ; catch any other masto buffer (if buffer (pop-to-buffer buffer '(display-buffer-same-window)) ;; we need to update credential-account in case setting have been changed ;; outside mastodon.el in the meantime: (mastodon-return-credential-account :force) (mastodon-tl-get-home-timeline) (message "Loading fediverse account %s on %s..." (mastodon-auth--user-acct) mastodon-instance-url)))) (defvar mastodon-profile-credential-account nil) ;; TODO: the get request in mastodon-http--get-response often returns nil ;; after waking from sleep, not sure how to fix, or if just my pc. ;; interestingly it only happens with this function tho. (defun mastodon-return-credential-account (&optional force) "Return the CredentialAccount entity. Either from `mastodon-profile-credential-account' or from the server if that var is nil. FORCE means to fetch from the server in any case and update `mastodon-profile-credential-account'." (if (or force (not mastodon-profile-credential-account)) (setq mastodon-profile-credential-account ;; TODO: we should signal a quit condition after 5 secs here (condition-case nil (mastodon-http--get-json (mastodon-http--api "accounts/verify_credentials") nil :silent) (t ; req fails, return old value mastodon-profile-credential-account))) ;; else just return the var: mastodon-profile-credential-account)) (defvar mastodon-instance-data nil "Instance data from the instance endpoint.") (defun mastodon-instance-data () "Return `mastodon-instnace-data' or else fetch from instance endpoint." (or mastodon-instance-data (setq mastodon-instance-data (mastodon-http--get-json (mastodon-http--api "instance"))))) (defun mastodon-instance-version () "Return the version string of user's instance." (alist-get 'version (mastodon-instance-data))) ;;;###autoload (defun mastodon-toot (&optional user reply-to-id reply-json) "Update instance with new toot. Content is captured in a new buffer. If USER is non-nil, insert after @ symbol to begin new toot. If REPLY-TO-ID is non-nil, attach new toot to a conversation. If REPLY-JSON is the json of the toot being replied to." (interactive) (mastodon-toot--compose-buffer user reply-to-id reply-json)) ;;;###autoload (defun mastodon-notifications-get (&optional type buffer-name max-id) "Display NOTIFICATIONS in buffer. Optionally only print notifications of type TYPE, a string. BUFFER-NAME is added to \"*mastodon-\" to create the buffer name. MAX-ID is a request parameter for pagination." (interactive) (let* ((buffer-name (or buffer-name "notifications")) (buffer (concat "*mastodon-" buffer-name "*"))) (message "Loading your notifications...") (mastodon-tl--init-sync buffer-name "notifications" 'mastodon-notifications--timeline type `(,@(when mastodon-group-notifications (mastodon-http--build-array-params-alist "grouped_types[]" mastodon-notifications-grouped-types)) ,@(when max-id `(("max_id" . ,(mastodon-tl--buffer-property 'max-id))))) nil nil nil (if (or (not mastodon-group-notifications) ;; if version less than 1st grouped notifs release: (> 4.3 (string-to-number (mastodon-instance-version)))) "v1" "v2")) (with-current-buffer (get-buffer-create buffer) (use-local-map mastodon-notifications--map)) (message "Loading your notifications... Done"))) ;; URL lookup: should be available even if `mastodon.el' not loaded: ;;;###autoload (defun mastodon-url-lookup (&optional query-url force) "If a URL resembles a fediverse link, try to load in `mastodon.el'. Does a WebFinger lookup on the server. URL can be arg QUERY-URL, or URL at point, or provided by the user. If a status or account is found, load it in `mastodon.el', if not, just browse the URL in the normal fashion. If FORCE, do a lookup regardless of the result of `mastodon--fedi-url-p'." (interactive) (let* ((query (or query-url (mastodon-tl--property 'shr-url :no-move) (thing-at-point-url-at-point) (read-string "Lookup URL: ")))) (if (and (not force) (not (mastodon--fedi-url-p query))) ;; (shr-browse-url query) ; doesn't work (keep our shr keymap) (progn (message "Using external browser") (browse-url query)) (message "Performing lookup...") (let* ((url (format "%s/api/v2/search" mastodon-instance-url)) (params `(("q" . ,query) ("resolve" . "t"))) ; webfinger (response (mastodon-http--get-json url params :silent))) (cond ((not (seq-empty-p (alist-get 'statuses response))) (let* ((statuses (assoc 'statuses response)) (status (seq-first (cdr statuses))) (status-id (alist-get 'id status))) (mastodon-tl--thread-do status-id))) ((not (seq-empty-p (alist-get 'accounts response))) (let* ((accounts (assoc 'accounts response)) (account (seq-first (cdr accounts)))) (mastodon-profile--make-author-buffer account))) (t (message "Lookup failed. Using external browser") (browse-url query))))))) (defun mastodon-url-lookup-force () "Call `mastodon-url-lookup' without checking if URL is fedi-like." (interactive) (mastodon-url-lookup nil :force)) (defun mastodon--fedi-url-p (query) "Check if QUERY resembles a fediverse URL." ;; calqued off https://github.com/tuskyapp/Tusky/blob/c8fc2418b8f5458a817bba221d025b822225e130/app/src/main/java/com/keylesspalace/tusky/BottomSheetActivity.kt ;; thx to Conny Duck! ;; mastodon at least seems to allow only [a-z0-9_] for usernames, plus "." ;; but not at beginning or end, see https://github.com/mastodon/mastodon/issues/6830 ;; objects may have - in them (let* ((uri-parsed (url-generic-parse-url query)) (query (url-filename uri-parsed))) (save-match-data (or (string-match "^/@[^/]+$" query) (string-match "^/@[^/]+/[[:digit:]]+$" query) (string-match "^/user[s]?/@?[[:alnum:]_]+$" query) ; @: pleroma or soapbox (string-match "^/notice/[[:alnum:]]+$" query) (string-match "^/objects/[-a-f0-9]+$" query) (string-match "^/notes/[a-z0-9]+$" query) (string-match "^/display/[-a-f0-9]+$" query) (string-match "^/profile/[[:alpha:]_]+$" query) (string-match "^/p/[[:alpha:]_]+/[[:digit:]]+$" query) (string-match "^/[[:alpha:]_]+$" query) (string-match "^/u/[[:alpha:]_]+$" query) (string-match "^/c/[[:alnum:]_]+$" query) (string-match "^/post/[[:digit:]]+$" query) (string-match "^/comment/[[:digit:]]+$" query) ; lemmy (string-match "^/@[^/]+/statuses/[[:alnum:]]" query) ; GTS (string-match "^/user[s]?/[[:alnum:]_]+/statuses/[[:digit:]]+$" query) ; hometown (string-match "^/notes/[[:alnum:]]+$" query) ; misskey post (string-match "^/w/[[:alnum:]_]+$" query) ; peertube post )))) (defun mastodon-live-buffers () "Return a list of open mastodon buffers. Calls `mastodon-tl--get-buffer-type', which see." (cl-loop for x in (buffer-list) when (with-current-buffer x (mastodon-tl--get-buffer-type)) collect (get-buffer x))) (defun mastodon-buffer-p (&optional buffer) "Non-nil if BUFFER or `current-buffer' is a mastodon one." (let ((buf (or buffer (current-buffer)))) (member buf (mastodon-live-buffers)))) (defun mastodon-kill-all-buffers () "Kill any and all open mastodon buffers, hopefully." (interactive) (let ((mastodon-buffers (mastodon-live-buffers))) (cl-loop for x in mastodon-buffers do (kill-buffer x)))) (defun mastodon-switch-to-buffer () "Switch to a live mastodon buffer." (interactive) (let ((choice (completing-read "Switch to mastodon buffer: " (mapcar #'buffer-name (mastodon-live-buffers)) nil :match))) (switch-to-buffer choice))) (defun mastodon--url-at-point () "`thing-at-point' provider function." (get-text-property (point) 'shr-url)) (defun mastodon-mode-hook-fun () "Function to add to `mastodon-mode-hook'." (when (and mastodon-use-emojify (require 'emojify nil :noerror)) (emojify-mode t) (when mastodon-toot--enable-custom-instance-emoji (mastodon-toot-enable-custom-emoji))) (mastodon-profile--fetch-server-account-settings) (when (and mastodon-tl--highlight-current-toot (fboundp #'cursor-face-highlight-mode)) (cursor-face-highlight-mode)) ; 29.1 ;; make `thing-at-point' functions work: (setq-local thing-at-point-provider-alist (append thing-at-point-provider-alist '((url . mastodon--url-at-point))))) ;;;###autoload (add-hook 'mastodon-mode-hook #'mastodon-mode-hook-fun) (define-derived-mode mastodon-mode special-mode "Mastodon" "Major mode for fediverse services using the Mastodon API." (read-only-mode 1)) (provide 'mastodon) ;;; mastodon.el ends here mastodon.el/mastodon-index.org000066400000000000000000001224741501733112700167550ustar00rootroot00000000000000 * mastodon commands index #+BEGIN_SRC emacs-lisp :results table :colnames '("Binding" "Command" "Description") :exports results (let (rows) (mapatoms (lambda (symbol) (when (and (string-match "^mastodon" (symbol-name symbol)) (commandp symbol)) (let* ((doc (car (split-string (or (documentation symbol t) "") "\n"))) ;; add more keymaps here ;; some keys are in sub 'keymap keys inside a map (maps (list mastodon-mode-map mastodon-toot-mode-map mastodon-profile-mode-map mastodon-notifications--map mastodon-tl--shr-image-map-replacement mastodon-profile-update-mode-map mastodon-views-map mastodon-views--follow-suggestions-map mastodon-views--scheduled-map mastodon-views--view-lists-keymap mastodon-views--view-follow-requests-keymap mastodon-views--view-filters-keymap)) (binding-code (let ((keys (where-is-internal symbol maps nil nil (command-remapping symbol)))) ;; just take first 2 bindings: (if (> (length keys) 2) (list (car keys) (cadr keys)) keys))) ;; (or (car (rassoc symbol mastodon-mode-map)) ;; (car (rassoc symbol (cadr mastodon-toot-mode-map))) ;; (car (rassoc symbol (cadr mastodon-profile-mode-map))) ;; (car (rassoc symbol mastodon-notifications--map)))) (binding-str (if binding-code (mapconcat #'help--key-description-fontified binding-code ", ") ""))) (push `(,binding-str ,symbol ,doc) rows) rows)))) (sort rows (lambda (x y) (string-lessp (cadr x) (cadr y))))) #+END_SRC #+RESULTS: | Binding | Command | Description | |------------------+---------------------------------------------------+--------------------------------------------------------------------------------| | | mastodon | Connect client to `mastodon-instance-url' instance. | | | mastodon-async-mode | Async Mastodon. | | C-c C-p | mastodon-create-poll | A transient for creating a poll. | | | mastodon-create-poll-done | Update current user profile fields. | | C-M-q | mastodon-kill-all-buffers | Kill any and all open mastodon buffers, hopefully. | | Q | mastodon-kill-window | Quit window and delete helper. | | | mastodon-mode | Major mode for fediverse services using the Mastodon API. | | | mastodon-forget-all-logins | Delete `mastodon-client--token-file'. | | | mastodon-notifications-clear-all | Clear all notifications. | | C-k | mastodon-notifications-clear-current | Dismiss the notification at point. | | | mastodon-notifications-cycle-type | Cycle the current notifications view. | | | mastodon-notifications-follow-request-accept | Accept a follow request. | | j | mastodon-notifications-follow-request-reject | Reject a follow request. | | N | mastodon-notifications-get | Display NOTIFICATIONS in buffer. | | | mastodon-notifications-get-boosts | Display boost notifications in buffer. | | | mastodon-notifications-get-edits | Display edited post notifications in buffer. | | | mastodon-notifications-get-favourites | Display favourite notifications in buffer. | | | mastodon-notifications-get-follow-requests | Display follow request notifications in buffer. | | | mastodon-notifications-get-follows | Display follow notifications in buffer. | | @ | mastodon-notifications-get-mentions | Display mention notifications in buffer. | | | mastodon-notifications-get-polls | Display poll notifications in buffer. | | | mastodon-notifications-get-single-notif | Return a single notification JSON for v2 notifs. | | | mastodon-notifications-get-statuses | Display status notifications in buffer. | | | mastodon-notifications-get-type | Read a notification type and load its timeline. | | C-: | mastodon-notifications-policy | A transient to set notifications policy options. | | | mastodon-notifications-policy-update | Send updated notification policy settings. | | | mastodon-notifications-request-accept | Accept a notification request for a user. | | | mastodon-notifications-request-reject | Reject a notification request for a user. | | C-S-n | mastodon-notifications-requests | Open a new buffer displaying the user's notification requests. | | | mastodon-profile-account-bot-toggle | Toggle the bot status of your account. | | | mastodon-profile-account-discoverable-toggle | Toggle the discoverable status of your account. | | | mastodon-profile-account-locked-toggle | Toggle the locked status of your account. | | | mastodon-profile-account-search | Run a statuses search QUERY for the currently viewed account. | | | mastodon-profile-account-sensitive-toggle | Toggle the sensitive status of your account. | | | mastodon-profile-account-view-cycle | Cycle through profile view: toots, toot sans boosts, followers, and following. | | | mastodon-profile-add-account-to-list | Add account of current profile buffer to a list. | | | mastodon-profile-add-private-note-to-account | Add a private note to an account. | | | mastodon-profile-fields | A transient for setting profile fields. | | | mastodon-profile-fields-update | Update current user profile fields. | | A | mastodon-profile-get-toot-author | Open profile of author of toot under point. | | | mastodon-profile-mode | Toggle mastodon profile minor mode. | | O | mastodon-profile-my-profile | Show the profile of the currently signed in user. | | | mastodon-profile-open-followers | Open a profile buffer showing the accounts following the current profile. | | | mastodon-profile-open-following | Open a profile buffer showing the accounts that current profile follows. | | | mastodon-profile-open-statuses | Open a profile showing statuses. | | | mastodon-profile-open-statuses-no-reblogs | Open a profile buffer showing statuses without reblogs. | | | mastodon-profile-open-statuses-no-replies | Open a profile buffer showing statuses without replies. | | | mastodon-profile-open-statuses-only-media | Open a profile buffer showing only statuses with media. | | C-c # | mastodon-profile-open-statuses-tagged | Prompt for a hashtag and display a profile with only statuses containing it. | | | mastodon-profile-remove-from-followers-at-point | Prompt for a user in the item at point and remove from followers. | | | mastodon-profile-remove-from-followers-list | Select a user from your followers and remove from followers. | | | mastodon-profile-remove-user-from-followers | Remove a user from your followers. | | | mastodon-profile-show-familiar-followers | Show a list of familiar followers. | | P | mastodon-profile-show-user | Query for USER-HANDLE from current status and show that user's profile. | | | mastodon-profile-update-display-name | Update display name for your account. | | | mastodon-profile-update-meta-fields | Prompt for new metadata fields information and PATCH the server. | | | mastodon-profile-update-mode | Minor mode to update user profile. | | | mastodon-profile-update-profile-note-cancel | Cancel updating user profile and kill buffer and window. | | U | mastodon-profile-update-user-profile-note | Fetch user's profile note and display for editing. | | | mastodon-profile-user-profile-send-updated | Send PATCH request with the updated profile note. | | | mastodon-profile-view-account-private-note | Display the private note about a user. | | K | mastodon-profile-view-bookmarks | Open a new buffer displaying the user's bookmarks. | | V | mastodon-profile-view-favourites | Open a new buffer displaying the user's favourites. | | | mastodon-profile-view-preferences | View user preferences in another window. | | | mastodon-search-load-link-posts | Load timeline of posts containing link at point. | | | mastodon-search-mode | Toggle mastodon search minor mode. | | s | mastodon-search-query | Prompt for a search QUERY and return accounts, statuses, and hashtags. | | | mastodon-search-query-accounts-followed | Run an accounts search QUERY, limited to your followers. | | | mastodon-search-query-cycle | Cycle through search types: accounts, hashtags, and statuses. | | | mastodon-search-trending-links | Display a list of links trending on your instance. | | | mastodon-search-trending-statuses | Display a list of statuses trending on your instance. | | | mastodon-search-trending-tags | Display a list of tags trending on your instance. | | / | mastodon-switch-to-buffer | Switch to a live mastodon buffer. | | | mastodon-tl-announcements | Display announcements from your instance. | | | mastodon-tl-block-domain | Read a domain and block it. | | B | mastodon-tl-block-user | Query for USER-HANDLE from current status and block that user. | | | mastodon-tl-click-image-or-video | Click to play video with `mpv.el'. | | | mastodon-tl-copy-image-caption | Copy the caption of the image at point. | | | mastodon-tl-disable-notify-user-posts | Query for USER-HANDLE and disable notifications when they post. | | m | mastodon-tl-dm-user | Query for USER-HANDLE from current status and compose a message to that user. | | | mastodon-tl-do-link-action | Do the action of the link at point. | | | mastodon-tl-do-link-action-at-point | Do the action of the link at POS. | | | mastodon-tl-enable-notify-user-posts | Query for USER-HANDLE and enable notifications when they post. | | | mastodon-tl-filter-user-user-posts-by-language | Query for USER-HANDLE and filter display of their posts by language. | | | mastodon-tl-fold-post | Fold post at point, if it is too long. | | ! | mastodon-tl-fold-post-toggle | Toggle the folding status of the toot at point. | | | mastodon-tl-follow-tag | Prompt for a tag (from post at point) and follow it. | | W | mastodon-tl-follow-user | Query for USER-HANDLE from current status and follow that user. | | | mastodon-tl-follow-user-by-handle | Prompt for a USER-HANDLE and follow that user. | | | mastodon-tl-follow-user-disable-boosts | Prompt for a USER-HANDLE, and disable display of boosts in home timeline. | | | mastodon-tl-follow-user-enable-boosts | Prompt for a USER-HANDLE, and enable display of boosts in home timeline. | | ' | mastodon-tl-followed-tags-timeline | Open a timeline of multiple tags. | | F | mastodon-tl-get-federated-timeline | Open federated timeline. | | H | mastodon-tl-get-home-timeline | Open home timeline. | | L | mastodon-tl-get-local-timeline | Open local timeline. | | \ | mastodon-tl-get-remote-local-timeline | Prompt for an instance domain and try to display its local timeline. | | # | mastodon-tl-get-tag-timeline | Prompt for tag and opens its timeline. | | n | mastodon-tl-goto-next-item | Jump to next item. | | p | mastodon-tl-goto-prev-item | Jump to previous item. | | " | mastodon-tl-list-followed-tags | List followed tags. View timeline of tag user choses. | | C- | mastodon-tl-mpv-play-video-at-point | Play the video or gif at point with an mpv process. | | | mastodon-tl-mpv-play-video-from-byline | Run `mastodon-tl-mpv-play-video-at-point' on first moving image in post. | | | mastodon-tl-mute-thread | Mute the thread displayed in the current buffer. | | M | mastodon-tl-mute-user | Query for USER-HANDLE from current status and mute that user. | | | mastodon-tl-next-full-image | From full image view buffer, load the toot's next image. | | TAB, M-n | mastodon-tl-next-tab-item | Move to the next interesting item. | | v | mastodon-tl-poll-vote | If there is a poll at point, prompt user for OPTION to vote on it. | | | mastodon-tl-prev-full-image | From full image view buffer, load the toot's prev image. | | S-TAB, | mastodon-tl-previous-tab-item | Move to the previous interesting item. | | | mastodon-tl-remote-tag-timeline | Call `mastodon-tl-get-remote-local-timeline' but for a TAG timeline. | | Z | mastodon-tl-report-to-mods | Report the author of the toot at point to your instance moderators. | | SPC | mastodon-tl-scroll-up-command | Call `scroll-up-command', loading more toots if necessary. | | | mastodon-tl-shr-browse-image | Browse the image under point. | | | mastodon-tl-single-toot | View toot at point in separate buffer. | | | mastodon-tl-some-followed-tags-timeline | Prompt for some tags, and open a timeline for them. | | C-' | mastodon-tl-tag-group-timeline | Load a timeline of a tag group from `mastodon-tl--tags-groups'. | | RET, T | mastodon-tl-thread | Open thread buffer for toot at point. | | | mastodon-tl-toggle-sensitive-image | Toggle dislay of sensitive image at point. | | | mastodon-tl-toggle-spoiler-in-thread | Toggler content warning for all posts in current thread. | | c | mastodon-tl-toggle-spoiler-text-in-toot | Toggle the visibility of the spoiler text in the current toot. | | | mastodon-tl-unblock-domain | Read a blocked domain and unblock it. | | C-S-b | mastodon-tl-unblock-user | Query for USER-HANDLE from list of blocked users and unblock that user. | | | mastodon-tl-unfilter-user-languages | Remove any language filters for USER-HANDLE. | | | mastodon-tl-unfold-post | Unfold the toot at point if it is folded (read-more). | | | mastodon-tl-unfollow-tag | Prompt for a followed tag, and unfollow it. | | C-S-w | mastodon-tl-unfollow-user | Query for USER-HANDLE from current status and unfollow that user. | | | mastodon-tl-unmute-thread | Unmute the thread displayed in the current buffer. | | S-RET | mastodon-tl-unmute-user | Query for USER-HANDLE from list of muted users and unmute that user. | | u, g | mastodon-tl-update | Update timeline with new toots. | | = | mastodon-tl-view-first-full-image | From item byline, fetch load its first full image. | | | mastodon-tl-view-full-image-at-point | Browse full-sized version of image at point in a new window. | | | mastodon-tl-view-full-image-or-play-video | View full sized version of image at point, or try to play video. | | | mastodon-tl-view-item-on-own-instance | Load current toot on your own instance. | | | mastodon-tl-view-whole-thread | From a thread view, view entire thread. | | t | mastodon-toot | Update instance with new toot. Content is captured in a new buffer. | | C-c C-a | mastodon-toot-attach-media | Prompt for an attachment FILE with DESCRIPTION. | | o | mastodon-toot-browse-toot-url | Browse URL of toot at point. | | C-c C-k | mastodon-toot-cancel | Kill new-toot buffer/window. Does not POST content. | | C-c C-v | mastodon-toot-change-visibility | Change the current visibility to the next valid value. | | C-c ! | mastodon-toot-clear-all-attachments | Remove all attachments from a toot draft. | | C-c C-o | mastodon-toot-clear-poll | Remove poll from toot compose buffer. | | | mastodon-toot-copy-toot-text | Copy text of toot at point. | | C | mastodon-toot-copy-toot-url | Copy URL of toot at point. | | C-c C-p | mastodon-toot-create-poll | Prompt for new poll options and return as a list. | | | mastodon-toot-delete-all-drafts | Delete all drafts. | | D | mastodon-toot-delete-and-redraft-toot | Delete and redraft user's toot at point synchronously. | | | mastodon-toot-delete-draft-toot | Prompt for a draft toot and delete it. | | d | mastodon-toot-delete-toot | Delete user's toot at point synchronously. | | | mastodon-toot-download-custom-emoji | Download `mastodon-instance-url's custom emoji. | | | mastodon-toot-edit-media-description | Prompt for an attachment, and update its description. | | e | mastodon-toot-edit-toot-at-point | Edit the user's toot at point. | | | mastodon-toot-enable-custom-emoji | Add `mastodon-instance-url's custom emoji to `emojify'. | | C-c C-e | mastodon-toot-insert-emoji | Prompt to insert an emoji. | | . | mastodon-toot-list-boosters | List the boosters of toot at point. | | , | mastodon-toot-list-favouriters | List the favouriters of toot at point. | | | mastodon-toot-mode | Minor mode for composing toots. | | | mastodon-toot-open-draft-toot | Prompt for a draft and compose a toot with it. | | i | mastodon-toot-pin-toot-toggle | Pin or unpin user's toot at point. | | r | mastodon-toot-reply | Reply to toot at `point'. | | | mastodon-toot-save-draft | Save the current compose toot text as a draft. | | C-c C-s | mastodon-toot-schedule-toot | Read a date (+ time) in the minibuffer and schedule the current toot. | | C-c C-c | mastodon-toot-send | POST contents of new-toot buffer to fediverse instance and kill buffer. | | C-c C-w | mastodon-toot-set-content-warning | Set a content warning for the current toot. | | | mastodon-toot-set-default-visibility | Set the default visibility for toots on the server. | | C-c C-l | mastodon-toot-set-toot-language | Prompt for a language and set `mastodon-toot--language'. | | k | mastodon-toot-toggle-bookmark | Bookmark or unbookmark toot at point. | | b | mastodon-toot-toggle-boost | Boost/unboost toot at `point'. | | f | mastodon-toot-toggle-favourite | Favourite/unfavourite toot at `point'. | | C-c C-n | mastodon-toot-toggle-nsfw | Toggle `mastodon-toot--content-nsfw'. | | a | mastodon-toot-translate-toot-text | Translate text of toot at point. | | E | mastodon-toot-view-toot-edits | View editing history of the toot at point in a popup buffer. | | | mastodon-transient--prefix-inspect | Inspect a transient prefix's arguments and scope. | | | mastodon-transient-choice-add | Add another poll choice if possible. | | | mastodon-update-profile-note | Update current user profile note. | | | mastodon-url-lookup | If a URL resembles a fediverse link, try to load in `mastodon.el'. | | | mastodon-url-lookup-force | Call `mastodon-url-lookup' without checking if URL is fedi-like. | | : | mastodon-user-settings | A transient for setting current user settings. | | | mastodon-user-settings-update | Update current user settings on the server. | | | mastodon-views-add-account-to-list | Prompt for a list and for an account, add account to list. | | | mastodon-views-add-account-to-list-at-point | Prompt for account and add to list at point. | | | mastodon-views-add-filter-kw | Add a keyword to filter at point. | | | mastodon-views-add-toot-account-at-point-to-list | Prompt for a list, and add the account of the toot at point to it. | | | mastodon-views-cancel-scheduled-toot | Cancel the scheduled toot at point. | | | mastodon-views-copy-scheduled-toot-text | Copy the text of the scheduled toot at point. | | | mastodon-views-create-filter | Create a filter for a word. | | | mastodon-views-create-list | Create a new list. | | | mastodon-views-delete-filter | Delete filter at point. | | | mastodon-views-delete-list | Prompt for a list and delete it. | | | mastodon-views-delete-list-at-point | Delete list at point. | | | mastodon-views-edit-list | Prompt for a list and edit the name and replies policy. | | | mastodon-views-edit-list-at-point | Edit list at point. | | | mastodon-views-edit-scheduled-as-new | Edit scheduled status as new toot. | | | mastodon-views-instance-desc-misskey | Show instance description for a misskey/firefish server. | | | mastodon-views-remove-account-from-list | Prompt for a list, select an account and remove from list. | | | mastodon-views-remove-account-from-list-at-point | Prompt for account and remove from list at point. | | | mastodon-views-remove-filter-kw | Remove keyword from filter at point. | | | mastodon-views-reschedule-toot | Reschedule the scheduled toot at point. | | | mastodon-views-update-filter | Update filter at point. | | | mastodon-views-update-filter-kw | Update filter keyword. | | I | mastodon-views-view-filters | View the user's filters in a new buffer. | | R | mastodon-views-view-follow-requests | Open a new buffer displaying the user's follow requests. | | G | mastodon-views-view-follow-suggestions | Display a buffer of suggested accounts to follow. | | ; | mastodon-views-view-instance-description | View the details of the instance the current post's author is on. | | | mastodon-views-view-instance-description-brief | View brief details of the instance the current post's author is on. | | | mastodon-views-view-list-timeline | Prompt for a list and view its timeline. | | X | mastodon-views-view-lists | Show the user's lists in a new buffer. | | | mastodon-views-view-own-instance | View details of your own instance. | | | mastodon-views-view-own-instance-brief | View brief details of your own instance. | | S | mastodon-views-view-scheduled-toots | Show the user's scheduled toots in a new buffer. | | | mastodon-views-view-timeline-list-at-point | View timeline of list at point. | * mastodon custom variables index #+BEGIN_SRC emacs-lisp :results table :colnames '("Custom variable" "Description") :exports results (let (rows) (mapatoms (lambda (symbol) (when (and (string-match "^mastodon" (symbol-name symbol)) (custom-variable-p symbol)) (let* ((doc (car (split-string (or (get (indirect-variable symbol) 'variable-documentation) (get symbol 'variable-documentation) "") "\n")))) (push `(,symbol ,doc) rows) rows)))) (sort rows (lambda (x y) (string-lessp (car x) (car y))))) #+end_src #+RESULTS: | Custom variable | Description | |----------------------------------------------------+------------------------------------------------------------------------------| | mastodon-active-user | Username of the active user. | | mastodon-auth-use-auth-source | Whether to use auth sources for user credentials. | | mastodon-client--token-file | File path where Mastodon access tokens are stored. | | mastodon-group-notifications | Whether to use grouped notifications. | | mastodon-images-in-notifs | Whether to display attached images in notifications. | | mastodon-instance-url | Base URL for the fediverse instance you want to be active. | | mastodon-media--avatar-height | Height of the user avatar images (if shown). | | mastodon-media--enable-image-caching | Whether images should be cached. | | mastodon-media--hide-sensitive-media | Whether media marked as sensitive should be hidden. | | mastodon-media--preview-max-height | Max height of any media attachment preview to be shown in timelines. | | mastodon-mode-hook | Hook run when entering Mastodon mode. | | mastodon-notifications-grouped-names-count | The number of notification authors to display. | | mastodon-profile-mode-hook | Hook run after entering or leaving `mastodon-profile-mode'. | | mastodon-profile-note-in-foll-reqs | If non-nil, show a user's profile note in follow request notifications. | | mastodon-profile-note-in-foll-reqs-max-length | The max character length for user profile note in follow requests. | | mastodon-profile-update-mode-hook | Hook run after entering or leaving `mastodon-profile-update-mode'. | | mastodon-search-mode-hook | Hook run after entering or leaving `mastodon-search-mode'. | | mastodon-tl--display-caption-not-url-when-no-media | Display an image's caption rather than URL. | | mastodon-tl--display-media-p | A boolean value stating whether to show media in timelines. | | mastodon-tl--enable-proportional-fonts | Nonnil to enable using proportional fonts when rendering HTML. | | mastodon-tl--enable-relative-timestamps | Whether to show relative (to the current time) timestamps. | | mastodon-tl--expand-content-warnings | Whether to expand content warnings by default. | | mastodon-tl--fold-toots-at-length | Length, in characters, to fold a toot at. | | mastodon-tl--hide-replies | Whether to hide replies from the timelines. | | mastodon-tl--highlight-current-toot | Whether to highlight the toot at point. Uses `cursor-face' special property. | | mastodon-tl--load-full-sized-images-in-emacs | Whether to load full-sized images inside Emacs. | | mastodon-tl--no-fill-on-render | Non-nil to disable filling by shr.el while rendering toot body. | | mastodon-tl--remote-local-domains | A list of domains to view the local timelines of. | | mastodon-tl--show-avatars | Whether to enable display of user avatars in timelines. | | mastodon-tl--show-stats | Whether to show toot stats (faves, boosts, replies counts). | | mastodon-tl--symbols | A set of symbols (and fallback strings) to be used in timeline. | | mastodon-tl--tag-timeline-tags | A list of up to four tags for use with `mastodon-tl-followed-tags-timeline'. | | mastodon-tl--tags-groups | A list containing lists of up to four tags each. | | mastodon-tl--timeline-posts-count | Number of posts to display when loading a timeline. | | mastodon-tl-position-after-update | Defines where `point' should be located after a timeline update. | | mastodon-toot--attachment-height | Height of the attached images preview in the toot draft buffer. | | mastodon-toot--completion-style-for-mentions | The company completion style to use for mentions. | | mastodon-toot--default-media-directory | The default directory when prompting for a media file to upload. | | mastodon-toot--default-reply-visibility | Default visibility settings when replying. | | mastodon-toot--enable-completion | Whether to enable completion of mentions and hashtags. | | mastodon-toot--enable-custom-instance-emoji | Whether to enable your instance's custom emoji by default. | | mastodon-toot--proportional-fonts-compose | Nonnil to enable using proportional fonts in the compose buffer. | | mastodon-toot--use-company-for-completion | Whether to enable company for completion. | | mastodon-toot-display-orig-in-reply-buffer | Display a copy of the toot replied to in the compose buffer. | | mastodon-toot-mode-hook | Hook run after entering or leaving `mastodon-toot-mode'. | | mastodon-toot-orig-in-reply-length | Length to crop toot replied to in the compose buffer to. | | mastodon-toot-poll-use-transient | Whether to use the transient menu to create a poll. | | mastodon-toot-timestamp-format | Format to use for timestamps. | | mastodon-use-emojify | Whether to use emojify.el to display emojis. | mastodon.el/mastodon.info000066400000000000000000000764321501733112700160160ustar00rootroot00000000000000This is mastodon.info, produced by makeinfo version 6.8 from mastodon.texi. INFO-DIR-SECTION Emacs START-INFO-DIR-ENTRY * Mastodon: (mastodon). Client for fediverse services using the Mastodon API. END-INFO-DIR-ENTRY  File: mastodon.info, Node: Top, Next: README, Up: (dir) A Mastodon client ***************** * Menu: * README:: — The Detailed Node Listing — README * Installation:: * Usage:: * Dependencies:: * Network compatibility:: * Contributing:: * Supporting ‘mastodon.el’: Supporting mastodonel. * Contributors:: * Screenshots:: Installation * ELPA:: * MELPA:: * Repo:: * Emoji:: * Discover:: Usage * Logging in to your instance:: * Timelines:: * Composing toots:: * Other commands and account settings:: * Notifications:: * Customization:: * Commands and variables index:: * Packages related to ‘mastodon.el’: Packages related to mastodonel. * Live-updating timelines mastodon-async-mode:: * Translating toots:: * Bookmarks and ‘mastodon.el’: Bookmarks and mastodonel. Contributing * Bug reports:: * Fixes and features:: * Coding style::  File: mastodon.info, Node: README, Prev: Top, Up: Top 1 README ******** ‘mastodon.el’ is an Emacs client for the ActivityPub social networks that implement the Mastodon API. For info see joinmastodon.org (https://joinmastodon.org/). NB: ‘mastodon.el’ now ships this readme as an .info file, so if you have it installed you should be able to browse this readme inside emacs. ‘C-h i’ for info, then ‘m masto RET’ should load it for you. * Menu: * Installation:: * Usage:: * Dependencies:: * Network compatibility:: * Contributing:: * Supporting ‘mastodon.el’: Supporting mastodonel. * Contributors:: * Screenshots::  File: mastodon.info, Node: Installation, Next: Usage, Up: README 1.1 Installation ================ You can install ‘mastodon.el’ from ELPA, MELPA, or directly from this repo. It is also available as a GUIX package. * Menu: * ELPA:: * MELPA:: * Repo:: * Emoji:: * Discover::  File: mastodon.info, Node: ELPA, Next: MELPA, Up: Installation 1.1.1 ELPA ---------- You should be able to directly install with: ‘M-x package-refresh-contents RET’ ‘M-x package-install RET mastodon RET’  File: mastodon.info, Node: MELPA, Next: Repo, Prev: ELPA, Up: Installation 1.1.2 MELPA ----------- Add ‘MELPA’ to your archives: (require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t) Update and install: ‘M-x package-refresh-contents RET’ ‘M-x package-install RET mastodon RET’  File: mastodon.info, Node: Repo, Next: Emoji, Prev: MELPA, Up: Installation 1.1.3 Repo ---------- Clone this repository and add the lisp directory to your load path. Then, require it and go. (add-to-list 'load-path "/path/to/mastodon.el/lisp") (require 'mastodon) Or, with ‘use-package’: (use-package mastodon :ensure t) The minimum Emacs version is now 28.1. But if you are running an older version it shouldn’t be very hard to get it working.  File: mastodon.info, Node: Emoji, Next: Discover, Prev: Repo, Up: Installation 1.1.4 Emoji ----------- Since Emacs 28, it has builtin emoji support with ‘emoji.el’. If you prefer to use Emojify (https://github.com/iqbalansari/emacs-emojify), ‘require’ it and set ‘mastodon-use-emojify’ to non-nil to display emoji in timelines and to use it when composing toots. ‘Emoji.el’ is the better option, but for now only ‘emojify’ supports downloading and using custom emoji from your instance. From personal experience, ‘emojify’ also tends to result in less TOFU.  File: mastodon.info, Node: Discover, Prev: Emoji, Up: Installation 1.1.5 Discover -------------- ‘mastodon-mode’ can provide a context menu for its keybindings if Discover (https://github.com/mickeynp/discover.el) is installed. It is not required. if you have Discover, add the following to your Emacs init configuration: (require 'mastodon-discover) (with-eval-after-load 'mastodon (mastodon-discover)) Or, with ‘use-package’: (use-package mastodon :ensure t :config (mastodon-discover))  File: mastodon.info, Node: Usage, Next: Dependencies, Prev: Installation, Up: README 1.2 Usage ========= * Menu: * Logging in to your instance:: * Timelines:: * Composing toots:: * Other commands and account settings:: * Notifications:: * Customization:: * Commands and variables index:: * Packages related to ‘mastodon.el’: Packages related to mastodonel. * Live-updating timelines mastodon-async-mode:: * Translating toots:: * Bookmarks and ‘mastodon.el’: Bookmarks and mastodonel.  File: mastodon.info, Node: Logging in to your instance, Next: Timelines, Up: Usage 1.2.1 Logging in to your instance --------------------------------- You need to set 2 variables in your init file to get started: 1. ‘mastodon-instance-url’ 2. ‘mastodon-active-user’ (see their doc strings for details). For example If you want to post toots as "example_user@social.instance.org", then put this in your init file: (setq mastodon-instance-url "https://social.instance.org" mastodon-active-user "example_user") Then *restart* Emacs and run ‘M-x mastodon’. Make sure you are connected to internet before you do this. If you have multiple mastodon accounts you can activate one at a time by changing those two variables and restarting Emacs. If you were using mastodon.el before 2FA was implemented and the above steps do not work, call ‘(mastodon-forget-all-logins)’, restart Emacs and follow the steps again. 1. encrypted access tokens (from 2.0.0) By default, user access tokens are now stored in the user’s auth source file (typically ‘~/.authinfo.gpg’, check the value of ‘auth-sources’). When you first update to 2.0.0, or if you encounter issues due to old credentials, call ‘(mastodon-forget-all-logins)’ to remove the old mastodon.el plstore, and then authenticate again. If you don’t want to use the auth source file, set ‘mastodon-auth-use-auth-source’ to nil. Entries will instead be stored encrypted in ‘mastodon-client--token-file’, a plstore. If for some reason you reauthenticate, you’ll need to either remove the entry in your auth sources file, or manually update the token in it after doing so, as mastodon.el is unable to reliably update (or even remove) entires. The format for a mastodon.el auth source entry is as follows: ‘machine INSTANCE login USERNAME password AUTHTOKEN’ with the token being what you copy from the browser when authenticating. If you have ‘auth-source-save-behavior’ set to nil, you’ll also need to add such an entry manually. Finally, if you find you’re asked for your key passphrase too often while authenticating, consider setting ‘epa-file-encrypt-to’ (for auth-source encryption) and ‘plstore-encrypt-to’ (for plstore encryption) to your preferred key ID.  File: mastodon.info, Node: Timelines, Next: Composing toots, Prev: Logging in to your instance, Up: Usage 1.2.2 Timelines --------------- ‘M-x mastodon’ Opens a ‘*mastodon-home*’ buffer in the major mode and displays toots. If your credentials are not yet saved, you will be prompted for email and password. The app registration process will take place if your ‘mastodon-token-file’ does not contain ‘:client_id’ and ‘:client_secret’. 1. Keybindings For a full list of commands and variables, see mastodon-index.org (mastodon-index.org). Key Action ----------------------------------------------------------------------------------------------------------- *Help* ‘?’ Show discover menu of all bindings, if ‘discover’ is available *Timeline actions* ‘n’ Go to next item (toot, notification, user) ‘p’ Go to previous item (toot, notification, user) ‘M-n/’ Go to the next interesting thing that has an action ‘M-p/’ Go to the previous interesting thing that has an action ‘F’ Open federated timeline (1 prefix arg: hide-replies, 2 prefix args: media only) ‘H’ Open home timeline (1 prefix arg: hide-replies) ‘L’ Open local timeline (1 prefix arg: hide-replies, 2 prefix args: media only) ‘N’ Open notifications timeline ‘@’ Open mentions-only notifications timeline ‘u’ Update current timeline ‘T’ Open thread for toot at point ‘#’ Prompt for tag and open its timeline ‘A’ Open author profile of toot at point ‘P’ Open profile of user attached to toot at point ‘O’ View own profile ‘U’ update your profile bio note ‘;’ view instance description for toot at point ‘:’ view followed tags and load a tag timeline ‘C-:’ view timeline of all followed tags ‘,’ view favouriters of toot at point ‘.’ view boosters of toot at point ‘/’ switch between mastodon buffers ‘\’ prompt for an instance domain and view its local timeline (if poss) ‘Z’ report user/toot at point to instances moderators *Other views* ‘s’ search (posts, users, tags) (NB: only posts you have interacted with) ‘I’, ‘c’, ‘d’ view, create, and delete filters ‘R’, ‘a’, ‘j’ view/accept/reject follow requests ‘G’ view follow suggestions ‘V’ view your favourited toots ‘K’ view bookmarked toots ‘X’ view/edit/create/delete lists ‘S’ view your scheduled toots ‘S-:’ view profile/account settings transient menu *Toot actions* ‘t’ Compose a new toot ‘c’ Toggle content warning content ‘b’ Boost toot under ‘point’ ‘f’ Favourite toot under ‘point’ ‘k’ toggle bookmark of toot at point ‘r’ Reply to toot under ‘point’ ‘v’ Vote on poll at point ‘C’ copy url of toot at point ‘C-RET’ play video/gif at point (requires ‘mpv’) ‘e’ edit your toot at point ‘E’ view edits of toot at point ‘i’ (un)pin your toot at point ‘d’ delete your toot at point, and reload current timeline ‘D’ delete and redraft toot at point, preserving reply/CW/visibility ‘!’ toggle folding of toot at point (‘S-C-’) ‘W’, ‘M’, ‘B’ (un)follow, (un)mute, (un)block author of toot at point *Profile view* ‘C-c C-c’ cycle between statuses, statuses without boosts, followers, and following ‘mastodon-profile--add-account-to-list’ (see lists view) *Notifications view* ‘a’, ‘j’ accept/reject follow request ‘C-k’ clear notification at point ‘C-c C-c’ cycle between notification types see ‘mastodon-notifications--get-*’ functions for filtered views *Quitting* ‘q’ Quit mastodon buffer, leave window open ‘Q’ Quit mastodon buffer and kill window ‘C-M-q’ Quit and kill all mastodon buffers 2. Toot byline legend Marker Meaning -------------------------------------------- ‘(🔁)’ (or I boosted this toot ‘(B)’) ‘(⭐)’ (or I favourited this toot ‘(F)’) ‘(🔖)’ (or I bookmarked this toot ‘(K)’)  File: mastodon.info, Node: Composing toots, Next: Other commands and account settings, Prev: Timelines, Up: Usage 1.2.3 Composing toots --------------------- ‘M-x mastodon-toot’ (or ‘t’ from a mastodon.el buffer) opens a new buffer/window in ‘text-mode’ and ‘mastodon-toot’ minor mode. Enter the contents of your toot here. ‘C-c C-c’ sends the toot. ‘C-c C-k’ cancels. Both actions kill the buffer and window. Further keybindings are displayed in the buffer, and in the following subsection. Replies preserve visibility status/content warnings, and include boosters by default. If the region is active when you start a reply, it will be yanked into the compose buffer prefixed with ‘>’ to form a rough reply quote. Server’s max toot length, with running char count, and attachment previews, are shown. You can download and use your instance’s custom emoji (‘mastodon-toot--download-custom-emoji’, ‘mastodon-toot--enable-custom-emoji’). If you want to view some of the toot being replied to in the compose buffer, set ‘mastodon-toot-display-orig-in-reply-buffer’ to non-nil. The compose buffer uses ‘text-mode’ so any configuration you have for that mode will be enabled. If any of your existing config conflicts with ‘mastodon-toot’, you can disable it in the ‘mastodon-toot-mode-hook’. For example, the default value of that hook is as follows: (add-hook 'mastodon-toot-mode-hook (lambda () (auto-fill-mode -1))) 1. Keybindings Key Action -------------------------------------------- ‘C-c C-c’ Send toot ‘C-c C-k’ Cancel toot ‘C-c C-w’ Add content warning ‘C-c C-v’ Change toot visibility ‘C-c C-n’ Add sensitive media/nsfw flag ‘C-c C-a’ Upload attachment(s) ‘C-c !’ Remove all attachments ‘C-c C-e’ Insert emoji ‘C-c C-p’ Create a poll ‘C-c C-o’ Cancel poll ‘C-c C-l’ Set toot language ‘C-c C-s’ Schedule toot 2. Autocompletion of mentions, tags and emoji Autocompletion of mentions, tags, and emojis is provided by ‘completion-at-point-functions’ (capf) backends. ‘mastodon-toot--enable-completion’ is enabled by default. To trigger completion, type a prefix followed by a few letters, ‘@’ for mentions, ‘#’ for tags, and ‘:’ for emoji (for now this only works when using ‘emojify.el’). If you want to enable ‘company-mode’ in the toot compose buffer, set ‘mastodon-toot--use-company-for-completion’ to ‘t’. (‘mastodon.el’ used to run its own native company backends, but these have been removed in favour of capfs.) If you don’t run ‘company’ and want immediate, keyless completion, you’ll need to have another completion engine running that handles capfs. A common combination is ‘consult’ and ‘corfu’. 3. Draft toots • Compose buffer text is saved as you type, kept in ‘mastodon-toot-current-toot-text’. • ‘mastodon-toot--save-draft’: save the current toot as a draft. • ‘mastodon-toot--open-draft-toot’: Open a compose buffer and insert one of your draft toots. • ‘mastodon-toot--delete-draft-toot’: Delete a draft toot. • ‘mastodon-toot--delete-all-drafts’: Delete all your drafts.  File: mastodon.info, Node: Other commands and account settings, Next: Notifications, Prev: Composing toots, Up: Usage 1.2.4 Other commands and account settings: ------------------------------------------ In addition to ‘mastodon’, the following three functions are autoloaded and should work without first loading a ‘mastodon.el’ buffer: • ‘mastodon-toot’: Compose new toot • ‘mastodon-notifications-get’: View all notifications • ‘mastodon-url-lookup’: Attempt to load a URL in ‘mastodon.el’. URL may be at point or provided in the minibuffer. • ‘mastodon-tl--view-instance-description’: View information about the instance that the author of the toot at point is on. • ‘mastodon-tl--view-own-instance’: View information about your own instance. • ‘mastodon-search--trending-tags’: View a list of trending hashtags on your instance. • ‘mastodon-search--trending-statuses’: View a list of trending statuses on your instance. • ‘mastodon-search--trending-links’: View a list of trending links on your instance (+ click through to a timeline of posts featuring a given link) • ‘mastodon-tl--add-toot-account-at-point-to-list’: Add the account of the toot at point to a list. • ‘mastodon-tl--dm-user’: Send a direct message to one of the users at point. • ‘mastodon-profile--add-private-note-to-account’: Add a private note to another user’s account. • ‘mastodon-profile--view-account-private-note’: View a private note on a user’s account. • ‘mastodon-profile--show-familiar-followers’: Show a list of “familiar followers” for a given account. Familiar followers are accounts that you follow, and that follow the account. • ‘mastodon-tl--follow-tag’: Follow a tag (works like following a user) • ‘mastodon-tl--unfollow-tag’: Unfollow a tag • ‘mastodon-tl--list-followed-tags’: View a list of tags you’re following. • ‘mastodon-tl--followed-tags-timeline’: View a timeline of all your followed tags. • ‘mastodon-tl--some-followed-tags-timleine’: View a timeline of multiple tags, from your followed tags or any other. • ‘mastodon-switch-to-buffer’: switch between mastodon buffers. • ‘mastodon-tl--get-remote-local-timeline’: View a local timeline of a remote instance. • ‘mastodon-tl--remote-tag-timeline’: View a tag timeline on a remote instance. • ‘mastodon-user-settings’: Launch a transient menu to update various account settings.  File: mastodon.info, Node: Notifications, Next: Customization, Prev: Other commands and account settings, Up: Usage 1.2.5 Notifications ------------------- Mastodon from 4.3 supports grouped notifications. These are implemented by ‘mastodon.el’ but disabled by default out of consideration to users on instances that don’t support them. If you are on an instance that implements grouped notifications, set ‘mastodon-group-notifications’ to ‘t’ to enable them.  File: mastodon.info, Node: Customization, Next: Commands and variables index, Prev: Notifications, Up: Usage 1.2.6 Customization ------------------- See ‘M-x customize-group RET mastodon’ to view all customize options. • Timeline options: • Use proportional fonts • Default number of posts displayed • Timestamp format • Relative timestamps • Display user avatars • Avatar image height • Enable image caching • Hide replies in timelines • Show toot stats in byline • Compose options: • Completion style for mentions and tags • Enable custom emoji • Display toot being replied to • Set default reply visibility • Nofitication options: • Display user’s profile note in follow requests • Group notifications  File: mastodon.info, Node: Commands and variables index, Next: Packages related to mastodonel, Prev: Customization, Up: Usage 1.2.7 Commands and variables index ---------------------------------- An index of all user-facing commands and custom variables is available here: mastodon-index.org (mastodon-index.org). You can also hit ‘?’ in any ‘mastodon.el’ buffer to see the available bindings, or run ‘M-X’ (upper-case ‘X’) to view all commands in the buffer with completion, and call one.  File: mastodon.info, Node: Packages related to mastodonel, Next: Live-updating timelines mastodon-async-mode, Prev: Commands and variables index, Up: Usage 1.2.8 Packages related to ‘mastodon.el’ --------------------------------------- 1. Alternative timeline layout The incomparable Nicholas Rougier has written an alternative timeline layout for ‘mastodon.el’. The repo is at mastodon-alt (https://github.com/rougier/mastodon-alt). 2. Org links, archive search toot-suite (https://codeberg.org/chrmoe/toot-suite) implements an org link type for fediverse posts, and also provides a way to browse an offline archive of your account. 3. Mastodon hydra A user made a hydra for handling basic ‘mastodon.el’ commands. It’s available at . 4. Narrow to timeline item A simple code snippet to enable narrowing to current item in timelines: 5. Sachac’s config goodies The incomparable sachac has a bunch of ‘mastodon.el’ extensions and goodies in their literate config, available here: .  File: mastodon.info, Node: Live-updating timelines mastodon-async-mode, Next: Translating toots, Prev: Packages related to mastodonel, Up: Usage 1.2.9 Live-updating timelines: ‘mastodon-async-mode’ ---------------------------------------------------- (code taken from mastodon-future (https://github.com/alexjgriffith/mastodon-future.el).) Works for federated, local, and home timelines and for notifications. It’s a little touchy, one thing to avoid is trying to load a timeline more than once at a time. It can go off the rails a bit, but it’s still pretty cool. The current maintainer of ‘mastodon.el’ is unable to debug or improve this feature. To enable, it, add ‘(require 'mastodon-async)’ to your ‘init.el’. Then you can view a timeline with one of the commands that begin with ‘mastodon-async--stream-’.  File: mastodon.info, Node: Translating toots, Next: Bookmarks and mastodonel, Prev: Live-updating timelines mastodon-async-mode, Up: Usage 1.2.10 Translating toots ------------------------ You can translate toots with ‘mastodon-toot--translate-toot-text’ (‘a’ in a timeline). At the moment this requires lingva.el (https://codeberg.org/martianh/lingva.el), a little interface I wrote to lingva.ml (https://lingva.ml), to be installed to work. You could easily modify the simple function to use your Emacs translator of choice (‘libretrans.el’ , ‘google-translate’, ‘babel’, ‘go-translate’, etc.), you just need to fetch the toot’s content with ‘(mastodon-tl--content toot)’ and pass it to your translator function as its text argument. Here’s what ‘mastodon-toot--translate-toot-text’ looks like: (defun mastodon-toot-translate-toot-text () "Translate text of toot at point. Uses `lingva.el'." (interactive) (let* ((toot (mastodon-tl--property 'item-json))) (if toot (lingva-translate nil (mastodon-tl--content toot)) (message "No toot to translate?"))))  File: mastodon.info, Node: Bookmarks and mastodonel, Prev: Translating toots, Up: Usage 1.2.11 Bookmarks and ‘mastodon.el’ ---------------------------------- ‘mastodon.el’ implements a basic bookmark record and handler. Currently, this means that you can bookmark a post item and later load it in thread view. This could be expanded to any item with an id, but probably not to things like timeline views. If you want to be able to bookmark something, open an issue and ask, as it’s trivial to expand the bookmarking code.  File: mastodon.info, Node: Dependencies, Next: Network compatibility, Prev: Usage, Up: README 1.3 Dependencies ================ Hard dependencies (should all install with ‘mastodon.el’): • ‘request’ (for uploading attachments, emacs-request (https://github.com/tkf/emacs-request)) • ‘persist’ (for storing some settings across sessions, persist (https://elpa.gnu.org/packages/persist.html)) • ‘tp.el’ (for transient menus, tp.el (https://codeberg.org/martianh/tp.el)) Optional dependencies (install yourself, ‘mastodon.el’ can use them): • ‘emojify’ to use custom emoji (else we use builtin ‘emoji.el’) • ‘mpv’ and ‘mpv.el’ for viewing videos and gifs • ‘lingva.el’ for translating toots  File: mastodon.info, Node: Network compatibility, Next: Contributing, Prev: Dependencies, Up: README 1.4 Network compatibility ========================= ‘mastodon.el’ should work with ActivityPub servers that implement the Mastodon API. Apart from Mastodon itself, it is currently known to work with: • Pleroma (pleroma.social (https://pleroma.social/)) • Akkoma (akkoma.social (https://akkoma.social/)) • Gotosocial (gotosocial.org (https://gotosocial.org/)) • Sharkey (joinsharkey.org (https://joinsharkey.org)) It does not support the non-Mastodon API servers Misskey (misskey.io (https://misskey.io/)), Firefish (joinfirefish.org (https://joinfirefish.org/), formerly Calkey) and Friendica, but it should fully support displaying and interacting with posts and users on those platforms. If you attempt to use ‘mastodon.el’ with a server and run into problems, feel free to open an issue.  File: mastodon.info, Node: Contributing, Next: Supporting mastodonel, Prev: Network compatibility, Up: README 1.5 Contributing ================ PRs, issues, feature requests, and general feedback are very welcome! If you prefer emailing patches to the process described below, feel free to send them on. Ideally they’d be patches that can be applied with ‘git am’, if you want to actually contribute a commit. * Menu: * Bug reports:: * Fixes and features:: * Coding style::  File: mastodon.info, Node: Bug reports, Next: Fixes and features, Up: Contributing 1.5.1 Bug reports ----------------- 1. ‘mastodon.el’ has bugs, as well as lots of room for improvement. 2. I receive very little feedback, so if I don’t run into the bug it often doesn’t get fixed. 3. If you run into something that seems broken, first try running ‘mastodon.el’ in emacs with no init file (i.e. ‘emacs -q’ (instructions and code for doing this are here (https://codeberg.org/martianh/mastodon.el/issues/300)) to see if it also happens independently of your own config (it probably does). 4. Else enable debug on error (‘toggle-debug-on-error’), make the bug happen again, and copy the backtrace that appears. 5. Open an issue here and explain what is going on. Provide your emacs version and what kind of server your account is on.  File: mastodon.info, Node: Fixes and features, Next: Coding style, Prev: Bug reports, Up: Contributing 1.5.2 Fixes and features ------------------------ 1. Create an issue (https://codeberg.org/martianh/mastodon.el/issues) detailing what you’d like to do. 2. Fork the repository and create a branch off of ‘develop’. 3. Run the tests and ensure that your code doesn’t break any of them. 4. Create a pull request (to develop) referencing the issue created in step 1.  File: mastodon.info, Node: Coding style, Prev: Fixes and features, Up: Contributing 1.5.3 Coding style ------------------ • This library uses an unconvential double dash (‘--’) between file namespaces and function names, which contradicts normal Elisp style. This needs to be respected until the whole library is changed. • Use ‘aggressive-indent-mode’ or similar to keep your code indented. • Single spaces end sentences in docstrings. • There’s no need for a blank line after the first docstring line (one is added automatically when documentation is displayed).  File: mastodon.info, Node: Supporting mastodonel, Next: Contributors, Prev: Contributing, Up: README 1.6 Supporting ‘mastodon.el’ ============================ If you’d like to support continued development of ‘mastodon.el’, I accept donations via paypal: paypal.me/martianh (https://paypal.me/martianh). If you would prefer a different payment method, please write to me at and I can provide IBAN or other bank account details. I don’t have a tech worker’s income, so even a small tip would help out.  File: mastodon.info, Node: Contributors, Next: Screenshots, Prev: Supporting mastodonel, Up: README 1.7 Contributors ================ ‘mastodon.el’ is the work of a number of people. Some significant contributors are: • [original author] • • • •  File: mastodon.info, Node: Screenshots, Prev: Contributors, Up: README 1.8 Screenshots =============== Here’s a (federated) timeline: [image src="screenshot-tl.png"] Here’s a notifcations view plus a compose buffer: [image src="screenshot-notifs+compose.png"] Here’s a user settings transient (active values green, current server values commented and, if a boolean, underlined): [image src="screenshot-transient-1.jpg"] Here’s a user profile fields transient (changed fields green, current server values commented): [image src="screenshot-transient-2.jpg"]  Tag Table: Node: Top219 Node: README1083 Node: Installation1732 Node: ELPA2021 Node: MELPA2249 Node: Repo2629 Node: Emoji3122 Node: Discover3716 Node: Usage4268 Node: Logging in to your instance4770 Ref: encrypted access tokens (from 200)5742 Node: Timelines7200 Ref: Keybindings7675 Ref: Toot byline legend12657 Node: Composing toots12966 Ref: Keybindings (1)14518 Ref: Autocompletion of mentions tags and emoji15073 Ref: Draft toots15998 Node: Other commands and account settings16469 Node: Notifications19144 Node: Customization19629 Node: Commands and variables index20517 Node: Packages related to mastodonel21036 Ref: Alternative timeline layout21289 Ref: Org links archive search21516 Ref: Mastodon hydra21735 Ref: Narrow to timeline item21919 Ref: Sachac's config goodies22126 Node: Live-updating timelines mastodon-async-mode22345 Node: Translating toots23200 Node: Bookmarks and mastodonel24383 Node: Dependencies24925 Node: Network compatibility25711 Node: Contributing26652 Node: Bug reports27148 Node: Fixes and features28059 Node: Coding style28560 Node: Supporting mastodonel29184 Node: Contributors29741 Node: Screenshots30176  End Tag Table  Local Variables: coding: utf-8 End: mastodon.el/mastodon.texi000066400000000000000000000666451501733112700160410ustar00rootroot00000000000000\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename mastodon.info @settitle A Mastodon client @documentencoding UTF-8 @documentlanguage en @c %**end of header @dircategory Emacs @direntry * Mastodon: (mastodon). Client for fediverse services using the Mastodon API. @end direntry @finalout @titlepage @title A Mastodon client @end titlepage @contents @ifnottex @node Top @top A Mastodon client @end ifnottex @menu * README:: @detailmenu --- The Detailed Node Listing --- README * Installation:: * Usage:: * Dependencies:: * Network compatibility:: * Contributing:: * Supporting @samp{mastodon.el}: Supporting @samp{mastodonel}. * Contributors:: * Screenshots:: Installation * ELPA:: * MELPA:: * Repo:: * Emoji:: * Discover:: Usage * Logging in to your instance:: * Timelines:: * Composing toots:: * Other commands and account settings:: * Notifications:: * Customization:: * Commands and variables index:: * Packages related to @samp{mastodon.el}: Packages related to @samp{mastodonel}. * Live-updating timelines @samp{mastodon-async-mode}:: * Translating toots:: * Bookmarks and @samp{mastodon.el}: Bookmarks and @samp{mastodonel}. Contributing * Bug reports:: * Fixes and features:: * Coding style:: @end detailmenu @end menu @node README @chapter README @samp{mastodon.el} is an Emacs client for the ActivityPub social networks that implement the Mastodon API@. For info see @uref{https://joinmastodon.org/, joinmastodon.org}. NB: @samp{mastodon.el} now ships this readme as an .info file, so if you have it installed you should be able to browse this readme inside emacs. @samp{C-h i} for info, then @samp{m masto RET} should load it for you. @menu * Installation:: * Usage:: * Dependencies:: * Network compatibility:: * Contributing:: * Supporting @samp{mastodon.el}: Supporting @samp{mastodonel}. * Contributors:: * Screenshots:: @end menu @node Installation @section Installation You can install @samp{mastodon.el} from ELPA, MELPA, or directly from this repo. It is also available as a GUIX package. @menu * ELPA:: * MELPA:: * Repo:: * Emoji:: * Discover:: @end menu @node ELPA @subsection ELPA You should be able to directly install with: @samp{M-x package-refresh-contents RET} @samp{M-x package-install RET mastodon RET} @node MELPA @subsection MELPA Add @samp{MELPA} to your archives: @lisp (require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/") t) @end lisp Update and install: @samp{M-x package-refresh-contents RET} @samp{M-x package-install RET mastodon RET} @node Repo @subsection Repo Clone this repository and add the lisp directory to your load path. Then, require it and go. @lisp (add-to-list 'load-path "/path/to/mastodon.el/lisp") (require 'mastodon) @end lisp Or, with @samp{use-package}: @lisp (use-package mastodon :ensure t) @end lisp The minimum Emacs version is now 28.1. But if you are running an older version it shouldn't be very hard to get it working. @node Emoji @subsection Emoji Since Emacs 28, it has builtin emoji support with @samp{emoji.el}. If you prefer to use @uref{https://github.com/iqbalansari/emacs-emojify, Emojify}, @samp{require} it and set @samp{mastodon-use-emojify} to non-nil to display emoji in timelines and to use it when composing toots. @samp{Emoji.el} is the better option, but for now only @samp{emojify} supports downloading and using custom emoji from your instance. From personal experience, @samp{emojify} also tends to result in less TOFU@. @node Discover @subsection Discover @samp{mastodon-mode} can provide a context menu for its keybindings if @uref{https://github.com/mickeynp/discover.el, Discover} is installed. It is not required. if you have Discover, add the following to your Emacs init configuration: @lisp (require 'mastodon-discover) (with-eval-after-load 'mastodon (mastodon-discover)) @end lisp Or, with @samp{use-package}: @lisp (use-package mastodon :ensure t :config (mastodon-discover)) @end lisp @node Usage @section Usage @menu * Logging in to your instance:: * Timelines:: * Composing toots:: * Other commands and account settings:: * Notifications:: * Customization:: * Commands and variables index:: * Packages related to @samp{mastodon.el}: Packages related to @samp{mastodonel}. * Live-updating timelines @samp{mastodon-async-mode}:: * Translating toots:: * Bookmarks and @samp{mastodon.el}: Bookmarks and @samp{mastodonel}. @end menu @node Logging in to your instance @subsection Logging in to your instance You need to set 2 variables in your init file to get started: @enumerate @item @samp{mastodon-instance-url} @item @samp{mastodon-active-user} @end enumerate (see their doc strings for details). For example If you want to post toots as "example@math{_user}@@social.instance.org", then put this in your init file: @lisp (setq mastodon-instance-url "https://social.instance.org" mastodon-active-user "example_user") @end lisp Then @strong{restart} Emacs and run @samp{M-x mastodon}. Make sure you are connected to internet before you do this. If you have multiple mastodon accounts you can activate one at a time by changing those two variables and restarting Emacs. If you were using mastodon.el before 2FA was implemented and the above steps do not work, call @samp{(mastodon-forget-all-logins)}, restart Emacs and follow the steps again. @enumerate @item @anchor{encrypted access tokens (from 200)}encrypted access tokens (from 2.0.0) By default, user access tokens are now stored in the user's auth source file (typically @samp{~/.authinfo.gpg}, check the value of @samp{auth-sources}). When you first update to 2.0.0, or if you encounter issues due to old credentials, call @samp{(mastodon-forget-all-logins)} to remove the old mastodon.el plstore, and then authenticate again. If you don't want to use the auth source file, set @samp{mastodon-auth-use-auth-source} to nil. Entries will instead be stored encrypted in @samp{mastodon-client--token-file}, a plstore. If for some reason you reauthenticate, you'll need to either remove the entry in your auth sources file, or manually update the token in it after doing so, as mastodon.el is unable to reliably update (or even remove) entires. The format for a mastodon.el auth source entry is as follows: @samp{machine INSTANCE login USERNAME password AUTHTOKEN} with the token being what you copy from the browser when authenticating. If you have @samp{auth-source-save-behavior} set to nil, you'll also need to add such an entry manually. Finally, if you find you're asked for your key passphrase too often while authenticating, consider setting @samp{epa-file-encrypt-to} (for auth-source encryption) and @samp{plstore-encrypt-to} (for plstore encryption) to your preferred key ID@. @end enumerate @node Timelines @subsection Timelines @samp{M-x mastodon} Opens a @samp{*mastodon-home*} buffer in the major mode and displays toots. If your credentials are not yet saved, you will be prompted for email and password. The app registration process will take place if your @samp{mastodon-token-file} does not contain @samp{:client_id} and @samp{:client_secret}. @enumerate @item @anchor{Keybindings}Keybindings For a full list of commands and variables, see @uref{mastodon-index.org, mastodon-index.org}. @multitable {aaaaaaaaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} @headitem Key @tab Action @item @tab @strong{Help} @item @samp{?} @tab Show discover menu of all bindings, if @samp{discover} is available @item @tab @strong{Timeline actions} @item @samp{n} @tab Go to next item (toot, notification, user) @item @samp{p} @tab Go to previous item (toot, notification, user) @item @samp{M-n/} @tab Go to the next interesting thing that has an action @item @samp{M-p/} @tab Go to the previous interesting thing that has an action @item @samp{F} @tab Open federated timeline (1 prefix arg: hide-replies, 2 prefix args: media only) @item @samp{H} @tab Open home timeline (1 prefix arg: hide-replies) @item @samp{L} @tab Open local timeline (1 prefix arg: hide-replies, 2 prefix args: media only) @item @samp{N} @tab Open notifications timeline @item @samp{@@} @tab Open mentions-only notifications timeline @item @samp{u} @tab Update current timeline @item @samp{T} @tab Open thread for toot at point @item @samp{#} @tab Prompt for tag and open its timeline @item @samp{A} @tab Open author profile of toot at point @item @samp{P} @tab Open profile of user attached to toot at point @item @samp{O} @tab View own profile @item @samp{U} @tab update your profile bio note @item @samp{;} @tab view instance description for toot at point @item @samp{:} @tab view followed tags and load a tag timeline @item @samp{C-:} @tab view timeline of all followed tags @item @samp{,} @tab view favouriters of toot at point @item @samp{.} @tab view boosters of toot at point @item @samp{/} @tab switch between mastodon buffers @item @samp{\} @tab prompt for an instance domain and view its local timeline (if poss) @item @samp{Z} @tab report user/toot at point to instances moderators @item @tab @strong{Other views} @item @samp{s} @tab search (posts, users, tags) (NB: only posts you have interacted with) @item @samp{I}, @samp{c}, @samp{d} @tab view, create, and delete filters @item @samp{R}, @samp{a}, @samp{j} @tab view/accept/reject follow requests @item @samp{G} @tab view follow suggestions @item @samp{V} @tab view your favourited toots @item @samp{K} @tab view bookmarked toots @item @samp{X} @tab view/edit/create/delete lists @item @samp{S} @tab view your scheduled toots @item @samp{S-:} @tab view profile/account settings transient menu @item @tab @strong{Toot actions} @item @samp{t} @tab Compose a new toot @item @samp{c} @tab Toggle content warning content @item @samp{b} @tab Boost toot under @samp{point} @item @samp{f} @tab Favourite toot under @samp{point} @item @samp{k} @tab toggle bookmark of toot at point @item @samp{r} @tab Reply to toot under @samp{point} @item @samp{v} @tab Vote on poll at point @item @samp{C} @tab copy url of toot at point @item @samp{C-RET} @tab play video/gif at point (requires @samp{mpv}) @item @samp{e} @tab edit your toot at point @item @samp{E} @tab view edits of toot at point @item @samp{i} @tab (un)pin your toot at point @item @samp{d} @tab delete your toot at point, and reload current timeline @item @samp{D} @tab delete and redraft toot at point, preserving reply/CW/visibility @item @samp{!} @tab toggle folding of toot at point @item (@samp{S-C-}) @samp{W}, @samp{M}, @samp{B} @tab (un)follow, (un)mute, (un)block author of toot at point @item @tab @strong{Profile view} @item @samp{C-c C-c} @tab cycle between statuses, statuses without boosts, followers, and following @item @tab @samp{mastodon-profile--add-account-to-list} (see lists view) @item @tab @strong{Notifications view} @item @samp{a}, @samp{j} @tab accept/reject follow request @item @samp{C-k} @tab clear notification at point @item @samp{C-c C-c} @tab cycle between notification types @item @tab see @samp{mastodon-notifications--get-*} functions for filtered views @item @tab @strong{Quitting} @item @samp{q} @tab Quit mastodon buffer, leave window open @item @samp{Q} @tab Quit mastodon buffer and kill window @item @samp{C-M-q} @tab Quit and kill all mastodon buffers @end multitable @item @anchor{Toot byline legend}Toot byline legend @multitable {aaaaaaaaaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaa} @headitem Marker @tab Meaning @item @samp{(🔁)} (or @samp{(B)}) @tab I boosted this toot @item @samp{(⭐)} (or @samp{(F)}) @tab I favourited this toot @item @samp{(🔖)} (or @samp{(K)}) @tab I bookmarked this toot @end multitable @end enumerate @node Composing toots @subsection Composing toots @samp{M-x mastodon-toot} (or @samp{t} from a mastodon.el buffer) opens a new buffer/window in @samp{text-mode} and @samp{mastodon-toot} minor mode. Enter the contents of your toot here. @samp{C-c C-c} sends the toot. @samp{C-c C-k} cancels. Both actions kill the buffer and window. Further keybindings are displayed in the buffer, and in the following subsection. Replies preserve visibility status/content warnings, and include boosters by default. If the region is active when you start a reply, it will be yanked into the compose buffer prefixed with @samp{>} to form a rough reply quote. Server's max toot length, with running char count, and attachment previews, are shown. You can download and use your instance's custom emoji (@samp{mastodon-toot--download-custom-emoji}, @samp{mastodon-toot--enable-custom-emoji}). If you want to view some of the toot being replied to in the compose buffer, set @samp{mastodon-toot-display-orig-in-reply-buffer} to non-nil. The compose buffer uses @samp{text-mode} so any configuration you have for that mode will be enabled. If any of your existing config conflicts with @samp{mastodon-toot}, you can disable it in the @samp{mastodon-toot-mode-hook}. For example, the default value of that hook is as follows: @lisp (add-hook 'mastodon-toot-mode-hook (lambda () (auto-fill-mode -1))) @end lisp @enumerate @item @anchor{Keybindings (1)}Keybindings @multitable {aaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaaaaaaaaaa} @headitem Key @tab Action @item @samp{C-c C-c} @tab Send toot @item @samp{C-c C-k} @tab Cancel toot @item @samp{C-c C-w} @tab Add content warning @item @samp{C-c C-v} @tab Change toot visibility @item @samp{C-c C-n} @tab Add sensitive media/nsfw flag @item @samp{C-c C-a} @tab Upload attachment(s) @item @samp{C-c !} @tab Remove all attachments @item @samp{C-c C-e} @tab Insert emoji @item @samp{C-c C-p} @tab Create a poll @item @samp{C-c C-o} @tab Cancel poll @item @samp{C-c C-l} @tab Set toot language @item @samp{C-c C-s} @tab Schedule toot @end multitable @item @anchor{Autocompletion of mentions tags and emoji}Autocompletion of mentions, tags and emoji Autocompletion of mentions, tags, and emojis is provided by @samp{completion-at-point-functions} (capf) backends. @samp{mastodon-toot--enable-completion} is enabled by default. To trigger completion, type a prefix followed by a few letters, @samp{@@} for mentions, @samp{#} for tags, and @samp{:} for emoji (for now this only works when using @samp{emojify.el}). If you want to enable @samp{company-mode} in the toot compose buffer, set @samp{mastodon-toot--use-company-for-completion} to @samp{t}. (@samp{mastodon.el} used to run its own native company backends, but these have been removed in favour of capfs.) If you don’t run @samp{company} and want immediate, keyless completion, you’ll need to have another completion engine running that handles capfs. A common combination is @samp{consult} and @samp{corfu}. @item @anchor{Draft toots}Draft toots @itemize @item Compose buffer text is saved as you type, kept in @samp{mastodon-toot-current-toot-text}. @item @samp{mastodon-toot--save-draft}: save the current toot as a draft. @item @samp{mastodon-toot--open-draft-toot}: Open a compose buffer and insert one of your draft toots. @item @samp{mastodon-toot--delete-draft-toot}: Delete a draft toot. @item @samp{mastodon-toot--delete-all-drafts}: Delete all your drafts. @end itemize @end enumerate @node Other commands and account settings @subsection Other commands and account settings: In addition to @samp{mastodon}, the following three functions are autoloaded and should work without first loading a @samp{mastodon.el} buffer: @itemize @item @samp{mastodon-toot}: Compose new toot @item @samp{mastodon-notifications-get}: View all notifications @item @samp{mastodon-url-lookup}: Attempt to load a URL in @samp{mastodon.el}. URL may be at point or provided in the minibuffer. @end itemize @itemize @item @samp{mastodon-tl--view-instance-description}: View information about the instance that the author of the toot at point is on. @item @samp{mastodon-tl--view-own-instance}: View information about your own instance. @item @samp{mastodon-search--trending-tags}: View a list of trending hashtags on your instance. @item @samp{mastodon-search--trending-statuses}: View a list of trending statuses on your instance. @item @samp{mastodon-search--trending-links}: View a list of trending links on your instance (+ click through to a timeline of posts featuring a given link) @item @samp{mastodon-tl--add-toot-account-at-point-to-list}: Add the account of the toot at point to a list. @end itemize @itemize @item @samp{mastodon-tl--dm-user}: Send a direct message to one of the users at point. @end itemize @itemize @item @samp{mastodon-profile--add-private-note-to-account}: Add a private note to another user’s account. @item @samp{mastodon-profile--view-account-private-note}: View a private note on a user’s account. @end itemize @itemize @item @samp{mastodon-profile--show-familiar-followers}: Show a list of “familiar followers” for a given account. Familiar followers are accounts that you follow, and that follow the account. @end itemize @itemize @item @samp{mastodon-tl--follow-tag}: Follow a tag (works like following a user) @item @samp{mastodon-tl--unfollow-tag}: Unfollow a tag @item @samp{mastodon-tl--list-followed-tags}: View a list of tags you're following. @item @samp{mastodon-tl--followed-tags-timeline}: View a timeline of all your followed tags. @item @samp{mastodon-tl--some-followed-tags-timleine}: View a timeline of multiple tags, from your followed tags or any other. @end itemize @itemize @item @samp{mastodon-switch-to-buffer}: switch between mastodon buffers. @end itemize @itemize @item @samp{mastodon-tl--get-remote-local-timeline}: View a local timeline of a remote instance. @item @samp{mastodon-tl--remote-tag-timeline}: View a tag timeline on a remote instance. @end itemize @itemize @item @samp{mastodon-user-settings}: Launch a transient menu to update various account settings. @end itemize @node Notifications @subsection Notifications Mastodon from 4.3 supports grouped notifications. These are implemented by @samp{mastodon.el} but disabled by default out of consideration to users on instances that don't support them. If you are on an instance that implements grouped notifications, set @samp{mastodon-group-notifications} to @samp{t} to enable them. @node Customization @subsection Customization See @samp{M-x customize-group RET mastodon} to view all customize options. @itemize @item Timeline options: @itemize @item Use proportional fonts @item Default number of posts displayed @item Timestamp format @item Relative timestamps @item Display user avatars @item Avatar image height @item Enable image caching @item Hide replies in timelines @item Show toot stats in byline @end itemize @item Compose options: @itemize @item Completion style for mentions and tags @item Enable custom emoji @item Display toot being replied to @item Set default reply visibility @end itemize @item Nofitication options: @itemize @item Display user's profile note in follow requests @item Group notifications @end itemize @end itemize @node Commands and variables index @subsection Commands and variables index An index of all user-facing commands and custom variables is available here: @uref{mastodon-index.org, mastodon-index.org}. You can also hit @samp{?} in any @samp{mastodon.el} buffer to see the available bindings, or run @samp{M-X} (upper-case @samp{X}) to view all commands in the buffer with completion, and call one. @node Packages related to @samp{mastodonel} @subsection Packages related to @samp{mastodon.el} @enumerate @item @anchor{Alternative timeline layout}Alternative timeline layout The incomparable Nicholas Rougier has written an alternative timeline layout for @samp{mastodon.el}. The repo is at @uref{https://github.com/rougier/mastodon-alt, mastodon-alt}. @item @anchor{Org links archive search}Org links, archive search @uref{https://codeberg.org/chrmoe/toot-suite, toot-suite} implements an org link type for fediverse posts, and also provides a way to browse an offline archive of your account. @item @anchor{Mastodon hydra}Mastodon hydra A user made a hydra for handling basic @samp{mastodon.el} commands. It's available at @uref{https://holgerschurig.github.io/en/emacs-mastodon-hydra/}. @item @anchor{Narrow to timeline item}Narrow to timeline item A simple code snippet to enable narrowing to current item in timelines: @uref{http://takeonrules.com/2024/10/31/hacking-on-mastodon-emacs-package-to-narrow-viewing/} @item @anchor{Sachac's config goodies}Sachac's config goodies The incomparable sachac has a bunch of @samp{mastodon.el} extensions and goodies in their literate config, available here: @uref{https://sachachua.com/dotemacs/index.html#mastodon}. @end enumerate @node Live-updating timelines @samp{mastodon-async-mode} @subsection Live-updating timelines: @samp{mastodon-async-mode} (code taken from @uref{https://github.com/alexjgriffith/mastodon-future.el, mastodon-future}.) Works for federated, local, and home timelines and for notifications. It's a little touchy, one thing to avoid is trying to load a timeline more than once at a time. It can go off the rails a bit, but it's still pretty cool. The current maintainer of @samp{mastodon.el} is unable to debug or improve this feature. To enable, it, add @samp{(require 'mastodon-async)} to your @samp{init.el}. Then you can view a timeline with one of the commands that begin with @samp{mastodon-async--stream-}. @node Translating toots @subsection Translating toots You can translate toots with @samp{mastodon-toot--translate-toot-text} (@samp{a} in a timeline). At the moment this requires @uref{https://codeberg.org/martianh/lingva.el, lingva.el}, a little interface I wrote to @uref{https://lingva.ml, lingva.ml}, to be installed to work. You could easily modify the simple function to use your Emacs translator of choice (@samp{libretrans.el} , @samp{google-translate}, @samp{babel}, @samp{go-translate}, etc.), you just need to fetch the toot's content with @samp{(mastodon-tl--content toot)} and pass it to your translator function as its text argument. Here's what @samp{mastodon-toot--translate-toot-text} looks like: @lisp (defun mastodon-toot-translate-toot-text () "Translate text of toot at point. Uses `lingva.el'." (interactive) (let* ((toot (mastodon-tl--property 'item-json))) (if toot (lingva-translate nil (mastodon-tl--content toot)) (message "No toot to translate?")))) @end lisp @node Bookmarks and @samp{mastodonel} @subsection Bookmarks and @samp{mastodon.el} @samp{mastodon.el} implements a basic bookmark record and handler. Currently, this means that you can bookmark a post item and later load it in thread view. This could be expanded to any item with an id, but probably not to things like timeline views. If you want to be able to bookmark something, open an issue and ask, as it's trivial to expand the bookmarking code. @node Dependencies @section Dependencies Hard dependencies (should all install with @samp{mastodon.el}): @itemize @item @samp{request} (for uploading attachments, @uref{https://github.com/tkf/emacs-request, emacs-request}) @item @samp{persist} (for storing some settings across sessions, @uref{https://elpa.gnu.org/packages/persist.html, persist}) @item @samp{tp.el} (for transient menus, @uref{https://codeberg.org/martianh/tp.el, tp.el}) @end itemize Optional dependencies (install yourself, @samp{mastodon.el} can use them): @itemize @item @samp{emojify} to use custom emoji (else we use builtin @samp{emoji.el}) @item @samp{mpv} and @samp{mpv.el} for viewing videos and gifs @item @samp{lingva.el} for translating toots @end itemize @node Network compatibility @section Network compatibility @samp{mastodon.el} should work with ActivityPub servers that implement the Mastodon API@. Apart from Mastodon itself, it is currently known to work with: @itemize @item Pleroma (@uref{https://pleroma.social/, pleroma.social}) @item Akkoma (@uref{https://akkoma.social/, akkoma.social}) @item Gotosocial (@uref{https://gotosocial.org/, gotosocial.org}) @item Sharkey (@uref{https://joinsharkey.org, joinsharkey.org}) @end itemize It does not support the non-Mastodon API servers Misskey (@uref{https://misskey.io/, misskey.io}), Firefish (@uref{https://joinfirefish.org/, joinfirefish.org}, formerly Calkey) and Friendica, but it should fully support displaying and interacting with posts and users on those platforms. If you attempt to use @samp{mastodon.el} with a server and run into problems, feel free to open an issue. @node Contributing @section Contributing PRs, issues, feature requests, and general feedback are very welcome! If you prefer emailing patches to the process described below, feel free to send them on. Ideally they'd be patches that can be applied with @samp{git am}, if you want to actually contribute a commit. @menu * Bug reports:: * Fixes and features:: * Coding style:: @end menu @node Bug reports @subsection Bug reports @enumerate @item @samp{mastodon.el} has bugs, as well as lots of room for improvement. @item I receive very little feedback, so if I don't run into the bug it often doesn't get fixed. @item If you run into something that seems broken, first try running @samp{mastodon.el} in emacs with no init file (i.e. @samp{emacs -q} (instructions and code for doing this are @uref{https://codeberg.org/martianh/mastodon.el/issues/300, here}) to see if it also happens independently of your own config (it probably does). @item Else enable debug on error (@samp{toggle-debug-on-error}), make the bug happen again, and copy the backtrace that appears. @item Open an issue here and explain what is going on. Provide your emacs version and what kind of server your account is on. @end enumerate @node Fixes and features @subsection Fixes and features @enumerate @item Create an @uref{https://codeberg.org/martianh/mastodon.el/issues, issue} detailing what you'd like to do. @item Fork the repository and create a branch off of @samp{develop}. @item Run the tests and ensure that your code doesn't break any of them. @item Create a pull request (to develop) referencing the issue created in step 1. @end enumerate @node Coding style @subsection Coding style @itemize @item This library uses an unconvential double dash (@samp{--}) between file namespaces and function names, which contradicts normal Elisp style. This needs to be respected until the whole library is changed. @item Use @samp{aggressive-indent-mode} or similar to keep your code indented. @item Single spaces end sentences in docstrings. @item There's no need for a blank line after the first docstring line (one is added automatically when documentation is displayed). @end itemize @node Supporting @samp{mastodonel} @section Supporting @samp{mastodon.el} If you'd like to support continued development of @samp{mastodon.el}, I accept donations via paypal: @uref{https://paypal.me/martianh, paypal.me/martianh}. If you would prefer a different payment method, please write to me at and I can provide IBAN or other bank account details. I don't have a tech worker's income, so even a small tip would help out. @node Contributors @section Contributors @samp{mastodon.el} is the work of a number of people. Some significant contributors are: @itemize @item @uref{https://github.com/jdenen} [original author] @item @uref{http://atomized.org} @item @uref{https://alexjgriffith.itch.io} @item @uref{https://github.com/hdurer} @item @uref{https://codeberg.org/Red_Starfish} @end itemize @node Screenshots @section Screenshots Here's a (federated) timeline: @image{screenshot-tl,,,,png} Here's a notifcations view plus a compose buffer: @image{screenshot-notifs+compose,,,,png} Here's a user settings transient (active values green, current server values commented and, if a boolean, underlined): @image{screenshot-transient-1,,,,jpg} Here's a user profile fields transient (changed fields green, current server values commented): @image{screenshot-transient-2,,,,jpg} @bye mastodon.el/screenshot-notifs+compose.png000066400000000000000000006242611501733112700211400ustar00rootroot00000000000000‰PNG  IHDRŤ8ďˇJćsBIT|dˆ IDATxœěÝyœ\W}çýĎšˇŞşzßWő˘ÖžX’-o`c0Ć8ŠY‚1[†e <3“`’^~ž—ąĎž˙ţűYż~=żů›żÉWżúUĆĆĆ(,,䳟ý,ŐŐŐźď}ďăk_űZJÇuŤŞŞž8t.öďB˙/""W™ü(řøkšc-ĺŰGi?Őœgh?ߎÜńĐCěyźšó|âƒďăWŢş›ľšxľehƁ ¸ůţOóŠ_˙ďšűvŽ[ărţĐF€ş˙ü˙Ąü1;’ŘľřxčĎŢËö§ăĽXü%÷sńçw>ĂcĎE/K^Óg˙”˙ťÁëďáž{îុăąÇăŸwÓ}żÁÇ?úŢwĎ[šycąłG9?>žůśĎyĚ/šzěŮł‡={ö°nÝ:|>'Ož\í$­ˆ={ö,¸ý‘GÉŘg=z”­[ˇRWWÇu×]ÇĄC‡đűý<đŔÔÔÔĐŃŃÁßýÝ߉DR:Ž[UUőE˜;@],XÝž};ŸýěgšóÎ;éęꢡˇwI™‘ž@ŰŮÓôlýWÜ9ú×tŐ˝“ś‡żÎS§§´Ś{îáö[›iýů7řǟ>Î+ç‹y×ű?@ý/ă@bŸŇýżU÷<˙űkßá'Ď'vŰÇů7äą—š‡{ŢŮÍcuűŰďĺí§Ąh×/x,q€÷~ŕęžö3ž˝Ě?ţőwřŃSŻŇžw'ýänN?ś—ţEśŸ™ë˜I”ƒˆˆ\ŚŐX,†ľ– â ´śśŽrĘ2o*XýÜç>Ç#˝áš/˙’3ƒ„†/đâ? ˙Žr€—÷÷S€OÖŔ/ż}śż'ńţmÜüŕb˛ ŽćwwZţóO8|qŃĄ.Ž˙âĎyŠ&ţÝÍÉl_B9ˆˆHV› T=Ďă;ßůßüć7‰ĹběŮł‡wżűÝŤźkŢČČ_ůĘW¸xń"uuuTWW/)PđMýîAy|”o{Ÿ§.Ÿ˛Ó ?ő×ŰČv˙˙]—ö~Ö}üNnâŁ|Ő~„ő´ň?cßă&ţ=oćÇźXüŕö'ŕˇ~29ó5ËĎGáíżź˛Řöy›L9ˆˆH֚¨~űŰßf˙ţř™ĺ›ßü&ŸřÄ'¸űîťŢP÷°f×uq]7í÷űŚŽšNŞŠ,Źô˝ď}|ä#—ţ_DDŽ6C}|ęţÓC^Â[raü?ÎEĆ ~Ąö’§™ŕŢ„żM˝f¸7쏓Ů>×1EDäjFç T§Ě XŁŃčGXŤšo*éȄ‚‚>ó™Ď\6ő×Ă<@]]żó;żĂWżúU†‡‡S:Ž3ő?‹=[UĎ^‘+uđĺ×=žđqn[_IqQ  ۸ýÝë§w9đ¸÷s?ăüíÔ9ęŔِűaö`ůöŕüGď;Üújň‚T¸@7˙őĺ~˙]lŤ.$ˇ ‚ďx;iăoö“ÄöšŽ)""WłÇœ/}éKsŞS<ȟ˙ůŸgt‘Ą7˛O}ęSÔÖÖ^vęčč(őWEWWŐŐŐ|ôŁMů¸fëÖ­ŚW˙MfUŕšV ‘kĎ=ÄŻ}ĺA<7ýÚú‡⡞ű ^äsĂŻ}˜ťŽ_OuŸČH§˙˙ëŸÚŰ]~÷Ą˙BCä+<ř…é}䡇¸‰GyđÁ_̟ßM|ěw÷°ľŚŻ÷?ňG˙e˛ă×>Ę˝7l "×cŕü!žůŢ÷xŽgęM‹lŸó˜"""’Žşş:îťď>~řá+Śűň‰O|‚üŕtuuĽt\łeË;W Ş`UDDDDDDV‹3óMő‘lÔ=ŤómSp+""""""™ŕXkç :ˆŠˆˆˆˆˆČjqßEDDDDDDde͏ꪪˆˆˆˆˆˆŹŚEŻŹÎ \ĊˆˆˆˆˆČJ¸b5ŕdR­""""""’IşgUDDDDDD˛Ž‚UÉ: VEDDDDD$ëřBĄƘK˙MýĚż"""""""Ë%//OWVEDDDDD$ű(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘Źă[íČň1AË]7GšgƒĽ.ĎBŘĐrĆĺG/š]íÔĽŻfk”ß[ŒŸáđ+>žô˛Ăřj'* äZË,őĺ–ĆJĘ~—‡^qˆĽs0%%–†2† ËşjK÷~?ßo_îT‹ˆˆˆˆ$GÁę5Â=>ýĄ÷–ĂĄ§|úÜôŤÜe{üÎ?ştŮŐNeŒĺÍ×ÇX› `ŮšŰcË>‡WӊȮy[#<źÇĂ?ăľĐ Ň Vo óˇYÜŻí=š´4Šˆˆˆˆ,EÚӀ×ßá‹ďŠrweâŸÇ'>áówxԚeJÝŘú›#üÉť“/ßő7FŮS&ćđJŤ! ԖģS×9+–ňef 톊8;2hčö2˙ąŠ–˙J?ćç“ßđńÂ2]1oŰŕŸ;ô]?hˆˆˆˆČ5)˝+ŤĆ˛ąÉăşz8ýjü%ˇÔcwG˝ëđÝeLŕ’ąljňŘQo8ľ?ţ҂ĺk,×5$ފ9–Š`ÄđËg}˜:8{ŇĽmľ‚Ÿĺý÷E¸żÄđ?ňó/ÝŠbďă~ţčŒÇ×pň´Ă…Lç%Őň_%ăýúංe8˜…îłg=rwńÝłÂ2Ô-É^é]Yu-*Ŕ† '{ă/ĺW[ęčď2tëęĚҸ–•ńň=‘Lůȝšj,ŰÖX ÷źË^vŮ7°‚iŸCKnÇMk,i]”ŒŽœpyě¨ĂŮ02˝,XŞĺżŠźeL‹ľˢź%cfÝ‘kKZWVÝRuđ:NE㯭Ťąř€SçYŕĹąlÚăÝ[=śUZŠ4tt9<óŞË˙9gˆ&`ٸƲŽŇc]•ecĺČŁ~äÄřČ-1nŹśäD §Nť|ď—×GĄv}ŒÝă†*KnĚpú´Ëß?ërdć*<Öm‰ňkŰăŸ_äë GOťüô5‡ÓĄšJȲkGŒ{7{l*łú!4n8{Áᑽ>žď#>EŐąl˝.Ć{ˇzl.ˇů!2´w9ź|Äĺg-&éEÜ2őˆu,Vž–í7ĸwŁÇ ĺÓďßtG˜ŢÄžň7~ž Ĺóą{WŒ=›<6–M§ďB—ĂK‡\ţĎ)ĂTöMŽe{ƒÇşJKsľeSĺĐĎüŔÄřÔí1n(ł _tůú/|쎿Ç_äąçŚw4Yę ,``ĐáőV‡~lČáš3ÓÓy“­nĄÇ[7ZšĘ=ÖVZ֖[.>ŕ^qŹňśźĺ?C˛ő$ÍôżĺÖÝ1~u“ÇşKĐ3\hwč+^$3I–ó|ďÝzCŒ_ßéąąŘâMZNťüË.ÇgWćdŰw떈ˆˆˆ\[Ěć͛íäädüc.ý7ő÷Ľ ÜóŢ0Ť38äŔXCÄcŔuÁď@,  Lş<ôuűŁ€Ďrďť"üĆ:‹6<ţœ§űáĆ7G¸o ŕžÄĎ_œ0řš˘üĺ˝1ę‚\ş wń˘C°ĘĂ1ř -E‰iŠá—˙ŐbůŘ­áC ĐR˜Řęôń…ďťœMD[ŢćośŹá…_řůG žÚ(tŒ>ˆ ¸|éű>öÍ„› ÇG~-Âë€I‡~ÔÇłO˝+ĘÎ ŘI‡‡˙ÁϏ,ˇď‰đ{[,Ž5ěÖÇ×[ ›Ł|ţ6"§_ đ˙žhˆĚűMX~őž0Ÿ¨ äř&韯|ÇśEššśmą%7žďh§ËăçÁó /ěu9íóřřű#źŻŒ…ÖŁ>žě‚ŚÍ1ޙ¸ {?~ĘaŔ‚ż!ʗîŃ”7ýœ=íʎÄĆ ˛40Œˇúů­Ÿ8LTĆřŁűŁ\— Œ;|ďI—ăŽÇ=°†'~ě獧f ő!ˇ1Ę˙sWŒĽÓi9ńL€/ěËSËŰü-!˝ňßMĄžô§—^ôřŘű#ÜW/ƒžó.?:fç[îź!ƖźD?áç?sŚëX ĺlrb|áßFš%ńVWŸÁçž?m(YăŽÄçOöşüé÷| §ţ9žL×-š&äĺĺĽ0 ŘXęË čä `œřßA| ŕúOzýÍoŽđŠuń{*Ďěóó?:=ďđg]:-ÇrŰí1śű rÎÇo?ě缗–*sá[ßÎáß|=Ŕoý‹ËĹĨ4Păß^7˝í3?qéIl VÇŘł&q×ăέńA0žáÄą‘‹.O]Œďâ/ńńë/_ őúˇDů@]<Ż‡]ž{*~ĽěÄX˘HržőźËĄąéC´;üýs>žő‚ËŠ(ÜřÖ(ż–4†[üüéc.??čň?äăŠÄ=M;Łü_›âÓt#ç}|ţ~^˜ń4ŐÁĎžŕłűů›łńŤ„9…–BÇňö;âÁ„ÚůřA‹ĂÁă>ţ_…4–íőÓe›J}oóńÇßóńÚ<—˙RÍŰr—?$_OLšéÝy{4Üą—˙ô/>~rÄĺŃ˝./pŸf*ĺ<—Ę€Ă_˙ŔĎ×_đńĺňó|⇜œŠŸÜe/u)ľď ×-šv$Źz†Ż?œĂ‡˙‡Ÿď÷Ć˙ţö7rx˙—sřŔ÷ăAb䜏Oýe÷ýeřűř˘>&Çă=×ŧPâ^=k.Mٌő9´%ţpŠ˜řqÜ*Ë&ßôű{ŚמáÇ?đdž%:nY0‡–ÉŐA0>Ë>fÇq—Ÿżîňůżňás`<‰żemIňĺť_•eăT>ţéŽäŚť.G9_ě7Ě|JP÷ Á#~Ó)‰/8Őł í{šę–ć‹ˆˆˆ\[RVÝRb˝ćҕ˝†Ęřö\ϕ‹Ď -SN×ăӟœä“3śq3œéËÜ}gą1‡'ö:ÔÖy\ż+FUžĹg fžŤJš–źĺÉYAÎčŘôFrřű§6žÓŁÚăZśl˛e; wš|˙i—Ÿu$d”z4şë2´%"……Ęw1šů–Üů›•‰IƒM¤Ě8Pš óßX›`alęJgŘáÔܜxi^ŽĹĎk~žej‘≇NoyëC&ň–jů§ROŇIoNĄĽhę=&N˙”ĺ(çPäň×C3Ňk|–<'í{ uKDDDDŽ-ÉŤ~Ď|,ĘÍp]CС6Ę˙­ƀ/qßÍďœäťwC´ÍÇ?vf֕ϘĂwžďăĽ9ŚtZĎĐ?zĺëËĽ¤1Ćgťđ ťÇáÜPb!9˜YÓ EŚvóó`_ŒűßăŽfKQâŞnQuŒOßďQő/>?ĎĹżÇďýF„[üÄ÷q€ş(_y ~9Öuç/ßEÍN÷r˙` ?ÁĺmďŽQëÂŚM­.>=Ű<|ăůîuƒéŔ –^–+oK(˙”ęIéugNÔˇ†ČŹhyžĎ[–v7+}3Ób-Dm†ŰwŠuKDDDDŽ-IŤNĄĽ>A7>`Z|&ǍV§ěŽ/>…ąwÄ\\nřΡüó€Á]ĺŻ>Ł´ÍÇżý'—Yˇáí2´DáŕXšĘVKšŚďŤ‹v:<ŃľřE­hátv$îˇk,ˇ˜yŚňúŁüő}1ʍáç? đ7ç Ď<ççl$Ě_ÜŸBęĆď{œ+Xőú\>˙ß\0–}4ĚŻ—ţţ[~ŘϢ坘hĄ5 ×'ĘżśčšŢ^]2˝ĘV´ÇĄeą)ŔóčżčđjoŒ7Ő^|ĘÇ?´G ĂłîŐ]Îú°\y[Jů§ROŇIotŔĐéÁZ0PYô%vr,uEó”ÍrˇťŠ{NŽt8´y+Óž“­[""""rmI~5`â+Ž/‰O˝kŠżVQm)3ĐŮéĚšřsy´ez•ÓŰnŒQ?#D6~Ë-ˇEřáz”dhEOÇL_rœZš7×ă†yîYľ#Íxvăśíń{u§nŮź3Ćm%€C|cŠ+Đ÷ MŻX0t/r_ÉńŘP v"ůň]Œux´u:Ű7xNm xÜÚ8˝2ňŤ‡şÓ™Jëłź˙ý>żĂ’3äđä)‡îŃř˘BW¤gëĂrç-ňOĽž¤“ŢXŸËž.•×öFďŇUĚÜzÝůó”Í2ˇ;§Čă-‰•ymĚđřA‡É |ÎR¨[""""rmIi%§Ü˛Ö…H‡ál 0Đ\ăáZ8Őeć]ügď3>~VáŢ (lŠň_#FK!ěˇ4VYĘĂËżœ€–T{lœ1/ʞl+„Ă#PXmY›3˝­ŹĆcSžËń1(Šńhœ1-˛˛Ţcs‹KËy‡Ö¨Ç¸Ő1>w7ź~ÔÇă},Şź)Ć{ÖYşNřřéƒ5–[oZ¸|kvGřë÷Ć. ŇĹoż!Ć[|śźˆáľc‰|-MˇođhĘ1œowůůó~ţę•ég~.ô?ŕĐ5+˘(Z~hŐ÷O:>()ąěÜěąvÄáůƒMĄ>`,×íđؒ¸´ďœË—éRĚŰr—˙Ľ4$QOŇMoxĐ᥋†ü"Kye}ƒe}źňœŸoZö4''Shš{—Ľűu—łQRjwř,wÜčQç^xÍe°Üăޛbźo§G“ĎpîźË??éăáłĂejßK­[ĎöčaŤ""""× żßŮźyłœœV1ř‚–răĐš~˝¤ÄL~Ń™_ź| ]3Q’Íĺë”Äř⿊˛#źa—/}×ÇËăńmÁ<˖mQ¸ÝŁÂXżËďËÇŠT3b,ďűp˜]˙óř3ţ`fstľ•˙ľ,Őşőo¤ţŘhÉNyyyŠÝł  şg­Ş:¨ü˛‰†.” ťËˇ~sěŇâUgöOo ě÷ń‹ÄUe§ŔR‘ÂĹŻÚľ1ŢƒGŁßĐ?ó¸œďyľ•˙ľ,Őş%""""×]А%qfüܑWd)fl7KMâ~ZoĐáb’WUňž7Ę:cpÚtÄâ÷3kčČĚUUÉ.ŠÖ-šś(X•%9wÄÇKŰ"ÜVšÍQţăű,ży“ÇÖ2‹™4œisů§ç]^ĘL>$űdŞn‰ˆˆˆHvËËËK.XýÖg"¸&>-Ďu ƀëġ;ł&̚âľţ˝ÉUHÉ“Ę˙Ú5×w+""""W§¤ƒU]Y‘•’ÖjŔ"""""""™Ś`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹăKő N^ۡ4ĐX$`˘ ő\äЉú#™H`\ňŠŠŠŠ($ÚŐFۨÍĐɊËćďÖř(,-Ľś<‡Ąś tMŽv‚V‰ă§°¸˜šâQ} IDATň\ĆŰĎÓ>ąČţ™üNłšžŔŠĽĎÉŤŕş­4çŕ'Â`wGfű`I_6×ŮlNŰlóőÇWS 6˝ Ž‘ş#ňFZ°ę°m×jŽóā!lůŢqă:nw&yäđ$ëoÚÎćÜ^ĺ§Ç—ŢđÝňuÜ}}-…>x´W‡rHűťu Ř|ăvśćrxßQZǖż>ä×o孛ËČ÷°œčn§kňWď‚u[xÇś r]Ŕ†9=pö‰ůË!“í5Űű‚KŸ[Čö6QŰ”Ç_ĖoŕŽÝ‰>řPWŒmW ˝ČܲšÎfsÚf›Ż?^4WKÝOľM˒]Mő_DRœě+­Ą1’Ž‹ĂLZŔqđţ`œBŞ‹ýřƒ%Ô/ĎěâXßž|Š• oŔ@áZ7ýÝŚřFŐ%~|ÁbjJRž”ąö<őęú˝ŒţŞę8Éă{ĎŇMn˙Lś×lď V*}ž˛ZÖćOŇŃ1tEě7sźaڋĚ-í>ndsÚf›Ż?^´Í]%u?ĺ6-K–íçš\ QĽ!ż(Ÿ›hßŃń!Úťť9vއąĐ0}LŒöŃ>[ŚäY"c}t/O‡,­fcC ůKŠĽ}”ŻYCmîŐpÉć´N}ˇ)F„áD=ë§} É(*ĺ¤y„űéYŕ*âƒÇäHÝIϒXŢöşrÇ^+‘>CAqÁź}đœ_ÓJ´—ʐ}]š}܊Čć´Í2oźH›[ÁşŸţŘ"6-óHĽČöóI6ög"Ť'ĽŸý~—Ü#;ÖÍkş[#´źşŸ– $rYş“CMs3;+ •ŃWxábz'/§°–ëˇÖ2đZťo•] iMůťľă´žşŸÖL$ćňZžzw °)D&Ë-Űż“L§/Ţ;ń>‹7ÚĹkşHĐJľ—Ő•Í}]6×ŮlNŰĺćďçÍĂJŐý%Ž-RnÓ2§tú€l­˙Ůܟ‰Ź†”~4&ţ–`pţח“CN6ţd'i;×ˤMżƒrrËš~gĽi\™u\wžÂ6řÜĺ/°Ľ¤őj`|ţŤzŠÔJך6$ÓĎůžh/ŤU§ŻőžN–&ău‰c‹tŰ´Lť–ú€k)/"Ë%ŠŢ1Pś†MĺT•0ŞśŢÄýŰ Dşxţ™StKŮX_AUy)•….í^fo÷ÂӋL €ľÍ 4WQôáxaFúhmmăĚđRŚě8V׳ľŠ’ŞÂr\ˆ„Ćéëdź w¤ƒ–žéă›@!ÍëęY[YDaЇ‹062Čůśó´tMßÓĽ´q7m¨ Řo€ënşux´|‰;ŻĚŻ/ż”†ęRŞ*ʨ)ŽqňĹľ€Kayu•%ÔT–Rm牗Î3l_.UUĺÔU•S[ĺřË­Œ×Že{})Ĺ9ąÉ1ş;.přLŁsÎśN>­Éĺ}nşľlŹ-Ą$׏kcLŒ sńüyŽľöí &ČƛwłŤÔÁĆ" Ÿ?Á'ńü4ÖWRS^BUi.#'öóLŰd|€ŕ(­(ŁŽ˛œş —óŻáBîvŹŻŚŞŔá úşÚy˝ľ›ĄŮsr¨j¨gc])eyü&ĆŘČvŽ_]–ç´ę€¤vm#›ëâŸiź0كœ=ÓĆŠţ0S5/é6•nœjÖÇëb‘ß29>ÂĹ ç9z~8éď:sí~ąc[jˇďćMkr¸7yQ†Ďăń“C؂5źí–ľT$Fľ6âĚÁ×xľ'–á4'×sĘŘŐ\‘čƒĄzŰ-|`Řp'Ďý˛•ŽšşŰ…Ú $WŻŮÇIˇN/ú}%SŽIôuÝžYýÂaÎÖpýć:Şs=†:ϲďX#)ˇ ă/ ŠšžćŞ" üŽń˜îçĚé6ZűĂ .óőqŠ”Í}Ţy[Œq)ŞmdGs•ů>źÄyćőÓ}ŒÍ|˛e´Rýń|2rŽHmlą˜dŰtŇçéĽÔ‡Ä{k+˨+÷Óqŕ]ĽkŮŮTFIŽ!<6̅łg9Ň1N | Ű7ÔPWŔDCôvup¤ľ“9V‚ZROŞŽĽ76KFFΧ ö§1Š3”‘Ť]RÁjt|˜‹í“Œ›ulŠđ1Ú~†ă}QŹbČĆôđSXŔ5IÜŻ(ă†[śĐěćčëyv Œ[PĹŽë׳űŚ<̋‡9ÖÔCAýVîÜV mě}ąƒŢ°CQM3ˇnŤ§&ÚÇ+ϟŁ7ŃϘ`7Ţź‰Śœm­­ę óçQˇv-[w•QÓz„gObă´œ§v}#k‚1şĎžĄm Ŕ264÷°Ä̧´ŹŒşŇ ŽKü‚JbÉôBŞŤĘŠĚuđF S›œź몊/ËĹG˜ćŰ z}:p€žˆňĆuě^ˇ…; Zxň`÷œ÷´$“ÖTň>wQh¸n'ˇTÇ8÷ú^ę'âŠÝ°…[śí "÷0Oˇ /đ^ÁĄ¨q[J˘tľśđęŮĆUĘřüäó)/Í'čXFÍôŕĹ䖰śĄŽĆň<üĆĂ۸•ľÁgĎ´Đ2飢i-ۚ6ńÖ <~°›Kˇ?šlŢ˝ëJ ým§yáŕ Ł1‡ü’jvl+wůňœN}?kśďŕÖŞ0­‡óbď$‹Ř°m3;o,&o˙öǒoSiçÁĽbă6*Ćť8ôꆢ~ʛÖsă–ë¨Ě;ĘSÇ_ľ2cí>ÉcŮÇĎť×sç 5ćěýěëITŽŃvž~f‚›Ţ˛•†ĐyžŢ×Ć@4łiNĽ FƇh?b”ől-wi?Íўȥ>xÎă/Đ^’ŤW΢űœ4éÔéĺ+×ĹúşËű…Ą†uԗúéźŘGns ĺőëŮÖŰĎËÝnjíb*ýţaŽ8ŔɁ0+¸éÖÍěşąŔރšo`9—JŮ$ˇŽĹÎɆÂĆmÜƧNŕD4@Ms3›×oĄ4p„Ǐ&Úv }NJôÇ ĺhŮĎŠ-’‘L›NĽXJ}˜zoCycńďÜAstˆ“'Žóz,HăĆf6^we5ä—8tž>ˋ'ŁäV5˛Ťio-pxr_#3ű˘Ľ´ńęZ:cłEeä|şXŸ{ˆ3™Č‹Č5 Љ^h„Žî>ú&â'ßđčí]˝tôŽ˛ŕ ĐÚrŠ–¤“KőĆő4ç[:[NrŹ/DÄó wrčěžż˜ÍMEŠÍOž”›"6Ź+!‡ ̈łœ8vŒ×ťŻ<ŮÚąn^Űˆ˝1ŔĄ8o‚×^9Áń‹ƒôö÷rüőłtD §˛†úŕÔťĘÖmb{™‰‹-źpź›žń0““!úťűč‹Ěúr–˜çtę9反ÉÁöľs´kœÉXŒÉąA.ôOb 5š˜TÚTşy0.…ž!źŢNçČdź.žhĽeÄPÔĐĚĆÂĹŽzd°Ý'}lK¨ˇÓCŒŸâœË(̧$ŕŃsĄ3¨f4ÍŠľAob˜öŽ^zÇ}đHźnď%4OˇťP{IŞ^%ąO(:˝lĺşx_wyżŕR]›ËšÇ9|ŽĄ™Ĺ’Rť˜J?ônĺÄ@ü*´Śŵ“G]E.sˇˆ…ű¸TĘ&éź-ʐoxy_+-]Côöőpäđyz=C~m-5SůNĄŒV¤?^Ŕ˛Ÿ+R[$gń6Zą”ú0őރ=1ŔŒőđÂ+­´t ŇŰŰɁ݌㧼ÂÇů‡Ůwś—îAΝ<ÍŠ1‹ż´–Ś˘™5~‰m<麖ŢŘla:Ÿ.ڟćÄÓžŹyš6,ߏxë%ј|Ľ4×ä`źa:z.ᄆF™°†ź˛ŠR˜ń3ĹääS’cŔŽ3|Ů3Ő"ŒŒ…ą¸”ĺ]ędŤo„óĄË§lĹF9ß9uňi¨ÍŸgБ$/Jxžrą‘ČÜWŁl„P8ţžPw73w˛!:{'đL€ÚŞÂôžŔĺČť7ÉؤˇˆM3Ň ŠNůţTeVŽç-ŰJ =ƋgǘűüęŽÄć™bc"Ăblď {fšĹĆ ĹțšNćÓź&ÇNpîl?‹>Ĺa9ňœb}0>~NAĽ—ËobˆÎžNuŽcSiSKČC¨ˇŢ™_ЧŤëäQ_˝H;É`ťOéŘv‚ŽŽ< ŕĽä_úÔÁŽ3făŸŰ=8ăňą 1:aÁäP0sĺÚĽśńe_¤ CçÓ¤ÎĺʒČŐnĹďčw )qÁN†=ЉD yšäLľĺ'ž Ţ+L­hjӁœ‚‚D:&™}UËčŘy`tNœé°ŒŒÎîŔ,că!,ůós 0D(ĹŁ.KŢcƒxé5Úň`thď˛#ŸnŚžŒĹĘÖr{] …śŸWچ—ü tĎťňsmb:×Ԍ0“_Dyl$qEd1˜çd؉úC–˛ü:nS-§Ű9Ó5ĚHÇi^čˆď㔤ЦŇ΃ÇČČĺűƒe"Ć$ż(?Ł\Q2ŮîS=öXW/ý‹¨(*Ł&ŘNëń=Ťň‰őľr1źi^Ýţ'™z…“Ä>iH­\ Žß‡ß™5ލE ES˝Ë2:2ž#ô?K߼mɡ “_@‰ˆ…™yľĂŽÓňĘ^Î8vÎn“éăŇŻs ĺmqž7Ť,­MŹż;cúöúżŒôÇË$™´Ľ2śX.Kë#–Vf—ˆľó­Ć<ýČgFţ—ÜwŽÂš6­´§Î¤ú\™ÓĘ/?ç÷“cŔäTńć;+f ~l$F$~߆F CY HA^üń:q.y~ C#ńŕĎ$ŇA4:ç Á‹D‰Zđâű­ÎłŁ-Ń9~öb1<ŔőůđĽÓ_/SŢmxœž°Á̧. ŽĽ˘ŹşŠ§Î‡!§”şBî#3ŽčŹ@šW­˙IŚ^%łO:R)WdÍťŮQ|y!ÇzNňÓWťSţQkĄÇ0%Ű.L @Ž^ŮGYčœŻ’ěă–PçR}ÄT:2Ů˙ĽÓŻ”TĆËf‰}ÄJԇy-CßšâçÚ4Ӟt:3՟ŠźŹÚZé6ÔĂ+{۸˘CľŘX”É”îšIđ†h9=Hý–bÖŽŻćÂáN†Ły•l,w‰śsŹc2ń{ńâ–÷wŇôŘ9Î8Ć8ńé&óţÚštÉäÝ-¨b×öľ4űˆŽ20bbŇIŁÜ,]­<Űęrí먏_ËŚöCÍô덉—Łçqĺ'™9óą|yN^¸ď,OżĐOScëęĘ(ÍÉĽŚi#U•Ĺě}ĺ$S?Ę&ŰŚŇʃőˆÍqbz{ru1#í>ŐcŰI:ş†ŮQVBYe)9çť0ĺ”yƒź2Çjž™LóB2Ý˙,VŻ.„’Ű']ɕë$ça`ö™*<žě?fĽŇ. @JWŇRëăVŤÎ-&Łý_ýńŠIalą’˛aŒ˛ĽÔăŐ8×^– œO3ٟŠ\ËV>XD[đ9 ‡ -kŸšn}püžř#.‘UşŞ:ż`0žÔ˝šL/mˑw_ ťvod]0LűŃ×Ř{a">ĺČ)á†ę JRúőÓŇßŮĂđ(7ţTä `Ĺ;썍1ěń琗‘P9Ćpß“c-<ůě^~ôÄ+<őz;=3ztot„Á˜@.…W,âg(,ČĹÁ2:<˙}xÉńˆĎ”4Šý?/eĽy8x ŽÎłŃ")Z†ź;Ľ•Ô ŢH'GÚ'ŇJÇ)cđěÎLXüĽ\WŠâěřŁ6>ý,wöwăR8ëă—'ĎŠŐSŘŔwlcĂÔĘĚ6Â`ç9^<ÚMČrss°)´ŠĺýŢňóƒ<F+Ž˙U7ť|:žăâ_JäŘÉ>BřYłŠ‘Ş ŘěäĂĆ_DŐŹe óŞ*˜ýd eÉs:őÁ)Ężü§dă –ń‰IźÚTúy0W. âPSćƒÉ>Nu.2.“í>­c‡éč"Šš TĹú9ß?k¨‘É4/C\˛ĹęU˛ű¤Z§—˝\Óč—gf*íâRú ¨ŻžrX77ü…Žü,ÔÇeúü¸ëóRíW\˛c‹ĺ’ }Dş–XSŻkKď.Éäů4™ţtÁźĚ1Śyp+**žxi‘c.ý7ő÷Ôżn°˜Ś†**rˆ†čš tŮŘÎPTSϚ|ęl§},žœyĂŚő4(rĆ8uqŒ#c–ĘÚrŞ*J)41<ă#Ż ˜5Mܸ­–Ŕ`݉‡úňJin¨¤4`°áQş'/4OÂäQß\Ią?—ŠĘRjŞ*h¨­ Ž˘˜˘€e|,DüqmcÓäWUP[UB~,¤ç,(eýÖől*†ţÓ'8Đ59cZ†‡Ż¤†Ćb?~& 9–WQ˜ bžDyŒGƒ4ÔQšgčďb̨hÚČM5>˘ţ9&ĘČŔƒ“^â¤ăRRˇ†ş<ƒL04%†K~i ťv4Qí qöČ N,řđ´…ŇM#1?•őe ă]˝ôG,žürśďZOsž‹ÂŁƒôŒDćůľŃŕĎ/Łšą"ţÝFĆčö :6ŠWVMmQ!ey1ĆF'ÄËĆ ÓŘPMUŽÁ†Çčęg2‘H'§˜ĆĆÄśČ]}c‰ma9ëëË(ňAtb˜ŽĄI˘6Ęđ„ŸşÚ2* ˝ĂŒĹ Á˛nŢ\Š‹ż‘ąş†#D—œçÔë9%ŹŻ/Ą$`b\?ůe5ěÚRG‰äđŃv˘ą¤ŰTĘߛńSQ_KuĐĽ¸4Řđ0ĄÖÉĄfĂFv”{´>ÁÉáxŽçoŻŠľűš,÷ąŁ!‡ňĆrŠý.“g9Ô5űǟLöUŠ÷?n°„ľUT D'čgb‘Ńň|íĹ$QŻÝâ$ę^ęuÚ.C]˜]– ő˗÷ ôŒšUnŠľ ‘QňÚ2**J)vbDgŚk Ánş&HŁK­l’ÉŰ|毯†œ’J6ԗďXÂŁƒt¤Ţ˙eş?Ž-˜‡ĺ>WüŘÂäŇźkoťŽžJoˆöĄČźÁäÂm:ő>b)őÁÉ)šńŢqşű§ĘÄĽ°Ş–őŐůŒÇÄŕ }ń…ÝÜxů—ĺźÉ‘eëďS_¤>6[ŽóI*éô’:—/’—oŽ1ľČľÍď÷c6oŢl''ăë_ÎŹş%kšëĆ: ˙ČBœÜ{€ĂĂSCíŽ[¸˝ÎĐöÚËěíöCIóuźe].C-‡yŽmzľ<_A›×ŐQ_–O~ŔÁF'ěëŚĺT;FăÍĎ­ÚĚťo¨źě~ éⅧ[¸8Ď 0PTˍׯcÍ<—,#ĂxaßYzóýL ćuő4WQ˜ăĂxƆšĐvž“]W,âar+ŘuÝZKrđŰ(ك˝œÎœiçüHtŃ_SKkŞyŸutň*š~c5Uy†ÉP„Čä(íç.ŽßÁ •ńŸŁ˝-<˛żëŠÇë¸Ő›yĎő•—ßóéćů§Orѧ¨‘ťnm¤$ž’cçó‹Î2îže 3żÚh?űž=J[ŢZ~ŽmÇčŞÚĆŻl/˝ěłź‘6žxą!k–Őą}}5ľ…Œcrl€S-Ř ×łť<žŘŕßŰAŹ"ýœˇ”ŐŐŇ\SJEQ.y~/b°ż‡–Sí´MŸŞ’iS)o&—͡Ţ@óŕ öłĽąœ?xÖ#4ÜĎéÓç97݋ɴ×äŇxĽĚŰOÓš"ĘŠ}űy­žAM†ú*Hž :%ÍÜ3ťîŰ Nźü*ŻÍÝĚůžD{9 PžX˝2Iě3ýi)öqéׅ9ËqžžîœSeż`ÜÚ˙ ŻőÍ,ˇÔű3_~9›ÖŐQ_^@AŔÁ‹„ěëĺT˘N§{ôř^’eă”ĚŃç͙ˇ+Í__[oŢĹ] .ťo4Ö×Ę#űť0IöžĘĺm:[ŔŰŽŸťÍuÍ_÷Ó=WL&9śđĘšőέ4řŔNtđËgOÓ;Çבl›NžHż>ĚůŢX?űž=AdóÍźŠÖ7ă*žeüÜaëŠŕWnŹ˝lćÄrő÷é´ÇTĆfËw>I!ŻŸd:^bóŽŠEŽUyyyÉŤ‹ýg(Ű´›ˇ78)X]Y&żŽˇ˝iÎ8§^;́Ţp|ĺ_×OaY ;ˇ7R“ƒ­xâTNšd*X…öƒ/ńb§nšY ŠŽ-LnwźexňůłsŹ(+""ÉČËťňv›”9<Ę 8@$ĹÚ؜D_ ÁňrĘ|ŕ wq˛/|)ľąĂ=8ŇÂb(,Î_˝göˆˆˆČU#Őą…u|Ć2ÖÓĎ<DD$IK VM>Űnš;wŐQâL-ą4ÉčÄr$-u֋?ëŃřý\ąx†|bS4Ńňŕ"""˛¨ÔĆ~jšk(ďäŔ™a5DD–h‰WVýäř šyԕçÂH?]ŤóSb¨ťƒśq‹ÉŻĺĆm5Tćđť.ţœ<Ş›6˛Ť.ŃaNžĘę›Ň`%AňŠ Čђo"""Ť"Ľą…qp':yqßi:łí™2""WĄ%ŢłęPPÓĚîU”ç:DGű9v¸…ÖáŐ M ŚŚZ+Š(Î ŕw x1&CńʼnÎ]¤c,{CUˇr#÷ŢP}Y€ę….ňÜł§X…Ű€EDDŢđŽöą…ˆČŐh™XYşeY`IDDDDDDdš)X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`UDDDDDD˛Ž‚UÉ: VEDDDDD$ë(X‘ŹŁ`u™˜ ď/’*Őąk‡žKy#ň%ťc~!Ź)őhŞ´4WY"§||ë”Áf2uW §"ß˝Çăâk>ţö€ab™÷ϤźBKc™ĽžÜŇXéQŮďňĐ+ątf ¤ÄŇPćŃPaYWméŢďçűí˝jYL6ŐąL3ź'Ę}k,‘—˙őcĎ ­NZň -őe–ŚJć*Kř¤‡[—ÖO.ô]š ĺŽ›ŁÜłÁR—g!lh9ăňlŸĺ˝ˇĆhđżâăK/;Œ/5słäZš*,ky<áăˇčœ """Ë'Š`ľpK„ŻÜeÉqŔu ĆŔ™žL'íęąakŒ%–œ Lf`˙LÉŰáá=ţŻ…N¸8V°ÚxK˜ż¸ÍâÎxmďÉĽĽQғ-ul%¸uďn°äČ­ˆńî.Ďí3x+œŽ˘íţîžËŰSKOüŞčR¸ůžKôřô‡"Ü[‡žđépÓ02ó IDATŻFxpG”ap–ť=śěsx5­_ ć6g^ť–žW‘™’šĐÇt÷ĚôĚpČáđ5äʲÚ˛Ö—ź–ľ^ÚűVëŐ[?ËŢ]zm?żç}ëő?śe[kŃM‰ZREó’ć ‡3=wßčntŁqPgfěUhTŁqTŞ€BOüŢë7SČČČ/żřžˆ/2.ÍÔřńärÓאőŰ6~ĺ?\Z­N~cďÚů;ß×XPŃęáRG6V-vŤŹÁôFGL &—gtoĽßĆŻ}Kgʚ ߼,]ĚńR„ŠńŢ  ´ňo.ŹÍNc6.˜­˛ŹôŰřľ?Źňť* …BĄPlĄäiŔ˓ƒY“Ž’ďŘD4XüĘłź†÷â:oĚW–ŚqvX|Ô ™q7J˜zXnúZłž¨qu>ćŠBffG4F,‹°žwňşŔüÂĎgůŀŕ˙űś?ž=lv  9ëÍĆöË^uƒľ¨óO_đLł$ť¤ńŢÄáîĹc÷2&ÎęäˇcY É…Y š$â‚˙Ä@´ÂȐF2dŃŚ îiLÔ@!ń‰ęžŤBĄP( ĹVĘęzĘ ž˘{šL~ő§s|"źó&!Ľ¤ŠW.ž1ń xď–Ćb ašéŤŠrH fźWŠä4x$Ď´Iž=[żkîJ•łmŹRJ­sŻÍĺ˙_?䚨VGw,K sp…äL›D›̏ë|sźđ÷9~ ědj0 ZÍwU( …BĄŘJ㤛4u›|éY“gš$.S0<Şóő×uŽ­Hžţd–_Râ-šlüÜŇüŃň˙ăU;ßdůŸöHó•8՚ßÄăxłĹéˆŕ[ß°1ؙă/?eq*(Ńł‚Ąo]ŇšźR$¤&9ý„ÉϞśč K|6ȤąwúužwO<´ńH[_Ž_ꓬë|íŠĆn3d…ËäSÝ@JăGC{wröLoH.œ3ůbŸĹɐÄkƒÔş`dBăďźšPƒ’§/˜źtŇâDhó˝&f4ŢžŽóÝű‚ÔÖçŰ$yÚä '-z§%˜ˆi,ř÷\“œwÎâŮ>“§„Îk…ľ`‹/)Ç ’ă’Ô Î­]śQm'iłk|˙‡6~ť_ĐuĘâ\łä٧$Éű:É|ÚżöĽ,żvVŇ憉ƒoÝԈť%ĎtZ\č3yÖĽńÎHQÇÉińWž”ĺWOKš]ˆéüÁűi8Ů.‰Fir :tŻhmœ!ůâĎdůg,şoži㫗uÖ"&í”<ŮgŃ×x{A—ď ŹF“˙í—rütť$di|ëĎ ţpXĐuŇâš‹3>ÁŤßłń{Sťë—ŤwŰ!Čš“ŮÚMţ/äřTŻäXXp€7(ůÂE“&şÜvˆF-^脕“˙ĺÓ&)0œŕ˛C¤Ńâcí‚nkÄ ˝žSĎđO?iŃë\}ÍÎo~×ŕť’ç/Z\ě´řĚqžŤ1™-ČQ†N>X„ěuĂý‹żýÉŸě–třÁmŔJLç‡ăůŽYŮňm§§€ä Ϙ´ p€ËÁäŁ˝pš^@“<ű´Ĺą‚?é‹Ďž”¤ă;ד啥 ľđgöЌߎNë|ďśĆ­˜Ć˝Œä‹1ůD—¤ŮN Ćt^ŮĂžËöő-ďş8ŚóňdýÎLP( …Bq´°Ůl•ŸłęĚhü_żkç˙üŽđí͍6la“/vŽżođďŢЈd÷oüÖ+ů2!¸śgHÜ3řň× îl…Brž~ď›6ţĂ%ƒóGß]Ę_Ň˝ý9 ; -~îd~]—•ĐřĂ+ąeÁťӅˆŞłÝÂ_ˆ˝„!iŘXk)ňúŽÉ §-lRpéśöČ(fšéŸüxŽ/ľć§:NßÔů˝űůՁľÂí‹§Ű$¸ř‰ž)Ÿv垍ň§:ßżŚóďžmđZa´Śë|Ž_=)L<˙BŽŸ+ÜcÎéüó?6řNżÎßŐyy—ő}Íň7zó:~ßĆżťŚqk\ăë?љ– 4ÉÇ^09ťĂ}Ł]㡞iăw.üŤ?´ńfaTÎ1ů• ň–óœě¸ÁßűO6.)ąŤž÷ ;÷Ť6ţýH~Úá•x5ɧ_ĚńDCţÝÇŽ|óžĆľ;ż}mcôMrśýá]ŒˇŁ\˝¸œťŘXvÔŕüލˇ‹ţŘŘżű_ü­ßąó?üąÎTÁ'ě&żöÄćľ/GgŽpÍŮdňR[!ÝâS§óŁżX‚ ARBbJ羊|[ĐäŻ>š)s9:˙`ďş!ÓůG_8żT"ßvzrÁ×˙‹ƒżů;vţűoč ę!ÝoňĹcr×éÉΌƿřĎvţńŽőäěR–wŽüî›:××6˙–ˆi|í ƒß˝¤Ó?lđżapĽĚ!ĐýúşBĄP( EľŠ¸ł:q_g pŽBv^cpăL-AYyĆ;`­ &2›ż×GuŢL~äňŁY1m¸×⤖?ƒĐťŃuY<Íw\A‰Űi Ţššš{­\×ř~ż`ՄůQ×wéÄéa“O6ľ¤ńŁÉ˝ĺß-˝h0ůŠ‚Î$ܙĐŒˆ­Žç;*Š%—G¸L^:šŠß›ƒłžeZă­ŃÂȆ<{Á"*ň#‚?ݡyĎÝ[:C%˛Âań瞐ůšâ–ŕňˆxp¤š 1VřĄů,žkÚ>…A+…H[Ś4Ţ*ÚüŚç¸E“¨ě92#˜,šFš0 óƒy@ä×ça ŽÜИÖ$ç[7×;N.nć=ľ°9ňŘŘ!iÝĽ×!*ĐűAËš—MĘ´`˘H–šű:ŻŚ–ŻÇ4nőˆ†oźR¸ś:Žq;ťĄIK°ĐAłӉByęOwţ. k›ĺÜľpËQŞNJ˘“ÁĚv‡ˆV*ß6zúQA™ykEË šƒťW˘ăƒ:˝–SO–[żlEf ™˝ÓmP _W( …BĄ¨6UűFž-š gÔj'آŕun1TĂłqE>řÓ\’vô/jÜK›49óŁŚ_ú‹ÎÝŃůţ ż÷o ֋;mRđÎ+vŢyeoQŽśčĐ`ôŽÎP ›Œě–^JNn”„ĚmʖŕOžiçUˇ$ˇ.HI°uKN›×§ˇŹ™›‰ƒč€ľ8nč,4Zœ´oć?4SÚT=˝ÉâŒcóžŮDŃEVsä-HH:B{4ߩҏŰŘ('Đ’V ć*|Nńł˛šü{#ß˙CŻŰ`=Ňaa/ęܙEvj™›9†ÄśËƨP( …BQ!u˛•‡ĎľšţKZ°PXĂ&tpć4ž÷ŻŰ$}*Ç_}Ú"˘çGö^zÎäO&ôëVKáâéüهďŢ.ńlŐ=Ň'×óSšmźÎóJŽ Ňiyt(§csĂiA<é ˜ň—Ř‹K˝řźĆmä*~V6%˜Ýg ęiŘě÷YŤ‚yŤ6Ď)feČŕý‘௟`ňBwŽőĺüp0rUůvâ0ʲÖ>¨P( …BQ Mgľ;şŮYÍÍjÜ˂љăˇ~Ţ$,ß˙–?.xý #Ů ˙ňcůu“şW<菜ŸĘń—NI’ă:˙ůÄ–çwáěĂd‰gŤ–>7'ĘÁšÂš°Î°Dě0=97'ĚÁ“ IZüŔĚćőŚŔć†/ššźrK‚i ş5@@ŁX($Ň$­žíeĎÍîĺŕŠÂłşÂ°ëÁł{ąąŢ­đ31Š1fŐŕ9۰8ĽqyŢäůfÁ[Żüţ˜ žŹlłŃ”ˇÍ䯞ăĽđŁĎŠœ°8g‡ĽAŤéGŻW’^&4ţ´(0=sÖ˘Łxó!é;oňą@~î7Ӟ=nń@Ev‹tnîxzůz^ć‚ÎűK<Ř­öl§ő`ĽĄÝâi÷r­éüđŢć.ˇťhŇ^ôyCŘ$Ď},Ë?ú„E „=f4ŸĹÇ ;ŢJSđň5t žó†ä~!Ëß;'q,kźz_cv5żaŐ#É>ăó',>ńl–ż|ź ‹ ô^S9‹(×&Ť…&6GÉ5;87vŢn°xŞZkB÷Q7ˆ|UŚćeš“}×Ú …BĄP(* ´‘UmEÓEĂ­'ok ʃŻIŇU4-2ÔbqĘŤs;‘?Öăć<ݒ,Ăż=+pz%coÚůß/ ŹRŇlŠ­ĎäçSÓH>z1ÇšÂócˇ ~űNaˇŘ ŹYŕÓáÄ)“O­j,ę’Ď4ŤLk|ómýÁ$h{œł*$/–yśjiéoţČŕt0ËÁޒă˙EÉŤƒ‚„.é;nńl^ýĄĆ[qÁ;?6řn8ËÓž“9ţaZçŐYč q-–€hťEwQ˝iÝÔăŽő$”U–ްEOą’ł~¸šźšńœľĂǘííť| śsî]ј˛ƒΐ¤ĹZV07§ńÝŰřw6F8KHŁIž}ÚâX!8Z^ŘÚ-~ć ‹N›`fFăĎ.Ůř×ďhÄ7ÎMMhź: 1“4„,>{Áä§NXř3‚ţ{_ýĄÁË ›r“$=OF`eĚŕk—7óĐM~íy‰wIçˇ/i,í1âUVúŹŕĘá ¸Yœď´čń ćÇtžúCߙ›ioŇ:%]/ˇčrĆc:ßÓĆżyoóP€L\ăí)Ű' {$Ç:$Ç<đŢ6ţK\ňROá8Żäs$ł7tFr›rĺňëMýI[Pâ×c:_űßފƐźxѢŐ\ş˘[|ń“Ÿ;oŃeFÇuţčUƒŻ<|ôP9ĎŃÂ&˙ä—sœ) üí~‹O‚;W5fśčŮז?#5şÍÚ\̀@@ržĎ˘;ĄńćŹĆ’\l“Č%ß{Kß<ߡL˝×TΚ|ŁTŰM–ťĂ’żýË9Î=×´řt/\Iţç_27íÜ!‹ĎöA˙Ű?œ„ƒ’Pƒ¤1,iśÁ•wmüëűđš>‰Đ$/^$ďęÜs—§“˝ę+lňOţRŽÓE˛;üŸ<'żdđ'SՓoŕŽäŻ˙ľĎ­)ˇű$Ÿ8'™šŚ3ޔă_ţ˘ůĐŹˆ†`žžź:ąG=)K/Ëć§łüÖϚuí~‹O?eňqCă‡c)$Oœł8UuaTç•)RßÍžKôA˝-Çżú &Eďę Y|î4|ăƒÚOŘQ( …BńřcłŮ}}}2ÎĎ7ŰŠłş×ÝâËżšĺ§ Ł ŻŰůě §>‘áŸ]” _˛óżžł÷‘ĺŚWT-`ň•˙6Ç9X+:˙â÷ Ţ)lžĺtINÉńw^°ˆh`.ęüýß5¸UМĘĆŞZ–Bňsż”áݎäŢyÝÎop}ŠP( …Bą\.׏Y}\0,>uR"r?žSâŮŞĺ¤WԄö>óÁ&;KĂŹo^K­ Ž~`đg…ŃuÍ#‰ŇzźŠäT6öřPĽ˛lé6ů…§ňłM‹m¨Šg×* …BĄPÍnŔľFo´8Űé˜Ć›+ŐOݍ ZŃç—Oâ–ŠŽ ť¤š0ZoĹ5ŚŠÇW‰œzł˛ąÇ…jÔZŘä7~6GŻhcv&ÍüZX!“KjTUĄP( ĹŃŁ¤5Ť‡> X@´Ă䋧%áÂ)ÍŒÍhĚĽć8 šŞńňMŤądőÓ+jĂňŠ ó¸E‡lA‹g›ÁÓ iKÎôZüÂ'rź2‚?ţSo,9-ec Ő¨/Dƒäłç-ÂB01 §ÎXtŘ!ˇ¨óßŇXPCď …BĄP(ŽGfͪޖăßţ“Ć­łßřşßŸ;1Gá”|äŹÉ ÝÇB’ ě:䲂Ÿŕî˜Ć+×tŽňčäQ‘SQżtžÎń+ĎXœIDZ0<Śó‡oęźwHa …BĄP(*Ĺĺr•ÖYýÝ/gŃE~Ş˘ŽĺwÖľüuMŔAP(Šúĺç˙Çމ …BĄP(ö äÎęaŹ* …BĄP( …âĂƒÚ XĄP( …BĄP(u‰ęŹ* …BĄP( …˘îPU…BĄP( …BĄPÔŞłŞP( …BĄP(ŠşCuV …BĄP( …BQw¨ÎŞBĄP( …BĄP(ęŐYU( …BĄP( EÝĄ:Ť …BĄP( …BĄ¨;TgUĄP( …BĄP(u‡ęŹ* …BĄP( …˘îPU…BĄP( …BĄPÔŞłŞP( …BĄP(ŠşCuV …BĄP( …BQw¨ÎŞBĄP( …BĄP(ęŐYU( …BĄP( EÝĄ:Ť …BĄP( …BĄ¨;TgUĄP( …BĄP(u‡ęŹ* …BĄP( …˘îPU…BĄP( …BĄPÔŞłŞP( …BĄP(ŠşCuV …BĄP( …BQw¨ÎŞBĄP( …BĄP(ęŐYU( …BĄP( EÝĄ:Ť …BĄP( …BĄ¨;TgUĄP( …BĄP(u‡qŘ:š ŻßOs¸őŘ8ąä!ć-t\>?Í/š™1ĆVe…ŮíšŢ`–°ƒĺą fŇóŘ#K˝ëë°ěHĄŘŽz÷—ýPgžŚš"ót//hi~p}Ç­żZËöűĂÂĄč°BśmßwóĂşóŃŁÂ~ĘHĄ¨ĽOśš‰úmNMÇc@65y——ßa6wřy› Ăźúö Č­Ĺxíň‹Ö>śfh./§ACЇGT?˙z×׌ś$ Eýű 6M†ÓOsm[˝ůšjĄŰfrr™´4 °9ŘjP6ľlż?,Š+ô7Řž}ß-v:ʏęČł2R(jAéŐL‚ŠĹ$Éľ%&—śŤŮ Âmm´4ĽVŃ"X`ś&ŁÄĺć-ÉŽ-0˝rŔ•Ş´HĹ™{LžHËt†”™N“z䕪`ŁuŻŻ ;Şuďŕ(úűăD%ú?„2Ť{2+L.$IŽ-+Ťm;(_+ÇďÁŽDT[_&6;ËíűsUŸaR Î`':¸kś3F-Űď­<ŽőÝAę°@ĹţśSűž[ěTݸj˙6}Děhe¤PԂŇ]NŽ3tí*?¸4ŔČ6‡ćmáÉÓm´¸Ş)ŢÁ kXO—›÷á„tňž[}dz„ ćZň‘­z6Z˙úŞľ|GŮß*Ń˙á•Yű‹\gđň|÷; o´ďĽˇzy7›Ía§Á‘ ­ŐŽ\˝Ëí…C˜,4÷ôpţĚi.4ŐvdŚ–í÷{}w:Ü|Xĺţś[űžŰ+TĺőŞ`ÓGƎöY'*ŐŚěďC°=2ĽHkóäů‚joaĹa#“ŹŹYŹ­%1‹ţŹl´zÔł.5]ߥRúăń¸ý×s™Ő G˝m@Ă鏃i{2ÍŘčó˝XÄŽ˝Í[ÓŰL‘2ˆFĂ´FĂ´rÜygő–nÎśń;4Ěôł“Ü^`Ő4;ÁHˆÖĆ0­ńË7ľˇńd_+M ËÓ#ź{ŽDáQÂˇîF^§ffYKÄçŢL’—ghšĺĺđŮ$éőSăÜ_áÁ’ÝIkw''ZlčŇ$šśÂÔř8ˇc v\QJޏ đ÷œă“'|Ř7* +K|ôŻŢ]ĆŇ<ůąÓsé@š–Çň×vyÇhG;'Zƒ„\vlÂd-‘D:śäËŐĽ°{čîé 'ęĂç4ĐŹ ‰ĽÇ^)J­9ié5ŻGaeX/12<ĆýĹ Ö#eŢĎDCçŽ5őŘ “da&ƍÁY–‹…)Fn^g*ť^hPt‚ÇˡŃŇWá.<ŃÎkĽÝg °H­,196ƕŘZţ=ěQ^xąƒ•÷/scš`06/=Ç:9ŐÄ­ƒ4Ó _ťĚĺšâŹu|-œë‰Ňč6° žuchľâ×.ÉŽËŐĺţěˇT]î MA˘‘Í~“ťo]ĺöŞtźá­šƒ„r1^y{œGg„UY˙‹śŇꈲmź[.ýžŠëÍbŽšżô0ď Ó 6ř€×ÇŇČJt]ŞŻmGĽí ŕwpĄ'B4hGMgžăKg@fŚyăǃ̔Ű.–ŐŢjx›Ú9ÝŐHÔëŔĄC6ľÎÂ|œuO=1É˝šÍR,š}¨„=ÚŘňë‰ ŰŽ‚ţZC´†mL^˝ÍL°›ó]!Afm…‰‘ú'׹‡Ű8{ţĺxë IDATź™VŻ‘K1?3I˙ŕ4K[Ă÷´*Ĺ %Ć)—ŁÍCg{cĺţöHű^ ŞmÓű‹A*÷ŰcŚ­ěˇŒöŠí~ťn{+ó“—ď.—d9ŠÚĄG"‘Ż˜fţ•âÁżßšÝM4Ś5ęĂĽ R‹ÓŒ-› 4ě6d| éőă3LfGîs;śČäě"3ń5Öˇq ÍÓČŠî:#nœşŽÓĄÓ™ŕV˙}nŒĚąl9ŢÓF—'ÍÄĚ9W˜SÇÚčiňá˛Hôt4°8˝Š p$ڈ­I„3ÂĹçÎp*$˜ćú˝ †çÖŔß̊ޢr™‰Ľ"‡6"í-49ş7D“śČÍ[÷é] áˆpúX;mścó),a§ăÜžď°1wç6—n qkluW3OoŁY[fl1]YŢyÍhiŁÍ ‰™ &V%éř ÷ç,Â-ܚÉT˙üx¤PQËÓăóäBÍ41ËĽ7op}6˝s%Ž{čťxžgŰÝdfFxżˆţ‘YćRáˆˇžc!6ĹlaÐ˛uińôsg9ăĎ2Ü›wnrŢ$ŘŮI_ť—ôô,ůĺ6ڞ¸Ŕóíą;wxť”{Ókآœí`‹Ď2+BEenĂćôŃ՘c`|‰dCˆîś&:Ü)ĆgÖ jÍl†ĚƒĎŽv›(ŰFD_Ed֖‰Ífv„ńŠăýך<“ypÝiç|Ť†Ě"C‹…ż[âK9üQ|ŤăüčŇ-†Ve‘ přéô›L q7śLÖĄ§­‰V{‚Ńš‚Ý•l×ĺë˛Rű-G—_„ŽÖF:BN ˛ĚOL3—Éű_°)JWk#Q—™†'–Ůn?œŞéÍVr!Ş×JąńJlš´{öcťGŮ_†ł.š#aښ|¸4H.L1şœ+YoeűÚv”ŰŽlA’Ÿ™´ˆ¸‰ŘW†f™˜‰ł´ž!WŚŽEÉí-xÚĎđésÍx’Sźwů—§˜Ézč=ÖB“çƒw™Účx•Ü>”AmŹ­ěz˘˛śŁXn›W(L‡;Ĺđŕ“ŤčĄfŽw4ŇčŃ×ífubŒţá楗žÎş9&§<°ćí#YiŹPnœ˛r÷>ýmkűžÁŁąSiב°6]y Ršß–3U݌öŽífś,#<蜡?Q.6›­´iŔ2çŢŔˇćˇÖ+ółŒL.žZ$ćg‰Í0›ÝqS keŠ÷?¸Í„a'čZĺęľQ&VR$“ŤLÜ˝ÇŔ˛Äí˘/¤!×fšňÁuŽÎ›€NSKŁWďpstĺ‡D2h9ŃK—K2ďď,0ŸXciqŽţkw¸ˇŽ>vŒŰm+tźĆ2WoĘN¤ór r/!đuôpÂ+ŔŇľ#Ź ńř:iKbe“ÄcĚXÎś]ĘPJŢť[™äöTţËV8âÇţĐ+{{k3Óů÷6h„zOr6dœşÇĽ;ł,ŹgH§S,Î.°ÝZVĺęR§éÄ1zܒé{wš˝"kY¤VŚš>˛ŒeóÓ×ĺËœ#LołšăÖĚ:iÓ$˝gb1Ôœ4GŕĄ2×đť’\yo€;Sqćçšsc„É,8›iwîöŢfE6Z{}mCf‘‰E„A4â)rNpcoc_Qš7@ŁÍb!6ľM€ p‹%Ţy{3ËĚ/ĚŃsœyKŕniĄyĂVKśëĘtYžý–§ËäÂ—Ż 1ąŐţe†™áAŢź=żëČTUő_F!ËśńJô_Ę=U°Ý#ę/2šÄŔíŰܘÝÚś•Ťë}m;*mW XÉb3óĚŻçťł™Äą™ybsŤ…MhĘÓuÉí­ćăxoI†ďŽ3łžĂĚeXšf`ÁBŘt6nx{íC%”ĐƖ_OTVßmčďڜ œć—ŢäŢLœůůiŽ̲ŽpÄ`üęMŢ™gv)ÎčÝ!îŻIlÁşŠś űŘWŹPRœ˛żrŹžżŐˆšŘtĽďśż­ˇÔě,ÓĹÓ^dŠéů$–°Óő„4IŚňĎOĎĆ^“`Ž2r‚ťƒ÷čŸ3ÁŇľ#ŹăÓŠ‡e5WŸN"57-îm&5żŔCýqšÎĚbŠšhor#Ź4ki ş]ŢMĺ™R9@sŕśm˙ş{潍˛,ćcs$$Ř#QZŠ<Ë ŐSLÎŹî1ę᧧ͅ&“ŒŽ,n;şôĺęŇŇÓě@X+LÎ=ěáŠĺU’Rŕ 𠆁M€ćń|„ Źä2ÓssܟޘâłQć’xl’Ůb1×YNĺ?v¸v˜b¸/j­ŻmÉ13ťLŽźŽ|ĂĐź4‡  TJImlUę‰R0IŚó~˝2=GźŘ.Ö×Y“€šĘlźč ŁLąš” xŠwY-Ë>ö+ěŠĂŞ”c•cÉ*RW6˝/żÝo{RY•Űmĺ ŰŢ*ÄԊĽ–HKŤ[ X˛śžB"pşţęd5ą^X\Ÿea|„ë÷Xľ@óxčů !ńČÉęZ Ççْ'€E"ąžĹ8%ÉT‰Ŕísa3ă\}ű Ż˝s…WVJ›ŸN#6vš(?ď”Ďae†ą F _ Ó `$˜XŢ˝Zna;Čě ó%đ\Ž.5ˇ>ĹęÖ?›#Wn2™`1%îV^xţ4g[}¸t‹Ää—.ßep›Ł ,ëQ™ó;ŠíUžOj­ŻHĎ/˛`‚pˆž~ o&{šxÂD 7-Î|ů ;aryŠz–ľE—Röf› \Ĺv]:ĺŘoľtY űÖ˙>tyĐ6žA5ôý¸řË~(ÉלŁĆţˇ?]ďÜŢ"44ń ŮĂw~?XJTFűPűockĹVor§Ýą7Ҋ˻Lű¨Ěv°RŹ}ÄvÝöî3ŚV,uĐYÍi܊Z~ŘwÇŻ•ąc˝!-ĚmžDm^ĎËĄ{˘\8ŰM—ß ˇžĘŇjŠdZŰýËy‰yďĹúô Ó'´ůŁt¸Ś¸ç ÓdO16[Ât!ňú´ŹmŇîńĺ§,ˇů›LÍńŢťc,=ňBićHŚeFřŃĽEş:[ém t4ĐÜu‚hٟwßťËDށŞÉéëdšŠšÂ~Âa?śŘ*͑ÖçX˜s2“‹Đá ŃěŒ1ě  nV‰Td×e˛/űÝBÍbĄ*č˙ tyĐě)ű‡Ě_ŞÍaŰLEĎą–š7§ý”ŸîcMLܜf%§ájěäDXÇ\q{˛°aZá–Rۇ˛ŠR[Ż”kŐľeč°fĺxŘԓM—@=ś)Çv‡ĐöV3&QԖşčŹn‡Ó™–ˇRéŇżełů-ę cŰ)?šÍ@@&ťMžrŰ/Č6#Ż"3!­¸đô zbˇŽđîDáŹ/-ŔSM;~/!ďRŢ1ťČđl†Ö67-mAësÄJ™ŽË‘•ŕĐuSčĆw.W—Ů, †f&Cj7Ov‡ Ň+ ß]ařž@S+Oœl§ŮŐȝSLŢMneQk}íBrn‘Ľ“~BÁáƒfošŠ5Ź\ŠŘBŽŽf/­'qˇcy’ÉýNi4*ľë2)Ő~Ť¨ËJؗţJ—Ő¤úţ0ůKľŠľÍÔ̟$‰ąŰüŘěâ|o7?ő™rŚ@Y–f†yăî$Nř(§}¨ˆŰŘzŒî÷˘ű¨(V(A‡™Z—ăaSG6}Čí`Eě3ś;đśw?1ľâ@Ѓ5ŤŰa şĐ°ˆÇWK>üŮZM7AŘđ>2‰_ŕő4 !Y]Y-q:†ŰíD`ą´”@iw ŹÄ4ýąýJýpŢĽĺe2;1ǚřZ{8ľł6[ÚtšždUć§ë5lm°mNź[jĂrui­­ąb°9píń Dx;řԋg8žąÓ§ĚŸĺ­[ł¤¤ ĄÁqč1E­őľëł“‹L&$ Ł;L0łÄäŠrĚĚÄÉ njŁ3dciv˙SľŞÚőn”fż•éŇ"?[m˙ëqöŁ˙ƒÓeő¨†í~˜üĽÚÔÚfŞß.c˛˛°ÄRÚbmňŻţä]žýĘ{źv#Ć\Q]NűP=śkcŤWO•ŮGĺąÂ–§?¤Ă졔ăAS6][ż­ űíží­–Ÿ(jM•:Ťů˝%ZrÔ<͏ČĚC[wAۍ\œŃ™ RóŇŃě|Ř)t/M kąŠľmňÜ<_śHšC¤¸?FčzţK–i>|F•ŚcŰľáŰ;ďRßŃZželU"|„ĽďX&ÓKLŻX›č–íé\ŃĄ­ĺVŽ.łKL,ä@óŇ}´BŇœĹĎN|î‡?u M Ź'w>S°rʳњëkׇ§˜š[ĂN:ŰdçX,($;?ĎlôP3Ýî5błeřÇheŰuĺţ^’ýV˘K™beÝaÇÝP,”†?â´ľűĐůşŹ„JôżË=U°ÝÇ×_ŞŰśmGÍmښşŢŠ=Âł9Ă)o‚[ó$29śÝlˇÜöĄlJlc+Ş'joťQŠ}”+” Ăš—ăáꨥM—ůnľôŰ}ąÇ{ě'ś;„śˇŇ˜Zq°”\čNaˇŽœ^Ţâi]2Ăňj) [˘D|^šZŰ9.e˙='&ě˛cˇŮń…ŰxöÉNB$š5Äxa˜_sřˆxňĎođء=Çôŕcë‚ȉÓ<Ó&ěu E9űdÇ]& C÷ÜîPhaŁëL'ƒöźR4ÍÇ{čq¤š5ĚdĚĺeLĐź!Ú\ůçî0çž>Fť ŔN0äžŐ1JČŔpů 7ˆźN‚<Ű}­“kŒĆň_‰ĺúą•Ť)™dčŢ4+˛žžN˘ŽüsœĄžéi “0đ6ä/W—YĆǙĎ4÷ĺšŢ(-!?ŃĆ('Oá§>v†ţâ L§ŠŁÖ€ŸŰE¨ŠƒçN5bĎĆš;žŠdk™űđm…nóřÚóůř‚Ţ˝Črm´ćúÚUXł‹$$2LÍM›ÉĹó ¤°<Ďä6ë?vś#ĂďĂoŔF ˜—˝lťŢż—dż•č2ÇÔřkŇ ľ§#_^šHwĎF!Ÿşiô•r¸tĺú/W—Ůx%úßőž*ŘîöÝYTžňÚśr}m;*nWz?Qoţ\AGą•—ŻëŇÚ[ŔĄ 0B\xî<Ÿ¸x–?}šçĎăL{€Í˜ľŒöA4Đsá"ţłĎňń.÷ŁÓʡŁÄ6ś˘z˘ÓŢúsúüřDË:ސ—´"Aǃ÷Ó6mÉđ?°ĽŠíŁÜXĄ$–ŰÎ?Ę~üm'v‹JŠŤŠŠ…MWônűőŰĘcŚý•ŃŢąÝÎ\ŰťůČ cjŁ˘G"‘Ż<ŘíMˆ˙6~čn>ó‘^Ú4„Ř}aŽwzXÍłlHÖWÓŘ˝^B‘(˝maBś ssqâ非QčZŰhu ,a§šŤ‹'ŽľŃq’‹ĎĐó‹Ů|§%ĐÍç_8A[ƒěŢ˝ÝM8â“L'ˇd›[gj:NJwŃÜÖ‰îVzš}83Ë Ý˝Ë•ńľ‡żş‘öfÜ3wxkĆ ëxçzŰ8ŢŮHЊsűć]îä ˇĆ\Bŕöéém٧ľ‰ÎÁňč0“F”ˇ ´…cţ4#SkäĘČ[öń3é"b/yţFŽu8ˆ.˛5^ËŚAä䡜;_s{ŹdœXÜÄläÔń.úşZh÷d˝=Äźť‰—7ŇÂń°Il2AşL]ĘL‚‰šu¤ĂM´š‰ŢŽ&:=Ř3KÜš9ČŕĘĆîJIâ) ݤ§ťžîV:C˛KS\ż9ĚŘşľM™‡9V°štËžpą€!@h¸ĂMÂäÄň.ç;–oŁľÖ׎dM\-M„ĺ<ýwŘ< Ä")<kr˛<:Ä˝řĂ9îlGKč˝řüů( žh ÇFĆg˜*ÇŽ+ň÷˘W+Ĺ~+ĐĽľgzÜÁFúNtsş3Œ7;Çľţd´‰ĆÍí­D˛łŒ-ď1I¨Bý—SGŒ&ůlE6^‰ţ÷¸§ ś{ýE ôđůߌ 6ÎĆÜYo ˙‰˛}mtjőŃw*ˇ]ŮrűĆ;´ŢÁć ŃÓAŸŸfvŁB,C×ĺ´ˇvŸśhŸM`ظ] xÜ.|^/Ń(ÝĹ™8ëVíƒî§ďL AĂŔí–ĚŒ-ąžSš—Ó~oXDŮőDyţśU6O¨`S‹¸Ď>Ë'{óťź ‘ÖVşl+ Ëv^zžwó#OQűŸČVn%Őľeę°är܆ýřŰNuŰnąS˛ąô¸jƒšŘ4•˝Űţüś˛˜i?e´”XŰ3śŰ“h{+ňĹĄałŮ}}}2Î›ëNŐ˝ţ[áăéžř,ĎD vímޚVďĽ"ź|îůFŚß˝Ě ľ\qÄPöŤP}„ť•O>ßKD[çţ•›\ĎyBˇá 5sţl'͈^ĺ•űĺMUÔZyńă˝D’źúćČ6;­*JAŐľĺQK›VÔ/ĘOę—ËUŻ,)BsŠř S:ŢhORMWP”ý*Îp˜ÖĘ w‹F#¤™een‚ţɁ×ď.űŘŠiB˛6ˇˆŠË@Őľű˘–6­¨#”Ÿ9TgľîzĎňé§{éh {éiq‘˜šS_›Geż Ĺ㈴ňçn ›G6+Eŕ°ĺ×ëĺ2Ů27,ąŃÜӌo}šŤĂ+jł“’Quí~ŠM+ęĺ'G‘Cű8¤9=œůiÄ.ŸÇĚJýœUg†DŰZŽzŢWSPGeż ĹăGjv’ą?=î.žIqmd‘xĘĂA¨šƒ ­vČ­pwtšźăx„†žœć­ÁÓőr&ÇAŐľűŁf6­¨+”Ÿ=eÍŞŢx‚/>Քßd €•šâŸÜgV}Žzá ńÄ˝ôíXk‹ ÜäîÖĹĺ E˘ěWĄx<v/]]-tF|ř]vlşË$J_\`xtŠÉ5ÖŞŽÝ?ĘŚ”Ÿ-\.×an°¤P( …BĄP( ĹŁ¨ – …BĄP( …BQ—¨ÎŞBĄP( …BĄP(ęŐYU( …BĄP( EÝĄ:Ť …BĄP( …BĄ¨;ŽÖšĆBÇĺóÓń’›clUm4˝/„7¤%ě`yl‚™ôa tH”Ł͆×ď§9ÜŔzlœXňŔ¤TlĽëƒz”IĄ8(öŃŚhŽOœî¤ĂďŔF–řě$×&Y̖v]Q;”îŁb&E82U=ÜËçžlÁkŔ"ś6ŽÁ}ŕn?Í'úB¸ 2ÉŔlŒ™z:čVóĐwń,§]ŤÜ|˙ƒkeČfđěóÇi\âG×gYßĺÖrôŕl=ĹgĎDhĐ™ahi‚X˛ŽtśÁ~twD¨Çú Ş2Uť ?6ńĄĄNËr׺t/™u/gŸ:IËâ-^žG†ó™§{yAKóƒë d÷şžÁëIŸő$ËľÔ}‰7?ő\;žmćJi‘M'Y^Zbt4ĆčrY¸çóiǝͥů{RŹ,Ǚ1ź>çŚÖŁ}쑉™uϑ™l. óęۃL|XG˙ŞĚZl€×.O°XŻçÚÚ<4lN?́ňžŠh./§ACЇgÓ•ĘŃCjň./ż;Âl˝ÇľÝęą>¨ŞLŐ.ÁM|h¨Ó˛Üľ.ÝCf#ÔBˇ;Íää2i h`s:°‰˝Żď‹zŇg=ÉR Śş/š<Ÿ˝úŻ\ądŠĄ+ďńWŢć;Ż_ĺíűËhávžyîĎ49…{ţôŐ÷yíú$KfţžáŤďóWŢâŰŻ}ŔëˇgIyšyňâSźŘă9#7uhťqdb&EÝSfgŐ ÜÚJłł–5”A¸­–†­Ďdט^Šuďj§ç?fH‹T|‘šzýʕYar!Irm‘ŘŇv5ÝÎĺ$ÓRd:MjŻ×+KéÄłť ŐÖ{ęî ¨Ľ/T}PU”iö_Y~•đ!Š+덺ńď-ěV—î*łŔă÷`G" ˇć֗‰ÍÎrűţërŻëű”ťžôy€˛8ƒMœčŕŢ5 ŹąîË@ši–ć–ˆ›™T†t.G&ľÎěÄoܜf]8é<ŐA“^¸'—baf‘Ĺ\ţžt2M:g’ËډĎNđΕQć-ƒČń^z]G Ť'[-‰ƒŒ™T{ô8SÖ§ÍÓÄůS-ÄŻM3Ş@šˇ…'Oˇ°te’Šmćś×Úä÷zţㅬš>+FŽ3xůw¸ź[9Éô: |kÉÓňô ëViöĐÝAqžTEQ™öa˙•äW Žş˛Ž¨˙ޞęŇ=dśŮ  HŹŐŽ\)\{\߯Ču¤Ďƒ’E8hîéá|Ł 1÷—ŚvîřÔT÷U$ť0ĎtŚ™^GfŸ`ziďšXŽĎ3ąÜM$äĄ)dăîzć$ÝődŤep1“joJYŐBœ{˘@ 'k až<ßAđ&'öó" Ű#Sö,'™deÍbm-y4֥ԈítwP(_ŞŮ™ůU‚*ßĂç0ýťRv’Y §sűďç{]ŻĽl‡AÍe‘iĆFçIË˝?Ž„̑ÎJ6ö•'ł¤˛8uRü{ROśZ+4]ߥƒ"0ô‡_^ľG?%Ő>öă<Ő!`×@čô\ü(DŽ@Éäőwxk:?íMŘ˝ôôśÓÝčĂë4ĐĚ,k‰8ăcăܛI˛óˇ;`çqž9Áo€Ţg^ ‹Řľˇ<ăBÇ×ŇÉšž(n+˝Ćěä7†X+NŞ;iíîäDK€@ƒ ]š$×V˜çv,‘_ƒQÉó‹E)ő˝5;ÁHˆÖĆ0­ńËýL4´qîXQ 2IfbÜœe9ˇőş{:č‰úđ9 4+CbiÁÁ1†WJ˜˘9ˆv´s˘5HČeÇ&LÖI¤c›oO ü=çřä Ú+K|ôŻŢ]ĆŇ<ůąÓséůľ#f†ĺąüľ˝%›‡ÎöFšĂ˘ÁđúXYj9É#7Ż3•]´!.G%č´ůX7gۃřl’ôz‚ЉqnŻPźGSĹeW‰˝ě¨ť"ylşzÚé‰úđŘ44a‘\YdxhŒÁĹ̃´•É]ş/U^_lCŠőAĎ­ŠœÂɉgŸćBPCšYVĆxe ž˝?ě×ţKΏ lěËWsŇŇÝI_kžV†Őř#ĂcÜ_Ě<Đ]šőoKcˆÖ°ÉŤˇ™ vsž+DŔ!ČŹ­012B˙ä:öpg7Óęľ#r)ćg&éœfi›Ýd>\ţ],‰ué.2;Â\č‰ Ú@әçřҐ™iŢřń ńŕî×g2w–łOó|›ƒąŹ•ceô6/ß]FzÚřäsÝD Qž4S ÷ßeŢŢ]ŸťęÉÄíŕěąVÚ}‹ÔĘ“cc\‰­ĺóąGyáĹV޿̍ĺBÎ6/=Ç:9Őĭ秸÷ě,KĹąƒ†ˇŠÓ]D˝:dSë,ĚÇY÷„Ń“ܛ۞Ź÷*› ÝW˙ÜdÔŢƓ}­45X,Ođţí9•Ž˘Đě4ŘČ,Ů\‰CyŽŤ0bœÉäv︗)˙îv#ś­^ťĚĺš †öˆ™ wŽŚ ŃHˆfżÉݡŽr{U:Ţp„ÖĆ͍ABšŻź=ΊÜ_ěŽ8:č‘Hä+Ś™7:!ăżěväĘ:x}ř “ůŃa&—˜œ]d&žÎz„3ÂĹçÎp*$˜ćú˝ †çÖŔß̊ޢr™‰ĽĚ ťMŒŻ!˝~|†ÉěČ}nÇ ĎXc=—OhiŁÍ-Ŕá§Óo21<ĆÝŘ2YO„žś&Zí FçRůç;ç.đ|‡š;ˇštcˆ[c ŹťšyâxÍÚ2c‹iŹ’Ÿ˙(埡p…9uŹž&.› ›ÓGOTczdŒń%’ !şŰščp§ŸYŰŹäí!ž~î,güY†űoóέQîϛ;;ék÷’žže×ĺ ş‡ž‹çyśÝMff„÷ű‡č™e.eŽřqë9bSĚŚK×Y2>Ăý9‹pKˇf2Ő˙?)teŠéńyrĄfš˜ĺқ7¸>›.yz¤p¸iŽ„ikňáŇ š0ĹčrŽ ;3›!łľ.-G;ąëëü IDAT g#ŇŢB“C {C4i‹ÜźuŸţŃŽ§ľÓfK06_°Á}”]%ö˛łî ŘC<ý‘łœ dşŃĎۡGš;•&ÔÓE_Gą0Ë\ZîCîŇĘhőĹćłĘŞ(˙šĺËš!$f&˜X•€†ŻŤgÚuîßá'Wš3—ÚŃŞa˙ĽĺW‰TůÚh{âϡkÄîÜáíţQîMŻa‹vrś7‚->ËLRV\˙şmv\Ą0îÃc LŽ˘‡š9ŢŃHŁ?D_ˇ›Ő‰1ú‡g˜—^z:[č䘜JđĐDÁ(Ł.ÝMfI~ŮFŇ â$bC\šeb&ÎŇz†ŹÜýúĂ"JVçŚYąÓÚěÁN†‘Ťďó“ńdŢ×2 FĆ×pľEđŽóڥیd]{ës=Í,/›Íěă9ĆűŻsyfÓJl‘vΡúhČ,2´Xřť•!ž”Ăßš:Ώ.ÝbxY*‹žö3|ú\3žäď]žĂĺÁ)f˛zľĐdÄůŕÝAŚvŘÎwŻ˛ÉąŸřÇ@â §ŁĹéUŒ`€p €#1Elˇn…“–Ž(!=ËüÄtQ[-pľtsžĹ…ž[âî˝yVŹ˝î#ĐΓ˝~œr•ĄťS,첾qYňďi73ŒO][*g—ű2b&›/BGk#!'ůňšËäó6E˙öŢ,6˛,˝óűűž#‚;™űZ{UwuuˇZęn4#–4śĆlX~˛ řÁ€žý:~ lcÇxŒńŒ,uľJŞęŞęĘľrcrÉ$“dŒ•ÁŘ×{ýĚLŕ’y~@"AĆeœď|ç;˙łŢs…Ű PĎ3żźAí}wÉŮÁd2uś ¸Ił¸š%×P)¤S,ÄźXImŚ`$z~‚QťFzö ˇ2¤ %Öł)˙”ٲŔä$ç÷=šľE>da%ł9s­RH'Yˆ'Xˆ'÷8°Aŕëüööł‰ ҙ-‘VŽh”ČËőbŁŃ°ĄÖÉĺĘÔT ľQ!>'Ą*xG˘ ťI˙%úň­•’Üťó€űé ŕąW¸wkš§Ť9ŇŮ4O.°ŇK(őeÎO2îĐX›a*SĽĄŞTók  ü¸ę7RYĺë§I2ĺ:ľZ•l2CŚą#oű šůŚVŰ+> óśďqp J‰5:_Ń*ëLOMń0šs´Ům9uá‡Ă\Ć î?ŒłV¨QŠYžžcś psŢ%8jŮu/űűŽ-ö@ćůӛľš']Ň@ą ÚG˛ť“2:Ş^ě*ŒÎô@wş˝°Sŕˆ]ŕGlĚ<ćëgë”™îuüúcě˜Ę×`"bAËÄy’(Skľ¨•r,gkhŠ•HІčRżOľľ•âë[sĚ&r¤ÓkܟNRĆD hdéţ#n/¤IŽçx1óœg% “/ʨ{ŤÍocý˝ZzÍj%O<‘&]n,ę…uâ‰4ńT‘Şvřç{x•j:ÎóövPË˛mk§°:đšURËkŹ7;őg~ŞgYÎś@ [|§y1!p…ül Ĺĺ%dRÉÄWľĽŤžƒâć܄ ćg–H”›´šu֗ç™Î¨“—‘yWZ–ÍŃú?˘6^ÜĘŁ6ş~_GÁlw3|î?žŔBľ™ŹtŸŽP0ۜDGÎńŮťƒxD“ôłv?ˆÎíď4nÎnŹvE}ŚJf™ť÷žłźłĎ¨ŐIĚĎń›Š4ŰozňĆźâtâ5€VŤPŘľŠŚQ,UPąăt;1SěÉ@AUwȑŚmžC(^ c+Çýoďąh‡âFy›€iĐ>9@ˆ—?éć¨ůVŐÝéśOM›‡€âtmŚQĽ¸ł–6šÔ§Ý†C@nl‡›€´Ććěúačô™šO°˜äšÇËHŘĚârť …˝+ –7ŽĽ{r(şýp(*…ByGٍQŠÖѰâpŰą8G*ť])v/!NźF UĽ°uĆQ+3{ë;ćfKCń-ćŁzщčMˇqD;Íţ1>EpiYn-ćĎD#{ÔƒŢ”ŻV)­jř1>ýÄÂěó8ó‰<…•ç|˝˛™Ž÷héěĚŠŚíw*řëk;”-N8Ş6ďäŹÔďŢkiď)%ŇdĎť şýDŹqć*´OŔ ;hećXí`ˇŢň­ĽłdZ~^ÂÖE6* \>Ě5r—ƒhČĘÓbM˜ ěhóŹvŃ!ę(V„‚ň˛ŠÖözöőŤ^Ýp´zŽQ,”7'ďd–ČčI\Ť2˙ŕ ł•fłAľŢÁDˆVeáÁSžU 8ƒÜ8çÇbj‘ËŐş8ˆqűˇž¸yÓcő5‡÷™LŃšOň–Đ›ăÝL&,h6÷쐊&M Lćösľclß´z™L]`˛:ŘÍXĚfl67~Cžü8ň˝™†°„ůÁOƒ;*şBű<}Úaą` Uktş#B—Ď´ ‹ń .{źcAěńJŠ›XŔHy%ÓŐ`Śt㇃ѨÖvĎĹžz˙ŰdÂl>ZŮőa6c 5›ťg‘5•ćËűˆ1w('Ľ:ÓmÉN…Đp„Fł…fôqyÂK|*§ďШłJ/ĘWÝŕÉă8ţ›Cř._pér…D|™'Ďdë=Jç(ôťžčä¸ęwďľ´÷hŐ Ëš1‚~ą ™gKu°řˆšT’;\ Öë§ú:+9•€“€‰Ůĺ&Ž {9ĹWó6~p=ˆ7ěÇą§ht3ŕ†ělśo>ÔŞEruđ›­8í /2ഛ¨lö8„°SŽX˙Žv‰J˝RĄ ëţN•ZšD.Ż‘Ű(Ą9ßç“hŒ#Iţn^żöľ_gÜź=ąÚAŸI Ť’=9śłČŠ˝Ţ…ÁććŐ1F=Fšĺ"ëĹ*•šrlöô*­šâÖw‹ěž:LCk5Ší75(D{›Şîą5FěiŸ^Ÿ•׏÷2č 3l_eÖ`Ŕ\e1Ůíŕ>ЅDSií1ťýúó׍4]—]@§Kd'i÷Ié…Ţt÷^Ł’˜ăË9ď~§ßîűUúIŤąš*p3ŕ!đ`Љm”S2)+‰fáÍŐły§—€(0ĽăŕAݨĚ>Ď1tÉĂŘäˏÖČ7ěĄÎ ´ŠqŚVú˜>'§ă‡Ódu)E)Ă7%¸řŒnˇ==qóVÄŞŽ>“D˛“Ţ VöąÓF#{˝ޘŒíăšëc]UĹčĺć{癰։?šÇw˛÷n*^Ţâ=ęęęqäťŃ ŽQV˝NUo_ˇŮ¤ĄĹ``Wv…ŁqGsҍĎYć“ubƒ†ŁN˛&–rŠř)Ů č÷ĂĄh{ÎŹšŒí*ժթՏXv˝f3^MĂÁ˙¨1ץÇŽzÓ=’Ůľů"|˙b€ŸM:9q€ĹŰŤč9HńLҋň f‹ jyćgňĚϚđĸvaˆˆ=Äľ‘U֒'ÜîôťžtaĎąÔďžki¨$Ód.x űü„ÍY”°‹fz†D§ý˙.üTIeYżŕÁď󰉸jŹN—P›Uâ™&Ăą •œĂƒqc…•^źľ/…Ĺ)ţž5ʍ‰1~ţłqš-A4XOĚóŐĚ :ÇBŰ9­ýžQsI–JQ.;BL†Iíw,˛^ş‰›ˇ"V;č3ľßܑHvѓ–Ôb\ „نk×ár—Ó†‚F1źűŃ_ˆ!Ť@-Źń8^é⽄ƒ9Ž|ŤĽy„É‚˝‹Š­\Ą¨ľˇnŮvŠ€ÉŠkG+ӝĎZ$—S”4;6ÎŐ°™Rňôlý~č‡ĂŠ@e}˝@ăˆe×k^ĆŠ§őđçúe÷Ié…Ţt{c§JnažůІÉ7ÂľžÚŠŚ~Ža~úŮν<1Xk[{Á7O’T5ÍfA;áv§ßő¤[{ú]żGKŽVͲœSÁč!6$ćSY[Íuüîx7~Ň*YV Âěex,€ŻžÎJ^š$9ę(ń›XOöo đkZä3ëŹ×TJ+łüúËďř÷ŸßâďĆŰWÓÚďë­ÄŇj U‰‡śnt4şŠ›ˇ6Vˇ÷™ÚýM•öÎŕÎĎIźů菪´Ď0(;˙Ş™ăE˘ŽŚ¸ŽXˇOŒ\ Řj‰ĹŐŇ!Ëü¤ŃŠÁОŮkľśżĂŁ0íY tŚßł|@cĺLCaËŽI'ĹbÁz€­ZmľźŠ0š ď8ŢŃâßńˇú}ÖFÝH˛XÔ67Ë~§ Ü×ůŏßĺØőhúăDŻGě>œBqńĄ–áŮZ íˆe×s^Ůădh`÷)›‡#Ç\›ăĐ čMˇWv6sLÍd¨bbđÂá#lzŤ“=ˇĄW~V܎íkwB4ʕęIĹŃKŢŇúÝ{-íuVÖ6hb$rn„p+ËRVǔu7~ŇŞŹŚJ¨ÂĘȐ—F*Cvł!l¤Ó$`đGs”ˆ'÷żkšg˜ƒ|řń.š <™NS¨7Ůç Uýœtý;2…Ő$Y Ţă]ożƒŽę×ŰŤô™6íʗUfś­F+x‚žÝdŔéh%ýÄ ˙ęŐ ÎBźú÷ňç×˙Ť˜ź {L˜¨“Ż)¸!b–*ŮJ“Rž†#$öâh5¨Š V§É˓\đ@öů4÷ľCŢaT1z#ŒxL˜¨‘Ť*¸abć يŠŃîc|8„Ď,ĐęE’š őÍľxCœňâP4ęĹÉBƒfËDhȏÓ,('ŇdFG€Ť7'w@˝˜#UhźšŃ9(ý˝ě՛oĹâadd€°M 5J$2%j›y0šLůqĄYɓبŃÔT %P4@8čĂ%Z¨ÂˆÝéapd”÷ŻD1çR$÷žth’Ż˜ˆEý„\‚őtžRK`őóáEŒ˜h”ÖIäťńŮK”A ˘œŕÁ\ŽĘNS„…á “ŒşÍ¸•ĎV÷żĘĂ`ő02źé§z‰Dśźé§nĘIżöm&^^pm5ŕńŮiĺóŹW[hŠ…Čšó\¨,>šf&ߎZvÝÄËAžS)UQ?Á Ň˘šŐžËĚš$‰JóČv\F˝Ń ˝zĐŇ]_ő>/09üŒŰ65J¤ÖŤÔUh–Ѝţ˘n~{‹RąBšĄîŰčuüô}ÝÄXżËWXźLyńš5 ĺ&Â`ÂápóR Ż–ăѓ8ëÍnô×˝%Że’Ů—y5ŕ G™p`*•\ŽLĽ}¨Á֎3żE Ö [âěm­ßúľô ř3X˝Œ„ Y4+dre*[FT‡}~ÍŞB`$€Çd śśŔƒÄîN÷ţěÂOőŚ™Ą!Vę,Î-°úrIJ­ƒ;ˀ–‹są°kĺŹçőTŘá1ن|DÂA†ŁAbAnłFšTĺ +ĆöýQű?ŇëeŞ•ĽŔhu2‹0r`ƒhQŠ6¨6ZűëˆŃ‚?<ŔxąM´Ó̗ëԚ›iśjo„˜Ă‚Ë.Úş|ŔɝŮß]ܜŠX6ĆoŢä'׆ŠÄ7űfuő™Úy)7­ GÝřě‚ljƒ’f&8zž"Fš&3Ѥ°žAŽö˛ íŚO(9+˜L&ÄŋľZ­˝ýŕÁ*(ö 7ތ2ěłbĄEi#Ăěě"óůöœ0ťŸb<ěĆe1"ÔĽ|ŽĺĹ%f•ŽNÂś 7Ż1âľ`Қsiff^°häżÚön„ÖHđős”ÇoňłsÎmďĎ´2süő"8Â;çŰľjƒF­HüĹ*őĄëźjOÁ4ÓłüőŐŇ™Ç=mî0ߊwŒ_|4„sëĚP3Ëí/§H„ŻđËŤžmE>˙f‘ ŒÎ 'b ů8Ě ZłF.“döYœĺâa3pŤ?ĆŐɢ.3BmQ+­ólvíÜ;źhűĄ•›çWß­ĐŇéłWX"|öŮ$öĹüíLaϕUďř5~4accö_-î}Ÿâç îá§',lî'ꦜôů!ţúđÄm_aăâÇď2ž›ćvŃĂĽ‘^¨šJ5Ÿĺůó%^ä›ŰňŐmŮu/żž2đɇűÎčpa"ĆPŔ‰ÓŹ 6Şä2ižÍÇY*źößŃbîđ2:Š^ÂťĐƒ5*šţt;}Ţ0p‘ňNhűű‚$żůb†U÷?űxŻ Qzńˆ˙ďéĆŽzŇëř?čűíÝkR?Ëa&‹2ńt۰›Ôz•\6Ĺěł8ńRkËŁGĐßV–Ű_NÓ¸ř!ŸD[V$4Ę/ń7Š ż|?şm6żgłŹnÜŰYż;×ŇĎgĚüp›í{ÄŚVaúˇwy¸Ąíť[>?Łď}Ŕ‡Á&Ďnßá^v{m뤎éö“príӛ\4&řęË9[1E.ń7üä§ďňŋ탑~Ôӊ+ĘűďL0¸÷rü2_ß^ ľÇ~ÓN}¤ú§Őyvç÷2—ĽpňóO†÷¸űW#;s—ż›ŻěęKě˙7*é§wůűM˙[b—ůýëÍśD#˙ü{ţvś¸ëűôÚŻż~XĹŕăŸ^fŘZe…ż˙ň9é}ĎĐßgçŔ0×ÇC„œf”Vőä ćŠD?źÁ%G{-5u‡XlŻČv×'”œěvťžÁę~˙K$Â5Âď}bíťN;‰D"‘HzpÄřÉ'•2Ďî=â~şŢîÔL¸ün\!bÜÜ}>vZˇęJN+Š-Ćg?š XYć׿YŘăb‰¤7Říť_k‘H:Gąŕzpްg%Cр…ĹeľăL[–™n„™č…Qœ+s̤żöä$cZ"yÉAúv†´Oąšvy„a rÉLݐmœ´eo0g(>$ÉŮAVOC`‚ß{'ŠË(•xiIŠ{8†.óă‹~FZ…édœDíxü&ËŹŒĎ_ĺ}OŠ/çΠŻ'ßżĘe{‘GˇŸ0Wę}N2Śű‚9ȇŸœ#´ńœ/$)ŸáŹźM¤ogJű .Žž{hö żş›C œăgďMđŠRăŻdăŐŢsŚâă4˝kNłmzxSň!9ČmŔ'H+3ĎŻżcYŽ č˘Ÿćďî.“U?mYfúąLňńPƒŠGq6Îâ•~&'^FŤ‡ˆˇ?ó{'Óý@ąťZŘ|nœň†ł3Ăk}ŰÝą<čłÓ†ŃeĚQceeƒš( FŔdľ`’ńŘÎR|‡ŚwÍiśMoJ>$§‚S8X5$j{ZF)ĂZţ,÷PO ź4•j.KŞŇĎFqż|W™śzĐĽ=FW/¨-.0F–׏žÎ{qźTÇzž•L…J)K|˝šÇ_ô ŹŽ%Ś­V§ŞVŤQݕĽÓۧÓⓗúśWôŮiBŕô81ŁĄmšÚ,oO&™z–’Ťü}ăxăc—NëyöPM?;×ś>kÎq´›’ˇ†S7XU\Q޹΍+—š9°9Ź•™ť{‡˙÷Ť§{¸{WVýéăDŤ•)´ UŞěœśŘ> œ6Ÿ‡g!FM&#36Kť#ŹÜť?ĂTFnî7Ç{鴞gŃôąó%Çd[ß5çŘÚMÉŰŔŠŹ*śďÜĆ×'ŤƒaŸ Œ9ťŁ—~—×IqŇů:éôwŇľ=Š‹ń!'ÍT’•z_Lë=ZĹijÚîN—0švm!ÂA?O‹™oî3UÔŽ@XČK$äĂߌóůˇKäľv~}A˙f~ ,Ý}Ä ó ď\Œ1`SŮX[ŕöTŠ‚ú2NĆƇťq[(jÂz†ššEćó:śqîč×ÇÄFÔZ‰äĘ2Ÿg(íČţá~8ĂĂ\Œ1ä6"PŠć×YY\ä^źÔNs˜O?&ű.76ĽÔäb|r„KC>ĐZ5ćżżËÝÔÖ.gçĺŐYů‚b!<<Äů˜żÝŒI´(*h–˝•źű4ťˆĂNËĚ`%66Âůh;N Z‹J)ĎęŇSńBű˝*Ýé <ă×ůÉy7旮Pä^<ĺ×3¨/ďüđ2“vĐZu6§ŰŸŃIÜĄ^Š7İM%ý,ˇű@“Í: ů‰LŹÜŸ"áăƨŻEP/ĺY^XŕńJs`Ťç"Ä\fDłJ:ąÂăš5Öw~iG>~eށ!.†ť,X Ш–É¤s” …fSM09  x űlŚďđ‹5´#úŚß1Ýą&˘Ÿę.-|̲­­ýa§iíת,é0.ő”Ńžub‰´ç"ŸuŮ&lĂh# ˆz›<ýíĺčW‡|x, ­ÍśîŃ|†â!gťé‡ľ3ڙNëyv_Mߍź;Ô;]v@_lŰĘ1iÎQŰÍ5_ňö`ƒŐjľ•Fńęß˟ťŸ ă1ĆÂněffŤ‹ń°ÂÚÂÓË9*6?cƒ ;Ş,%JŻ‚XXƒź˙Ń.ůŠ…yĚ.3Ÿ*'ÂĽ‰(amƒĺő:* f“ ’+Ąš<¸-’ ϘŠgYIfIäJ”÷Ź&ŻÝä“!…řÓ§|űřłk%LáŽN1ĺ’äL~†c!†ýVŒ4H/Ż‘Ş„o Ěh,DŘn€zžůĺ j€°¸49Čř€ťÉˆ†…ńaŮľ"FŸ—€×‹Ľ°J꤁ŮĎ{]劧Áüă)~űäĎŇ-|##\rQ[Krđk Ţč ƒ#žËó‹ĚÄ7h8ƒŒ3x‘Şžî”uä×ŐŇńdßp—h˛ôřwŻ—¸LÁ!nÄÜŘęYžg7ŻÖÉ­7ńŒ„q—řâë'<ßu˘_gĺŐyůĄN.žƒ‡Ô Ü~üœÇ IRU# ‡ĄI&žJ˛Ś7ćö.‹ÎâPg™ 3Ă×oňɰ‰ÔÓ)ž~řœ'‹Ęö×Î Q6XĚÖşŞľ\‚g)•@ԋCiąúřż°9@ĐŞŹ-Ľiú# äëß<äArłáë(nť­—ďĐç} çVIďXYÝZÇ&3v€aG•ůšEŚWŠüÎ ‡yü\sP\^äń|‚´ćb|$ʘˇÉʒƒĆ IDATjW_ŰąŰś9‡Žđ;×#8+ŤÜşű”ťsŤ$N&&Ł sÜůnŽŐ‹ƒH0Ŕŕ€ť•Ě*/6š:bĺbşcM:\?“ÂżE M˜ŹîMí_dzi}_íh5ęÔ_ubű§ń‰ŠNîđٞÇč.ŽIGuՍś]m}ƒBb™ĺmúż˙g'ß.ľWŻ´Z™ŠŮKĐ.(ğsďy’ĺDŽőrfÇvśýŠŤ/°ĆĽŽ2:¸N´ćňőbK›°3:!.E :° X=AFŹž<~ĆÅFçĆuÖXN”6'$÷Ž‹;¨ťŚG§{Łé;ËťS˝ÓcçÁôŢś]Ľz,šs´vłC͗ź5˜LŚÎśkĺ4î?ćAŚ(¸íUîߞazmƒt6ÍӇ Ź4ŔŠ0d}ůWF˘ç'ľk¤gŸp{!CşPb=›âń÷O™-LNrŢ)€ůt’…•ĚćL´J!d!ž`!žÜ˙ĐK€‰ˆ-çI˘L­Ő˘VĘąœ­Ą)V"AŐĚ2wď=gygAŤ“˜Ÿă7Sé]łĘZ)É˝;¸Ÿn˘6^ÜĘŁ™§™8?ɸCcmv†ŠL•†ŞRÍŻń`aŐäá⨝ýÖ‡X硡ç˜MlÎ¤xüh‰´*pDŁD^­ëń+Pϲœm0:ˇŘ˘y1!p…ü¸ˇ,č(./!“J&žşĎ@ť“ňŇiçž(ř'.pŐo¤˛:Ë×O“dĘujľ*Ůd†Lcg\5M˝qŘa™}Œ†ÍľN.WŚŚj¨ ńš8 UÁ;Ľý:Kwő ™_ajľ=kz0os‰“€KPJŹńş?ŘiÜvY/7Ó𸏾Jqç^ÖąďS-@`mĽřúÖł‰éô÷§“”1Yş˙ˆŰ i’ë9^Ě<çYIĂä‹2ş5h;ö1 ¸97áĹB…ů™%ĺ&­főĺyŚ3*Âäe$Ôö˘VYgzjŠ‡ÉKÝúŚß1­C“:ĐOśiĄ‚Ç^áŢ­ižŽćĐţ˝čŸĆ ]:Üůł=ŃŽ|ŇŐS7şć4´K VňÄiŇĺv7ş^X'žHO7úŇggç}˝Đ—zʨƒ:ŃŇÝ&ěáËü*ˇďLń´ 0ăłš˙ý –óU*•"Ë3łLohXĂŁ\ôÜËŠtŃÓŁÓ˝ŃôĺÝĄŢéąóznŰ.ŽGsŽÔnvŇ.IŢ:těoQ­ľĐĐŘXY!šu–¨UfŁÚ4űËmlF#a3B-°´VÝ>s×*˛´VAS Gtť-_˜(N7žW­@­l°–Jńlms6QmRoíÝҍ}î\kQŠśĐ€Z2Î|IƒV‘…gËĚĚÍň8ŐŁńˆĄćYImWáęF‘Š&°ű˝Ř_y…Jrq…ő-u[ŤWČ×ĂQüÚ$‘Ü IŰ×K[‘€§Ÿ˜ăĺ§ßƒ]ÍOŐť?,Ąĺođ0>hGŃ*źXČrčm1ÇsŰé°ĚÔĽš7çG]Ż+]ŤNľ (ŚŁŮ‘Ž§(h`†‰niMţaC••Ä–Žzˇű ĚŘŹ­^§şď’O‹ĘŚŚä×Räśúą\ڤ­"ÉܖžŠś9řœ[OÔácaqŕľĐĘ䡭ˆ4(”ęhđşí[ÄQĽŢhőćŕ~Ç´Ž˛íX?_iĄF.ށö÷ŽlÔĎşcż‡1Ú ˝Đ´žëO7vžĽvЃžŔ>iukzôŤŁzŤłMŘ­AľŢöR5™dmkÝ×ŞŹĽ+¨ÂL4ě:ź3ŠłŚG§{ŤéúôNڇŃ;Űş˘gý¨îÚÍNâ[ňöŃŐ|ŞŞîąR˘ˆÍƒ @q:ń@ŤU(욽Ó(–*¨Řqş˜)ŢiŰ­R [Őđ;b|ú‰…Ůçqćy +ĎůzĽ‹/Ü;Š…ňć!! 2K d6?Qܮ͉~ÔśŽĽ_/9kôď¨<“ ‹šÍ=W.ŐF“Ś&sűšŽxP7xň8Ž˙ć~G€Ë×\ş\!_ćÉóŮś¸čAŰĎśÍ< K˜ü4¸c–RÁ,@k´hô˛׍_ëëŹäTN&f—›¸‚>ěĺ_ÍŰřÁő ްÇBœ˘Ń̀˛łYŽôZ@Ę_X,XhŐZgśGĚu‰V/“Š LVť‹ŮŒÍćĆočUă\öx ƂŘă+”7ą€‘ňJf{ÇűXâV{ŐpúXŤÉŐÁośâ´ (źtŽ§Ý„@eٰłcÖúÓ =eŰ:ý<hźž<Ÿ„f…iZßőç-i—öí V§ąÖquÚďŃÓ&ŠFsU2ľŐB F#ĆŁÍwěNQ‡NŸ¤ŚëJ[X9÷ţ{\÷l˜Vj†˙p7šĎ.żcć¤űQÇÔŻ—œ-Nô\÷^ôꙞř:ËčHŒ‰˜ŸĹFdô<ᐇďnͰÜÓŠž˝ŃŞ)n}ˇČúŽJŤĄľšÔ:YZę!ťüŞŐXM¸đx0ŋD‚6ĘŠ ™”•D3ȰŰOÄgŢé% LísčB_íÜő€hoQŐ=ś+‰Žâç¤ú g˜›WÇői–‹ŹŤTjJOí)Ż%X;ďeĐf؞ʏ5Ŕ€šĘbrďí^ýŰ&`1´­?†‰Ž}Źn0ű<ÇĐ%c“,?Z#ßT°‡F80Đ*ƙZéSüSLwZś§A?ă0_Nśw’gEÇłg…Nbć8ôç0ޘvI'Ćšž2ę´ŢęmĚÇ#u!”vÚw—ÁĐŁÓ'ŠézŇÖj,M=f}gĎť^îěf„SBżuă,´K’ăĽƒŐFƒšFŁ‘˝^‡QLF ¨7şŸ™ f‹ jyćgňĚϚđĸvaˆˆ=Äľ‘UVf ý;ćşŃ ŽQÖďćő6ÍnüZIeYżŕÁď󰉸jŹN—P›Uâ™&Ăą •œĂƒqc…•ŁîíčEů7›44° ěZŒĆ’y1× F/7ß;τľNüÉ=ž[Ţź{Rńňî@oŻV7Yć“ubƒ†ŁN˛&–rŠřÎí^ǡZbEE¸,XčűYóş|ŹQXœâď[ŁÜ˜ăç?§ŮDƒőÄ<_ÍŹĐÉ-]Ńď˜ÖSś'­ŸĐkIy> Í> ˝Đ´ăПˇŠ]ґVÇąŚ§ŒôÔŰNۄ.ąZŰWŠŐZÚT=:}‚šŽ+m•ňFŽSýÖĺI÷Ł:ˆďĺ™B–œfúv%ŻZ,k0Űpí:MŕrÚPĐ(ć‹í0Â5ĚO?ťÂš—§’i rk/řćI’Ş&°Ů,›3@*íŰyzű^•Z*‘WA˜,؏iş[żj•,+ aö2<ŔW_g%ŻM‰uƒŒřMŹ'¸ŐęvnE+W(jí­“ťÎ)1YqíPŇ㈚nP|!†Źľ°ĆăxĽŁw8ťŁEr9EI¸că\ ›)%wo÷:ž¸UŮȗQ… Ł˙ë7ú}Ü"ŸYg˝ŚRZ™ĺ×_~Çż˙ü÷0Nޏ3ýŽi=eŰš~žŘ¨éČóIhöQ腦‡ţźMíRÇiéˆ5=e¤ŻŢvÖ&t‡żĎŽ‚J.Wě Žşé‡éŃé“Ńô“Oťˇœt?Ş“ř–ź}ôm°J3NjDMq1ąnďô\ Řj‰ĹŐҖ­*íójJ§– +nÇöŠaĄĺĘć˝dZ•|YaĆaŰúĹ ž gw§ąSë,gš ¸ ďîŘ)–ÍUĽ^ҕ_­ĘjŞ„*ʌ yi¤2d7gzé4ÉüĆ%âÉj‡Űe(ŻníÜjrmľźŠ0š ď8šÖ˛ë´ü¤yhžş@1Ú3‘­Öö­>ĘćŮŚŻn$Y,j››€eŸuÇm7öh”29ŠX xű?čŃícs?žÂ%W'Ói ő&űTyú|Ó÷˜Ö[śčgOéƒĆëÉóIhöĄôWGőëOœŞvŠvvƒŽXÓ]F:ęmGmB(Îç‚F´ú:ĎwžťÝôĂôčtĎ4˝ N2íŽčŻć)}84ž%o†`0řW­ötBˆW˙^ţüňĹâax(LČŚ 5ʤ˛eęš&W€É!?n#4+y5ššJ)_Ă {q´ÔTŤÓÇäĺI.x ű|šű‰­ÂŞbôFń˜0Q#WUpÂÄ̲•=Ţđ˛x™ňâ5kĘM„Á„ĂáćĽ^-ÇŁ'ńÍűŘTĘM+ĂQ7>ť ›Ú ¤™ Žžçƒˆ‘ŚÉŒE4)ŹoŤŠh€bń022@Ř&ĐŇëeŞťÔGĽPŇE„ƒ>\˘…*ŒŘGFy˙Js.E˛ş•6Ú}Œ‡đ™Z˝H2WĄžY‰-Ţ熼8z1G˛Đ E7~mSošň`ĽÎâÜŤ/§ŠŐ:¸# š hš8÷ žčPy5ťśó5Mňą¨ŸK°žÎSj Źţa>źčÀ“Ň:‰üŃ|ÓyžTÝeÖl™ ůqšĺDšlCĂčpőć$ă¨s¤ ÍŮi}ő`; Ɗ‰ QNđ`.Geüé‹Ű.íŠ70‡Ł ŰŞźX-îŠ)ĹâŢRÇĘ$ł%j*€W8Ę䀳PŠärd*íĂ= śśďýZ+źň˝Ś×ÇÂÎĐxÉF0ä#2  zp›5ĘĽ*/Ż<5X=Œ oÚY/‘Č–7íěĆ7ýŽéÎËśSýÜŽ…%™—ĺ´ŸöŸýĐř–ŽxÖű˝ŒŃî|rtŐ[7öסƒ>;=í’Áęel$LČ* Y!“+Si˝Ö2˝vvÖŘť\;5=e¤vÜďyI'mžŢÄ$foç}ŁÔ¤…‡/ÂÍëŁ Ť,<žfzóŇكb§›~˜î•ŚwĽwzě<Ě㽜mOúÝw;BťŠşďÜYzÁWrdL&ââŋZ­ÖžŠŘo°jđŽňł÷q)˘=ť!Jk;_M“¸Â/Żúś˝üŞůü›E64făCŒ‡Ý¸,F„Ú ”Ďąź¸ÄL˘˛ëĽra róÚ#^ &­I1—ffćóů=˘S˜ ̌G|Ý6ě&ľ^%—M1ű,Nź´ucŠ‚s`˜ëă!BN3JŤĆzr…GsE˘Ţŕ’C*ŠŠ;|•ňó†ŘvçąVçٝ[ÜËěŽýFg‹1†üf­Y#—I2ű,Îrq˙Í1†đEţńťĄmďh_1Gyü&?;çÜö^[+3Ç_ßYŁŇ…_Űţrríӛ\4&řęË9[L3E.ń7üä§ďňŋÎg°+ŻŽěܞVŒŤ“D]f„Ú˘VZçŮě Úšwx/О–kĺćůŐwq ÝúŚĂ|-Z'ť(ł"8Â;çŰľjƒF­HüĹ*őĄëźj硙žĺŻď$¨vŕ׹DřěłIě‹řŰŢ9ÔˇÝÚcźÂĎŻ˜™ýć{ŚŠŻŁJńŽń‹uŹ•ĺö—Ó4.~Č'Qă–]ň‹GüM*Č/ߏn›oű~–UU`uîcŐĺýw&Üg[E#żĚסČ8ĆůĹGƒŰílfšýĺęÝúŚ˙1ÝQŮv Ÿ{–S3Ëí/§H„Öţýč—Ćë‰çNží}ŒviZçuăo—źüޞú6K2¸_{ő:o'Ý.)Ţ=ęŤVaúˇwy¸%(;ľsĎ8 /°ĹĽýşťŽŁă~Ď&ś ť11öţ‡|”óšN“ Ő¨’Ëf˜ŸłThś'iöíĎlýÎűa˙°XĂÔĄN§`/ÚťÓťŠŤs;bĎř=˘műiq?5ç |ÚnýzÉۀÝnďl°zŘ˙‰äô \#üŢ'!ÖžŰŢA;'W>žÁDišży9Öw…÷C8büä“ ‚J™g÷q?]oߌk0áňG¸qu„ˆrs÷ůüYśJ$É Ň}›đr° ńďżĺ›ľă;‘LN˙zÍÏOHÓe{"‘ôťÝŢÇwV%Éń Xđ=¸ŒW؏ł’!ž?͢ZdúÉ2ŐĐ8W§ăDk €ßj>ÁLŚţŞó ľäSË<^Š˘!py'{ˇ—D"‘tĂin:DN;OPÓe{"‘ô9X•HÎ4ďÄU~ç˝ †m .ĆŁv ŤŠ=îő;ZK|ű´Dôę9FŹ'żCSŰw “‰]‡"°˜Úš›őĆÉ^Ű"‘H$ş9ýmB'čŃéÖ jşlO$’ţ#ŤÉÇhT áÁ(—Żg˜áéŇiÚn¤QŒOóĺôúńŢoťŐä ‹e áˆňţ•!‡“Á€Ébg`ô<7cfhć™yąŃÇk†$‰¤?ôŞMPŹNźÖöAšvˇË1Î5ęŃéŇ jşlO$’ţ#ßY•HÎ8ÂęçÚľ &|fÔR–é'sĚČăňD˜]ŒŽF şńŘ͘ ÔľjĽ}pȋUVäA‰ä ҋ6Á:Ďź;°m€ŞVWůęËg$i‰PNŸ¤ŚËöD"éň€%‰D"‘H$‰D"‘œ:äK‰D"‘H$‰D"9•ČÁŞD"‘H$‰D"‘HNr°*‘H$‰D"‘H$’S‡ŹJ$‰D"‘H$‰äÔĄűŽbĹäęĽaFźV̢ÉFj•Ó+dý0ď-ÇěçúËOăŹËĂ]%‰D"‘H$É[„ž•Uƒ“+7Ď-Ďóůßňä°Ć&řôrSŸ 슓‹~Ěö“ŤœsœŇSëE2DůáÎSj˘D"‘H$‰D"‘ô]ƒUŁ/ˆŁĆĘjžš( FŔdľ`:kƒ)““Ż ŁŐCÄŤ{ů˜¨łňtŽÇ8M81œ´9‰D"‘H$‰DrLčŹ nf44­ý›fyƒx2ÉÔłe­? #ÁA˘ś=FŇő<+™ •R–řiŢcŰĚńdnÇř“§uX"‘H$‰D"‘HzŒŽ%E“É€Í"  Ą•’ÜťŸě—mGFqEyçr”ő{+ŹVv|¨•™ť{‡šąLľDœ…É\œ °đ Mý¤ ’H$‰D"‘H$’>Łk°í?ąZ÷ă*Ă>_*0ŽoePąxçĆ0žCr(ŒŚÓż…Y-ňbľŒi Ć¨í¤‘H$‰D"‘H$’ţ#.^ź¨ŐjľöBźú÷ňgK`ˆëŁÂ>'6cűsEh$řÍ?<#có1<ŕ#ôń´˜ůć>SE 0ŕ ‰…źDB>üÍ8ŸťD^3ž ŸX(@,h`éîc–mƒ\Ÿ ě4A˝B&çá\’ťt…ÉÉčřăa7N“‚"T*ů,óϙ˜đŽœăƒsA<ťFĄ*ńďżĺ›Œ‘Ą‘€—°ĎFaú˙°XcëNfav1>1ÄXȍËjDi5(r,-.1›¨đʤnóĄX‰Žp1ćĹk3!Ô:ĹÜ: ó‹<ËÖQw”gŒ_|řř"7ßwaţî!Kĺuf§ËD'G´śH.ĚłXĐ(mhŁ ›ŐAŔçŔŞhĹöA­°y˙Ă ŒZŞ,ÎÍń SĽe˛ăňM?‘šÇ|ůź@łë|˜źzĂuć=â›t ŹnÎ]šČ÷=ŘďÜçűlk›MZąŔzK0čwcZ¨Ę­Ŕ‰D"‘H$‰äŚŁmŔjľŔJ2CŚŇ^ďŤ׉'ŇŹ¤KT5¨d–š{ď9Ë;GPZÄüż™JˇOŢúQ)É˝;¸Ÿn {…{ˇŚyşš#Móôá+ °„" Y_ţ•ó“Œ; ó|Žéőö ¤Z͓.i Ř‰-ŇIV2Ź7ÔöĎń ń$Њ†VYgzjЇÉíÂ6F˘ç'ľk¤gŸp{!CşPb=›âń÷O™-LNr~ó.™Žňa 0ą eâ„ŃˆI€âtă{ľś-P+ŹĽR<[+ďśKŤSŠił[ďJM"‘H$‰D"‘HN%§ć‚QUÝ=Äl_‘#^m+'^#ĐŞR¨ly^+3{ë;ćć>ćNQœNźĐj ťöÚjKTě8ÝNĚŠu‘­R [Őđ;b|ú‰…Ůçqćy +Ďůze?ËTš-@0€˝…%‰D"‘H$‰ä áL­Ń ł‹­Ůd×ͨšzä*&4›{ŽŤ&M 0o>× ęOÇÉ6Ŕčpůú ţŃOßçG—đ›÷˙łö`WCžŽ$‘H$‰D"‘HŢtÎÔ`ho˝'űŇf/RŻgřâëܙOł^SF‘Ńóüôă [ŢŃ݊“P[Ô媪D"‘H$‰D"yĂ95ۀ;˘Ń ŚÉ`čŸá›iFL{|ʘŒPoě:4Şc„‚Ůb‚Zžů™<ół&ź1Ž]"bqmd••™Âöëk„›U UŤ”ĺĘŞD"‘H$‰D"yĂéáĘŞJŤ[ßÍě5jŠD^ Î=W{Fą@ŽÂlĂľkKŽŔĺ´Ą QĚťž>F¸†ůégW8ç|ůkƒÜÚ žy’¤Ş l6ËîŐ[ŁUĐ,)ĘÁŞD"‘H$‰D"yĂéÝ`UŤ’/Ť Ě8śWŤŕ z°őbŰXg9ÓĹÉЀ}—ń›‡áĺO*Ş Pô䲙ăE˘ŽŚ¸ŽXˇ .†lľÄâjéhŻŽ +î×ĆśĽĺJműŞ*`pťń*-ҙü–÷uîáËüâÇďňaĚړíɉD"‘H$‰Drčxg°ş 9 ŔćńâłěüÓ&ŤK)Jš‘Řř0a‹ĹLpě"†Ą=Žur›^%ŞXÜ_}§זk\LN7>3€ˇĎ…Uh°<ťH˛Ąŕ?w…OÎ  x‡Â\¸t…ßűäç<›@­ÎFą&Œ„˘a‚ną!ÎLŻňó*mˇ—QźĘÇÚÜs˂ŕůË|0 ŕrŕó‡šúÎEÎŮ[dž?cnËňŚţ|´$ćuŕvŘń óŃĽćFŽ™Ľâށ°‚?ěĂÚ\gqë˝8ÂL8âÇms0ńěšmY"‘H$‰D"‘HÎ"ââŋZ­Öž€Eńęß˟ Ţ1~ö~ —"ÚŤB Pećťű<ĘoV)8†š>"ä4Ł´jŹ'Wx4W$úá .9 ’šşĂWů(?˙hçÖĺŔf–Ű_N‘_á—W}ŰŢKU ‹|ţÍ"ZűÝ 1†NœfľQ%—Iól>ÎRaËşŁ-ČÍkcŒx-˜´&Ĺ\š™™źP†ůĹGƒ{¤ý„…Í˝˝Âěb|bˆń°—ĹˆP”ň9–—˜IT^­n*Ţ1~Ą7ߎaŒFřşmŘM j˝J.›böYœxiÇ JĆ}v oüŸĎśÜZ#đŽ_ăG66fńŐâ÷łJ$‰D"‘H$ÉĂnˇw6X=ěI?¸'nđť#žűz†xˇ/ĘJ$‰D"‘H$ÉÁnßýÚ§ä”!ěŢ3ŸZU‰D"‘H$‰DňÖ Ť§ƒ‹Ë7†1.Ns/!GމD"‘H$‰äíálÝłúÖĄRXzĘłxžĆáK$‰D"‘H$ÉƒŹžfZ%–â'm„D"‘H$‰D"‘?r°D"‘H$‰D"‘HN­Źţ‹˙ţOů_˙ˇŰo[$Ią[-'m‚¤ ĘŐÚI› ‘H$‰Dr"ȕU‰D"‘H$‰D"‘œ:ä`U"‘H$‰D"‘H$§9XÝa‰ň‡˙íÉ_üŔá¤‘ź1Ć~ŔżřË?ăOĎwUVŽţÁó?˙é%˛Śö %öń̟^> ۤޛ?ăúď~Îü⤍‘źi“Ÿü„żřç˙˙Ë_ţ9ő?ţ˙ô˘Í!ßö>9 Ťü7˙ě]† %~űo˙=˙)Žś?N~đO˙ˆ_Ćö›U‰őřסň¨Çf­D"9ÍČÁę„uˆOßń’r‹™ę~OńO^âłwĆ8qă0Au#ĹÔ˝űüę~ŠňqÜsŢ伝=Ô̡–Žđ‡œ'<űDZo­œäŢŁ$Ľż/ŚŠźeUuĺ{ţŐżz€Śě\áŒđţçX/=—ƒŐ3„âŠńń'Čgy˜l}§ĎßŰ?˘#X›+üÇ/žđ¨~Ňö…Č͏ůÛFŇËŤL˝(RQ쌜ĺÓߏ1ćů˙ço3ňŽň“@8yď'W‰ uw˝Đę,=|ŔŻvN˜ ü“W¸*1żX<ցj+~‡ů/ďÚ:őX"yűƒŐm\ÎsÉRŕŰé4{Ε +çňťüÉ +‰Ši~u?CŽŚŕ˝ŔO~üťüšíoůßż9Ł ä›œˇ3K…§Óküň“ź{ÂZîÍ I+§řţî)Ů2­–t„äMG`ą˜­ľ7bŽE#˙ü˙ǝ‹Ż3$ž[äţŤŸňÎךňŕ žŻœ ‰o%׼÷řI`•[Ó>žźsPZgůÉ#–wţ™1Ěď_˝ŽššçűäqŻŠj´ZoDĽHŢH:Ź4ţ‡^ç‡f`P@"@h‚óoĚüťě–ç…ĆŸüŮ˙ĎŢ}GÇq凞˙Vu7ÝČ9'" &0%JŁ<#i,iĆ<Áö8ěú˝ľ7źˇű޳ߎ÷í9ëă=öł=ö{4#˛(Q)1ˆbÎ A"ç 4Ýh4şťj˙@‚d7›Ôďs ˇoŞ[őŤşˇjŒ—1ňű6oő˛3]'Ú `PůՇFŽ9ƒĆŸ˙ÄÖšr˘ÍJ7mç%”üźD ŽZęć<‹Wˆ/ßÎ ĽpaĎÇ|Ö<5-łŠ­“V×#ühó*JŽć’0dňŇOvP2g~ű9đÚ>Ž Lű%ŠíŻ<Ĺ.Žđł}vЎ–°*=špƒÇ@+>ŕÆŠúąoçwFréĂO9Ř1­Ţ”H6˝đۨćľv 6S’I˜ęĂikă‹}¨qč XXó̓<–69MŁń‹˝ź}mÖÄA5šm/=ʖiëGŁw=Ë_ěšřĆ×Ăgż92ľOÂXąş„…I$EŒď]Í ?]KËČĚž`ŒNgۖ•ŹL ÇěĄýz5ç2wѐŔăßŮM…ű˙řF}Ó?N ŁâĹgůZLŻ˙ň$ľí§XذeëWÄkQsŘhŹŠâЙVú§ˇEöfţýóŮ4~üo×Nő°҇ůłGŁ8?}Şř?žČŻýXáĄo=ÉÎřŠv‹}ěEţÓcßřşŘű‹œ›ěŹţŽ;Śh-Ĺ5ž‡\Ź7łœËˇţ4w2ĂTň6o]ŸÖĐ´›?}'ŕc€ßtl­­Řf˙t´‹k­ʋ#IˆTXĐT?Çę`؇–ňř%4Gś&ÓsfעbٟŤ@͙y”Fj´^lš9nůýšö3ĹʆžçЌÉc€şĎßç7•ˇ.ˇšŮnŸN]âjś$˘Ýą?,z[xndŒÎäĄ]ŤXŮ뤼ú2'F‹xuł#żţ”/űgžůÓ…¸WüV5…>1qDU@_˨¨°k——Ą ˇ;Á2küŢs:Zف×ö)8T˘B(3ŕO÷M˜>žŠ:ťvyŮnž•n Ű·)žědok]sÄ Jh;7ĆŃv?šgh ýŐu4nYOV˘ĘĽF ´Ž~xˆ‹3ňÁŞ]ë(30ěž{ČRĚŠ<ţ\>ză5îÂĽ†‘Q˜DŘÍ: ]?ˇ ¸lj$ëŸŢ͓™-U78Đ5‚‘ČŞŐkův˛•ßźyžĆ›íĄ’šōӗYUÎş“ŃUÇŃ/űÉßTĘŽŠt.}Ԅ PŹÉTŹKCmlĺrýś…đ”,6lŘÎ÷Nń/ÖĎXOiŒ/âŐב­Ř¸VYə7jX š…+Y›rƒĆÉ%œőO>ĚŠ.Ž_źĚŠ~†°pSÓ)ĚçxłkŢA ßy˜¨Í”Ší$9ťštöÄdPąŞˆçw;čz§†9ş„îę§ÝYЉÄ)Ýô,ĆY‡!„ˆ¨pźÓÓŇ5F#¸&ŤĚ’ČÚŐ)(-íT6Úr)„%e°fÍ&^‰;ÇŻö5a×O/5MŁ”¤“ÖČ%çT˘†¤ ň#4:Ž´14ůcc,[ŸÚÁćX7ÍU×8?ŕ#<%›uk7“}†×>oaxĄe Iâá§V 5ßŕČA;ŁŞ•´ÜÂL“euS{üKúÍ ÄĺńôÖÔšÓŃ\=t„(ąš<ľ-áË'9ŇmáŮsUD˜§ÝąM˘ ͈Łú,ďëœ6Ĺű2ŞŞĚ}Ly§>ZĎO?¨Ą_h Çô,Że~3sEišƒţ! 5-Š8,Ćł\Ԙ|^|%ćug?ŘĎá‰+5úH+{_ŻÇîšV†šFZ=ťyĽ,•Ń͜Ômuí çP˜ĘĺŞÉ+Ç*ŠšŠDůú9Ű8u59<%ëăÚOĺËĂău­™Nm7/•°!ŠCs]- ¤|Q1č'đÎĺá›űPccă´-4ý˝8•´;œOJç{ĺ3űÒíÇ~Q ‰ŤWł*b”Ť{đ~¸xĂĆsżť“ňYÁęrô_!jŢ/ĈÎőňgëuş.ůÇëĘmÔş[e_•âß@0‘îżŰ ÓuńÎéş­?K(VEgttŽ'O¨$§Ćcčé˘iPcŘúĚśĆÚ8ţéA^ŰWĂpv!+Ăo?ĺ%~ç kÚ°B‡ŸOä1ÄřřÓÇ|„ľů?ď’n Ű.Q‘!¸‡†qę`HÍe]Âgß>ÁńNĐEó€ÄM~ xţą„śçőă=ÜöAÀ>lŸZx¤{űm,›N\¤Š–ÇŤ?ɛół|Ăă…ÉűOšoânŚŁĄÝ´5]Uö>[‰…%ě,Ď";1ŤQ™¸x0ŚžS##ˆVuú†îţЧąvŽî"s[ ßýaC˝}´÷ ĐÚŘČĽzŰëíNĘ0ý`:ů˝Ď§ĄŁbXĆ#‚îśÓÔĐv—,‰Ď+bKY™ńaXÓňŒÓ_Ačë§ŚŃɚŇtňÂëš0ŹcLÎ /ÜG˚Ί“F%„Ť}̉mÖY‰>ěÄŽ+Ć[PZPpŁ ŰXîľ6j1‘ Š5‡~3ç&>ÇÄ~ĄXˆ°*č'ö­5ěvúBÂuÝIuu'ěΤ,ý"MÍ^ ‰Ů”Äj´mœjsĹLD¸Ć Îj mŘÁŚaEšeU`€Ů `<ťŤ%ڏw–Ě’•m~îŘnôÉîć˙1`žLąl~jĂű9üŢIŽ.x-cu°ěC÷źď(Ĕ­c[ü G_o l‡!žň•1(öë\jYř ˝”ýĚ힄뚳Ý÷zŒRŹD…+hŽal3˘vűÚôcË2ő_!*đ`5DçĽ'ź”y üí>­w;Łô)xü¸B4^~ŇË*݁˙÷né˛mt×(#şBhhČ­§ŠŠ“ĆĆƏƈ0Âuí˝SŽĐéԉž%ż ězr-+źMźłď:˝wÉŻîóá×ĂII÷NŰÎłlZßuŢ98÷z}ĚÉôXˇ-Ό_(D•lĺ{ĽŕnŞá‹}Ýô:Çđę`H_͡ˇĹßŇ.ţŸBzé<żŤM /;‰Œ”DVäł˛Źˆľńó#Ýó~'ßҟĆą˜Uđšq.ۋ"‹6ňĘŽ$Ü-u?ÔCŸÓƒOCj /mŠ›ľ˝Fg]ś˛ sŹ\ź2JZn*žŽ6-÷i6 iţíCKńŃýu|ôĺÜënuĎÄ~ąÄĆŮĐ@­;˘â>kî Š0‹X_7'o8—ýŐ ~g~YŠý8đqgi,Ý5‹ŰnţćÉĹú'âŃd'ö|Áą€ÖÜîŢ÷śď(Ą<´)÷cԌYˆ P 3)€BˆŐJdř#Žą[fمdäR}gĺ\nIű™_îýľ<ă•Ë'°`UŃŠŘéĺŮ…÷9˝Xˇ3MyůzŹÂžwœşÓš…@ś f˘o ŠcÂ1Ń7óΎîĂăŁqźĘź#.\J ‘a 7Ÿc˛1{މbĄřĄ­lľsâÝ3\s.҈HşwŰ6вiúíJœwOmw8/hĐT,§:tƒ7>ş8íŔĽl¸e*ŠffPSˆÂÄ0ţź6pĚŢKő•^ŞŻ€ËÎggi>+Žwsmç7óÉCŔÔpâ˘T4ۡyĘâSBÉ+H&Ô^Ç{űŻĐ>­-˘’ sśŤÖ×Ću[!+҈ş6DQv(cm-ÔOUő1†G|(IaD[`úň%"ŒHEÇápMMÖ4|€Á Â͟*XŹćĺ? ëw9ßŃF´ë(ą*îž~:îԟtv§ŽF¤ 7ëW%2҂˛Ŕ{!úh—ëFY™—C~¸—Źü0Ú/Ď\çťvř 9œ 3v¤F„Ľę O[V ůŚľĹd†ŹaĄËŢíÇwrwüNćUg‹=F-‰@űÎR2DPţřĂ|-c”łć`ŰŘňĹ%AśÚwL–p"Ě ú˜‹Á‘t.ł•hłBTÉvţdŽ÷kž~žrwżýé ŽĎ8†™)(Í$\ŕtÍಞ[uŠ-ę~ČĽ`sč¨ŃDŠĐ7ăŘbE>Ń:˜öc!î  ‰‡Še^~\•ÇLüścń.TĽ­öň“b¸ňĽ‰×ď’n ŰĚŰGsˇ†!1ä[jĆÐ}ŒĐčpŹ€ŻŁ‘ŤCąlڞG˛YA1†S´ľŒ‚k UâWoá™b _ăpG ë8î$týŮ6вR{Ł›1k&[ˢn˝âa´6Ÿ9­*ƒÂ-­jŠgCiü-UnăZ—k^1ëăfMîQC ö˝ÁD謌ęcú†ďtx4’ľ~+/>šÝásžL”‡yRŹq¤FÁpGýËvÔ_Ÿ :úôĎ4ĹR^;÷T*ÍFMýJR:+ 3Čľzh¨ëšvyéhëgLŁ8/bZ›šČ.H#‚Zڇ§Ś:Gpč* ‰ŃSýĚEaNÔ˛ŻŁŃ=Ćt°Xn(R_߃ǒÎĆâČ[ëČ`!Ę:‘k}˘œ–dŠŇLSۄ&ł2s1q/ŐÍ …¤°ngĹannTˇÍZ.ἾĽOYáôü†°be‘8ilZWŹ;FÖU“bŚľE4+sŁ—Ż-ćąëcc¸uëm/p6îřŸn€u6Ż1ę^ Źď,5œŇÇá™^.~rˆýÍ ĐU`‚dšWßQÉŘň8ňýçřńś¤ů­ ›ü,gŸt˜×÷L˙w„Ďę\čú(׏ፏŻÝň-%<“5Ů!x;¸:ř€„DK˛0FéN[†ĐŹŠŹĘžš%¨˜“(ɞ}Q$Höc!îÂďńIÖřńf 󀑳#:ëruĆßš ĐҢŇ9uIjŒ?ŢŽaî7pÚŠł>wćÎ8=Ý@śŸQnÔvóřĂ)ä%¨4uOßE5ş:úĐ SÉąÔrĹŐËá˝g°>ą–ýáĐ|ؚÚiw…O+[!ĎnOÁÔ_G3ŠüܨiéŃŰŇ=Żľ\¤ëßś–Mg¨úrw󵝻ůAJWŰě¸ bbăX‘›Ěȉ=üŚ2ŔťCş“ú†ŢZČóO霩ˇá6E‘WšK|XfmďŕÜĄËꏖGżů8ŠWiCľF“S…ďĚޝxmŒ‘ĎŤ/çămhŚŽËŽĂk :mšFěךhšóJ§JtZ&Ľ+TzlŐ¸1Çőň0_ÖĚTŇ'kű–ďAúM6śmĚăŠÇuÎ7Ú3E°˘8‡œˇśĹřŃWßFďş*6FarˇSÓzkwÔVsžd'›6n煰:n řKÍa}găYÎN{°>ÔIÝ@ ŰJ6đœVOðřY¤\3×ŢČMJ” Pâ,€Đč82SÇóë˘Ă6ó>š>ÔKťs%kJËŮÍéC×Ýôu 2<ńášKÉŮĹŁ[âŰɍ\kĆm%*6†ěěD\g>x—ŤNOe׊6SöȸÜ8ţęšâ|rÔĹš¨ĺíl r°íičŽ:Ž4ßÚĂ5W8ľúQśoy˜WÂŻs­ĎGxz.›Š­8ëNpŞcŞÇiśvŽ÷ŻbתÍ|SżA­Ý@bŢ 2 # [c€ůěÇÚP­…őŤ×óĐH--/şîڎ­Ÿ!;ţŚK`u6ż1ęŢ ¤ď, •ôÍń|qŁíu8ňؖ0ý÷>zn\Łf‰ƒ `؇ćŰwTu<ňú´…9^­łgĽâJ÷˘ŁbëhçFűěG!Ž8l“‡şęće=Š1<†´čń`NM°bDÁ“@vúřyŸsśÁŔďŇ/É~ĐĽÓsů2WJvRžű´sľ4:M¤—ą÷-ç˝ß…¸;żƒUŢe€8?|҇A…Ş€˘+źöZď žŢm€xđĚě§ŠÎL7mçGÇQ[K͖í”ĹóEwόőŽĆFŽďŘĘŚŐ1TŸÄÓ_ĎżiäÓ°PĚ>7ĂŁ`‰´ ş<ůľnS|O?3ëADZ?^ŰÇąš^Źy¤ë– Ÿł}Ę@y[Vć°#7ŁĎ}ČFkő%.ˇŒň~uzÎɛę:*+`÷ Ç őWOđĆ@.ż˙ô­ďAóö]ăßÚŮTQLYń*Š, cÎa:šŽqźsZĐăęćĘőxĘŇsؚJ¨QgÔ>Hă™/9tśmAO ô7ó˘X)*JĆĐWŅe=hčô]>Áj9ŰVćňP–ŻÓFcőŢľeó˝ÝsŸŔëś6júV˛3рłŚ•ćšćE{ű9öńœ%ŹÉ/áŃPsˆć '9zĄ}ćZOmˆłĎąs%Eeed¸†h¨şČŢŃžł#ržeSË]Ă7ˇĆϸűVž•—ËÇËî¨:ĘOżěžyqŔ×Ëą—1oÎcőśÍl4*(ž>űÍ.MNgֆš¸ď ƒeĹTd°9;ƒ6†Ă>DűőJ*§?ů×ŐÎţN3˛ľ˜•k×°Ňç¤íú%>qçńőő ~Ü hƒ\Š`ËÖX†ëç>Iňöqř˝ƒ8śŹbCájž,Ÿx!ü™Ł<Ó2őn܉ôN|zšČGË()/'kÄFݕłźç*ćGD͑řâ›×~ěíćđ§ç1o/dÝCŰŮfTP|]ěýĹÎ9`>ăŽéP-ĺľ$é;KB!"*  aiů캼™<\íťNÍŕ›A°ÍŤď(¤$„€6ÄĹʞe~r: Ć˛ze,ŞŤ™ËőË}G\!<ßٕ8ăž~'ß] 3|ĺ{°3ŕzYšý8°1JwľńńťGŮľŠňM”z†iŽ:ĎGM+yuł2sśÔ=ߏ…¸;Ľ°°PwťÇ—{+Šróßä÷˙óOžÉ˙óoßňóÉ˙,*IŸŕGk†y˙ߎR5cdQˆ[ý0?ÜaĽú“ƒ|\?ňMxËv˙RăËřńŤ…ôďßË;×v@ˇ†.Ň{oIJ˙ŁżâÖ?ÎOś†pňÍ˝Xŕťk…%,Ÿo˙^ÉőÇř‡OšYÄLj ¤şői~¸n„vóK˙ !…Őj•×'ÝJŁçâE.ŽĽł˝|öÚ<ţ+Çyű˘‡•O}ď=RDQráfĄÖŇÓ˘ąŢŁ\/܃\śűU(+7ÓYÉĄÚĺžň,î{Ćx֕ĆA_Wş%PBL IM"NŸi‘@őŁ Î>ťW#Y‘>ĐC[ĐMÓâÎäÎꟉÉ)dWE>EÉá˜'Ÿ™ânĺý_áĘ}=<Čeűj“;Ť÷§@ďŹ")J"!ݘ­yfę?ű˜7Ťĺ‰ŽBń• DąíŰČlŚŚÍ†S%ľh%[VŠůôSŢťá’へoX­Ö=î+ĚË`cď7Va0[‰ 7cVź Ű8‚ě!{Ë&ă/$˝„Ż?žŠî˘îėě•@U!ž:t7ívň xte(fŋ˝Ż““_âË: TĹýG‚ŐňšGp?˜“˙ä˛ ń rUćżVßë\!„¸7FŠ?u”úS÷:B,żŚßí!„B!ž*Â,!8]s=ö^L ‹ŠÄ˜ˆ)9 Ĺ:ţ&}ą§ŤooÎ!ű=ÎĄf2 X!„Bˆgß°9wíg$H…ĹĹb)_ĽbćŹÔđp0L„>/šĂťš˙S¸.ĂŮż wOޗ"0eĺ€É´°„<<͍ ÷ö.NƂŒŤB!„BŕŃőă˙K°zŤč’R"Ÿ‘Đ’2ĂĄ†‚!&y÷7] IDATkL,–˛ŐŒVmÁôÁ;ŘŞ*—?ł÷HDr21ßýĄŤ×ĄÜňřćŔčšĆčĽ čŻýGgç"ĺ0xČŤk„B!„đSRŹ™uE°ŽhüëĽfH.âëť×°2"ř—ßĹŽŻ î÷˙ËŞ5sŞł(#–Ukˆűý?!v}Ţĺ#Řë,¤p%ĄŤÖ˘  ( ú§ „–ŻÁRśú^kIȝU!„Bqß1F&Qš“@\„•p‹ ƒîĂ墣ľ•kíƖčѡyi“˘N|­Ń}_Í`5›šJf|qŃDYŒ(Žvž8ÚH˙ë+ş¤”˜ďücRňˇÓŮ!¤1)™˜ďüÍ5„wXżÎÔˇžwţƒCDĢĽLäÎŞB!„¸ď#ăH §­ŸĆŚ6jZząInÉ*vćGąŔ•€ˇľśP!,ÂBÇżžŻ(fRr2X‘`‘Ĺ{-aX\,‘Ď˝8g ŞĎúe4`R´YŰ“’‰|îEÂâb'S‹e‰ęLřGîŹ !„BˆűÎh[5ŸśÍúĄŇNţ†ľŹÎL#ľiˆćE~XoB´™ŠâŠľ˘X!!ÚLŻÍ˝¸´TtőÎR3:†pJˇŽŚpn]YĘ×ZZ6óŁ€EÁ<í˘ŽÎÓń1ěŒ|Ř7H“Ë=ăNkhi–ňő8~śđL-–%Şłé4@×uE™q'ѧßş5L{Ëíś}PI°*„B! ş§KCÁbRXěšŔY)Ÿ1ő}~ĆřĎzm‹ú1KHctňu;‹tS8,*KĹŚ›kTuŔ¤(l‹Ž`{tQFĂÍmu Ţd$Ćh¤,ĚÂçƒvö÷۰y}(LŹa­ŘDŘšSAôZ›ĹŻłŮ˛CC(´Z¸>â˘etüłĚŞĘÚ+†GpkÚmˇ}I°*„B!î[Ş)„Pيj !*>•˛d#ŒÓ?x š‘hfs)„…*hĚü{ͧ°:˘Â§~/?˘PœŠj˜š˝Š‚sTçDĽN[σT ÉĚžů˝ <͡“ăUU<ş>Ł&'C×8“‘Ň0 §††œVB2ł1&$BĐŤKG *?LMdU¸•+Žţ[svŻ‘aüqúř´ężoëâđ HŁá–m>mŠbč  ÁŞB!„¸O)Dĺ”ńpŽeâ„]ÇmďáRU˝žŔSs¸Ŕ`€ßý¤Äů7ÉňŠ- OmĎËt}:˙ňĄ‚Óx>î'Śä´›÷с¤OĹE˘¨|ÚoăäăćúT]×y<.šœP3÷Ű8jłăŐǧ {'§źFD`JNƒşş{S eŚ˘`™˜*mQUԉ~dVULęÔ×wÚöAvOƒUEQPüŠc}âÉa˛í˝­Ś/Ńcű„Bń€ŇqtÔsŇfŔ` %.)xĆpűćwN18ěćĎĄŽÝĚ}*VúyŽ:ŚÁŠ*xOçüőűd-ë(–P˜˜Źé:ń&# !FZÜnŢěî§×ăŸâ;ą˝KÓńitŽyXa剸hŢę vdU Ćń4ż`Řçăß:{)ăҰ“aŸUQ85丘žr *ƜŰ>čáę˝ V ™źř“”ř‘­ż…ĆčLr ˛íťmßUţňľËwßP!„bĂF‡cüë֎^2WŻĄb˝ íd-óœ}{śÚÍč3óÝ'ŕ…*V‹ÁŻcŢ<¤ńúgĐŃ÷ળ)(¸5óĂNöőŰôúČ0‡`5¨ÔŽŒpcdôćŘď§$’bâýžAô9_jóŐpĹéâĘÄ-x•ńZ°ű||Đ7ß+ˇŮöAwď‚U_Ţü”ăţôIŻĄ “lűo;âÇFB!„w ŃŢicmR+ščh÷Ě;Šö7˙ý=3×[}üči•Ź”;o_׌óÓŕËË`w~uUÝ5 >/¨!¨ 4şů›–.Œ |-.š§â˘iułżß†2q›Úl‰Ž #4„ÖŃ1ú<ÔÉ[Ř>ďxš_!sÓÔťmű ť‡Ó€ÇěégđŢe@!„B<`TUEAÁd2 ŕa!‹Œ†nŢ= Ž‘Pţú,暡s¸ŕoŢÔ9|ţŤ¤NňtľăĆŔ˜Ž“m6ńĂÔDJĂ,¨ŠBŞŮÄŚiOŚRŁ˘0ŞiěëˇŃ71UŔ7<Œ§Ť}ů rŸÓŻ~Ÿ, !„BˆűŒˆ(3nűČ̡ÓÂX‘A÷`wŒ-(P.&ĚŚŰ˙Ţb†„¨Eú°űŒˇˇ‡ą–Ś›ÁŞ y}T:]¤„˜H1a÷ůf¤6#6;'‡3ŇkiÂŰŰł|¸|>XÄgľčšöŔލ–`U!„BÜ_”R‹×°Ňě¤gĐÁ°k Ÿ!”¸„8Ź*îžFnôkwOÇV3›J@˝ĂüKƒ KáÓSf†G‚ůîŞBxB*‘*BźI%‚ě$^{/u˝ŁůÎ!;–3§°”­F1Q›×Ç[Ýýœą;x6>†>—=˝(ÓÂUˇŚáÖőÓZuŸי`zÇ*,Ešëkq××ZP´(9ô460ZuuQŇ 6Ź !„Bˆű‹>FwKÉŃÄĆÄŸdÄ űŚéF;5̓8éĆUr,”ćN}ďőÁƿ޾Œ’\•ŤŤ3ԏáPˆHĘ $mzIN^$î6ő^ŽKç­Ü‚eőš‰O×ŕrómÝX *ß̋ ˇŽż­źŠëŇš?}Š-~Ů››ág˙€Ľl jD8ş˘`]W)=€ąĆ\W.€ŚßőiÔ>‡“ŃŤą75TŞű…ŤB!„â>ăĂÖŃĚšŽć%˙¤˛\HŽěđÚ~w˙ŽŞ ~÷q•ŘČńmJr ŽmÉł´•§x§rqSuö`ÚóŚäŒIÉ7Ž]gĚ{÷WŹxťť°ďyg˙ŔâfnÁ–ŚÎěÍÍăA+`ľZ0&$cJĎÄÓÜŔŔ/ţ‰Ą×÷ďS_ľJ !„Bá—p‹™Š• Ž5éüď?ÓxmŸNŻÍMŻÍÍkűĆv­IÇh€ÍĽf š×Ůž'lU• ţęçxťťnů?ęŕŻ~Ž­j‘#Âű‰Şŕéędŕľ_H :ÜYB!„b Ѱ2>>ĄóĎ{tn´Î\ętqč´u›ůńsPœ‰Ń Ž{“ß{mŕÜ4בϿHhIŠáÎĄ†îó2Zuűď|ĽUEQđuwa;úśŤćÚÓů’`U!„Bˆ9$D+źu>=ĽŃ?4vŰín´şůë×BřÚ&•„h…ĆÎeĚdąUUâéęŔRžKĹ&ĚY9¨áá0¸úźhîćF\gNáşt.§ţ./]Óţě4§ăîĹ(………şŰ=~•HQ”›˙&ż÷ç!„B!4Ńáf|~?á7ÂjĆ ‚ÍĚO^>aQ‘1%§ĄX-č#.<]íx{{‚슿"ŘX­V V…B!„BŤŐ*XB!„B|$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„Bt$XB!„BtŒ÷:B!–‰b"*1‰üœ8ĆjŻpĽ_˙jçC/é#ž%lSĹ`&.9™źŹH†Ş*š6tŸ÷—;ŐŐbŐŁB|j*YVz.]ŁÎ9˙:3FgńČĂŤ(M˛‚›îúk|öĺuÚFçä˝%ăOPYÔ`5$Œ:Œz@[̄żŞˆŽÖɈŐȈ×Y‘¤ÓsŢÄ[í÷:cS )ëřŁß)&V™ýUżËŰ7tňwƒWKĚĚŢDs\çW??KS Ecű‹;ٞő‡>ă­*ˇF )křÉ7Kˆťe†ƒ{xíĘČm˙ö+ĎËÖo<̎čž{˜3RSˇeˆeű ł-˛ĎŢ9ÂyŰ=ŹŤŰ´›1k=đTqfՃU\é÷.{öć•é‹~{Ćź`éŤbń,e›FoçGfaTPtçŰŤ‚"Xőg_ĚÉs/o"§ű,żř¤‘!ýÎuľ8ő¨SşďîĚ *DAŃ쯿Fsž5&°ëŮÍäˇáŸŢďBËŞŕGĎŻçĂ÷™“u‹9v/Ăą@ßŕcˆ˙Ď>ŸEQnţ›üţN˙G'ëç“é‹ţ{ĆśĹűłľÎ¨˝ęK-ôh€6DÍŐ:†˝S(4śîVÎÔ˘š­ó7ú›gÁ4v§˙‡ot˜ćë­´ťuĐGi­mĽĂá]„“ś2JŠ)ˆşĺśň}äöeĐGz¨iĆ>ĐĆľöą%<ÉUOËeóŞb Kö!KJwvSÓ2Œ˝ż•kËqv>íŚ3:ĐF]ď˝>辏ĺë‹Á*°ąféĆź…¤ Ł­ÔöÜëžş˜„ăĹB,e›úéiĽap9úËâs„a 4Çř˙ăî4F.Ň8ŽűptśŃ4źĐQA!69 :úDR[75u 9ŐÄĐ"Ýw?,Ć~,ÇJ1)ŕiŔ‘i>ţüIĹaŕě4ňwŸ9iťuťĂ— ü[”Ćď<îĺů,ńŠÎŰšřm;_ÁyŇĄ§IĽIӈ[Ś“xŢń˝'=<gm† ş‹;ŃkTGGglÄĹŘ=ʅ!ž'. ëĂëAqw>îXÍƙ={8łÔ™PŹäŻ_Ëî˛ĆŢă͚ű0Ńlœú`§–éăćßn:ZPTn€ůXŽž¤řąfNÁŇWǃІ ˇ´mşýeąŰQwŘđč$ŮěĚLîNuľXő¸é(XBCPT#‘a*ŕĂŰ_ĎÇ{ë'~?ş¸c÷]Ž‹×>Öřsż čÎŞ)Îǟ=éŁĐÎ6#˙彚ŐIcC*Ż˝gâ7í@¨ĆKĎzŘ-wX˘ëŕ[Ś&<ÉÇ˙đŇx Ü×~uĆ<>@ghčŢŹż2Dfň䓥¤Ţ§wÁ˙2¨!fB—ňšáş“+—Zpęăýýţ=>(„„[ą.ń3փŚÝL“‘š›O%Ä4ł€_ĽąćAőU/0ťçű˘f§gĐÇŕ€ýśË™‚ÝřŇ@áá!ˇ=w\ěą{Žôd?{půgU…§öRŞ Şüë~M^ˆLöńb… )`ö!0bS¸xÍŔ{WU˝ |ndݡ˝Ź ŐřöNg?40 ƒ˘“ŸŚł"AcE˘N~˛NŐţö¨>^Žđą.IÇěU¨o0đć W’ëă›ë|ŹIÔąř üú¨Ş‘Ů%ÓYťÚÇůą:‘&UhëV9uĹŔÇő 7RŚ@T”NVźFv˘ÎŠ†“&>ě™őť‰:-§Mź×5˝ntŠK}<[ŹQ7őYíÝ*§Ť |RŤ0#{ŞNAą§‹5V&čD…€×­ĐŃ­ňĺ7+ˇ´Tâ5>^YĽ‘ĽŁšj üö¤šyׁÎڝţÇrˆi;Ĺ×Üź˙ľńŻŻ á˙¸ź„!Ź1‚˘uŤŘT”LJ”Łîa¸ż—ëW+9RŮÇČě›GšhŘl΅­‡6ZHÍĘ pE:EY&*÷¤*˛„G7ć’o—–×8p˛î1iĺyfsIĄ Ö}ăUÖŕŁú“ˇyëúxë)–8Öl(emn‰fTŻ‹žŽVΜźĚĹ‡ł?˙ƒ\ [ɓ; ɍÔčž~‘=‡é›X–áWšĆp Ö­fkQ2ÉQf ŢQú:Űš|î*gZ=$߼ o7GRZ–C~F +Ň#čűňCţí’sî<ßľÎnfŠřüvŽÉ"'! ŤQÇí°ÓÚŘÁP|ŚŢN6úŸ\1G’“;žÂÔ1Žžy†Ą˘5ě*M%)LĹă°ŃXSĹĄ3­ô{Żk՚Ŕš +Ył"„đTď(ƒ˝]T]Şädýć}5:Me™ädŚ’`äÚGďđ^ýÔ:żŰ PBcY˝Ą„uš‰Ä†Şážv.œžĚé6/) i7ę4€ź.ĹßϙfhěËtÇž>ÂmW48ćĚüŰŔ÷sl*ĽyŠäd§‘—äĺäëŸp¤_ŒÄeeQœBފTŇÜŐüó•ôęţ5󧐟a7ßݒ€ebě×˝Łt]<ĘϏuă5ŚđľßÝÁ†čń5Cş×E÷ĽcüËŃn|řÓދU# …ŤxŹ"‡ě˜|N×*ůüt+ƒÓřŽmj¤ŕŃgyŠÔŠiâpŚűĆč˝x„ŸíF+ćťß\Kf¨‚h>ŮËŢď<űś˙ĺ÷wźšckŢqüpĄ2¸Üőłď˜ńp6˝ô §Ŕ;JĎĺcüó—]ˇßwďF #oc9ŻJ%1TÇ9ŘÇőŤW9rĽ§dű˘îŕŇţĎšáś/íł]ŒaŹXUÂŚ˘TŇb,˜C˝v|asoîOË*ĺ‰uYä¤YP€ÜG^ŕ?=úHżţŮ)Lwťç1†ŢţX°Čçes×ČźĆĘ:Ú˝­÷•çw°šÂË×Ć︾^5rÔjź˙đ˘—T á?ŸS0Śzůż_ňńtŠĆúq@exĐŔ' ^Š <ŰÇ#ąŢîcŠ?}ÂGjčԝ<óV[5´aE…P‹NI‰—˙˜¨óóZooÔVPU1é­ôňcá}Ë@Óä }¨Ćď~ĂĂóI čPWmä­nČ*ôńXśźlŰ/›ř/‡Uu(Ü>Ć˙ľNŸşÍŹ+x/Y°mŒż^ŻĎ¸ýeĺ´o­{řł"ƒŽpţ¨‰_Ö)Äzůw[||+ÇÇćS!ü/'<F'Ÿňđ{+tÔ1…ÇL|1ë6{řzśœLź}&ţćş2çN“ľŢÿ׎ת fű؞¤łz•—˘TżzÓHŐ͝:°:đ:UN\×Y_¤7Ń]Í.ÝŃż„ŞbĄěńÝ|=ĎĂĺý‡xťÎ†ŰAţćí|ă‘GɊ<Č/Ž÷Î8XëşŽŽťZŘɚ™ÂšŐ…”eFŞřđnÝIy„›KgNrz$„Ě5kŘľv3߉ÔůéŢFěşÎ˜­ƒS_Ú(Ř´š•Ď_ŕň€č uN<ŹĚšĆS/í`­š‡/öďç×m#ăsx⊍<óHÔ×qnHŸőů^Ť6°2ÝL}M+‘ňÉ(ŰŔÎŚVŢ­óú&„Rüčn^ĚáĚţƒźŐě@Hdă#ŰŘýő$˘Ţ˙œów+Cˆ…¨ˆh2ŇŁ 7hô+Ęę @!ślß$Ľí ďţć:-# ÖńÂ#ĽäľňţŻ.ŃŔœn5:™UEšgFbĆŚÇ&Ü×Ęg{?ĄÍBFůžŽŘAfÜI~śˇá@ę:<“g_ÚĘę°aޜ<Íg-źĄŃŽ+gÇÓéäž<ČŻO÷3¨ řôPâă,˜ό+ËţˇŮ´mC{8´÷NľťĐ#˛xîwśąűëqXŢ>ŔŐ´ŰÝ’׼řűŰşc™îÖ×?e_ŤgŽĚ>ćLř> `Žˆ&%#˘´pŒš uň ˘„“ĎŠÜ ˛˘ h˝ĘÄńĆżąfatşÎîço›KxůĹrrĚ>jí卪Ńń㏷“O˙őc_z†ÝüöőÓÜpÍęŻwiA!Ą|'/+6Ξ<Ćą1+ůÖ˛măvRBóÓCă]ýlÓŢç˙ŤŻŕűĎć§Œp飏ŘÓ8ŃGúŻńŻżćšďě¤ÔQÉ/ß˝LűŘBúśŸÇ‹Ć›ŰÖŇ]Ǐ}|1ćçXo h˙đçłuÝŽ­ $–odGĘ 'NňŃůl :ŹÉŘş‹L[űßż@Ϙ™Œ5<óĐŁdGćGş Ş}Qgd°ŸŮ÷•)Ž­Ď=ÄŁé mĎóŰO:đ‰NÍĺŃGnŮÜßţîśőP}ŐÁěČ2ŃWu–/GŃ}ş5˙<âśé-îyŮÜć?VŠ…óóŚźÎęBpĐŽ_Wđ1é9ᎎżŽĆŐĽrixügIĹ>ś…]ŮŹŽß-TuÖfë(€§ŮȟüŤ‰SÓŢÔ`×~cćGż á?0Đ9ŃÖ! >~\:őťŸ|d wâwĄI>žH›JcÝ/Ď%ŔöZő™O/řé#‡'žv–ľĘË ĆóqýhzHĹ1Gżşq,„?ů\ĺvo˘Pc4ž/Đ1Ú°Ę{UڇŽŢPéšř›ĚtÉľŢ…›=|ĹřöçLüô˛JuŤĘëG té ¨:[śú(šÍe„„•zÇÄ/OůŰ÷LŸáĚń>žˇz*¨Źޜ3ňÓc*íÓ.íŐ_5ňOÇ˙}Ř6w~nĽ`4™1oýg˜űÄY1§˛j…EsŃŐ9„ÓŤăľSs˛šzŸ‘¤Ő…ä…ĚńwšƒűÂm ßűŒO˝čHŽ擷qôz'Í­ÍŰ‘šQ…°œ|VF*€—ŢŚ.UˇŇéŇ/}M \ŞŞçRUv0‘ťe#kc5ꎟŕhó0Ł>Žîz>;ߍ/4™­ĺ ă}fĆçYQÁ収rŕB+ݘ|:ˇ˙i*aéŹËˇ˘5_ăp §ÇËČ@'Ő­N4CyYVúďRÝŢÎąC_r ŢsËE“Ŕë 0$°ą"…0}˜ G+ЎásŃ^yžă­>MĄ,ÇĐôs_÷ >x˙Çz4P,¤E÷łďăKTw;°Ű¨:z’c]ášĺlË0P×!lÝŔęhćă_°ç|+-˝ƒt´6rxďQN šČظ‘MWuźƒíœ>~†S]łŻ‹űßf`œŘZϜćxť /ŕîĄePC1FS˝°vťł@ňş{w*ÓÝűz䜚ůŽ9“ßtěÍŐěÝsŽŞŮ'0úuçNóĆÍĚü•?cÍâp÷Ôp´f ŮI„ΨŤ82ăUk늿™AŰ{1Ę ­vňîť§9U×MKK#‡>Ť¤Ů§]œOžy2ŸţśŠŽŁŠšóÝşJR‚uFQÂcH˛úhşzƒŽą@Ę:ĘŘx37ƏHđs l˙đďłç>ŮT‰)ŢÂŤŰcé:vˆßž^h  (&âÍÝ|ş˙u}ΉcÁ)Nö*$Ź^ÇĆx‚z_\|Ň*6óp†űľSźq¤V› §s˜öúVÚ\łˇ÷żż{‡z¸VŰBóĐř˛Ź‘ŢŞk[¨nŔĄßyěžĎyÄíÓ[Üó˛; |Ź‹Áż`Ő S<řh#*×'îś ś¨TŽŒŻ33Lś°Ž0ě˙R1č$GŽí°)7§Ćé7;„îVh›ö¸ěŢz_öŻ[iWŠžČ6^5rpâwŽV•k“̝”˜ńŔSąúx˘`*hŤŹSąßü,•“Íw, Ť5ÇĎ#čhž¨Ý¤Cg“Jëmćg(Ą:ÇĹŞQž8^O֝0č>…Ó•ăOôUĚϔę㡳5… MĘÍi.ž~•–É金Is^Ęʼn:ŃGUNśM­ńËÉÓHRćY‹ĹÂ“ż÷;üoüň-˙ţüńŒ9oĺë^'ƒ#:ŮT?Ő7<.nĹF”ev&tˇ›{12íaŘá4:+khœÖçôą!z†5P­D…ůYQćTÖXQź˝Ô4şfIfęö IDAT<ŐŃ=ŔŽ•™BÂÍ˝oňóuFęŽqaPď—NUqňÄ 5xJS™XËaˆK Ő<šŠo¨‡ÚĆFÎÖů9ÝȇkôvgŐ™KJ˜Ú=ƒÓq7˝ýŽńƒURTŕ'×Gq¸ĆŻž:ꊛţr}˜ş&;šbĄ w˛_ůW׍ó,ŕëĽň†cf]yűŠŹB7ÄPV;m6†—1ĎŹƒS ý $•ŐůVTÍƍŚiS\•L Í;D}Űđ"´ŰmÜgůďďjî2͡ŻĎo̙mă†ćfä6ˇÇ´Q7Łs˙jřhŽj˘_SÍÎĄŔ2ő›ô rLŽ×öOMË\ňöž™ˇ†Ë5tLťAŽ ŃëŇQŒV"­'˛´Šî Śś •¤iDßl"…˜é$úşŠl˜(×R—u>ăÍlwŞËy] +6đ­GSqž;Â[ç™cÄ<č8›Zi™ž˜f§ĄŐ‰nˆŚ¤ fźƒv_\dĆ$֕DaІ¸tĄíîwp˝ż/ŢyÄÝÓťƒE+W€cĽX~MV,: WŃ4ťBßD+kƒţę—*˙?{ď]×q&xţęŢ÷đrΉˆ$ ˜IQ”¨dQÉśdËŮmˇ=ݞžžíÝî9˝gfśűŹwÎĚÎnĎîďnOŰă–mɒ-ɖ%+P)Q"%&1ˆ@ä <ŕĹ{k˙H ž‡LŠ~çPđîŤűUŐW_ŐWáŤD› ßĹDĺhL›™¸š˜ćďÄÄö°é^ň<Ď˜Ş“š˜ţ™7LĘe™LВ$)¸‘+SĐ5#T÷ĐÄ °X’Lň-:Ýv{ށŕ\2šő^ƒd;‹äéŻř(­Őyç˛Î˙ř˙Y°h0>™K˛É†*)č’Ž5"$™qŃ~űVŕ΁éwÖö L&œ-F’ŚAßBË`)0ű9ţÇłÔÍâDZ2ËřĆÎYźđ@_|“Ëą‚ŽĄi\J@fîfĚŃ1F–ř‡a˜3Ę\bšbşţ̓Oj06ĘŕĚĎăÁ-!.:’X Ś/ĆIú†';l­—.Đz#ͤŇíŁÝ%Ɉ+ćkφsęL gëzčŤ9Ăoj‚ËC(SfBÓ&ţ2ˆŇ´§'״Ōl%}}Ă3:ÉА I,áąQ8čĆ5ĺłůĘ:Ĺ:ĽąďśYgÉ@˙(1Ä&Ç⠟šîQEz&Ÿ•Qú§^% ‡9ńĘŤœŐM|ĺ›Š]¸Î.Í÷ŠšP]_€Í™Ľ°ŤŃÓČŞőěOIaSž“K—Ç‘XČÉK!l¤‰ęî[ˇŇőm3‘7"uNЧęT2ŘĐÂő݉d%ePYĂŠ "œÂu1ZOR7ž2yŐăoo´ُšm _– {782ĘůÚúâëź~ąg C“ŢžĄŰú‚ŃQ7’Hâc°1ŔmEýE‹K"Ó!ž^Zî܇ʖ-_nş”ů ĹV*–†ŕœU+ŘoLH&ÎIÂÂ%[7ؒ!Ɍ–DŰŔ2›biˇœÍ@`ů"~:Â%S'ÄÇf8anŻ@Nž]hë€ĹLçIĆ G5 4IÖ'V“‹K—ŔHˇÎËGuŢî˜p:í‘rb+5€nňýďzůÂ&oišűg?łęńO˙ťgŠěÂ"qj+_Ӑ^şzheúÎ1q ölęaş‡is l‘ądĆ8p:DG%‘6ť•Ňt 9>>ëÖíŐF8ě8ŕĚă+?ȞŢi ‡rĚÇl‹ÂćąŇCJ3Đ͇ďU“q`iq™ě}8“=űFhŹŞćčéFÚWa{Šé¤k\’ጠ>ZpsĆ q1v&Ý=C‹0!ńzoßjdř€ĹfĹ&˜Ś/s—ľm˘Ź˝ł×QŔëĂ/ÁfŸ¨“ą9Š3”:ӜÂ5Ŕç›f_'˛fŕ[ć0‘‹ŃŮĽřţ‚Y„އjs>óČQ.WusoJ*Ů볈šRË žDqvC5­tNiœŤVßw ”:•#mTwV•OQŽƒÓ—Ć!"Â$ƒĆCí7™ĺÎëR؛…ڏšl _– {ˇNîŚB<ŢŘŇŮť-…šş–H_LĆ\3ĺHüţ‰ťM…ÆCđůqV#œDh`şĆŚÜă:7kľm/–%ÍWśRą4ĺŹĘř&[ž°@Řä ‰#=ŔŸ2Č ƒÁ6ŢŇŠ”Ü÷¤ŸgfœŮ6¸tŹwX,_Ôł™}Ň ŒËťkŹüużÁ—wܟ+‰š\ ŠJ6řţ—M’ţĆ/ÚfŹ /žláä,ŰP¤)pÝţ÷‰§˙ŞOYŒ’łyƒkĐĄ›‰5~?PAyjŢÁ~:úÇ×çŘö$ëh⤯oMLéjćż˝Dűmĺ/‘~c p@‚Msźő<Ď=ßÎŚň"*7dEÁćäŽKâ÷ݜ zĽ˝ü@'ĎtS˛/™ŠyTj¤Ç§ť‰ŮŒţ>ŞYÜ5DćĚ%[&Wt'>\ŢH‹óLY˜lśböɜ•bą:ť:'ŞëĄŮœĎ’‘şFęw§˛>%—’ŘŤœŒĚ$ĎáârĂŔŹŰÚVŁžç#¤:•ăÔÖőň@F ëR żÔˆČÉ #ĐÉŽÝt­ĺu&Km?B)ËĐß-i8ÉóŸXxôŮ­ä”nfgŐťíY‚Í“ŇŔ?ß.”Uě V1Ů握LĚľƒd­ëűBYš|…n+‹#8gŐ#&ÂĂ[@‹Ä čC˛o§AŽd@ă7ďXx ŕ›ĹDEOŽöIAmťXśĘt ź€uňwçŒ v›źiPĽ CK°÷Dč`hź}PçEŤdgE€om6IĐ'V;ŮfđĆu‘ńé˛ů=‚žšœŇ ‰pÜę L— Ď\2XaŠ<üäN*ŁÜÔ~‹×ތL,ôę)ČË$ĺ6-•t^9KçĘKŇăĹ-ÁڃßíĆľýo(i G„ Ćz8wź‡sŸŘHÉ/f˙=%äÇ䲿˘ŽŤÇúVŘ Jú.|Č/ýe<¸­’?űó-řŤđĐQw–Ž×r-„HŔÁ!t †k|ÎĐŰ$u{—f Ă6Ëç[VŇă™÷z“PęLzźŒK°Y­ŹĆÂŢbuv9t>(Şë!ۜĎŇsón֗ÄQZG‡=đájflk[ľúžô##­´íM!7=ƒuŽv´źDü×>ŚaĘ,črçu)ě͒ۏĘraď6š^×BożäĐš|žż#Ž{óšôťŤąSőČY&=6›ĆÜÁ“>'(¤Ď‡O‚ŢßŢDXąÍřăšlŰKŔRç+X[ŠX‚›Dš&ż.)ˆ„$)|˛˝›0rø[$1S,îchë3L,€1 q¤}i„ŸUÔ^A͙M’=ýóä˜[™ôjÔßŘţjrk@#dĐ{ä-Y~ö^~öm?_L˙˜ŕŁăV~|ę–CŽGJbşőSdˎ_@§rălë䯣­ć"Ę`•°¤çP%0{ë9Z5˛d;’W s`ž`'zžˆ˘Ë•Ś–TĘ÷ž{˙­č‘Ś—Žş‹ź|¤ —DE…ŻŇꑟž–:Ç ՜ŕgĎýŽ˙ô˙žĆĎß­áZ°ždHXÉL‹EĂ łŁ?h˝2úéňƒpF‘ŕ˜ůŠ >! É`÷üçžBŠ3s`Ţ=‚Řˆ•E-Vg—CçƒaĄşžz6Ç 0i›C9ťrhžrA)H\_Éž<Cˇok[­úž…ÔŠtľQŐ€°dŠ ł)N PwľsڎĺÎëR؛ĽśĄ”ĺâŢmĐyöç‡%śŒRöڗɇԈ‹‹DĂ ăzßä•;k˝-. ćĐ0ý&hDÍu+ěQÄĎ$ˇŰöR°ôů ÎV*–†ŕĆŹRpŠeŇůŇMväI4)čŘa*Ź’}%’Ôx“/}!@9ˇ˘ÍŽĎ5ÉÉ đĽu€!8xÔBĂ2ÎÔH—Ćť ˇÎu–ä›DŢř0Ěd{Ö¤s'ç.iôL>(݂ž)+;éńˇ˘éĆŚš¤ÍUR—‹ IZě-ÇąXÜÜráô˜ ÇtŢ­żU6ť* 2ŚĚP ŤdŰ.?˙nŻ9%:áÜhQ&{Ň&& ¤!8|QĂťˆ2 Sš&ĹLnŇ’œH– -Ě:qÎŮďŸ~œnĹ6[ń°$ö=ý$ůŐ ňěł|ž"&Ä­HؓHOŐ­~Đؐ短óŐĂÉ ńÓÔÂIŒ›ž” é’‘×äDĘÜyX„3‹§žÝÇîÄ>Ž~ÔB˙¸™t—=ž€mšVpˇsśÎücoëÝ '˛ą0bş‘´$RZ… pŠvpţ l!ԙôtPŐęCęq”Dß>ßCěÍę\úz Mż4ËöňŁďŕ‹ë#&ěĎ2č|ĐĽë3žŞÍY*L˝CRs;m䨓’“LÔŹveŰi ł‰K}&":‰Źpľőˇok ˝ž—? ŤS7Wëzđc%oG)ë׊j›žpit{žü/˝ Í~ܙPĘrŃďöuňáÇ­¸°ł~÷&ríHÄĚZ˛Ä“ŸaƒąVN×MF,ž ÚâR ]Ô÷`O"7iÚ%MDĺe’ą㗕ceÇeÁŘJĹŇ '$$ü˝aL^˜+ÄÍ7~żństDP°Á$Í"ˆ‹ƒ†s}‚˘u&Ia‘kđčzÉČe+˙鸆5M’ qi&KœŁŻ´ňBËôóŞ1)&–š¤NnE†F]›FŻ˘RL”š$M*đ jŻkôů!&Íŕ@‰$á†rőý>A{‡ "ۤ lń’’đ‰íË÷í1x(qÂCoݞň§ľ[aźMÁP˜É˝QrăRLRm’˘őßÝ ńˆž4¸Ţ!łœ¸Žćő’H ˘l0ŕ†č“gwäŘŻĆoßłpa2„_G‡ 2ǤŔ ś“6š”g™ěŮdđ­{ L‡ÖŤ:wM:ťÉ=•&é“6FúíŁ[ŒÉÓŘĹÄdÂ1+?m¸ąšťŔ20qše‘p\†ÁýëMžŢi7Śó~çě´°8É(̧|],Nޑ!z†Ý¸ož„EÄS\’φd;‚C=ôť|$˜~9ĽéÄ95FZ¸î[l&÷ŘFEŒMHÜ}]4÷yHГŠy|W:q‘‘ř[ŻR7ç%ΓJn$3?Í DęésŃ74ŽË;}ΞČڞ<˛Łt¤gĆś!ƍ ší YlݔNbř†ťięŸÜćn`O- 4ن]ŽŃĺŇIČ^G‘s„öa˝ý&9Ĺä椑 haD'$ąžŹ‚'î/ÄŃŃDÓd´KD›ĘÖMźß;B[ű0َyqú‚LSD¤°uc )Iߐaľ—žĎ#űŠH‘9RC‡÷Ny`*—{jš,°Ě´Jśäl‹$k]*ůyٔeQ”D˘ĂdxŔ…ÇD›<ĚwÚ@śŃMM§g§ĐBęúőÇL÷0݃^üX‰M/ŕ‘‡Ëȡš8č8Çť'‚/WÖ&ÝcÄäeQ”—FlŔÍx@'<>•­÷ogg2´Ÿ:ÎŰőăS:&¤Â Ź“ô\­ŚfP†Tg ŻĎ Ť(ŹŹ4R,ü"Œčř$ŠË*x➝Í4Œ˜‹¨7AXL›ËrHs‚1ÖGS‡ ˇš~!œ”Ţłň$' ú ŸÖâ)ŻóÉ1;sĺ)x]ŸQĂ!ڜY5ovcŘÎƢ$Rcí×z2doŢÉ…ařěÂO˙őnşÇ“z?}ĎƝlŢüxÖSْC ź÷I'ˇ_#J}/$óéˆFxj.ŰJ’‰ą€g˛žźž…Պ߼‘Y–I˛]gěę5̸>&äźÎĆ|ů÷Ѳ˝™Ľ>‚´ÁŘŔĐÚG°ď–Řă2¨,Ë&Ő!0ǸÖ1ʸžAy$%íg „aˇ Ľ/6˛6˛.ŇJRz ž:FH‹“ü;ٟŕ⡏ů¤ç†ž­ĺś8Ÿţ‡j?˝ôŰ).J#7QŁ˝š‡!ż 2Ł„§îIÊť<ý4ôLÖgúnHŚź<ŹH |Ł´u MÓ§ĽG̗Ţҍ˂-ă`lĽbąX­VDQQ‘ôz'zóůœU€ĚÍţމł§˝ľVţݝ]’™$‰FĐŮ+蛲_$:N’!‘Áľ^qŰy -Ţŕ?3@ތUK9ŽóăW_ůf€â3Ć Îż{KđƒŻX7ó{.żűg — Ŕ*ŮVnđPIAœ$Ň>Ż ˝[ă䝷ęÄí÷Mi’˛-ž^j’^— şAçŐ3…|üiĆ9Ftţî9 U&8bLöl0ٙc’/ 0:*hhÓy÷S33ŽŽa’šäĹHÂő‰sŚÍípźoJL$›Á˙üĂ[|rQC&›%Hâlg^Żwj=§s¨MÜžUge`‰1ůÖýöĽKěA[‡ĆŃ :‡Zł)ԒËř_-%yć,–ôSýöďyĽÎ`ÝýOń2çm3ŽŚë*Ď˙óš Aôş2ݕGNŒ`|ԃgl€šóu¸KäŃ\řŽäżžÖŔ˜=GžŮCšĽ×_>Aő\w‡ZJ?új ˇ­Œ›´~řżě,äG_Ů@üÔ@Užv^î(ëîă_=˜Ćԉ^Ł÷?{ń]&hQY<üp›R"°ác Ł…Ç/pŽ{"8GX|6ťˇQ’KŹÓ‚ôŽŃŮŇĚÉSŐT÷O8OzęćŰßoŽóékŕ­ÖŰťĺ`ŇDsšžĘÂ4˛’ىśiÜ.şÚŽqęT5Őˇ:ŐšňpA/ĺ_>łž¸ŰĘĺ.GĎ"se6œXȏmĽ8ęśyo@âíŽćĽßŸçZ “/˙đ^Jm`ŽÔňËç>ĽeΊŠ/~‰'s4†{zń…Çk×x\t]oăܙj.÷úT֚3‘Í[7P‘—Db„-ŕe°ˇ‹+ç/s˘adF{Đ)zäË<ť^pĺWů]ă­^-¨:ťńll&;ˇł13ŽX§ŽéqŃŐÖÂéÓŐTőÝzv!őV•ş‡ż~"gÚš8éi䥟ž ÎEVÔ­đm‘t}|˜/ÜşË4˜ď[óî,Ç´’MŤœ3O<ÁëútBł93C ĚŞKAÚ Đ‰Ë/ĺÁm9äÄŰŃ|n:›j9ňI…O?Â=q0hţŕ ~uabčNśf*w˛yϝťó.žĎ7žˇ˜ ůÇcsߊn‡’‡šuä$Ă[žŔvĹM ¸áo9ĹO^k@ä.¤Ní”=ů$OĺúřôwođVŰěš %Żłq§ü‡fofçNöC Ú†Ţ>îônKţţúń™uÚÄK?ý„:,I›řţł›HŐ$Cçó“ăa<l_ ˘Řýě*;óz_2{*˛HľKځŤç:gOWqąŰ;ĂŮ]›mq>ٜšýœ,"3ŠšoG>…‰DŔĎř`g>žŠšó <–=y yÇYţŰË5ôË Ç/łŮfs„űGwÉym÷BĆ?˙ŔĘÓOĎŃLf—b\JŹ­T,§Óšł*4ŘőP€ż(’Ř4h­ ăż|¨Ń~—FS(+ƒ[Ěwžž…,}ˆ3oáŕ57& Yí$däóŕƒe„KşNźÍOO!˘‹ůÖwś5\Ĺϟ?OűU¨~ű^žşZĆHžçqžżŐÁ•7^ĺ÷ŞËRÜ˝h ›řá×rh|ĺMŢ[ĘËŠуî Š•GŮĘĺÇét†gE >yĎÂ>ŁŃo@öF?˙đm??Ún°%]’+ÉL4)+0xfżŸ˙ý1c …âs‚ "+“Œ00ť9Ńâž9ťmú=ô4Wq´z„ä8ŠëX…d¨ů:k9¸žîŒ!3Á&îy•|ËyWĄXt'9É$Ř y$ŒśQÝł†ŸâsÁÝŇ(>'([š*„ ß\|÷§{ÔüżâîB‹Č`˙ÕTŚ90ŰůřýSœč¸=`ŒBĄP|žQśrĺ :ŔŇó?ňŁ Đ4Đ5 kŸkâł}Ą˛â_üżlw~HĄP( …BĄP(IčрŐĘŞBĄP( …BĄP(–™ĐŁ+ …BĄP( …Bą(gUĄP( …BĄP(kŽGV(ŠŐ@IJœFQ–FlÔÄßGŕjŤI׀‰”ęx‚BĄP( ĹgĽwV…•č¤d răńŐ_âR˙*ĹČZ)9ÖJ~w'kQÖ˘L“¤Ć žšßÂ[,¤'‚=lÂ1őř$í˝přÓŻźoĐš†dV( …BĄP,Œ%uV-Ů[řł…ÄŰ4ՃU\ę_ůkVJŽľ’_Ĺj#HŘúž'=Čo˜}—ůů1+_|tméϲę´Ď=OßË=ÉĐřţ!^Žr…î}}Žŕß7ŒŠÂŰO/8킂L(Č´˛˝DăÇĎůŠmQŤBĄP( ĹÝ̒žY ´œăż˙ć45cŤ;H\)9ÖJ~k…×ϟŕ7Żá/żËŻNö`Fw /˙î}^|ăż;TMłgB_ŒÖľ§?ËŤÓ&›ƒ0‹“‚‚dě!|31Fđˇß´Îę¨ÎdsĄÎß~3ŒÄľXĄP( …ânf‰,™xÚ¨ď1—6ŮU—#ŒĚ’őFĎüŽT~çz˙jłVĺZäx }ÜHíľNŽľ÷Ň>čX9ôr˝­ƒşĆ.W]äŘU÷äŠâZi/SYF™L7#c K÷Ŕ.­ëƒ]ˇ†m4ě ţy…BĄP( ĹÚc˘KĚ5ąP´trč En=śVÚËT–K&?nD"ńťńů-›v—j„r­łßąY$¨BĄP( …b  ŽŽšzT>ş‘´UZ¤YÉ÷ëVËg.5ÂŹÓUeľËem!iźŔk§:ńń´Żő ż˙¨…Ąľ´ ş"H|~ }^Őjř¨ĐMU|”†UĹ;W( …BĄ¸k i('ěąlŞÜŔćź$â,šÄŐ×ÁůS9uÝÍíco ‰E›xp[.9ąacC4×\á˝Sm 3ŇvÄSąu#›óIŠ´ĄÜôu´qúÄEÎwűŚ l…=ޞ­%Tć%g×ЅÉhO;çć”cę—#ŘńĚă<œŽCŔCĎĹăüôŁ.ŒŰ´’^žÇwf“lT~éëT`Pýö+ź|ufŕ™ ók‰¤¸r;ŠSHśa‘~Fű{šzů ^éc\.ôýˇĐœ‰TlÝ@ĹşD#ÂĐ{ť¨şp… #7WľlqilĚO#7'üä'^|›ű%`!>;›ő9ŠäŻK#Ý[ÍO_şBŻ\„\– +ËŘ]œBJ´ =९ł‹Ÿ^ćtŰřÍ:VöPóŠĹAZv&Eë2(Îśrĺő#TE•đŔö<ňlŕĄľŽ†Ă'ščvŮoß@'Wƒ|Vş¨k™ľ€–P–!żóľ ëÖ4MŔdhhlţv:S‚Ç/ĐVđ=ţľ¸j­P( …BĄ– UáLăá/îŚÂŃĎGrşĂƒŒĚ抯îáĄ/Ćăxĺ ďwMQ ËďĺY1ęÇ9îsR°u3{śßCŞýţéýN<7ÓNçŔ3{ŮlëáčťďňÂőq, š m§Ońqť›`ŒöĐ:8—ˇä‰]ż‹ŻßG×ń÷ůÍŠůU€˝×š¸PÝF§[ŤŽ% IDATúŽ5qĄŞ‘ UM4ß6˛.żÂ–ĆŚu„錍s˜ą€$ŕĄöD5†…ä˛"ňĂňţ„Q¸{+e1’–ňúŮ6Z{éhkćƒ7qrĐJćöíěˆ€d¤Ľš7_˙”*÷Œôä8 ŸžâĽŁ-L˙har‰đ * œ˜-5|Đ0Ę?Ŕř@'Őmc˜z$ůŮQh!Éj^Áhâ­ßâć”˜QŢ~ĺ8ÇŽvŇŇÖÂńwĎSë„ç°!jĽĎá.ľţ,e~ço;ÁŐí”çM!ĚH ďž2rÝúŽ9š,Ű×cĐ×cLűŔKr茁T+Ť …BĄP(w-Á9Ťa)lĚs"Ěaę[ĆnmÉaXu30LăőŃŰú š.ÖŇ1%ŕŒŚ×-'QÎÉÁą-ŠB'"ĐKmł{Ęv_‰Ť{€a)ˆÎJ%QÂŇ(+p˘™CÔ] VAäş­|ă4Ć>ý—ĎrÇ88!\~e`ŒÁq –$v”'Ü<#*ýn\^‰°„íX„ŁdKŁ,ßF/Wę\ÓË"Đϕúa¤KiqÜ­Ę7˝ŒĎą ÔôxoŽ€/fĂŽŸHÚ͉ c¸‡úćfÎÔc†*űBňŠŸQ—0éźRKó”ĚIß0=Ł&hN˘ĂWÚY].ýYl~ďÜv‚ŞŰ)éIŻ‹ĄWź3}Aiŕ[Ä P8ěi;óřʲ§:: ä˜/ 9„k€/9tr7âńŔ–ÎŢm)Ô|ĐTÔÖĺÂtÓćŘ"cɌqŕt:ˆŽJ"=lń’pŘ&ĘÓë›5Żż›}˘ÜÇVj›d ›ߍ&ăŔŇâ2Ůűp&{öĐXUÍŃӍ´ťeȲ{×j^—™ĺԟéŮv‚¨Űhş†Çľ€ş¨o“<ĐŕożĽ—`AˆvçĚyx„Flź…€!ůĹŰMŸ‘ĘV( …BĄř|€ĽÉ˙,ׂ“t5ó‡ß^˘ýś1ŚDú}Œ&„ ]ÉHĂIž˙ÄÂŁĎn%§t3;ŤŢĺhĎÜŠ–kü:~ ‚ňÔ0źƒýtô1:Žćďo=ĎsϡłŠźˆĘ ¤…GQ°yšë’řý+'¨[mďVN‚o;wŞŰj×DŽąŽ&Núú¤ôx—`ł†"‡Éőşzű%‡Îĺóýqěܛϥß]e`5_ÂRyřɝTFšŠ9üŻ]™8¨§p /“”EŢ )ÝĆ%„ٰÍňšĹ†U€ôxn]q˛G„ Ćz8wź‡sŸŘHÉ/f˙=%äÇ䲿˘Žú†Đd_ły]N–YŚdŰ ˘nŻëĂ@Ňyĺ,‹hd ^8 ˘XÇbř'Uk˜`Ô-yáÝŽĺÚçŻP( …BĄXQ‚ZŒ1‡č3@čáÄD,­ˇj ŇěáD‡ÝůŮŢ=‚ؐĺ0č<{ŽóĂ[F)ű íËśJ<–ôJ˘fo=GŤF–<Г1ĐO—„3ŠÇĚOń QčHť¸uĚÓ 0šľ˜ó˛óĄ%•ň˝ďŢ+’ŻéĽŤî"/iÂ%QQá˘ě ËëÝÍrëĎěĚßv‚ŠŰĽ\őý´ÖäRƒÍ6qu„ŮçëLÎ׊ J …BĄP(Ÿ‚CJoľ×}H=– yŃ7#ŢŔCěWt¤§ƒęV?č lČsŢć@ęááD귞­jő!ő8J  ‡Ż“?nŅőť7‘{çxƒ€ ŁĎ|áĐÂŹXŕ÷3-ŻnĹ6kú!žßŰÁĹz7č‰l,Œ˜^Á–DJ ˘.ŐފĐjşč2š“بŠ/ŃIÉIfö[MP.Z8‰qÓ+HÓ54$##.ŒPe_H^CF#ąl/?úŢž¸>bU&8ŚI˛ţ,wj;wŞ[€°$ö=ý$ůŐ ňě eĚ ż|[ň‹ƒĎüęŕď~uĐÄ3GTk…BĄP( Ĺ݇žđ÷†1ą÷Vqóߍß'~ô÷›dŚ‘™•JŠĹŔŻ…ŸČúň ž¸ŻGg3 #’°˜46—ĺćcŹŚn@#<5—m%ÉÄXŔÓ×EsŸż Đ×o’SœAnN Z€€FtBëË*xâţBM4š@€ž>ƒŹ˘t˛˛ŇHąđ‹0˘ă“(.›.‡=.ƒĘ˛lRs|€kٌŕ$‘GAR™Ń~úGvĚ˝KÔŔžZ@i˛ ťŁËĽ“˝Ž"çíĂFČůőúl䔦çÔiháşlą™Üw`1V4!qO>;Řxž÷Ďv6Ďd {Œ˜ź,Šň҈ ¸č„ǧ˛őţíěL†öSÇyť~|J0+ƒaO8‹’H´_ëaČp˝y'O†áł;p?ýםé L:~ĄÉ%"RŘş1…‡¤oȇ°Ú‰KĎç‘}E¤ČNŽŠĄĂk„({čyľ„'˛Š,ě(餹mˆq@`OČbëŚtĂŔ7ÜMS÷8>é¤ôžm”'9IĐů´6˜ktœqɔnĚŁ0Á†Đ$ăĂ# š?–ź=üő9ÓÎJO#/ýô$Ă[žŔvĹM;$ëo9ĹO^ŤgDBX|6ťˇQ’KŹÓ‚ôŽŃŮŇĚÉSŐT÷ű§9“aą™ěÜ^ĚĆĚ8b:ŚÇEW[ §oȑż‡ż~|ŚMźôÓO¨3Ŕ’´‰ď?ť‰T@2tţ0?9ÚÍ\Çeľ¨,~¸‚M)Řđ1Đщ㸹mům@ä–ńčŽ!-ˆşö4yfĺ–6^ůՋ¸7)!1‰űxˆ˜ŘX4McxhˆĂ‡ŇŰÓ˝đD …BĄP(k§Óšł:×O…BĄXIl6;÷=đYŮš!hkkáýCďâń¨čJ …BĄP(ŸœNgđW×( ĹZÁëőŇÔ؈Đt¤iŇP_§U…BĄP(ŠĎĘYU(w!’úŤľôtw0<4´Ęň( …BĄP(–ĺŹ*Šť)%CƒƒŤ-†BĄP( …b™XĘë …BĄP( …BĄX”łŞP( …BĄP(Š5‡ÚŹP( Ĺ*â´ŰîübE÷xW[…BĄPLA­Ź* …BĄP( …bÍĄœU…BĄP( …BĄPŹ9ô„„„ż7 !ÄÍ7~ćçb°Ž đËďřÉéľp2„Ŕžzz€úžŸ —ÎG=‹—ăłJŮ~˙řT€gw<ťÓŕŃH7›ćžˇœĺ+lŠřÎcěˇwpţşš$‰:ČŰą›Ż~a_Ř[Áý;KHŹĽŞ˙N9˝Ëş]üÍwv‘Ň[KÍ`đŇéé[ř×ßż—|W—{!ż÷îEcÝţ/ń—OUrßÎMěŰYĘÖČ~N5Ţąn?że6‚¸Ę‡ůëŻAC-îՖgí˛tşłýľSňč“üiš¤Śś÷"˜ŐrwŸČŃŇĘůßŘMîXŐ}Ćj‹‚˜˛űů—OĺCs3×ÝŕÜMňŻôœüÍwď!­ż†ę%éŐ+ŒękŤŐ™U]ňĂďůŘďş6áŹj„€@‡…żxY§űłlŁ„ä‰Żřř“4pŐ[ůћŁ7>Š4ř_˙$@V•ďż§ąĐf."M-‘¸št>ěYźČç-ü}=Íä™' 2Ÿä"ŃHލ "ě:ż??@0Ă!@ŢAŻů•|yG*#՗x㚠ż”ŒtŞAÇ\ˆČTś•$ŕnŞáҢ;%“ÎóÇxž^-‰˝Ol$qI¤œ`ôaYŢť¤eŚX;,D=ԜŞcĎ×7rÁ5^˝ęYÔ¤›žž™>žG$ŽźóoˇÜĐ/ABĺ~žť-ÍčâŕóǸ´""™ÍĹqxŽŐQuW9ŸŠ;Fú†bʲHOM %: 1\Ă/~q–ÖĐçvw@/áť_Ż SăÔ+ŻóNű­B֒Ëůóg7’xŰG“öăoňó3#w\XP(>„<kŽiž˘1"nŹÄNţ}TŕZÁ¤ŃnáG?ą M–fe.DÂs î‰Ňx{diÓŐ"MŰaĐéŇř¨G,:oŽK€ÉŕŐĺ*_aĎ`wy #Őg¨óĚő”…¸źbî)ĎĄ %Šp+x†{Š9ĂzżíyÔŹděŢ>ZÍß FűY~ň“ó`Ť˘“Ą EŚą}G!Žz.÷-Ż{ ‡Ś@ˇR) ÚY ŽĚBՇĺaŠËLą8–˛˝-DÍţδmŕŔ–’ę/Ó˝ŁJŔÂşü$ÂZ:đhQĺEc ´Ü@$"R¨Ü’ĎŕXSPÎŞŮq‘ŸýěŇTCë5NaĺF*#Çéî ßžLÂjËôYED°ůŢR…9’ 5×ržÓ7ĺÉčőĹM€-„ťi Łř|˛ł*݇?Ői•Kł x1ŹÖné š&–HŢ=!‚ZźYúňDPlĺäŐžŮWŸ…‚{÷óô&;Ý5W9|ĄŸ!ŻFlv!÷îÝĎ7ďń܉~ü3ҾُÏwU+CrcK˝"XîPf ŇĹçƒŐnonjŻvńđCylNŤćë‹•ŤŤľ›ŘĚL˛Ă:¨÷—IQÔM×Ă)\ým1ó 1 5ź˝+0G9óúkuăńě˙Ö#$čŤ-ÔgAdńfîďäĚŐxśŻŸkź,nšĘGç]kŔA\m›ŞPĚÎň”ąJvWěÍ1Y#‰ąÁřˆĆ•Ť:/žŃhŸed)ě&>dđdžI ‚kÍ:/|¤sylęC’/|ŮǧtÚçß ăÇWf_“Gv<˛Î$Ő—ĆĽZ_ŸÖč\Ě.>żĆűő&Om0ŘpĆÂĺšŇ ś4Éמáă+SŚ7Sôńű'14ţŰ?[y×bşĄbů†Ž‚ü$tW= ˝łÖ ĺ÷đĺpîőˇ8ÔrkfńÚőNÚÜűůÁÎM”\ú€ cgdţ§§ňpŢěňřĆ_ćMţżAőŰŻđňŐÉĘąĆPRYÄŚœ$Rb‰°wdćŤ5|pŚ•žŮĘĚĎś‡*ؕG8nş›ë9ňQ5ÍcSdNś~ů)dŢŘÇcĐđŢküúĘ쳢‘ČÖ]›Ř˛.8‡Ŕ碚śŠ÷OˇŃ?E&ň–Có{ďѐTĆŽÂDbĂLF:š8|řŐĂSV0‚Í›Ë}ßx”{nušq>ÍßÝÔł.ŢüçĂ|ę 1ÝP şĚBӇPĘ÷–čtvl/Ś4;ž8‡†Ď5BÇľf>9]KłK†^f!Ę`ÍfßŢR6eFbŒŃZ}‰“sܜą,ş"‘ȶݛ¨ĚM Ίax< őuSőéyŽľL?žäuĄľˇĺŇß)¸[;h73(*HŕĐőîEO\:ŽÓ˜\Nq†•úŚIyéDu7qĘUHá̇őp֕•°˝(™äČ0„oŒŽ–&>>UOëř­ŇĐłśđŁGłh=z”ŚÄlˋ'&Ěd¤ł…>źÄՑI}ĐbŘóĚ슻Ľë1űžŕßě›üĹčáĐŻ?źŮÖ*”ÓoԅIóŃ7yĽfvŽx*ś•PžGŒCĂž–cçÚœŞżÁĘb9Xb2ŘłkŇ"°ă´_­ćÓĹÜTŁ'ňđˇb›÷˙řR}Ó@8۞~‚/Ä^ăĹçNPďżQ!śăˇ^ć•ú[šžń~ţęhÎÎŘR<\#“/ZŽő-œÂÜż1…ťœÓî,[9ˆhîůÚöq‰˙~p„őťKؔC„Ŕ5ĐĆá7Nqeś {:űw§Đsú 5Ń÷ą}žÂ›ÓI~ĆĆý‹˛#žÇ׸GU5#…8=Ôr’Oíy|K2Žń.>|ű'şoč@đ65Ôž%”ţ"hB´ë–˜,îۡ‰˛ŒHl1ZŤ/ň‰§˜ŻďÔůđ…wř¨˙–ĄöYŠ•#tgU—ÄG˛+7W].ÁčMÝ7y´ŇDkÖ8Ú(č‡ŘT“Gśúů‰ţć ™žJٞE˝oł`D›“ţłVžožÜ‚+î¤*Ą”ďB°&“˘hëŁk–¤…=“{ˇÇÓć]ˇL7”“ţęšwm!;IăBł‰ŮUĹKŻ6ĄŁ‘˝cű’ť9ňf ’ńţ[&_8SŘV™ŽÖÜĆĹĆa†ĆŠŮlÝz’x’Ÿ˝ŃČĐ´2łˇç2{[8}Ź3:ƒ­ĺ|=ÎÂ/~{‘ö›:éĄöĂĂôÚZb_ş7}îü[Ř÷Ľýě÷Đtń2§ú "ÓóŘžm/YqŸđłˇš™&ƒFîŽŘŤ.óćďĎ!ăÖńŕýĹ<ő‹ŽWk¸9~2oć(çŚŮ Z|!_ź/“‘łÇ8Ü<šýHú蟦gĄ–YYfĄęC¨ĺkI(ćëOW’#†¨šr…Ó^´đXňŠ6°9ľŽćz#ä2 EáĚâń/ďĄÔ:Ŕ…3gióŘČ.ŮÂS‘Sźßӝ 8Ý Á–Gďç‘47WĎ_ädż=<‚¤´ Š2#ř¸Ĺ}kľu!ľˇeÓß)Hw?í#–DźčŚgąc`ŁÚkOä§`ť6Nń:';pĹĎpUľHĘŮǃ’ëľ |ŘíAD$°aă&žNrđękivB#kŰlľ5źűć%ˆÍćŢ{ xôž1şß¨Ÿ´..ż˙!­VqyؓÎčĹ|Řrَ÷30U׼—ú?˘ß">ŸÇv§Í/Kťěegœ—–ŞÎD¤ćPšy'1§yţ˝VFgčďĺ ľ<üř6Xšrţ"í^™Ĺĺ<!Đz˜Ŕčăbí0ۡĺRšPÍS:^EiŞĆđĺ&šoaČířnCşí’ÇşšpćÄf˛mÓ,vgĘAŘŇxřÉds GăÖÂÉ,J&Ü3ÍëŇc%gg%%žŤę§`ÇFömËŕÂŻá†ĐĆ0“iŐˇ„Ň_„@(v]828đĺ{(ˇ qůě9ŽYÉ(ŮÂScÓţ̡͝›U=ÖŕożeL°„ŕ—ĂxŽcâ9Śń?§Ó;ľĽUéTů}ü¸ÜŕŢXWŚ|&Ŕ1ŞówŻë\3tΎűů/{ ž)ÔůŐˇVöz5]šóný‹-6x"jYůßÎNnŐ˝˘Soúřˇ%žH˝%ďB04]đÝRƒ„zžYž Ľzş5zÝ4ńŽAÁ•볯h†\ž!lů.-2šx+ŒšfMۑ›KĄÖÉ[—1-"˝÷W˛-' ›„ú ­^‡ML¤g„śë#€Žc\‚éŚűz÷¤MGŽľđűçęŸâ%W5ĐâŒď”QŰÄąŠ#x!­ă—Ż_ŚŰh¤nüţlo1{ Żň›ęΓÉhoŁ€.3ç ŹY\ĘÎDh;ö>/ž™ÔÉfÚÍ|­d;S[xˇc†ßq™ß}Ň2Ńiőžç˝ä ž[žI~ÄUNOŽî‚Ď[€Ąîn†ÝĚŔÄ=ŘËľ9ÎƄ\fA\™…Ş!•Żˆ ňžrrő^˙öO9—wćÓ*"m7ňZ™/ƒ Ľ|#ܜýœt~Ď_âŠoíĽlÁéN!Ý aOŚ0݂Ťú ŻďœRoŃ´éƗ§. ”öś|ú;UýĂ&Zz4ń:,>î–A{cžG2ČĎrSčěăä572~ę3‚Čâröe Žáľă“şŘĚĺë^žýd>{ŠxéŇŘtíŞá§Ű&¨}#MLăëĽéŹ oŕœkÂ> ÷ö2 hfŔ3ÔOkÇ\K&Žţ^\€Fúźψ‚ lI´Ÿ8ĆŤG'tĽŚ…Nó!ž\\ÂÖäëź?sóŽň†R‚äŇ Źwsů88é€_jćŔWvRr§j™IOm3[ËŮXĎG˝}“ĺ H(Ě%MŒđIuďM=]P;žŤĐˆđ4ňO¨e"=Ö'řZńtťłĺ Ĺćď𹑛şŮĐذ¨4ƒĹšRÂ#—ިŚÓ€Œš4ý ´5RŰŇO˙˜=2őĽů”íŰO˘í=~qrĄG\$WŻpüJ?6™FůCI4Ÿ=ĎéFI_R>ë2c‰×Žq݄PlęM‚č[Bé/BĘYĐv]TVĆŚH—ß<Ěk މ>śnˆ'żu/ĺ3œŐĎ~Űźť ůžUsTăW­üĂ[˙ţϡŹüoYř`ŞsÓ)MŤZť~ÉQˇ§Ű\§Ń:ĽˇëŞÓ¨7a}–Äސ@q–‰ÍÔřčęô3ĽŤ5ú‘lʒ‹ťdV >žŹáK7¸/~ŽgPAą\é.3ÂaÇ)$Ďl4RŇĐ{ş¸ć´Xv?ž—ÝqC|üΞ?XËhN"¸o)ŕžfÜ4MÇbžîA á$6jfş&]u-ôŢTÉ`]+íŚ•ŹŹ„lI°™•„ŐěăňՑ):飊şÂÉ͊šĄ“&-ݸ§ü>0äÂԜÄL-‡ó$˕nP„ŞĄ•ŻˆĚ`CŞÎxC5gf1݌.č.’dáädF!ĆŰŠj˝XCz:¸|Í;Ă^FÝ iđŔž”BFřŒˇ™S%^ uÁ 鯁Çk‚n›XąYÝ×iđŚpĎîLœ]m4Ţśźb#// ŤťƒKM^t]Ç2ůOöwŃ2Ś‘œOŘ´ďHşÚzŚéĂĐĐŚpžÜą',¤e$föSÓ0:eęçZ];Ł8ÉʈœąI2yC(á$+=áî˘öú”áż§‹ę֙í-4ĚĄk\ę0‰-Ě%óĆŮO-†EąĐwË=7rźv|ˇaŇ^×ĘŔÍJĐŐ=<ĂîŹL9HogŞF˝5?d´śď+&˛ĺG[ýóę–Ů[ĹKż?Á‘łu\¨mćě™3üúĽ¸0Ź“Vš‰’đ… !ŸĐkżŰKŔô2斀ÄíöÝ†}ÁÍ>¸ž%řţ"D‚ľë"œÜŹh´ńv.MéSĽ§“ËÍ3'›?móî&ôK^Ë Ú,eřJšIi’$Ň2ýhDŘ,‡ůűFŚĎ´Hˇ Ďë#$‘‚Đśě I\ŕtĎóoŽ zMȈ”h,|vŔŐŹs|ĚĎţR“7>ý™PË!X–+ÝŐĂJtTŢáQĆ$čiyT&Žsć•Oř¸ÓşhĐIúvłÓO**áŢňlr’"pZĔ2ócŃgę˛dxdl†NşöCV„‡H:i#2BŸ‹ÁŰtŇŰ)Hˆt"šö™×;˝ł“Ś4ôiV3ÔźËrĽÜťC҇ËW‹Š$F“ ô /Ý‚PdN˘ĂĹäß§=ÉđđćÔ˝ŹşžvŽŸę"kO ßůÓB†{űhď ­š™ CÜ î˝ęX]ý]F?W›˝l.łŃři'cŔ´ůP-œŘ(pćňĺďçΞ„kb0꽊Żoúš‰”“ú°Üý…#ŇŠ#}c ÍĐ9:ƈÄE8Đž2H BŢPĘA8ˆt ¤kŒ‘ímdč\ĚáM9Fuu'űʢ4ă<×ZčI9”Ä™´kžu$gířî▓tăwĂ0‘SíÎ •ƒĄĹ#ď bK+ٓ0Čą›YŔ¤ťƒSľĂ”mO$7YçBÓÂÜmӘPtiJL̛˘)MĐ4Óěƒę[‚í/B&Hť.œDGL×(CӊĐddd|IúXĹ ëv IDATĘą,–KüüřA÷5—j´M ě­˙˞ĐÝĂŐ¸S1(ďU *7¨źrűpŠËašÓ]n¤ŰøŘíaˇ „ŽŐ>ßDďb‰ 'BŃŢ;eř2:@ç˜$&ä7 ˘KvóÝSń^ŤĺčÁnzÇ|$če|sOÂŹC•ů†/kG'–ˇŐK7Ř×/§>Lžb Ä\ kF…‚&@çŮ#ü¤>‘üœd2S“X—żž ĽĹl>÷>?˙°›…ĆŞYúşX)ýľŕ°i`x[L ži˜´_:Í{-ôľx™k”ŮßŔ?šyÖséťý*šľc´‚#Hyƒ*‡eněcMMÔ{Ó)^ŸĘĄ–’‹˛‰3ş9Q7vśóĎŇ0XéŐžÉ};RđÖ§Öç *@#Ü*A˜ÓIT„q—ožíś’1—“Hěv¸6ƒú Ľš›r0łŠ” >÷ŁăĘݤ‹ á¸ý&‡uĽË/2>o`ŠŽ˘vSÍË]Éâô{qúĚ(7˘•ç[\”ťďŇnćrdMpšU׋‘gf*LV pŹÓˇŚěm´v7ŕ#ÉÄtl Á"ĘÁ\}W-˝ kVÁpÖrźyoöqôÖ8Q{ç^ěĺ˜'Ăŕ­Š Ťšy\ēÄLęšŠ‡˝ ?Ç;üG|î\Š•ƒFÓsŸĺç‹üÁó5Őƒc&ŚřÉwÎ˙÷ľ_Żńăጙćńőďß^]ŘČByŔˇiî¨ĹßĆóÇ|¨Ô,C[=6á¨Řńő˘Eœ×ÍŁQ w='[×\c5ôľnźŃq×Xń8öžgŐT|xOă+uţÝçáű#Š”ÍäLżA+ŠüV—$R>˙ő‹&?Tč~ƒ_=cŔ‚•żz¸"ŽÍkŇí/Ě.ąT^ňV˜ô7š…‰ä ÁHĄGîXřî)ƒ/=—ăóZxg*uţŮ1“č°•ď>ĆJŔë)ŢťaaŠK§JÁĘă”`DwâđšSyž’´p;†Š˜œR…;CťLCăíaĹÎéüťáŐyĐ ĹЈöŕŽt1ĺť;i‡ćůě'ęčŹŇ›_żĘçÜĚ"FO=mŽ!ާBüü{—qî,ż˙GçÁĐY›f:ĺ-ţmÍ#÷–řÄĹţůçM.,“ą•ÓŮßA qt\[üIÖ×͗żhçň`ĂßŔ…3Ő°p×‡ÎÉąz+hđN„Z•+ WE­…EsôD„ŠHáç؝ëź{ęS\zîüwŢťÜ^Ôń6vđĚ17‰áˇywf]3ťŮ7Ŕˆ.0Wő[ŸĽţĆ(Ł‘,šŰO[w úĺďđíĄőŸÇśeVTLćŻÝŕFß%NöđÁ“i'-ý=tj›ĺؗşłŽ†żĄ™ţv…ĺ[ütpóqŽůşřʗťČßgxn…xނżĄ VVn1śćÎ~};>ŢöąţŽĺnާQ%¸:´x€ š˜Äî|Čkm/ńŠ‹/óŰľŁÜžŽ‘ą8)ŻŹ ľľšÔĺWůźÓ˝C4Ätâ8gúOs)5ÂTBÇ43,ÎDˆ­î¨Ő㧮܆TŔ…pú4×n/ç“Qf– ýäńĄ[\é{‘gžžÄox†\ŇńÔˇńTˇ‹Äč{źˇŤFy1ĺ`˛ps€Ű˝Ďrâ“/ŔľŃÂŁkŽuŃśĹńśůŮ{܌ôpŠť3>Ěőńͷً9.Œĺiî†OňŇÉgů-sĄ ՝í4[’7ÇEe{/ýUVP.š] TSNĐjšäĆřĺh|_ćĽQiZ!ĘëĆăՅ|œÉэc5RyL4–gŚź˙LXĺ űĺ/đ)ß"#ÓË,Ĺł(w%]]őTŮSÜţÉ5îîŮԂG+Ś SŒbŽ;VÔyÝdáÚ5Ž÷˝ČéĎ|ăý!F6ű{i'łŠ~ď˙5V<Ž}™ł:qĹƟjyžrBç_ľC6ޏzĂĘ˙ž¤óg_ŘşĘ_{ÓĘÝ&/ž¨ă7ŁCVţňu #k*tEWž?yÉX—i˙S9ţăS…Ÿ#×müÁĎ´BŻW^ăë˙`ců9ĎőäůƒÓŽ+Ž_śńˇ—ľőď~L™) żëüfđńˁźĆ×_ąâž¤ó™—sü +(]㯿jăGńÇH|ÇĆ_ÚóüÖń<˙öL!Ý˙ú5™XáďE•ďŽ˜Ä‡†¸óÜ%úzƒüb~a]ZŠŃQîžp‘gNUpëÝšđ˙ôˇŁźâqâĐ3ÄŇŕ*sĄĽŠík7Y¸ň:ßÔÎńň‰n>Ón!0rămžžÔÁ~aŤçŠĺyóMښÎđ܋ÝxĚsCWůîëˇ× 7SxťÎóßżT˝îŽž÷Šůž*źoěúŤü§ŸÍ˛ůE~ţ?#ţÜIÎ÷œâWOŻ>túňüěňăѭűżo@~žŸżrÇĽν|‰ç­ ĽĎń˝Żţ”÷㏑.:SďźÎwíxńřYžxFCéóüŕks„cfQeVt}(˛|ó‹ˇůú7VxćÂ1N;IŻK‘MĘťÍ[ł[4Őś-łâň`&'řޡß$ńâ N^xŠůˇßçŸŇ=|ů™ ýDűRwŠcŚćš~7ȉĆ6.v9qZMŇ+F/żÎŤďMąn]Š}ů,Š9ŢöŤţŽĄÜôöÖbYŕƒƒnČ1ŽţđgDNăBwĎś:ąYâ+QŚďŢäćÔcŽ,هxó§×p<ŰÉŠçŸĺiŤBé üřo_ăĂ€ÂÓq†ßş\÷YxN_ä˧Lâođ7ŻĎŻžűÂźůý×H\čăLWŸr*r‰(ăźĂLďj!š˘Ë!5͏žűK’qüěŽë Śî~Č2üúS{°Ę”áú%žťXIlxtëĆx1DžáíW~I٧NĐwú4-Ée†ŻżÇ?¤ŽńűŸ,ŒŒj;OđrßÚľ#Ş8÷l`’¸šÄĺM×+‰rXĽ|ÔUŮÁˆrőćÂÁÝt2łĚ1yźšŚÎ =v 3›"<7̏߻ÁĺÉäôäن)BQ׋§ZÔyÝLMńýożAňĽ“œ~ćýšăWřîŘqžňŹZ?-žŽąâŃTOO™Énß(Ľ|Ý˝“ďBěœFÍӟă÷ĎÄřÇ˙öëÎXŠŔŠOđ{/¸šőƒŸńý‘ƒ8Y‹Ň%őA”.-x‚?řJá}oÝÝúšť;ĺvîŃsoÄcKŚwżLXŕŠĎňo.Úyç›ßă§GyçLjňtńŰż{Ú‘7ůËŒoxúŚxň(ę/~ß;—äű˙×ϸ˛éŃ`˘Ô¸Ýî#>őAA WŻr5Űȥӕć™„ŻżĹß_ÍqüóżÂżúd/˝ľ>źNˇĆ?îCĘľ8 RDŠrrüé*foňęĐăŞâ a rŽ?‹÷¸>/ęQaŻŻĄ%~yyBŐ'ŽBŰĺhe´7ű0—˜Ú]÷Ž8Ňł*J•Šś^şĐEo­Çý522“üă×^㺜`>f¤>ˆ'›ôŹ–Žb{V-eŐô֗SŐyŒ‹F~ü}žyKVâĐŠrž˙ĎÓçÎÔ2 ÓI}ďqžkˇrç•Wř‡Á”§G€Űí–`U”6‹ĂMš×Cĺ‰-ljçĺÔňq&őA<‰$X-ĹŤŽă/ó?ś3eřƒ÷řŢĺy饢$8éx攵v˜ů‹ĺÁ—עń…`ÔXCťËń`ťű<'Ná=waw™Ř/fŠ‘Ţă;ŻžĎĎŽŒ1“ŮűEľ @7ÍMźnščŚšŁmŸT2 X!„B1Оęed›“ž˙k#ÎŘtŒžŢ *­LÎím7X[ƒ˘§ĺá ֞E[ƒ:"ŤďO™)‡ďłŽöK!H}Ţďă’ßGšőaďł mV*ŹVNx\ü$˛ÂÂË,çuŤsXŸ˝Hě—o—Đcm ŇŠŐŇű4śŐi§Çíân2ĹDşđ^Măěę¤čbI2†ńČmŸdŹ !„Bˆ#FŁÜçB™+,ÇÖ÷1ĽbqŇŚrŸ5§˜02XޏxRĂëR{´ ĹŮ…ßű0bń{żýY+Ü5Ń´őŰkJO™źy]'-z÷Áţ”™˝ŚgKۚwĎüüvm§Ś‘3ÍuéÝ]6+ýďFcDVƒUgKöšZ2ăťŘÇŁĹźßŤŻć¤×Íőx’?Ÿa%Żót™‡ŰX ŔŸOÍńóČ eVËŚmăşą_1tI`U!„B-ʆӡŔ̑Î)Ę[űšÔncöćMŽ&˛dPxœvxŒ&V üîŹÔwüÚóV~íůÍżŸ™üĺ?äˆ'‹ČŔ~Ú§2ł×5`ń•Áę˙ŐŘm|>ŕÇŽ4^ /óN4ţ`ČŞiš|6ŕ§ÍéŕűáeŢX^!o‚])ňŤ7,ž2ěu ‹`@CáZ}|KÓĐVCO‡ŚaÓţüQŰ>É5XUJĄvRĆćęĘa˛í˝íĆ;˜B!„[Ó°h€ab á-óŕ´Y¨,łAÜÄ0Á˛‹çWfrđí_č NüOżeăŮ~ËÎÚ1kźuCç?˙]žŃRšY¸?eŚš\†ŚIĐfĽĘne"“á›óaBš|aˆďęö)Ă ŠĚfsœőšů\ŔĎßÍ/1”LŁŠÂP`ÍĺÚł˝.e ˆé:˙m6ÄiŸ‡c bşŽŚďFăÓwŁq4ĽśÜöIW/Xľ4óĽó};ȁž`ÔßLÇ\“mčś‹7ř˙Ďľí7B!„Ŕ@7MĄĄ3sű:ŻĎhĖ˜Ž 4şąű@ńƈÉ˙ňYţőlüËOZńě0vŠ%MţöÇyţďWt"ąRť żże Pd “+ą? /Éë49ě¸-CÉÂ,ŮÁdúAěďÔUSkˇń Ě-jóńp=‘âz"†Q+`E×ů§ĹŹžVŘöIwxÁŞ>ÇOżů oí¤Nćóä,ŘdŰ'xŰR##„Bˆ’gćHgL(łá´™I˛°Xř“ć°ăŔ$“Î5œuŁĽřO—ăθÁýşśúnĐ Nüůˇňüüźţoź_öŠĚŒT 3ŸGŮíh ĆŇţlbŤ‚_ řů|ŔĎh:ÏÂ˨Őnj đœßG“ÓÎd:Ëb.‡śú73ŸÇHĽönż€­‚ÎľęvŰ>Éqp–ČB˜Čáe@!„BIŃX łÚß§Aća ËçĹŠtfbéÇ Vryřî[:ą$ülĂíÜ:`§Lţô˙ÍńöRöťŃţ”Yvv=ś‚^›&­żW_MżÇ…Śőϔ{üX•"mü0źĚâęPa=śBvvúńvőcéÉě•ţ¸çB!„âČ3Y -ą‚ú†uŞyiiđĄrËL/íÝck*ËŔit0ŕr(ŞüĽ,ěO™eççH>x­€h^çf"E8WHoE×Og˜XýKgx%Á_LÍóăĽőK%§ÇGÉÎĎírSĎĂŽŐbF*˝ý†GŹ,„B!Žse†™*žŠďäŇ)7cOMí^đĐ$Ó{ôJ‹ϝ°đQkY4¸xRă{oé…yĄ%j?ĘĚĚdˆżóޓgPV+ XÎëüÝ|˜Ë+q~-XÁb.ĎwBK¨5˝Ă cšëzÎĚ|žř;o•Đ3VŢŞzšĘ4ŔNĐŚ@ůhmo˘ČŻ„×#$54ˆť÷؞ä0}o˜ÄÍ'sí V…B!Ä”cćÖMŢMˇrŹĄŽţjE>cěö87'ěUĚXPœęzdĺň&Ż^)¤ţ‰s6káo§;5jŠéPŠ-Ź´Öţ”YüĘe7Žá=sx8 ő^*Ă_MÍă˛hÄ7DńŠÍC<7Žżry—šŘ/ _M} kĂŚ2Ú: ëÉLĹ)2XÍÍÍ2÷W˙ďésX|>LĽđGs P>ăWŻ€a<˜çű(zٙi°Z°8œ`ą‚R`š˜šzt™Äí–ţéŰ,ýÓˇČíńężG­Ě2ăd&';%ĹfłĄzzzĚĚęŠ[Ź !„BQ`ˇ‚n°ă~-Zá+ťwOÍ9ҔÁ˝Ś{]šŰ €‘L’&;?WbŤţŠRăvťe°B!„[)6č,&°ý803™BáÄřagEQ˛Ŕ’B!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’#ÁŞB!„Bˆ’cpÚm(Ľ@)”R(…—ŤżcýĎŹţűżB!„B!ö Í…Ŕóţ×ý×;ů.„B!„BěˇŰ-À…B!„B”ëý>ýÜ4M[ýRüđ+‡™/!„B!„cŇł*„B!„˘äXˇßä€hv+VMâŔ0 t=O&Ťc˘|‹Hˇ$ľü !„BuGŹÍ~8ÁŞrŇŘ×Çů–í6ŐŹ¸źe4xËhh¨fôĆĚgvX¨6őҰŸg`ől3ĺ 0–ůŕő›ÜŰMŔP¤'˝-ľ‡Źzš:9ˇ6P5u2eˇcĐýi’ĎćČ)+N›VhĐXÜ´öu˛´2Ŕhjű÷Qîjşkěä‡yăÚI ÎňrŒěŮ3œ­i Ĺf0šłÁîR­/3˝ŠwWĂâK…˜ŰaZGᏏăX‡eDHMJĹß[ŖŻIdđ ßÜAŇ/_á€HOßâG7—>"Ř("Ý}ąĺpˆJâ˜WęښhwfˆFăÄm~|[oˆżš“3Mb‘ӓ‹ä”@M˝'*¨vß൑8ť;ümÔëçŮąů–u<Őő´ë§Ürƒ×ÇEO×H,Lq+óđvĽ˝˘–΀•Ů)Ś÷ËÔ$ąœ—@U!vHšŞyćé.ę,ićggOęXœNĘý•tľç˜^!łî¤j’Zœfh1‹‰†Í弞žŠžSTŢşĆŰSéç`ky#ĎľT)ćgg™Hćą8˝TW×Ó\`:‘.ú|­œUœżĐMƒ–`b|Œ;iťˇ’öŚV.V8yëaćh¤˛–Săט ¸+ýř|ؗ´ŮˇrđÁŞňŇÖ\ŽmőenyŠ_^›`.m Źnšăluž‘ëweĐŃđTˇň̉z*Ź l~:<Œ'vđV^Ę4ƒĽ…%Öľ'Í ł qŒťsď IDAT żWÁN›ĘN]['OU™,ĎLr;ŠĄPŘËŞ9ŮŰDGĽŘ˝$ Ăń=˜c+`ą`U&™TFćX´R9ćÍ#źÇt/ýOŃóˆĽńR Łüb,B8˝&G÷Â<őě1Z[›iœźĹxńÝ (_ý NrówyăZˆ4Ŕä2ŮgNŃŰŢDĂĚ&‹J×$ą8ĂíĹ­’Ž€•čܡä,*„ĹÓśśPgO1ôŢ5ŽGôusy[4yłË!†ĆÍťÓMźřL ľ­ľř§Çˆ˜€ĽŒă'ZŞ(7/p7öđ<}kЁϹť‹îš:ę:3×oňŢěý–ÎÚZki–Sáścˇ(Œ|–X4Âř˝ †#Ůu'{Y Ç:ë¨÷ťpYz.K2'43ÉőéŐk5Ď˝ÜMýÚýÓ*8÷ňóœ+ě‹wŽđÚřĂť`ĘQNggmU><6…žI°0;Ă­Ń+ë"%+M­œj Rá€Ôň<7ÝŐ˝łteí§ ŸąąĚÍë˔ˇ×QëľaŚ˘ŒÜâÖbv'ÂâÓÝQ~‹-_{-—^ě¤fíöF„÷1ŔŘşîR…Żí$Ÿîö­99*Ę;Ďđ…t×Í/ŘqşÓrVÔŇŰVC]š —Ĺ$“NY 14:Cčţ—ÖÉ}+‡">‹]|Ć;:†Š8ć÷—A:•˝żŤÁ$ąŢ|fĚ-3˝¤ÓZďÂçR-úž7eŐĘČ26.ŞFœąé=˝4TZ™œŰ˙Ű)Ę^F{g3ŐkęĂĚ7GĂÄ×´É´š^žxÚĎĚíaÁ&Z+]،,Ë 3\œ!ź‹€]!Jž˛QćľCn…čĆ.9ƒT|Ă=a!ŮLĽË‰GƒˆśŞzZÝc(śáĘgdˆí,éĆfˇ˘L“lnmš&ŮlÓ´s`3ŸŒ‘„‡Š@9>ŤżFv%NŚĚˇ~4“´ŮŮż6űÖćK“§C3K*łŐIÎJËŮ œŻRXhAŁÜçB™+,oh ¤bqŇŚrŸ5ˇĎ 4X|?×GŻ7ÇÂäĂqgE í˝źääg×B¤ÖeŔBCw;‹ă÷x{0‰éŇźçÝżxЍtŢ !ž4fžLÖ@Ůʨő[™[ÚĺMDŤCaęyr&€˘˘˛ 9Ś÷r4‘I,%ŮVGcg+Ąü,‹i›7Ŕńůĺq†–ędfqŮBecľŐNŞŹ&K‘βőo¤ÍžńŸöŠÍžĆĄĚY}0[× =Ť P6ü^;jŃNšWn—EâáśŰ˛Ńxâ4O×=\¸Łźąƒ§ˇŢş˘Š“§›LRłwůŮőŇ˝[¤[ÓŮĂšV?Žě2csqÚj­,ĚÄq5őđŠĆFĆďŢĺĘ̚ťšďž1ŽűĚ9NWjdçnńŁa'Ÿo'čôPnƒĽ,24e)c%Ç”#Čůgzhvúh­ó0´Ú€tW X=Ęľˇo2”4Ai¸Ę´řÖ,B’ńîŤ!@áď<Ă';Ü(c™ŤŻ0şŠWÁJmg;M.FŠńۃÜZÔń5vpĄ˝ťż‰ÓM‹üb,…Š<´ľV*˝gčć0Ł)}]tlŞřE¤ťöߔ">~ƒ×†ă؛úřĚq?VťŸ:żĆTč1NZŰŚ[D~‹*_ ;ĎۯΊŠîł|˘ÍőˆN2“řŘ ž38jyá…NŞ5“•{×řéHbs0°ăt{€“˝…@ŐĚ­0tgŒąHĺt¨ŽÁłśhwZ'÷­öŻîěř*â˜/ĺ9•–˛:Ú+52Ą9Ś}‚{4eĂéP`ćHçĺ­ý\jˇ1{ó&WY2(<ÎÂův?ËÁY×L—Oŕ­ąTá>bÉ8ĂņşËšśźnŒúŇ8—‡VĎëń .[=|ŽżžŞ9.Ô$(!„80:să3,W5ŃůÔST‡ĂĚ.­ŽD EÓŤçfĘfÇăŇ1QX]>šÚ[i´™$' şţđ¸­($vՃú9^ăÝ;6ÎwŐqáéúű›ćˇćY9°ťÂ&ŃĽ˛MUtt¸p’`d9OcˆͤÍ~0möu9+1JŠ´x$ă#v^óPUąÝ “›ŢgE9>m‘ô#“ΓĘf  pk"BŚú­ľżË!/­íőx˛9L֌ÔˤIčYŒ”‰"ĚĎ@€ ĹŠÝZ’gŚVekhíŞ[R Ą) ť­’ÇëÂBœ< ßßwÍMcs +Óac9RŃw˘EíôC–2Ť e–]çÚTŒ,šÇpőiŽű4*j*ńŒOˇűz ÍŇäô7çâčÄš1XNĂŮ5+Ę›îşÎˇS3qň˜čË+$L?ĺJĂé°ŔšűyšŻšcuîős Ě “ÓĚoŐ(ß.ÝÝć÷ˆ°UŠąčĚŢáĆĚęTšhdiÝśĹÔÉ}ąugçÇĐΏů’e+§żżv‘÷î„q3Î ąb"ŻHĹśş Şîň&Ţ2N›…Ę2ÄM ,Ú~Ď蹨ôa5W˜œM­9 äY˜ “j¨Ł:ŕF-Ż˝ĄcYŒŹ[í=ްd¨ xŃć—e}!Ä'ż<ÎkżLĐŐVOs°šž`Má÷ŠᇹĘl8÷)ĘZúřÜÚ ĚĚą<3Â{w— ×yeÁŞ)0 ň[Mz},&ůLŠ•č ‹‹,$MeUtˇvpQ3yăúľšôč KF un;f2ÄbĘdc_—´Ůw×fĽŹjlVíŁ'3çˇi"ďfő.ľÝż™ŹL ňŢꍾgfcŒŢšťĹŹ~żßuż:ŒÓ\RQhßYtžŕR‡÷‘†˛X°y =?ËD[9­.–N.ľtbd“,†™a.U|ĹPv'k!Çń•5ˇ0SDb:řŹ(— ‚„ÝąZšMVb‰˝ÝůX‚“uż˜t×Wü<Ůüę/ ăAUßxCóčn Źü‘™ÄœŸŮzŠómŇÝu~…Ëí,”•™$ů¨ Ť¸:šöłîěü*ţ˜/)/ݧzétƸ2ÄÄ#{U džX|ԟ1Đ @ShčĚÜžÎë3ąĽŚŤM­š ďeĹĺ´`ć3$6ÄÓf:MŇTřœöÂ(œ5ůN§7,ř‘Ë’6 č´łw—Q!„(-šŘ"ˇŽ/rKYpzźTŤčlŤĄ÷ôqĚË×X7Â$1;Ęőš &÷]“ žśÖÔэBŻ UŰŰq4Žš.^8ĺcöĘU> Żś*Â,dűůto§ę—ykú€Č­°7Š+Wä–Wˆî H›}ˇmöÇqđÁŞa|Äp^EyÇ)~­ăŁ“ĐłťmęyňX°}ôÄžї&yűŠF<ő˜Ź­’î–BĽ7ÓKܸqąh†Źáćřł§9îSëél˜+ď\cžŠ–Ć`27Nť›ę†VŞ*źýÎ0ł{4FŘ|>Rú[‘ĺpԂ˝Ł–ßÇQl•×$1;Č!â¸hîëă|óą-f&Îü<X9œxVť3Ą†—VWľ8ń:ˇÎĄ™‹3yo˜É{€ĹN ą“g{*qş‚4UÜcö‘K|?"˝lš„AMá-ó`%U¸Ł˘\T”2gŚR$L03Ň&”)…ĎçF#ŠXźŢMĎŁ*&ÝÝČĎŢćgw÷ż[yüü–r3Ř$•LcŕESnŞü6î&śžSš›:š!…ÇĎí>םÝC{uĚď;ÍIˉ>NWćůp€Ý.°ń€A4–ÂŹvă÷iyX6.Ÿ§Ň™‰˙l˝˘˜yRiUžşžÁšĎA9¸•IzSŔŹáq;P<œ_ٜ…•-séěYK!ö†žH7•śÝ4ýM"K+äT˝háŘޏʩsuřěŁn.*u°73ń( ńŐx7äHÚěťnw=ŽƒtP.Cjľ• <ľœ?‚O7ŕDM´Z¸tţ/ô×ŕU`f–œŮţą5ë˜9ćŚ 6ĐSLMEś_ů÷€˜Ů܃źŘź<ŤCƒýÍ ÔmąčąVŃŔéś ŽÂ*ąčYV˘ÉŐś›BŰTŽ&šüęP8夲ܜšúë+L… ={u §|xœ.j;Úéđ*Ŕ`yaŠPAł1…ť WšńxôuUáژp1閂]ĺwĺ["rKaćrjş{9YW†Ďĺ¤Ě_I{o§Ş §ƒbëdÁ—Ă>֝⏡#D9ięëç\•ÎŘľŽ-îdN­F°­›§Oőp˛vŤ›x&+Ą%V°SßŔůŕßź´4řPšeŚ; ގNx)F^•ŃTçZsá˛R]ŔE†…Ľ ])üľU”i_űj‚řUžĹ%yśâI¤đVVRnŰx&W¸Ť*ŠP&ńÄîn.ffO‚ˇą•N߆đAsŕsYśţǏbf‰§ °”Ó\ŰŔPřŞ+)S&+ądÉœŻĽÍ~8möƒlڈ&L>’N|q–ˇ'˜.v%2eŁś1ˆ7ZčYmlŹ`GD!flĄ™šZ;–Š6>qК„nÇçś&Tmź`÷ŃÖÝFg7ů,鼆ĂaŢŔĚ.3łźůNEVH˜eř”“śłOÓj˜˜,Ţý€7&2˜ä™eŞ˛›&§‹–ţSŹgŸ[žäÉՆ ™`tl‰Žţk˝gĎŇ Š4)Ó˛Ąň‘nIŘ]~ˇ/_;íçÎqşrľpÔęIKósöĽç8 `fžň×#ŔF‘éfšq'@ ?ˆË^F÷ɓt?HË`*˛úcąur_ĘaëÎ.ŽĄĂĽđVŐÓTŚv‚6ĘGk{Ő@~%Äp(‰˘˛ó8çëä"ó¤Ëjč-[“ŒiŸffӕFĂS¤ŠJą’˜ćĆ90Wf˜Šâ™úN.r3ŃńÔÔŃîŐ MrӉҳ 5 ˇŤ‹ÎYŚbŽĘ:ëěd†Úôš™äœu̕qî,ČJŔBˆ'“§Ž‹çĎę„CB+i˛faőŮćZ/śLˆťÓÉÝ];ő(7&Š8Ű̉ g¨š ą˜ÔќŞk*QăňÚ¸^dÚyfĆfX6ŃÜKů<óIGYö*9Ç­Šj'J›ýP>‹CV3„–R˜~÷ĂGؤš5žŔęrŕrÚqÚ­X0Čĺňd2âń8KK˄âš]Ţ]QxęzřluǞÍYÝ;9ڰfŰčŽőáu8q&V¸ws˝Ľ‡Ţ˛őy5c!îN*Ş+źx…GJš4‘ĺ0##“Ll1LшNqůś•͕T¸mŘ4 …‰śf̅™ńŢ/sD:i úđÚůt’ĐÜ4ˇî…X;ĺ-53Ä[Ö<§Zř퐊.00”¤ĺ|çŚ;5Ť[ v“ßmËWŇ4´MˇĐÔĂߙŰ,*ś•˘Ó5IĚÜĺŐô ˝m5ԕťpZAϤX ‡}°ŕBqurżĘażęÎnŽĄĂĽđŐ4Ń×°öt]F[g!ÍLĹY V]. GE-Ç+6ŚŁ3ŸŮ"X݉3ˇnňnş•c uôW+ňŠcˇÇš9™8˜ťŢzŒ[Wn’élŚ˝ś™3͊|:ÁÂčî…InÚ-šÁťD­tőÔa'ËňÜ(ďߝŚäîG!Ğ0‰LŽpÓ¨˘Ž˛‚ś ťf’ˤˆL2xo†…ǸĆĺ–'xýÝ8]íő4W×Sí°`ćŇ,‡g ďní}yœ×ßËpŹ˝–úĆꏠgÓ,ÍÜăÎđ,Ą˝œÓůؤÍ~TOO™ÉdřôsgĐ4mőKńĂ7Ž<\%u›ďEżŠˇ‘—ŸmĽň~Ť4żÄ{oÜb|/îÎk~ÎźĐO‡Ł¸33łźńú:.„âHĐjzůâi?S\ć˝=zΛB!–Űí>„9Ť€ŸĺúDňáÖJNë˘§ÎO…׉ËéŔëőQ]SEŐŚAŐ;yƒÝdęĐťB!„BąęžłŞł88Ŕ;FçZý¸4°—ŐpâdÍŚí&ކ ó¨#ÉârŽöÚbx1É,G‰É x!„B!„( ‡Źf†šĄ›ź2î!XéĂďuăsŮ 6u2Š$‘Ľ%f—Š łL޸J|ڜ2›śĹRŘóa˘ç’„ÂqŇťÝ!„B!„{ęđ‚ŐUF6ÁÂ\‚…˝M”H(Ddű-…B‚Ibq†Ű‹÷_+|m•tŹD猸]Ä0ÉĂĄ°Y-`čäJ=ŤűÎÄ0䌿JĄ|K!˘tH}âăčHŤśŞzZÝc(śĄĽfdˆĽÖ˙JŮËhďlŚŁÚ‡ÇŚĐ3 fڏ9&ŽßO´†ç_ęÄ>=E˛˛Ž:{Žšá!FŹMœk+Ǟ]ćöľť ŽţAŤé勧ýĚÜ&l˘ľŇ…ÍȲź0ĂőÁÂŮ]äaÍś]Í´WůđÚz.G2ejlŒ;‹Ůő¸ć¤śľ™žz?.+ä3DBsÜš!”ŮĺÉÜ⌹ľžć`~ˇ§ rŠ$Ąšiî-ÓˇOb+ćü Ü`ŽŹ…îZ^ŤI2˛Ŕ́QŚ6NäÚnßT'Ÿ?AG|ˆď_] ťŐ›*'.ž¤35Â+WćHď4łĘCßs§9ć}؟ćí{š/ő­ž0–ůŕő›Ü[3:´ŘĎxŰmw‘‡˘ię:[ékđ㳛¤vűYŹŰ97˝Ďœá8źz=ICW-•nœšA:ąČŤĂLŚw‘nŠŘ2Űé[ťřüŮŞD ĎşfőçÍsV‹Š“űeŰ<ěć8Vv:ž:ϙĘűa07°ő|ĆbĎ;wă˝Í´T:ąégĆĚ5pąóŃs*wÇJUWĎľ9Yş;Ŕ;ăqtď¤îheœźx‚ÎÜ8?ůĺąľŮR:Ÿ:Ç)OˆˇŢbnÍg­l>:ű[éŞńŕ$K44ǍťÓëëä~–Ż'Čńž&Z*]Ťĺ;ÁĐV#Jä3.ęzźSĹ^cűœşÓüZ*8wé8Íą~xeŽuMąűő53Əޛ&aYEԇ}١ľYŮÉ1TŹŁx-â€Y‚ÁŕŸčzá¨,íçŹ*‚Íí´•LŒ1“Úfs‹žóýô5˘3Ó ÍDXÁKSs=-Ţ4“óÉBÁ⼚5@Бgjt„+@s} ľ–eîŽEąjhv'K˘Ę¤ˇÖCYe9ćÂ8WîL21 ś´Đ0™›]áÁůe§yPN:Μät•bijŠĄŠ0ĄxÝQN•u…ń𚋣rŃ~ć$ćžZd!ő t×XĎ.“ÜEŻ‹rVqöD5֕3ó‹LÎ-łbşihn ­,ĂÔ\‚Ý\”;@wß‡#:ÍÁiƗ!ĐŘ@ť?ĎÔlěaCuGű–Çꯣɟg~"BrŤ7učíŹ@Ÿ`(RLŽ ’Ńefć˜XąPtťĂĺá9ĆgŸYb)™#ż›ĎxÇŰ™‡]|vo95ś“Ó‹„ŇV‚ľU4•íćłX›¸`cŐVEY]Ž•9îŽÍ0ś#çpAt‰Ľě.ŇÝW GE +sÓL'6꾖Ů™šáp˜‰™ WjŰ27>ćÎôă3!fŁi2ŽEÔɇ;Ic{O,ÄPh›Š;Ův'y0ws¤cQf瘈Y¨ ¸H‡fś"_ÔyÇ^Éš ˝txr̎Oq/”ÂZÝLOŔ†Ő˘šœgqËhzĘI]K5šĂ3qňĘFuw?Ďľ9Xź3Ŕ; ´‰wZwĚ,{€öZمyBkňĽÜľœęŽŔœĺĆBŚ0ŒÝłZTˌŒ/°˛RU_GGfŁk~ÚŻň rţéÚÝŚG§ §ą×Ü/ßü†ň-Ď¸˜ëqQŐĄČkě!ŸSwœ_3‹áŠĽĽĘF|fČšŒćoŕL‹—•ą†Łú.Ęaçőáaơ?G“‡âŽĄçawŸ›•–łĎđé“Í4Ş÷–vsbâč°ŮlGŠgՊÇmE‘ ą]  8ëšéň)ƒź5–*ŹÄ6bÉ8ĂņşËšśüp~Z|n’;Sqlf­ý>ĆĆY0‰•Őđ|ĽŻ ąô0ZD_çňĐbĄÇ.>ÁeŤ‡Ďő7ĐS5Çĺů|ńy°•SWa!33ÂťƒËkVŽG)ľîDçjhçdfŽóÎtfőoóŒ…ó|ňB} łź6^üÜ]3ťČĺ7fIf×üçôăo[\Чpfçůé•  ŹXÎń\Ýî>‹Í×h/Üů7ÇSęńüÂüƒżďWýÝ_ű[fŰĘĽ/Ľ {ىif‰F˘„śhŻwîŰ;˃ž‹ăŘü˙Ůťłç8ŽüĐóߓľŻ¨U( °/w‘Z,Ş[jˡ˝t؎pűŢš~˜˜‰‰˜çű/řaţÇ<ĚŰܙypŒÇOŰmÇő&Š­Ů)Š ÄžjAíű’ó€XČŠŹ"Ď'˘B‘ČúĺɓżsNćÉLJš %@Q˝§xÂćiňŽ g`ˆšĆęýîlíg‹Ń7?žŔçő-˝ů­ˆ­G3ÜY+rđâÍéëŽJf3NjxWĄßR IDATŮ\nˇŽ ˇ(ńt#{h݁ĄźÉ—wWÉ4wÖťYšÄďL†šĐťÉżoěĺ–ö”Ż+aŔTeéŢCž‹ď´‹›ŢżuÁÖŮűXC{ŹEŤmě›ĘЧˇIb3I)ÜKżßÄâę^ ž^Öf–§ąĘóď×VZëĂyoŰŽSC§×mĄ$˝~ÝóžUĄCŻP›ÔOźgA‡×ă@ŻfYÝ,HnubIJ˜x­‡œRŠě4 őj†Z§˛›ŔŞľ: ]DVI%R‡šˇJ2ĹśjŔďľďŞĆš ęM08\xM‡ŻXŤęÁí5 ö Ť&YÜŞĄ( şÝůą˛Ŕíq´v˘Q=”¸…PPČf 41ał´˛Ň=MRÉ́Š~*…bU˜°š÷ś÷ôŰVĘä(`ĹăÜ)mŰŔ4?űě=Žx@`ďąchćIśőĄDZöąö:Ů>*Š­$űípƒtśŘňžxA=Ĺüzé%Š6Ößśjs™›N¨g§ĄýÇń)ňŽŘ§şÍrü@‡ł–f5Q;§Ž˘‘ŕÔ%~kĐD|v†ŰGŞZëŽZŒłœVąýx÷ZqaĽ?hƒ\œ•ěѨUŇŃűŨRŘJRux˝t´ę´ĺkjŠľäKnľ+ńó(ß6ěăSˇÇľÚĆžŠœŞ!ŢF:ÁzYŕ z°ě™â ?`˘‘J°^nm˝mŁ9†ó>†ZÝoM ŰqV6ălćä뜤wCçő _FmĐhŞ ”A뫚8ĄÇbÖĄÖ+ŽËjšLQ8ĚF…ý3}{ ŞŇDĽŠřwEéÜ5)—<ĚŠVĽÜŸŮˆhjĄžÍě|ďD?Ÿ~¤˜ËłÍ“ŒÇXŠ÷§Ä3v‹@˜‚Üú"ž%â‰&ŠÓπ]eűIüđ}ŹťŰR,Um‹Z­Pl€×lÂ(hů°§)_‹éeĺ[9—ň=÷}|ÚöXłÖÚŘ7—S5ÄŰ̲śUa,âŁĎźÉłč\>úĚMâóÉ#ύho_ăܡ 8÷c¨ĺýÖ$ą4GâŘż¤ˇS÷ VŠS(ŐQ÷Îx{ƒSź$ůźxťîŃ­VMŇK3ü㖓^_>—“@ LĂËů×ŮĚĄRÍmpűQüřb¨WZęxXÓ|zŃE=ąÁٞ•: @qňŁ Gk›Ő‚Sm[#O2Ť2ŕ´cÖčí)2żPb(čÂĄËáv ĘŃ-ĎZ–€ÖꙪ6OœŞŐŽúŰ)Ţćm;wďĘqÜ,˛đĂ6˝řx`ŒëÉű܉ž8HŇRwĘń›u7}!7?$Rô„|؛žnľ0m°ŰË÷ÜikOŤŐ6öMĺTmńޤ˘ ňƒ}ôĚĚ/Wwޞ6ŇĚÄkgXo{œ{ -C˛˝¤“uŃ`U%ľĽŢďĹﳣ$s/OŢjRšč1a3ŔÁůşÂlĆ*TĘ峜1W°YMöď‡f36jĺęÎôŽc¨—˛ŹŻfY_ôvŚo^áB8H`.ĂzPËäK*ŘjšŰçődOa"ÔçÂXÚäëď—H(\[ňzڧjÚśŰéDx=Vź•4O6Š8†ƒôşŔmh˛ÎŸŰý-ÇÇŤaˇ˝NžłvŐłv­ˇtÂśľ\ĎTv/FćK^˝ŹŚ:ŕ8ŚJą ÂjĆ*8pUR`ąÇ?§X“f&ĘlźHi{Ž9Ď%&.Œą•yĚŇ^O´•şSKąźUŁż×OĐÜŔ×k˘žXfăŘGŸ Ź–#m–Ń„UőrĺśđU^Už&ÄšÝÜj /ßÇ'śÇZ´Ťí >A3›`­f˛×‹u­@żßH=™ z°x_K_ă„ŐR ZĄ“ňd´’Ô%şçžU Űdšöţ!ĆGBWL8,{w 4Hnç¨ '!ˁÔčóbĄBl[ëƒw¸‚~œĘţώ^.Q'ą˝×ąŇƒ˘Çpôڇz™\ůh7­J4šĄaô1Ůo}q*FlŚVҽ؝ör„ÎÉHŘńš*Š–mSÉŚsTőv†"=4ˇSdŤś˛VÂC.œHfΖýŐz:“Ńđ’öFË>n­NžCť´Ťžľş^ßđ^äJĐüšËâ´ÚUfZ´˜űÔ*ĽŠŠÁjÁ|Rˆ'.Ť%†öÇ'R+ĒETهˆďŔů[}ýžs>îęYÍŹ‘Öy¸z)„ăůĘ[Š; b Šz7#“}„Mu67R/ú \Aߥ6ËÖëĂ-ę$’9ÚZÂj…ŘvŒnú˝Ę×ŕ&âMyMë>>u{ŹEťÚŘę¨Ö˘Ečń ű ™D7SGrŻĄŻqbŽj%ÇЉ1źÍmĄ$Ż.ş˛ 42<|°Šű˝—?¸Ž#N˘Ř@1ŰôzËßóĹr(oŽ07p™Šń‹Ü2o˛–kbńô22R‰Í1—>KŁŁR3‡řř=óŃ"ŞŐÇŘ 5ťĚll˙ć*-1s/Ÿ|¤O͔(7l8ń™°¸ąŔƒŔŽM^áˇ]QVśKÔ#6›Ţ€‹ĘłoľżƒL­ĺš8âýŤ*ĎbEę: ˝ý˝ôPډń ĺuzZś­™Í‘n zŞ,.ĺiŇ$–(q}ŞQ\'yꗫO-fI”at`„‹ŐMĺ&¨5˛ŠüóÇÉkŮÇ­ÔÉÓÄĐ.mŠg-ŻWÁćö1ŕd ë<8ŸMÖŇŸ>„öľąÓ'PÉn%Ȏ29nCWK˛z´Nj\oKőá¤ŐĘśň:u źÝmĄ$§îŹľô _~“g|¤H €I‡Z+“Nn2đÝgž›Ą2a$ázDP/ˆ-Îňp!yä! Z5ˆ>}BĆ;Äřd#UŇŃEž}˛ÎĄ~ †Ôj–ĺ¨ƒˆ'ŔdŻƒNĽV*[˜ĺáÂöá3“ÍóßO>2ŔDŸŸ ~#ŠZŁT,’ÜXzy‡ĺ•T˛KłüZćbˆ+~…FĽŔÖęSž.ôň;×<­•VZś­–#YP Z2Dw ž˜L‘UX3Y^x ŚćX2<úaĂd#SSLꢙćî—3,ě]žĐRĎZŠ“§‰Ą]ÚRĎÚ¸ŢNĐ ŰÖRîk˛=˙˜ťú1.„‡š1(Í ßuĚ`ő4Ëj‰AĂqlîĺÇSÎCW!ĚĂřtxç˙ËŤ3üýŁ´öiĂŐmî}ű„ĘT„ĄŃ1%ë‹|—skLp–Ŕž¨IfiŽďUŽŽŽsaűfҍÖęŽZ`ełŔĸňVœÄKQMbOŸô 11ÂD•ĚÖwŸŹ‘:PXí+ß$wż}Be2Bdd„HŁBbsßTűřxěđľĄNŘǚÚăSkcŰA}ľ`5árŽňz‚Ř _­m˝­Ő‡“rT+Űvşcčô1Đí…$u199ŠV*;˝^!ÄóĎŢϧůďťDéâŻšXť{‡ß÷’CI’$é- p_緇ŞÜýb†ĹöŢŘŮ"cř ˙a\ĎÜíť<ČtĚ]ď]˘öą$IŇťËj=fšź$I’$˝[ċOxz˝ÔB–íN}Ąbg8l‡\Œĺ3O%yŰué>–$IzÇuÝ4`I’$I:WÂÂčI|…ŠeՈ;fŇYcý‡čŮo)8gŠĽ‡>—go˜QkčĚÖ1ďV•é˛},I’$퐃UI’$éÝŚÖH§J„‚A.‡čiPʧyz™Ů­zĽÔ.˝;Ě—ݨŐŃgłÜÝčź;N—ícI’$i‡źgU’$I’$I’$Ię(VŤU^YŐdôқŽ {ÍĎźé$I’^Nć÷ÖÉü.I’$ľ‰Źjd]Ÿ{Ó!tbxüM‡ I’t"™ßľ“ů]’$Ij'ů4`I’$I’$I’$ŠăČ+Ť’tß8?{ĎOüţ7|łŐţ÷ďڇŽňÓ ÁăŻďó8ŻőŃ ‚ŔôűühŔČŢ]畵‡üÝĂňÍÁ’$ÂŕĆşhŢÍ*ĹÇżâýˇ(7™$I’ôn‘ƒŐ3Đ;CÜxoœé7.Ťľœ'şśĆ˝ťłfĐkÇnT¨W+ň9śś˘Ě­eŠźéŰN%˝<ËW[ ˆ.\ŔůZż˙ĹÁňńT⏿ĺ˕J۟Ô)Ě.FĂŞńuV˛rČ.u_ž<ßx›lýđkţrAŠ˙ŢśD}ţڙßĎ/Oźý9PXúřô“ÜńYţöű„<É!IRËä`ľEĆŔňłK čň,>çQچÎćbhdœ÷–xš*tÔŁđť-Ţv–}8NHWfks“ĺbŮLËĂřHÍő,•w  Ş…,ą čyß_ˆ­ń¨˘{ţłŃdĚk ťšĆZao¨Ňő×R/…ŮÍŘhˆ|%*ŤR×ĺËvÄ[N'XN:×Tşb°Úîü~žyBć@I’¤Ó‘ƒŐVč}Üúü""Áýw’űç żžmĹkë°wśu[źmŁŕ$d,1÷›űüpčjƒ‚Ĺn˘ůnÄŚRHlđ8ą÷łŔ1ěaÔŤ']ăqLv”¤7¨ŰňeˇĹŰ6ݔße”$I:-9XmipŒË=‚Ôý|—<2šĽQ$™=ŰúőÎ7oŒsĄßƒŰ"¨rDWV¸swŽ•‚öÖśń ‹ëLsmЃۢŁQ)“Iƙýţߏ–:Ť“$ 8íF¨ĹˆeŽNJjRʗŽý3Ýî´˛ŻťQPŻ”HĹ㲰b"46ÄŰ ‡QĽ”Š1óp‘ľŇ‘’Ṗ"Löšp[ôPݐŠGy4ˇAüČŠÍÇôäƒ †F…ÄĆ sőă|Ů}łŚţ‹ülÚĘÂožĺűT‹{DCźí"ŒNFĆ"ŒŘ ‚FĽ@lc™Ĺ$ůF Ë ?žĆűţD<űĹůӋť?4ÓÜýr†…ˇ^¸t€Ěď]Ş•ü~šźÖAyâ­Í:+ýC}D|N\VfÔJEâŃu.$ČŘśçíÜĂDƒLŘő*ŗ´ľ:ŤéŠƒónűšĚÓZ˜[c‡Ÿů ŠýÔŻ–vyóm­$u9XŐL!öc˘ÂějęÜďĂĐ{Çůů]%"2é1ňŤŰ‹Ä÷B3ú¸qs’]žĺ…E’užđŁ#ĺ6ŃoťčL߸Ȕ˝Flu…gů&fw/c#S|fĘ?ߏóźrÚeŐ2KfˆéAŘCź?弴4˃Äîƨuňľ6o—Ôad~ďZZóűióZ§ä‰ˇ8 Ł‹ą!7"‘d9V˘XłËĎČđŸ9ćřç{[˙ř†őUî~ťö—/„_lkŽßœdĐPdui‘xEçyűŮú\SźZb脶V’:ŹjfÄĺ4"ÔéÜ9ńŤŸ\&˘$řňožâöłä÷žŸĹnlĺűÚŻ)ŔhHOáÉ=ţö›­ýŽŇ÷QсO–m]Ţ í`ěćMÉ$›ŰY’Š ńL™ÚŃâf†§†đ+fî<äIn‹ć×°ŽnĄŔ\Ý⟾Űk,cdu7ř8ä%hÚŕŮîŘŇáŠ6ţŔŻ×÷œąĹR˛Î焸Ţä‹ĺ2*W$€ŠĘŇ˝‡|ˇŰJ-nx˙ÖŰRF/:}źícEw’OňďKĽşľgťy[áA&zÜOŤ—mPČf(JÓC•j1K|[ŽPß]2żw/můýôy­3ňÄۜŐj‚;_mRŹŘIë[Ä×ů4"b1{hց@¤Vš=—  [â§—Ď"ŰZAĎŔ sŐű3ÜŮÚŮŚĹh›_`č ƒŐÓÇŤ-†Nhk%ŠÉ÷Źj%tô ęç|[Řű˜ *”ŸrďčtŽf™|š…ŐĆxiÖ¨6Ŕě śŽJÍΚ9čzz™/nĎň(ZDé 091ÎÇŢäg?şČ%żéĐ!Ěú] ŐŘ:óš#SľJŠztí*Š­$űmjƒtśˆ*LXÍ{ÓŹŒ„‚=čŞIˇj(Š‚n÷C>EŹ,p{;g‘„‰€×ŐkɧSk)Vâľ×Ô`iˆˇmtx=ôj–ŐÍҁ“ ubIJ˜x­ťOŐÔ˛Ź$!ó{W;}~ŚĹ[žŐC?!˛™MLŘ,G˙ I*™aż V)ˇŰZąťŐm–ăßľ4Ť‰3śŸ§WS ÝV'%éő‘ő^+ľA­ CŻ;iá= f›“˛ß<¨ő ŮŇáůÂa§G¨¤“YÎíźf㼺Éíocô4ĹţďGÉ&ˇŮŒ§X[Yffń<^Ł`40ˆq4jŤgë•Őr ýŕ‘ĐaśŮńűüŒ ÷2umőÎ}fvšwaą`*ů\ń”ÓëT*•Ă ĐΠ]đź(…ťE LAn}Íßž†Ü64‹lÄa`|ËŮM8ÜnGGůäÇ׍,ópŤ•‰L5â‰á‰aŽNőá5ëąŘô ňá'×ĚĎó´•÷dś)^áçżűĎ0í6cľZpyźŒ]žĘ­1ĺgůb!G¨9˝ŠiűÜ Ü#WřěR^‡›ŐŠËĺ˘?2ĚľáŒ•÷GÉ>?ŁY'“mâ îwă4č0š­x}&§F”ŁŹď>MIX˝L„lˇÖX;đÔB˝3Ŕ„ß@jcƒčîӀků<5g/Ł‘ }v=zŁ §ŰC8Ěĺéü•(+ٝŽc%_Ăęe°×…U˜ěnƧ Ttş:ńŐ-{'gë ,˝AÂ>.ƒŔhs14>HPßŔd‡bŘW§fö3tă1¨`´ŕ´h–Ęě=?BKź­î“ť—Q݁ltýy™ОPFçď%ňâ5 t&;}C#\îłP-ňÝrţů•!-ËîŔŮ ŻÇŠŇh ÍŘ-zš•Şź?č]!óűńÔ UŰWƂMM°8đ{Ě4˛JÍîÍď-嵶剷/ ƒƒĄˆŤŒ|žü?.#ŐL‘ŠÚ ft3Üë!ŕЁΈÓícrz5 &ÝĄ2ŃŇÖV UlÁ^ƒnl¨č­.F&wÚO˝žŃbűŠ-^-1´ż­•¤îc0ä`U“˝Î ĐČǙ]HS3; 31$ě2PŘXâޓ(‰o,h–’ˇwHuz ’ÔÝäӀ%I’$I’¤ˇ‹°0qc_!ÁFŞ@Y5â…™tÖX˙!Jöu< b¤.'Ť’$I’$IŇŰE­‘N•ƒ\ŃÓ ”Oóôţ2ł[Żéő=ƒ$u99XŐ¨Ó!H’$Im óť$˝MjlÍϲ5˙ŽÇ IÝMŢł*I’$I’$I’$uyeU#ů´HíäŐ I’şĚďÚÉü.I’$ľ“ź˛*I’$I’$I’$uyeU’Ž%LżĎŒě=už˛öż{˜â¸÷ŠK ­ĚdůJ’$˝d[ IŇů‘ƒŐ3Đ;CÜxoœé7.Ťľœ'şśĆ˝ťłGŠwŒ?¸Äź×;PUő*…\†Ő•UćśJÔ5ŻUK™˝Ýĺ+użn˗Ýo;œß;‹0ť ;¨Ć×YÉžŢřd[ IR§“ƒŐSüÉĎ.1 ËłřtžG™:›‹Ą‘qŢXâiŞĐQ$ďśxŰIßÓĎ­CřD‰­ÍMVŠutf;@cžë…2*P-d‰EĎțş-TJ‰ućUT ;}}~.^uăytŸŻ×ʚ넖2{űËWęVݖ/ť-Ţv:m~ď$Âěfl4Dž}íƒŐ˛-$ŠsÉÁj+ô>n}~‘‘ŕ‹żţŠ;ÉýłÖ_ßśâľuŘťłş-ŢvŇ9™ž<ˆOd˜šó'šýŽÁ٧&ŚúťS@5gnyż#űd}€O?$8ÄľžDę]* I‚î˗Ýo;ÉüŢ2ŮH’ÔŠä`ľŚÁ1.÷R÷đ]ňČôŞF‘dölë×;CÜź1΅~n‹ ZČ]YáÎÝ9V Ú[ŒvĆ+,^Žp‘kƒ\…Z>ĂňÜ,_Ý]'Ľ}îPŰü} Y!żźÄ\îČěf…\é +Ẇ"Löšp[ôPݐŠGy4ˇAźr`żéŹôőń9qYM˜ P+‰G×y¸ wtƞ°2őŃuŚYá_~(`ĐcĹŹ4)<¸÷ŒŐňâ> ‘O+FđXĚŘ؛=(ŒNFĆ"ŒŘ ‚FĽ@lc™Ĺ$ůwk†Ąô–“ů}‡nä#ţËď™űŐwdú/p)ěŔÜ,˛ľřŒűő3Ö˝7zќߵäÖóÎďÂĆŏŻqÁ.ž˙Šýâ‡üéĹ˝xÓÜýr†…ʁxOĂ9m$IBV5S†ý˜¨0ťšâźsłŢ;;˜“v IDATÎĎ˙č*‘áÉŁÇÜMWQŹ= Opuý+ Z¤6ĆŤ÷pëg?ćˇ<–>ćťíöĐ7Ţű-ú]wřŻ˙m…\Gőgn5Öůó}xƒ°0rí ×˝Më›<ČTÁěd02Ä'=F~u{‘řîŕ]]Œ š‰$ËąĹ*˜]~F†§řĚ1Ç?ßۢxLš ˝‹ŤďQăë}Čż/í~÷Zœíćun…™čIp?-{(ŇŰ@ć÷ÍőţîÎy€Ô#ţÎŕâţíI>Zŕ ľ“VđľžßOĘ­íÉď Ů @izh R-f‰o_ŚZbh…l $IęTr°Ş•ĐaĐ4¨Ÿóilaďc2¨Pš{Ę˝ŁÓššeň­Lől[źzúú}›I?Ë8‹]céé:šŠQ"ýD4sž_z6B‡^ 6Š7ĎłA5 ö ŤĆXÜŞĄ(^_œO+÷1ěq _.ShT)ŘB(ŮL&=Ř,@á˜ŻŠ§˜_/ăasđ"ż7xŕŸÔéy~ó$˝űH^˝šeuóŕw׉m$)…CźVDúÝy€‹ô“ůýˆ&›+[‡ŇQq-ĘfłHżÝBŹ_ښłä÷WćÖהß_Ic šÉś@’¤Î%ŤZŠ juzÝi˙HÁl3cRöďMQ벼Ăsv„ĂNPI'ł-68Ż1^aÄaŐĄV ¤œĹVs˛ŞŔcˇ p–ÁŞ‚ŃlŔ ÄѨQŹśŘ+S4š*e§Ss^MŞ0cˇ„)ȭσÇ.Ň,0 v§Sép†ú™Žřđ;̘tâŔ’ t/‰M-•Îůž •Âć"?D+¨ě˝Ž @žv໅‹Y‡ZŻP8R)Őr™˘*p˜dEz Čü~D“BĄrřŘŽ”)4ý6Ë;“ß_™[_S~%Í1h%ŰI’:—ŹjV%“Ť˘ .‡€Ě)ҲâćŁ?ţ ôě7ZőĽ;üĹ/—ŠźâĎÎGˇĹ{€°1ůţ&­űq4âOůĹÝX‹˝:…RÓÎŮíâ9ĹšKÍmpűQüřŐÖ+Ďď屆'ůô˘‹zbƒG2d+u€âäGŽ—Ż_mžűKŇë… 1Ůš¤ݖ/ŰŻ"đýg­:(żŸ&ˇś;żŸ*ÎSĆĐ ŮH’ÔŠä`Uł&ŃőŐé0‘7şľäÉľhć˜ůňkÖ Î S/4Čj.OFxźN äŠvrźj•\ąčľá:2­I8l8…J>Ć)Ťj‰ĺGł$\1P+ů^PţüŻImgŠ÷{ńűě(ÉÜ)ăSQU^Ţ9SËäK*ŘjšŰŻ*`a"ÔçÂXÚäëď—žß `ëQÎÜ˙;wjRšč1a3ŔÁŢŹ0›ą •rů¸WcœPf-/+Ií$óűa ==VšçǸ°ŮčŃŠT ĺ3äb:(żŸ´ÚČďZbhŮH’ô†('/"U^~ĆLÜ.sĂ{dî•΂Çyô@•ÄÚs‹ëĎ?ĎśŠ/4¤j~ƒ'Ń&–á ŽyŽŹW1a3wRźu6֒T/Ć*’Ą‰0ŠŹŹçÎx–śN6™d#ś˙ŮĚTδÎjl“ĺ"Řű‡sŠţŠ ‡ĺ˜štj•REĹ`ľ`>ś­fh}Lö[_<¨#6ÓŢŠÝi`G蜌„x@6Hnç¨ '!ˁřôúźX¨Ű.˝¸ON,ł—•¤6“ůýP`FđëööŒĐ+jŹŽőéĂ’ßO^kŰóťZŻSG`2^2NÓCťČś@’¤7CçóůţźŃŘir„Ď?{?Ÿćżď OCnšE6â00>Čĺ „ě&n7ƒŁŁ|ňăëŒU–y¸ŐĘDŚńDƒđÄ0W§úđšőXěúůđ“k ćçyÚʛšŰo5]ŔbzżîGŸĺnoQPť<żŸ2ˇś5żÔΞ}=V”FĹhĆnŃÓŹTŸßƒzú´‘m$IĚ`0ČÁŞ&{ ‘3ťŚfv20fb8HŘe °ąÄ˝'Q-Ţ<Ň,%y˛˘nu14azŹ~—Ňć÷ć’dZ|2G[âm–X]ŒQ2ťdz,HĐ\fyć{ţţëU2ťífGuf€f9ĂęVž†ŃŠßď%ÜëÁkÓQIŘßH‘yĄUT)Ľ3”ŒNB}˝ †|ôűMä×blďő{Ô:Š­Űu.Ż—HČOČcĹŞkŽm˛ÍRŘ]ś’I“ĆŒ×ďg0ä#ŕĐQؘçť-#ĂA šŹ˘VIÄ2T 6˝Cn\†*ąŐ~ó$AáŘţŃ)ĘŹĽe%ŠMd~?dg°jĺŮŻžaŢ:ÂÍ+Ìůt¤gůĺż>acwsWç÷ÓćÖvćwľÂvځĹĺ&204“[‹‘jhA ŮH’ÔÉ brrR­TvR´Źž`ôÖőš7E×)†Ça~ćM‡!I’ôr2ż˘ůˆ˙ňť˝<ůű˙ż[~ů;™ß%I’¤vąZšőA’$I’$I’$I’Ţ49X•$I’$I’$I’:ŽŹJ’$I’$I’$IGžgUŁbxüM‡ I’$ľĚďT’ü/›F!üڃ‘$I’ŢUr°*&”!I’$I’$IRƒUŢć§EĘŤ ’$˝ËŢćüŢ.˛Ý$I’ÚIŢł*I’$I’$I’$uyeUęr‚ŔôűühŔČŢ[+kůť‡)^ţfŔˇ‘–reÖ Ĺ7ÎĎŢóż˙ ßlɒ’$éőy[ň}č*?<ţú>óę żWÜ#üŢűA˛~ĂŻÖjo BI’:ŹžŢâĆ{ăL¸qYő¨ĺ<Ńľ5îݝĺIŞńŚĂ;†ŔsýˇůŸ>r2ű˙/żXěüOgq36&âłc7*¨ľ2Šd‚ů…5Ö M@%˝<ËW[ ˆ.\ŔůڃnaeęŁë\r Ş›ůĺI7ăZĘá5”ىńXÔěb4ě _g%űę:ŠeYi‡,łÖt[~ďśxŰJćŸSQ<ŁüţÍj,Ýű–oă{őDŕšĘďŒŰQš)žűâ!‹Ő7Ş$Iď09Xm‘10şüěş<‹Oçy”ŠĄłš罁%žŚ źxÎPŇBßÓĎ­CřD‰­ÍMVŠutf;@cžë…2*P-d‰EĎțşM„ĹMČŽ’ËW°y˝řtI6ô?ľ”CťËě4ń>_Öěfl4Dž=EgńôËJ;d™i×mů˝Űâm7™´i4BÁôńmęÂJЊÚhň|úÍkŇL-ň˙´ęŰSž’$ŹśBďăÖç žř미“ÜożžmĹkŤžSƒśĐ9™ž<ˆOd˜šó'šý†ëŃSSý*c‹Ďƒ[Ír˙Y‘‰Ť>B.…Ídç6ćÝŻ$=×mů˝Űâ} dţѢI*žĆćóÓŤßf˝ÂáŁßšg3i&ě{Ýń¨4›ďZ•$éUä`ľŚÁ1.÷R÷đ]ňČéÚF‘dölë×;CÜź1΅~n‹ ZČ]YáÎÝ9V ďF7řű˛B~y‰šÜ‘NFłBŽt†•+f‚C&ű\¸-z¨WHĹŁ<šŰ ^9Pž:+ýC}D|N\VfÔJEâŃu.$Č=Sż;őlšţĺ‡"áń=VĚJ“r!Áƒ{ĎX-ˇ°‘`ŔšeśE\ľÁ€%™éĐ{LOݰqńăk\°ďŸśˇ_ü?˝¸űC3ÍÝ/gX¨h\´ď7vŚ›†đÚąőJ‰T<ΓĹuâG÷™b"46ÄŰ ‡QĽ”Š1óp‘ľŇnÝ1ôňÉgc××(zB„Œ5˘Ďć˜×pc¸c5ÍăűOxš=Č)ëäóűÖ> ęd"čŔŽW)Ak™Âčdt<ˆ߁Ý(hÔjs֖–˜Mź;žnËďm‹×ĐĂÔŐ1Ś#>z{ŹXPÍgX™{ʯěŘŰ ßńüӂz*ÁŚk„~Żžő­Ž^/Öt”ŮrřĹW잶ýt6ӓ z,+ĚՏ @˝ů>×={eÜ$úđ%÷ŹśPž’$u79XŐL!öc˘ÂějŠó΋zď8?˙ŁŤDD†'s7]Eąö04>ÁŐőgŹ,ź ]FŰăÄ@ľDţ|dÂÂČľ+\÷6IŹoň Sł“ÁČŸôůŐíE⻍Š0şr#I–c%ŠU0ťüŒ Oń™cŽžˇEń˜Ý!ô.ŽžDŻóŕA‘Ş0á ö`Ň hĽËotr rKi 2[Ű †|Ü"C˛ŤĂiâUË,=˜!Śańţ”—ŇŇ,ť…ŻÖÉ×ZXíűMçčăÖÍü˘ŔúÚ*ó…:ÂdŁ7fd{“xů` ¸FŚčŠdX^\BľyčăćĽ2éo7Ř^ˆŔíł˛š°BľáÉKx3Q?Éí爇ĽďăTASÜ[ˇ| Ăú*wż]{€Ë‡cĐXf3#W.rŐUese™š|ĹdĆéňň˜xňÎ Vť-żˇ/^a đŢŐbe™Ĺ,™’ŔÖ;ŔőëńgŢoůß˙a‰l'V ™´kfY‹5ů(čÂŻĐßk"š´MŮqd¨Ş%W}ܸ9ɀ.ĎňÂ"Éş_x„÷ÍÁ‘¸Zccv†Ź„#Ä“ž—†Újť,IR÷’ƒU͌¸œF„š";çŒ(l\ýä2%Á—óˇœ%ż÷ý,văy}_§gr=6ŤAÂYŽ ĂáŠ6ţŔŻ×+ť%ąĹR˛Î焸Ţä‹ĺ{aŐj‚;_mRŹ(Żő-âë| ąĆ˜=ćJˆ°Úaö{~ľ\z>ĐފmľłŃëÁ§TXLQQ‰'r4{=„œK$3ˇ/OoƒB6CPš¨T‹YâŰÇ]ŽŃ˛ŹĆý&Ě O áW^œn>ż¸†ĹpôT‰Ŕ\Ý⟾ŰëĆČęnđqČKĐ´Áłç}0•|t•Ůľ<ŐÍĐ%ąĽ%ćc*9g/ŸxlŘEœmU[Ü‹A¤Vš=—Řěć–řÁéĺłČÁ´•†Bn•yžyš>p‚h!DÇgŒóÓmů˝}ńŞĹU~ń͓-8fY­ý”?ť<Ć´k™oRW3dţiE“äÖ6ľk>úźUÂŚ,OâUTÇáĽNŸŤŽH„S•Ľ{ůnwť¸Yŕý[|ąÔ(ĺ2”EőžňuŤí˛$IÝKžgU+ĄĂ hP?çÓîÂŢÇdPĄ´ř”{G§s5ËäËgOŔľZUmPëŘ)\€ĐĄW¨MęçzP°]5ÉâV EQĐí~ȧˆ•nc˙ NŁz¨ABAQ ›)ĐĄÍň’ŻŠ§˜_/Óa=@újš­ÝËŐí)ŐLČo}ÝĎž8…ˆWĂ~fý.…jlůŁÓÍŐ*Ľž€Š’ÚJ˛ßjÎQ… ŤůđÖU*;´zľFC­SٍŠZŤƒÁ€Q€ć: @“T2Ă~h*…bůŘN­Ů ŢƒĂ…×txŞúuüş-żˇ1^ęĺCUĄ(čtˆ§Š +.Gçe™Îv:ÁfÝÍĹ ~LŠ›•ŁőQCŽ&^ TSŹ%L ŠĽX‰×ÎvňŤŐvY’¤Ž%ŻŹjĽ6¨Őtču§ý#łÍŒIŮoLÔz…léđÍÂa§G¨¤“Ů—>f˙lT*•:*u*çú Fłƒ8°}Ĺj‹˝'ľAŁŠ‚Pv­çu]G˜ą[ÂäÖçÁci–w5@‡3ÔĎtćßaƤ;Řh {IljŠDţź:ŽşB=L’ŃÄN;\"U‚QżÇ|ĄłŚâuDź§ßoÂbÁ*Tňšâ)§PŞT*‡;[;(GúŠĎyŞJ•ŚzŕßąÓqÖ\'wÔj‡ŁÝůŽc8ľú6łóiźý|úib.Ďv6O2c)VlS>ę@ݖßŰ/čńMńńĺ">VýÁĘUÓđ}/ă\Ű ůç,šYÖb5F DŸmS]XՒŤ0b1Z.™’ŤR*UÎآˇÖ.K’Ô˝ä`Uł*™\UŘvÎ,ŸfŚâćŁ?ţ ôě'ŐúŇţâ—ËT^ńgíĐ(f‰o7IŸĂUÚ焍É÷Ż0iÝßžFü)ż¸kąSV§PŞŁî%-žSœťÔܡŏ_m˝ÂŢs*ŹáI>˝č˘žŘŕу ŮJ ¸ůф㸿ŢYżÚ<ˇűlun˝ĐűGůé§Ł‡Ůô´Ź‘í t:!^­űíľ_:fóO['ۧIzi†ÜrŇëëÁçr„éďďcxů!˙:›yGŹÝ–ßŰŻŔ9ő!öY/••güűżÄHj4TĐő]ä?~ä={čçŢnČüs6*ÉĽ§ÜÉčČÄkź,˛SĺŞ6nTŤí˛$IÝKV5k]OPpŁ[Kž|F´™cćËŻY78ƒ\L˝Đ Ťš<Uŕń:1§ďŕnŹ?ŕżţĺ9ŻT-ąüh–ä3íj%Ďqý;ĺ ImgŠ÷{ńűě(ÉÜ)*ęŤJľLž¤‚]Ą–ËąýŞ'L„ú\K›|ýýßz`ëQ^SCÁpaRs<ýa•řx…-Ŕő }~#sËGĎTŸP-/ŰŽxϑĆýŚ–JTĂaEGů uśEZęäkP/eY_Ͳž číL߼…pŔ\†őwâ)›Ý–ßŰŻ036Ĝ}Ć˙ó?Ř÷‚ž^Ýů¤‹so7dţ9+ľœeuóĽżÔŤŞË ŹfŹöo§X,&DŤ§q:˘]–$éu“÷Źś źüŒ™ ¸/\ć†÷Č\(óč9€*‰ľ ćןžm_€Šů žD›X†'¸ć9˛^ńÍ|öŘőÖB˝ÜŚłŻk_l2ÉFl˙ł™9[‡ Űdšöţ!ĆGŞŠbÂa9fšZĽTQ1X-űN•h4CĂčc˛ßúbĺWŒŘžßŻ'v§Ąs2vźžGąňQsIˇśŮŒď6VăÄë nżűĹm=ąZ\śMńŞő:u&ŁáÄÎĆÉËjŰojy›őLc ̈ýČo…łá„€ÎLKlÍŠĘWŃc8zHŐËäʝůr¤vęśüޞxwîO}~2kÁĂľ)gž œ{ť!óO›iČUj…ŘvŒnú˝ęŸÁMÄr9ż\´Ë’$˝v:ŸĎ÷çĆÎ)2!ÄóĎŢϧůď;ĂŔŰ†f‘8 ŒrůÂ!ť ‡ŰÍŕč(Ÿüř:c•enľ2‘ŠF<Ń <1ĚŐŠ>źf=ťƒžA>üäƒůyžžéé‹׼[ü˙aëÖSžŚŻŤćôB*v†őŸ#ľB2+đ‡zę÷á1°Úě‚!.NĐWłœ9zşNÍěg(čĆcPÁhÁi7Đ,•Ů{C-Ÿ§ćěe4¤ĎŽGo4át{臚<=‚że%ŰԌn†{=:Đqş}LNᣆÁ¤#]gýŕS…_?Ö˛gž¨ô„¸6褜šÂlňČŤCÔ:FOaˇBv-NúĐYî“ËĄľeŰo]ŕě Đ×cEi4PŒfě=ÍJőĐ}š§[Vë~Ť“É6ń†‚ ÷ťqtÍVźž“S#ĘŃçË Ť—‰âÖköťŢ`Âo ľąA´ čěD†<(É –3Ýż3‘^ß$Vł'ȈŤĆÚR’źŞĽNjˆAS™°„řń­ "v#&“ ›ÝA_dˆ !3ľč23[ĽsKÇéÖüޖxëT-!.ö1äӃނ74ŔG?şÂeLVÉgOxšV;ŚÝůç˜c˙ÂâaźĎN%žń<Çř-6ƒÎ›Ë;eŚ%WUň5ěĄ^{]XÉîf|j AE§Ť_Ý"ą;˝@gśáuZąYĚ؜.ú}Vš…yՈÍbƢ4(ŐZl—%IęjƒANnU%úˆżüŤ47ŢgzxœA‹ľRdkíw×Ę-ŸŽ'ŸňW•ăć Ś'ڎ(Ô 9˘ŤsÜŮzˇp-˝Â—ßäé#č#`ŇĄÖʤ“›ĚíŒĐd{ţ1wőc\scP šž˙*˝˙˘đf‰ůďż'`˘ĎĎżE­Q*In,ąüüɅ*ŮĽY~­ są?ÄżBŁR`kő)_zůk/Üů8ýlÔYŢ.3 şNćç?Ć{ÂŤž÷đӏů¤ßđzB“$Š+(žqţđ§óQŻěľ˘]šő¤ő*ţ ţč§żĹműíŐëŚ?ŕçżű şűůËîSue#Ií'§ŸŢâĆ{ăL¸qYő¨ĺ<Ńľ5îݝĺIŞńŚĂ{AˇĹŰŠ{„ß{żëqƒœfŠo˙í!Kľ×ÖšfŁaŐř:+Ůć™×§xÇřƒAĚÇ U˛ó÷ůoĎň¨gţ&Ięݖ/ť-ŢvŇY܌„‰řě؍ j­L*™`~aľÂŮsâŰÂşŔď_ńŸťÇż,äp…Đĺ÷ů8TçÉíťĚdŢć Ż’^žĺŤ-DŽŕ<ço8ďvY’Ţ%r°Ú"c`Š?ůŮ%tyŸÎó(SCgs142Î{K0ť ‘ŻDĎąQT)oGYŘŽžPO*Šę9}ÇiŐXžű +BĽyBĽmŚů‡ZUv¤Óëś|Ůmńś“ž§Ÿ[7†đ‰[››ŹëčĚv>Ć|1Ö ĺwŚ,NRMn“lxń{œ˜Š”ţRŘ ¸őPŽÍ˝XbíĘ­oj˝ŐB–XPôŒœăz÷´§]–¤wƒŹśBďăÖç žř미“Üá|}ۊ×öb‡ţęśxŰH-§yśÎ/#^…LtÇqŮxœ¤˛ĺń|gtzUľ‰zŞ@Tš'h%é n˗Ýo;éœL_Ä'2ĚÜyȓÜ~^ôԄĂTwĘâ4ji˘™&Á>}”ŐúţŻ„ÝEŔ,¨Źo“:śylWn•ë•$é09XmipŒË=‚Ôý|—çw_ϲT<Ý\ëçgvxŸ¨k‰€‡Q§˜Šńŕá<+ĽÝďO™]ŒŽ‡érâ0+ľĹ\†•…f{:Œš•ŔPˆÉ>^›ęRń(f#Ä+{ö›˛3őýKLłÄżŢ+`ĐgÇŞ5)ÜżýŒĺJgđgŰcugżÇż?ťů¤™ćÖgx^9–]ľÁÔĂGŸŒaŻPôőŇkŽ}6˜q€ËĂnĚŐ4ď>áivű3¨Ě.FĆBŒv;é0)•ąČ ć“äw}T¤Pŕ IDATžąKüdÔÎÖ;ÔKa~űů<É˝3efôĘU.ůśJ6‰>ü_ʜňńÝ⭐ř˜üéüˆ3É[üŸż|N~çď4??ú?âĂÂ=ţŻ˙ú”b›?.ŚŽ>†ě_\`6ˇ'ĂjVȕöů#ÍBďŘgƒœfŇ~ńÝ`§¨P§ Ý‚ŐľR‘x4ĚĂç r;v{Ťí†ÁŢÉôTˆAŸSŁB"˛ČÓZëcŠÇ_Ţĺq~GůVڍƒĐŤŹ% 4˝.ş=ˉí}fóšqRg%žăĹŰk1ś¸Ml#f+““ąsCŒ÷t`ĽJ&ĺţ“đîýp\mÁAˇŤZh—5ޟgŹśČż|˝ÂŽ‹ŮĘÂؕË\ěˆóťĎg‰~F€ Ń IV[ŚvaĄÂĚrŠŁŽF˙8ýç Š O=ćVşŠfw34>ÁĹđ3–žˇÚ c}5'üé'ü´_gećŸŽ•QŽNŚĎ]ŕßwŰř˙ö.Ko{„č‘Sta /së›yptsţL+çʤż‰đ˘ĄŹŒ\8ËEO•ŐĽEfó 4‹—ÇGŻĎ“] ł‘.pÉß$^ĺ~Ś VƒĄ!>r›ůâëyâő}jbôpńĂz<ĚýűEŞĘBgŔĹ¨ \fáţbFPŽ^ŽNů)-Ěp?ąš!˝Nţíłf˛ŕ°7^ş2QŤ”Šl÷fđvÚY}žDľáÉsř3Q?ÉÓ;Úϙ wâT NŚ/ŸeĘQ#śźÄł|Ťˇ‡ą‘)>q<ĺ7wăl÷ëtňá§|śn &Î0a~EEő‘™dM œ˝\›ô÷ˆÄwjqfƜŸčgŹcž;;’hCĎăÎ&‘{+œŹiŒ ŻĎ…‰+‰<+ŁđŒLáŽdXœ_@ďđ36Đ÷R|WfcC^T"ÉbŹDą VO#ĂS|âœĺ7ˇ×Ř}nö€í†ŮÇĽ+“ šŠ,/ĚŻńG¸jU(öœYlłÝx=|"En|€.Z"ˇšßŒtů¨FŠŐscZ‰­­´‰-Çlî‰I|šsOÖĐí>FCC|ÔĄńéÍ%ÖˇŞ|\mÁAˇŤˇĐ.7s,­ébŔćюlUŮ:đ(Š+1⒨Š÷$Ť-3ăq™QzŠô>ó8EupńŁó„´ŸýÝç|˝ă,ůí;38ĚíźŢqŐWáœú€OĎ~űţnfkq†yîŻTř~>ĆGSĎřżďŽđ5ß…J-óőlb#ÁĘ-pĎĺ瓐Ÿ€%Âłňf1“›^݁JdŽß?Mďč(-˘”Ú•ŕق#\č„Ő‡÷ř*\ŮüÝ É:?šÖËŮŕ*Ÿ.ž<ŻJŮ0s‡/K/śż[Űü_ƒB6CК>čT‹YâëGu5Qáœćß îůą^eî›?p{}Ťś:ůč23+yLş—ĄsNb ĚĹtrŽ>ňuŕPqÖu°ö†w*’Oňť…Í÷´g˝y‰ëÁA&Ü îŚˇ÷B˝”'^0ŃQÓáUÉ*:Ľ\† éţvZ…‰ď[Ź< “;3Ě䐕ťK›ńHŁo´w#ÉćK'lH­‘ťEÂ~WP÷Ľ°V×řőˇ[ dŒŹá2?čÝßőj‚›ŸŻRŹîxÇá5âKÜő˛Ç˜ŮuUü í†Â=0HČZcůînŽmÄęůh+?8ĂОdľÝvăMô|Šhq€qŸ‡Ę‘Őƒ‹nf*ElWŇBlmĄMl9f+…ŠźĘgˇ–É4ÖX­œă'ƒœéYĺw‘­JW[pĐíśŇ.ëdV㤆ču0“Ű:q pşđŞO#Ů#?&Äi kśˇJ0ԏ8j(G“ŇüSnďÎŐ,“/ˇŃ58śúZíĆTŠpďyƒÁ€qóĄ'Ł,4zúüŻÎ'N&Šd†í Ä:…b]Y°ď\ˇŮ Ţ“Óƒß˛{Ů\}×äJ3˝7†j’ůľšŚaŘ|O++ź>çţg‘ę)ćÂĽw”|éŁóüţÎĚîÇÝgĚçw.+•łĆőj†^§˛ŮÁŤÖę`2aVü>'F=ËňęÎ÷T'IRÂBˇ{ČŻo…Ä÷ęŃfsÁŃ Î­/˘ÁĎ䐝zd‰ŮüÉJUQŒš˝IýŔsuRkIśóĚélńĺřިîJT•ŇĐ4Čf 4ąĐa۝ݴj3ĆU×YŒďH^ji–ľ=ÉÜ!ڍ7î‚<ŃdĺđĐiŮř‘ćňĐij˛žHÓöਡ‰íĐIGlŻS¤SXKŇ řýN ‡Üúť˘ă,Śu.ü[˝se§?Đš8KŮöâ-‘+Ť­ŇÔęŒŽˆÖ+m;`ëő ŮŇî1;ĘéŔ­tŇÉ,G6ťî¸ęŤuŕu)”}˜żţŸ†÷ÝJ#oyĹíN^łŐ„Ií¨GŁFąúvĎ-Öjť_oŁĄUh;ß[}™š4ţ‰~nÜPĚĺYĎćIĆc,ĊŰÇSYqŘĘŕúOűž^łź‘ĐŐö´KzŠ´gçŰU˧ Ż˝yĽ]§ÉöŠ˝şŽƒŚ6PeÄf5 ×+ö|Řőr™˘ŽpZÍ(NƂNâ=!ń}[#ÉĚ|KçúsĚq+§c 0ćh°ôÍęîyŹm9âřŽ7h4uPÚFŇz ČĄSŠěN 7ËŮß1ŕęíg:ÔI—ӊŰó— űźŢ›Ű 3vëVźŰ]§Riχh7ŢLg=žŚ2ĐI×ČóŐNż;žď]kĄmۢS,UvŐMŻV(6Ŕoľ`VP: ‡^!Nsţ\'!ßńDÍŐŀCgýIœŁě!Äi!ÉjËŞdrUtՁNJ8ФÍË÷ţ#Žšˇ¸úÂMţćW‹{gĽƒă­o3ůŒřliß Ş× ęäťę`ňę&wÜľĘ/oĹŽŽłwdš¤đĎk.z:Ýtz\twéďďcxń!˙6“ŮUg=áëGńý'ŠWömhu˝yş‡´JC+N<‰ďۚŹ>[!}~‚Éa;ˇď• ŽöáŹĹř|ĄźwŤ­;ňř^§PŞŁo]é<•ŸěÁInœőPODxt?CśR§hŢA>žpÝ ˝A;íĆA4ŇëÄëÝtůœ˘%ş}vôü2ŃCe|­ľ‰Gęˇ5ĺxŒŐş—ž^/÷)Ü˝8šžŽÉ-—ÄűK’Ő–5‰†T§ƒ„źV’ožCĐĚńŕł/ ›vœA.Ś^ Ôz.OFWřü.LäŰ~ó6ęŰ,’Ęę(ŸF%‘$Ňň —X|4CrÇ˝’ç8^ę¨ÔKYÂËYÂˀŃÁô• œ čžÍnz™|I‡F-—Ű^â}Ł×)•(ˇ…ěě%+ŤťŇ)—ߣ[nˆBâűŽ˘‰ž¤'š6Äý8ĂԐ•ęĘsGŤ}|×I­gŠ÷űéęt %sGsrOYčíó`.­ňĺ’;6ÚáÖ1UĄJą ĘnĹŽŘqÂWał™Q;?!ÇÝnÔ3ŹŚšôű×ŢsU+fçĂ/Ď֊/5¤z>“hŰđřölWłĐa=Iő-37Łfëç{g\/Ď1ŘpŰűńŞ“M&‰ÄśŤ™ĘÉL`4#Ś˝;Ą^&WŢ{”ŤDŁćN&űí/53–Ăľ’z˝N…Ĺl:Ás>$×sԕ‹^ێý`¤ťĎ ąő“ś€‹xH|ߥ™ff.ƒęégzr€Q{çϢMżůčă{5śĘbýCŒ9÷DW͂ÓÖÎlFľ9Ěwƒ‹‘ łýN”^!–,˘›}„:w#Ł›ţνąű¸Ű:ąx–ŚÍMoŸżVe-‘?\ü=p›Ř…'ЉKŰ~ŢŃӉWŐI$s‡[„HŻRŞč˜ěśCNcÚłŮˇË b‘EŁ—‘É>‚–:Ť‘Ô[Ľ!ÄÉ%WVŰQ‹óĹż>"đgÓÜř‹Ÿ2đt™ĺl c‡‡Á‘>¸÷/üç{mÜ|\/p÷‹ŒýůnüüÇô<^d)]Ełš őÓřöWüňyţX꫓›šĂ§ĂŸđÇ×Ä Ěó8œŁb°âöyęŚtóWü?OVˆUVŁ}NL ,^3 w Ÿ3.š%"‹‰ÍŐ[Ýn}/@#ž š)Qnhtxťí6PŠÄw-7_Œ<ç~÷>˜źŔ=Q–ÖKÔ43zş=Tž}s¨űŔéĹ,‰2ŒŒpśşJ˘Ü˝F6•§xˆ~‚Ĺŕ /_íÔóIžžŞłűĺŐ%fÎ35~–ëÖUVrMlžĆzÍTbłĚŚŰŤŹÁځ×nDĘiFCaśťčňm\łiV $ 'ůúźx§$žďŹ4‰šâ—Ďrí{nL•03Ë'oĆ  ď/ăý0Äůk—čŠÄIhÖş{|¨Ĺ;|şřňíˇ^KŻĺ9;ŢËՋ:ĎbEę=ý=¸)Ól{AĚň"KÁ3 ž;‡>żJŹbÄßßG/Żăn7*É)}˜‘!+Śj‚č>CĘ[‰­­´‰-Çl]§fí噋iÚ}Œ†Ü]äq´Öţvô+keƆ¸6 Ů:M˝J*–~q?ÝvśŰJťÜLÇX.ô2đĄW˘,&Ľ˝ď7IVŰT‰>âżü"ÍĺǙgĐf@ŻY[yĆ­•öçԓOůĹ/r\š<ÁôÄ4ă6Z!Gty–›kíŸç<–ú6sÜţ§ß:†küѐCłJ>›!üä{ăíc l>&ĆúŘ1M O_@3EiĽ˝dUŻfYŒ: ůş™ě1a2čÔJbĎgxř|}÷°¤f‰š;wȇ˜čëâL—MŻQ*IFß053<ş7i˛‘Š)& ľóćămQX}˝Lďs;šFŹüę+3ŻÓČńčŰTĆBŒB\ )ęĺąů>OîYtäŕŹ=ŁüpĘľëęƒuř 76×+/?ŕż=JŸîůżâXI|ߌ§W˜ILsŁŰ@af™Ĺ~ďěZz‰Ď~Ÿg|¤PwÝz­L:šĘ\˛Š:مžŇ†9Űß˅.FĽŔÚňSž,ôđÇâޝŐunó„ĘTˆĄŃ1%áyžMš>ŚŘľhî1ˇz9E47L§ŰHu5EbŸË“­ÄÖVÚÄÖcv“ŘÓ'$}CLLöbĄJfm[OVH5łÝmŻĎ=ć–qŒ3Áa.*T3ÝϷ“ŐśśŰJťŹXZ-01ŢAy-žďąâ}˘&''őJe㛢”zńŘz~ßŁç°‡gßu-Nbpćźëjˆď ׯňĄ=Âż}ąŔşŒGAâ{[$ž5…wü?ŞrëÓ̟đ“â8(œĂř鸑ٯoq˙ § ńeˇď3őA!N4͊ӮĐ+Ő#š;'„ď‚âĽsţĘFß†^Ȳ~ň'‰ˇAs0t@.ƢÜ[U,„8ů”ÍMż×‚Baóő2lk’X\?÷ŇBecâň$…‘T˛nĆŰdŇU#|/z$ŤńŠÓCłšéóŘpőľ×‰>X“{Ť $ŤBˆSŔŕéăĘy? Y+[x­ešďœâÓk¤S%zÎÍiPʧyzw‘™5šu×űĆč ríź˝Z"úl†[ů 2gľ5ŁçŢu N/™Ó$„8É$žˇOâťBˆc sV…B!„BœH2 ¸E˛ZdëŠÁńw]!„x#‰ď­“ř.„â8ɕU!„B!„'Ž\YâÄRtO_ĺă3[łĂ++ůLJŠ=71˙PfzFF9ßďÁe1 Š&áťżçŤčwî !ďU|?&šw„?˝ űč|ą"÷ůâťJ’ŐC0şzšüá8Ó^ýŰĎš™Ü>kýĺ×vü'ěŢX§­žÇB§ˆđ8ąő\áö1ę7’‰Žđ8&Ýk5Ş”tĂÁćžuÇWa2 Ů &‡Aźk§-^žśú ‰ď-ÓŤäŠ p[°€}N*‹›Ň)Nę=­ušÍ“Y3!Äёdľ –Á1ÎťŠť÷ů6šgxUŁH2{¸í]˝\š<Ι~^›˘ZČ]Zâć­Y– ­ć㪯!t…˙ĺĎB,ýöˇ<ď:ÇľQ?s“ěę"Ÿ}z'ŮÓßAPf#c!Fťt˜JXd…óIň{vĽÁŢÉôTˆAŸSŁB"˛ČÓZëcŠÇ_ŢĺńŽqV­”m‰f%0b˛Ďƒ×f„z…T<ĘŁŮńJűşŢHł°ćb˛/@×üą×Œ*TfŁă!Fşœ8̊F­F1—aea™ÄvÇYëçgö`y1n݇~Úłů˙Í9Ťk.|tžŃü,˙x;öbňîtrţúĆJsüíˇŃśßŁ ńÍϏţÏř`ýüďżZ¤źo7ţűs9÷-˙ŰíW\•;Ţďřž™„*3vŤ‚ź"pî*׃F’3ßňébÍjÁJƒTasŘ´ÁN˙PĄNťŤ jĽ"ńh˜‡Ďäöś ĘÎÔ÷/1Í˙zŻHp|€AŸŤÖ¤\Hp˙ö3–Ë[mAń‡÷‰ş™8quŠŠÎłRÚńޔ™Ń+WšäŰj8šDî?gľĽírŒÇMq(’ŹśL#ěÂB…™ĺG=ČčçŻ˙ü"!•áÉŁÇÜJWŃěn†Ć'¸~ĆŇóVƒĺńÖ4B׎`™yĚ?˙ňxšńń8öŁk?Kú4Çvƒ“éËg™rԈ-/ń,ßÄęíaldŠOOůÍÝ8/Ú:łKW&4Y^˜'^1⠎pŐŞPTvoˇ•˛­P6F>¸Ŕ%“Dx•ű™*X] ††řČm拯牷=ÄśIrel0ČH×"ąč+6¤ŹŒ\8ËEO•ŐĽEfó 4‹—ÇGŻĎ“Éj3łÂ—ßÄĐPtŽNs֕áţÖ7 TňMĐ $3 Ć˝NÜ*F|żĎ“فךŐ\ťoNˆMßifÇę\ řčÖYÚÍKŔŠł>ťN‘îŁxշoď:Ĺb‰&ěV `Ĺë4‚nweŹ6 *ä7w„2{ň˘Ic%ŠU°zşžâç,żš˝śďźVeôpńĂz<ĚýűEŞĘBgŔĹ¨ŕE‹ čĂ^ćÖ7óŕčćü™ WΕIٞSŤ×ˆĚ< kĺěĺÚ¤ďM;î`Ű=Žă&„84IV[fĆă2ŁôéÜgbރ‹'¤%řěď>çëgÉoߙÁançőŽąž[˘ů‡›Ë”Y~ŰŐÇ<d¤ăˇNń™Hkoˆq§"ůô!ż[(m, ´g˝y‰ëÁA&Ü îŚu@á$d­ą|÷7×6ÎđÎG \ůÁ†v5t­”m-8…NX}xŻÂ[ ˆŹąŹó“k˝œ ŽňébűĂšô|ŒçŠ~.ôwa_[eߊŤ&7˝^•ČżšŢąčŇ"JŠÝŻ]+‘\/ć~]Ż’Ieˆďę7HĽ č^›"^ÔA3b1B˝V§ĄƒÁĺŔ­j„ÓG>™Vźw$žCƒŐŐ4Í/§b)كÁ„Ýʍ•ŤÔt0vúčÖŞ<‰ćhžŇdUâ;4‹% řą[(Cގ:ąD™N§§ZÇh3ٚyr›ÉŞ^MpóóUŠŐŻ^#޸čP/!{Œ™}F(ťfîđĹbéE›°[Ű[ •ZćëŮÄĆšÜ÷\~> ů X"<{q‰_§”ËP4Ý€…ý˛Ýă;nBˆĂ“űŹśJ0ԏř´ťrô1Đ(Í?ĺöŢá\Í2ůvV88ĆúnЉ.Çv$.MŇéMeĂŐńúuO6~ŸŁžeyľ´ŁAŹ‹$)aĄŰoßXyRmţżşÎb|ÇP¤ZšĺDmw硕˛-1Ópc¨&™_ŤĄi†Íůą˛ÂësňěT…•ĺuŢCŽWŰfƒzLN~Ëî2şŢŢť+er°ăsm„ŤŽi~öɇ\đi€Âáv`jćI~†‹wLâ; Sˆ%I㌡Ó(Üg?âţ˙„O‚ß9_ˇKcpü´~ç$žčĽ…ŚÂfľ 9¸É^ÉR˛9đ˜4lV3”ËŰC˘Ő]‰ŞRšŮL&:lŻxĄzŠšpé ‰e“T2łcއNĄXFW–aĘm;Ŕví¸ !Ž‚\Ym•Ţ V0`4źŠđ k‡‹śpőz…li÷˜ĺtŕV:éd–#ťcŘ1Öwó7TŞťž‘”hüzŻŽ‡Ůj¤vÔŁQŁX} ˇaPFlVz˝BaĎÁĐËeŠşÂi5Ł( cĆnÝúůŽ’”J{7iĽl+őľâ°)”%ŔőŸö-Ň,›0+¨˘ĺ­&˘,WÎ1Řďâéü>ęëĚĚĽńOôsăF€b.Ďz6O2c!Vlës­çłŹ×ƒřÝhŃ]ţęun*YĆë˛A>ÎşŹ",Kâ;Íő$Ńę$ÁÚ\žPż‡ZľI¨ßƒśR ťËëKŹî;‰üŕőř~ĐúS|o”ÉU ÓfÁćt`-fHŽI5;ń:­­ŠfąČöĹRŽŢ~ŚCt9­X ;“Čmç°ŢmzŠôŇŕýÔjť mô%Ú!Ď{żyťÇt܄GB’Ő–UÉäŞčޏSÁAîŠyůţĎÄ5÷vÄ­/Üäo~ľř—ź…úśyĹěT“W/0iߎG#ţ”_ފ]gď;FĎEřúQœâ~żŹW(öP5˛Ě‡‹Œ„Vö›#Ú$˝đ€^sŃÓéŚÓ㢝;HËůˇ™LëÇŽ‘'™Őp9°Mô¸‹Ě=/1đŕ4äđşĺhŽ6ÖŚb‰ď?Xg%ŃdŞË‹Ăle¨;Ë­os\ëÁkLŇŰŠČ?OnM‰ď-;ňřŽ—ÉuŒV+ÝŘŠgWČ7JŹçôť(+”Óĺ ۃ“Ü8롞ˆđč~†lĽNĐźƒ|<á|őËčÍC݇[ń~“dľeM˘áŐé Ą/†•䛾hćxđٗ„M;Î S/5Čz.OFWřü.Lä÷_ůôŐ÷Řé%͐ÜqĹ@Żä÷[a˙^ťNŠÜ@š-t˜`gŻSY­Ř•NšźuĆľJą ĘnĹŽ`{ę˜Âf3ŁvÉVĘ'ƒ_ńëňĆ"Z.Çúą]œĐÉF˘$‡‡ T^Yz)Kx9Kx0:˜žr3ÁÝłÂ-×­Ćzş!'~Ÿ%͓Hçp€xMMÖÓyé ‰# ń}C…ŐhuŢO__`q›O2ř/0€€­Éj4}¸ďœÄ÷zGń˝NžXƒ.}fôb†^#•­1íóŃ4éä ĺăŹ,ôöy0—VůňÎɿí˝˛ę§CťÇMń6ȜŐ6”Ÿń Ţ3çšěß3öĘ`ĂçÚ{ Jb%Âě|řĹăŮZńĽ†^ĎGxmbžŕߞíj:Ź'ŤžÇŻN6™$Ű~Źf*oiHNƒäzŽşr1ĐkŰńE1ŇÝçÇF…ŘziŁ.z…X˛ˆnöęÜą/nú;MťńVĘîúť*ĽŠŽÉnc˙é;U˘Ń s'“ýö—żŘš™ËŃt'ôRœçqÎ`7/M]Ռ˜öGŹ—É•óéŃÉŚsT†Bnšë)˛Ő kY;Á!.6V â(H|ĐIF×)™|\8ßMc%Jźg>îfâb¤ Ż6­”řžýwď*žo$ŁXÝtŰ+Źgk€N&ŻżŞ“1NZmóÝĂŕb$č<ݝÉv›⭐+Ťí¨Ĺůâ_řłinüĹOxşĚrś†ąĂĂŕHÜűţó˝z덎^ŕîűó ÜřůéyźČRşŠfsë§ńíŻřĺó6:ýÇUßď¸ňęłç™?Ëuë*+š&6_c˝f*ąYfÓ[ÇB'łźČRđ ƒçÎĄĎŻŤń÷÷ŃĂŢýÚJٝV`e­ĚŘĐ×&a![§ŠWIĹŇ/îmWŒ<ç~÷>˜źŔ=Q–ÖKÔ43zş=Tž}łď˝čZW'˛§ÜӋ]ą{-Lk}/@#ž š)Qnhtxťí6PŠÄ‰ˇ™S6ł9ŇÍ_•ů…î^âű†JĄD7–FžőÍcZĎćČŞNüzéĹJŔ袹Oî^ˆĄşÎíožP™ 14:Ć@ŁD"<ϡ‰Šëí–}ĄÉúÜcnÇ8ćň B53Üů|ť3CłÄܝ;äCLôuqŚËŒŚ×(‹$# ,&n€]c}ĹB€3{.­ęŐ,‹Q'!_7“=&LZŠ@ěů ŸŻˇ?˜Ş–#YĐ Ř2D7;‘ĹdŠŹîžɒ•°8B߁Ę:áT“WŒůčFÉŽŹ‘hvâŽ%9ľ o‘řlŽʃ9—c+?×KyRŸV&˙âl¤Nva†Ż´aÎö÷rĄKŁQ)°śü”/ =üńoşßéѰöŒňĂ)׎+šÖá3ÜŢřyů˙íQCÔŰ:nBˆˇAMNNę•ĘF4RJ˝xl=?ČżďŃsŘĂłďş§N18sŢu5Ţ…wü?ŞrëÓĚż6SkĽŹâČI|o‹Äw‰ďß]r܄x×ěö}Ś>!ÚĄxé܍˛Ń㡥˛Ź×Ú-+„âݒřţÝ'ÇMˆ“J† q”‰Ë“tDRĘşooIWđ˝čîaŞ­”BńnI|˙î“ă&ĉ%ÉŞGAŻ‘N•č 84c¤A)ŸćéÝEfÖöÜTꕞB!Ţ-‰ďß}r܄8ądÎj+FĎ˝ëœ^ďĺœ&!ÄŠ!ń˝}߅B™ł*„B!„âD’aŔ-’Ő"[W Žżë*!ÄI|oÄw!„ÇIŽŹ !„B!„8qäĘŞhŸÖÍO˙ÓšžÍ˙ńsäe‚wHŃ=}•ĚlÍ$ŻŹ<äŚZż9şBˆ#ĺşČŸL(y—ÇŇX !āI˛zFW/—?gzŔ‹ÇnD/牮ŹpűÖ ORw]˝—œśú'ƒÍËŘHP§‡YCŻ•I%Ě=_aĽpÓ;ô⠟Żi Üœš4€ë]WIˆSě´ĹËÓVßă˘ŮźŒôoÄözľB!Ÿcm-ĘěJ–ĘťŽ Bˆ–H˛Ú&s÷őłs ňĚ?ăQچĄĂĂĐČ8,đ4U8QKŸśú'ŁťŸë—‡čT%ÖVWY*Ö1Xtw÷1Ö#\(ŸĘ}Q-d‰ÍČČťŽŒ§Ři‹—§­žÇEŮşůţ÷Ćé5”Y[]eąŘŔ`ľâöřŠąÎRyv„B|‡H˛Úc'×r–•ŕÓżýœ›ÉíłÖ_~mÇßqÂîÉuÚę{œ .ŚĎŇŠ2<¸ů'šíŤ¨žZpZęďĎžBźě´ĹËÓVßcŁŃ94HŻšÄěîro×Őd ›ĂBóýŘBń"Éj,ƒcœw+RwďómrĎđŞF‘döpŰ7şzšryœ3ý>ź6Eľ#ş´ÄÍ[ł,Zomťžť™řŢGüŐD~˙˙őnŠâQnţL]} Ů!ż¸ŔlnĎpßf…\iÇsƒţĄ>B.LźźŁ f%0b˛Ďƒ×f„z…T<ĘŁŮqšL đ’ř~źő=6ʄËa†ZŒXfď°ç&Ľ|éĺż9`lm5ž::™ž`ĐgĂÔ¨ˆ,1[?†÷,„ďIV[ŚvaĄÂĚrŠŁž dôó×~‘ĘđäŃcnĽŤhv7Că\ ?céyŤƒă­ď.ĘÂŕ÷>â//ÚXţÝgüýƒ ľă|˝–)ź>&jŹ$ňo\xH™=Œ yQ‰$‹ąĹ*X=]Œ Oń‰s–ßÜ^ُëp(şĆÇ0…—šőÍ<8ş9&ȕseŇßDv-@epöqýĘ]Ş@xe™šBeé §7ČČú*ńňf픍‘.pÉß$^ĺ~Ś VƒĄ!>r›ůâëyâŇ âˆH|?Ţú#˝NĽÚD™\>Ëš.ˎO;ąőń]YčöŰ šb%šŁŹĽXŠ×䤢B´Aúš­ŇÔęŒ†ƒţ‘†ľĂŠEŰNXôz…liwJ§œÜJ'ĚÝđŮcŹďCď? l4ĂţŽĚä8Ŕ…ËŐĂl5aR;ęѨQŹśŮ+Ó4š:(m#i}c×Á€ŤˇŸéP']N+ƒÚńť†}śQŤíŽ›Žë€bÇŽDŮlؕN>W|ý°=eĹaS(K€ë? ě[¤Y6aVźtŐ@щďÇ[ß=ő8ŇřžŠ–Kđč^‚GʀľĂAWgcĂ=L}0~ó.3Íścë›ăť›ôryϝRŠ"ÉŞB´A’Ő–UÉäŞčޏSAć͏ćĺű?˙×Üۍr}á&óŤĹˇpϡˇPßz–ťżţšgÄ_Ÿ˝ÂŻüš_ÎÁĐTŐÁäŐ LÚˇëш?嗷bmvžęJuô­Ť˘oXůÉœäĆYőD„G÷3d+u€ćäă g[5آŢ\ä=áëGńýŤ[ݰĎÚMBˆśH|kŽ<žďĄ7(ç3,ç3D˛MţäJ/Ą^3ŮëHlBˆ“O’Ő–5‰†T§ƒ„źV’o^Ô˘™ăÁg_6í8ƒ\L˝Ô ëš<]áóť0‘ß1ÜčdÖwK#6ÇW‹ňáořŚďW?žĚBěKîv•^bńŃ ÉW ôJţCŒuRëYęý~ş:hÉÜŤYRzű<˜KŤ|ygäŽ‚n­ĽdóĽZ”Jt…ÓiÇ@ůŐďG/“/éŕШĺrŹř‚ƒÎć !DK$žo}wžŔQÇ÷WkŠäu…Ď´Ůĺi;śžI•b”ÝŠ]Áv¨°Ů,¨ˇ{:@!ždÎjʋĎxď™ó\öď{e°ásí=P%ąav>üâńl­řR˘¤ç#<‰6ą OđoĎv5 ֓UߗÔüîßfX3őňăá?ô§ŤN6™$Ű~Źf7”Ş[eąŽţ!Ü{*¨YpÚśöÚ滇ÁĹHĐy¨/Ž^^'œibî2âŘł%eÂjzQ[˘Ń s'“ýö—_S3Óa٧Žz•REÇdˇa•„Uˆ–H|?Ţún;ęřŽpř|¸M{ƒžÂŢĺĂŤtň…­?mĆÖ7Ń+Ä֋`öŇďßąßM^B]&9(„m0tvvţŻĆĆiEĽÔ‹ÇÖóƒüűŢđucĘ­CłH$ボ?3@ŻĂ‚Óëept”~x‰ąĘ"×ÚČT#žhœćâT~Ť›ĂIßŔ ßűčósOÍŐĂh(@ŸĂˆŃlÁĺőŃ r~z„ŽJ”ĽěŢnfšľ‹Ą€ŸIł —ĂDłTŚ*Ăڄ؟Ä÷śę[;1ń]ášŔ'çô8mtŘíx<úCĂ|0ěĆ\Ip÷q”ěćUÔVbk+ń˝’Żáčía°Çƒ]SX^Ƨ ˜t †:ńĺ5G~™Z!ž›L&“$Ť-Ůę̍|œ™çijVƒA&†=& ‘n?‰’hs˛Kł”äÉóuť‡Ą‘Óc}ô{L”VŸs{6IŚÍÉ<ÇRß}’UĐ)ƒTĂ\˜čB /ńLóžÎ̆f9ĂňZž†ŮNW—Ÿ`‡J*Ć\$Ef3ŁŤdҤąâďęb°ˇ“n§BdŽo×Ě läÚNVAŻćX‰ĺi˜;čéî"đăď0RKE™‹f)l…Óë¤ÖŹ×Mxü~B˝]ôúěŘ ŇąUžď,ť˝uJé %ł‹Ţž{;éﲐ_‰ńŚ[ ńޒřŢV}ON˛ ľJ…&œn=]~ú:]8MuŇŃ0ˇ,°şsn ąľĽřŢ(ą–(apxéďë"čľR/pÝƀO‘dU!Ěd2Ą&''őJe#‚K˛úŁç°‡gßu-Nbpćźëj!ÄŤI|o‹Äw!„ÇĹnßgކB!„BńŽI˛*„B!„âđdU!„B!ĉ#÷YmQ18ţŽŤ „âH|B!NIV[!‹H!Äw“Äw!„âđaŔB!„B!NIV…B!„Bœ8'*Y5ŚřË?šÄ´ó=ťŤB!„GHúŐâťŕD%ŤB!„B!H˛*„B!„â’dU!„B!ĉ#ÉŞB!„BˆçôÜgU3bˇߐ]7)—ŞÔ•”•˛RVĘJY)+eĽŹ”•˛ďQYýľ…„8•NM˛Şšřáľ Ž×-hÖLńí§Y´KY)+eĽŹ”•˛RVĘJY)űţ”ŻžŚŒ§”šœœÔ+•ĘĆĽ^<śžäߣbLńçl<ůęr{N™:řloČŽŤ¤âY )+eĽŹ”•˛RVĘJY)+eߣ˛ÍÝ?}mżZˆSŔnˇŸ˘dU!„Bq ŇŻ§Ýn?=À•ŐĂhЅůuůą^&˛#c’˛RVĘJY)+eĽŹ”•˛Röý)›nźŚŒ§Ô)JV˝ŒžyĚ~i9FVĘJY)+eĽŹ”•˛RVĘJŮ÷¨Ź$ŤâťH† !„Bń#ýjqÚŮívšĎŞB!„Bˆ“G’U!„B!„'Ž$ŤB!„B!NIV…B!„Bœ8’Ź !„B!„8q$YB!„Bq✨[×!„B!„rë!„B!„'’$ŤB!„B!NIV…B!„Bœ8Ćw]q:iăüěĂ.âwĎďךďş:ď5­k‚˙蝯š{ÝąPtO_ĺă3[łÍ++ůLJ)Ţt5ďz5@öŃřbĽvD5B!„âŐN]˛j°ű™ ňw`7)Ő2ŠDŒ'ĎÂŹ•ő݅5+˝#Cœéóŕś(jĹáĽ.çŠŕľ:Bçů锅…onqg}Ť;oÄ××G¨Ó‰ßăÄm3˘Ja~űů<É=/otőpn¸ żÓŽĂf 7(2D–—yÎSÝUž…íÚ=„‚Ýôw:qÚ-XTƒb.ĂĘŇ2OV H*!ö§“^œáó5 ”›3—p˝ë*˝#ĘÖǍFđĆgřű; ďşBB!„â%§*YUÖ.Ž^› ¨XZ\`ŚŹcvřâş×ĘďžzĆZ}Ť´‰Ţ3çřŁ ‰ÜZ„‡éÝ} Ÿ9‡ŰpŸĎ Żżšdp36čBĽçy–ÚQRYč`ÄZ!“É“7ypžbF—ŸŢHĽ“Ä×ęԕˇż“Ńłčś?äˇO3ۉ偷Ťđ„Ƹ4` —J^NPSfü=]L÷ŇmżĎ§syé|‹}U Yb@32ŇÂß5SóüÓŻ@—ŤčB!„âí8UÉŞ˝§—>KƒČ˝üau++]#޼ďG:ô=gms¤rör.hĽśö„ĎďĆ),§Š~˙"S##3,żćňŞ-dČVcy&F~ç•M˝ÄÜ­?0SŽŇŔÁšë™|ĹĚßňĘ#~ľ˛ç‡*ĚřŐš ҡaqŤ-lˇ›çˇ )’ĺ‰Ăó$Wţč CC!ú—moWˆ#ĄÓlęo.&„B!Ä9EÉŞÂd6˘tjmç՝jľŽŽ›Ńőí˛Žn?.Ş,„“‰*@3ĎB8Ç䔗 ĎČr´Îž4ŁC^ š%ž&ö–iR.Uˇ^ŚuzBЉî1c3)śÇtť:…ő$…˝?ŽĽ Ż7ęłá´íÜnë 6/ăŁAüfE˝R"ód>Lźź§°fĄwlˆłANłN)ăÁĂyVJ;^ß`§¨P§ Ý‚ŐľR‘x4ĚĂç r{/+;SßżÄ4Küë˝"Áń}vŹZ“r!ÁýŰĎXŢŹ‡2ť1ŇĺÄaV4jľ!Ń Ě$Şœ¤ôJë™âçxˆ<~FĄs€!Ÿ SłJ:áŢÓÉ'^5'ŘŇ–ŸMŰyţ‡o¸“Úýî”ÉÉŘš!Ć{:°R%r˙I˜xĽÍ˝ ĚŒ^šĘ%ßÖ˛Iôáë珜ôŮ9-Zřüž8nďu 2pâ0ę÷ű^{'ÓS!}VL ‰Č"OkAŽ)y—Çůˇđ ÖŹ†BLöyđڌPݐŠGy4ŮőŮiő˝ !„BÖ)JVurÉ Ĺá^údžˆ×WI”uL?ӃNęéEf_Ě+Őp;m(=K:ˇ{Řb)—§Ź;q;­¨h~ßdĆŇÝĎpGČý(Ů#či&3Vنf4ăîěă|ŔĺÉ˝slŀբ^ĽÔnrœ}\ż2B—*^YfŽPGY:čé 2˛žJ|çŐ\ž‘)ܕ ‹ó č~Ćú¸rŽLú›Č‹+ŇĘěalȋJ$YŒ•(VÁęébdxŠOœłüćöĹ}ŞŹŒ.~@‡šżHUYč ¸ą ƒ˛2rá,=UV—™Í7Đ,V\˝> ONX˛şÁ@pb„Äâsž|ZDˇwrnz˜ěżýf…LŰŁl5ş'&ńĺĚ=YCˇű ńQ‡Ć§7—Xog\¸^#2ó€Źic¤ÂľIßk‹ˇöŮ9=Z˙ü*şĆÇ0…—šőÍ<8ş9&řŇ÷łKW&4Y^˜'^1⠎pŐŞPT^Q#ƒ^ăj—";w—yś ;ř›ł1ňÁ.ů›$ÂŤÜĎTÁęb04ÄGn3_|=O|×ůşž7!„Bˆ#pŠ’UhŹ/đűWÇ{šö˝ž­Ÿ’‹<㷏ÖČnuȕ ŤE^Ł\S¸‡Îńńˆ‰Ő¸]¨RAŃaÝXőĽž•˛3<ěĂ\ˆđtí(–*R¸‡ĎóăaŰćSJ6Ɲ‡ ďpbŠÁŐˈOŁn÷ –˛2<5D—–áÁ͇<ّčĎÍŻ`3íM6ÖężţvŤ“#k¸Ězý,žmÖCŻ&¸ůů*ŝW{ĂkÄ—¸ę%d1Sxš—Ťě˜šĂ‹Ľó‹×bkŰLnz˝*‘9~˙4˝cň"JŠĂ'ŞĘÎĐT?ÝĆ&‰Ĺ9žř őEnÎ&6Žř痸iěŕOĎ™ěŠrsíWű߸Y…ŠźĘgˇ–7Ţ5V+çřăÉ gzVů]¤Ď˛N)—Ąhş˙ősź[ţě´čXŽĹÁ´ţůU¨Ô2_Ď&6rË-pĎĺç“ĐÎď…Â=0HČZcůînnÚůh+?8ĂĐ+“ŐŁe ŽpĄVŢăŤpeó;łĆB˛ÎOŽőr6¸Ę§‹ĺ߼ƒźˇ6˝Ăc,„Bˆ“é”ÝgU§^)‘ÍŹóěÉžź=ásičĺúšn/†Ďj4 ŠÓDĂáęŔj˛ás™@×ię`ĐöëŚÎ ŁNľĹŠ#š¤“ĚńŐíÇ|ý`žgńĽJ•Jă;b&7çÎőăŠ&¸;§ý\ŐGżGŁ 3ˇçŠ4z•ŇKó`uRkIśűé ŇŮ"ş˛`ˇîËܨîęč+ĽĄiÍhbĄĂöŠ ŐS̅KŻN’š ęM09=ř-ťÇNëúě_eĆŰÓM¨ŻóĽíˇO'•HíJE*É뺉.żă_Ht4Aśšýź°– ĽđűSĺhýłÓę Çą8 –?żMRÉ̎Çu ĹňîĐíˇŁŞë,ĆwœH¨ĽYNÔ^s˘ĽIa=ÎŇjœŐÜaOŚ™é ¸1T“ĚŻŐĐ4 Ăćƒ|ŠXYáő9÷œŃ<Ŕ{kם<ĆB!„8‘NՕUKĎ8?źčdőŰŰÜIn^–Œ%‰UĎńÓŠQ.öĽů]¸ 4i4MĄŃ ňřŸE4rët›MAŁšO ¤Ź ua-Żqső膐Öňi"ů˙/Gâ„.^âÚÍŻf‰śop0qqŠ1kއßβtˆ+ĘfĂŽtňšâWÖŠTvwŹ7áQhťúš\˝ýL‡:érZąvţ˛AŰ÷7zŠDţuŠŻ33—Ć?ŃύŠš<ëŮ<ÉxŒ…Xń„ާIš\ßýnkUĘM贚1Ŕďyş?bОkťzľBą~Ťł‚ăœRŘúgç4iýó[ŤíŢ 'Ov~/ĚŘ­ —Ë{†ë”JŻ‹=M ł$Ú3۔‡MĄ,Ž˙$°˙Ť•M˜ÔvTčÍďM!„âhœ˘dŐL߀[#I4ľłł¤SLŚČâŚÓç@ ŻÓÔk”+:¸LXM WŠÄ6{wšĹŒJůĺĄÁŰǘ’OÂ$ŽŤÇ­W ŻŚů°§‹‘Ž"áC¤Tš‘‹ÓœwWxrű13™ĂWú8ú›öŕ$7Îz¨'"<şŸ![ŠÓ4ď OźęĆ? ëÍ7$nMŇ řç5=n:=.şťƒô÷÷1źř›É.amf¸űůWÜšűÜh“zi'ŤcŮďťź…•ÇúŽéXDťŸßÓBĎEřúQœâ~żŹWŽő$Ç.ďđ !„âd:=ÉŞ2b5mt‡_ŐŮWjŤÓß$“+ĄwŰń85¨lw|lNVŐ ’+ďîż+3ĄáěŐ8wÂĺcíŰkš†Ba2PźnČßë6beđüY>đ՘ťó˙łwßŃu\÷Ąďż3szĂAウwŠ")Ғ%ˇÄ’lÇ-qŠít'7mÝűňŢ˝ëćţńÖ{7ÉKrł’—ć4Űy‰ă¸É-K˛:Ĺ"’b ’轡ƒÓĎĚź?’ žƒBâďł `cfĎn3żłgö4Ń4śĚg“˜á0ASÁëuĄaĺ[dćýąE~lá~ŢšŘÁhŇ5¨;C]•'ž˘ˇ{ŠŢnŔâaËž4wk’ŢĹď&†Ž/sŚs1*n—…đzWÜ*Ä#ąťł’ډ ¨sŚŤě6ë"ŰUp9çm×fÇĽA"ĺŢ |“Ů ąUą&mgîÖ .R°fí7F(ŠËK@ŇJćN§ e[uf„é° •x °źE¸V7CëSÇB!„ذ6Ď3ŤfŒé°ZĹ9Éě Ţź,|ŠÉT 4{Ąc25<Ć6ŠŠłqÜNŞz(/ö˘Ä'čÜŠž"jł&şzYě6éŃđf¸°ÍżšŐÜT•úŃĚ8SÓËźŐXqPşu{su:.5qiÉgÜRgFĆč4°ĺSĺ™×4”™Yęedvö6Éy4UĹޕ5@Ղuţ؉ ˝ęŹ‚ż Ÿz÷{o~~%ÁČŘô u3!Œ‚/Ă}÷ySŐEIž{‘2SđäĚŮŽ;?‡L%ÁČhŕŢ[sgWśşœŹôQÙüŽEŰŮÖ¨ýšQ†FC˜ś,Ęr’>3´dP’c]"VÉŠŹăŕÎzv8VřYCŒIt[ő%Ž{Eľá–gG…BąŽ6ĎĚ* ú:ú˜Č)ĽlŰv´ŒACv_UĹ^”Đ×zîÎ*™S}4őĺňHQ Gwşč×qçRĺŃ˝ŐM +Ĺůxăcœí Ý'đSđäQęS9V/UĽä‰ŠaZ†#˜Š˘ĆÝląŸ&ŽĄk˛słÉuŠDGÚš™D0°ĽŸĎYŠ#Ÿ# ЇG˜ ŃUܙyTçi„ű†WuľĺŐcwňčÖ™W×Ԕ{1§:işű)‰§şœ-Ľu4q罥šĂMŚË2sׂ׆Š‚Íĺ#7k&ŸF4Čhp6ĎkŃvŝC}ľóŢ>o„éíajÍÚŻÉdw']ō”oۆŮŢĎPÔBvIů$–ƒTܙ9”ć*L{š˛Ě˝ßękăJŢvŐďŕq˙]ca⪠ˇŰC~žŸhËš%ߍ+„Bą–6Q° úD'ožĽąŞ€˘’r - Ç"ŒőľŃÜŇĎđœkŞ8}׎r:RAcq!Űňá×;šÚœsŤ™â) >ĎB łw^ťo~)âNŠ´ IDAT[‹“‹ÎGeÍLÄ홦u8‚iĆěęÁ[ŕ'+3›œ| šŠ č¸ŮKsç8săɡ‹‚ÓiGEÁžYŔ–Ě{J‰ŽéžĺŤ€čĺä™0ľUE”–RdSIDĂLŒôqcY/5™ęhć”ZÉ֒BväŞčŃ ƒÝ7y'˜Ďw-ýîÎ%ˇ›˘sŔKYVőůVʚI<d¨­™Śśąq#ĺ2č ÜźÁdvľő…Řˆ11ĐΚ˝L$ŻäĆĺœ[K))+''b°ť•łąbžŘâZ`ťC7o0šUA]}!vbLvpáFĎ"ŤZŒľ^炥†ĆâJö–+(Ć$ßşŹ:ňŤyŹÁ7gĆÍQŮȱʙ˙GşŻrâÚÝW­~ŰY{Ş'‡-59÷ţÂeşk„)}íÚ/ą1Ţ;wƒhCŐ5”ęaFzŰ9?RĚá…ŐXĐúžŒ0­/2]VJ]Q.š6T3N8b´ŻƒÎŃŐżĄ[!„"UJ}}˝ÎźHCQ”;_ˇżOĺßÍÍBáö=<šäÂÉ&ÚWňž@!– ć7đô.?=ÎňîđĆ ŢÄzSČŹÝÍă1.źq•öů‰‹B!Ěsš\›kfuM¨6ÔéšFFWôÚ!„H‚˘˜sgP'ůŮNĚŕcr÷­B!rŹ!zŰťÖ;Bˆ‡â¤no=9ÁúƃDL™…ĹÔűâô^`ęA˝2F!„bƒ’`U!փgbĘtrŃŚZfwţ ľşB!„âaˇů‚U[&…~…@ÇA=Âŕ˜NEN™Ę$َŻőÍWŽ2dĹSČţ†lÂÍ\IĚţ>Át|iĹć§Ś"ed”ÎĄ0Ą8üšTU6pÜ{‹ż7H()ćĐźEŢWEޤˇ§›Ö`Ĺî&ż°˜Şą~†#ÉOI*řŤȈNŇŮށéÎŚŚ´ˆ}Ű"LœëcÚź›.3ÇE[ą’r*뷑=9ŔőÓV—ĐX•EÇíç2'Uťv°;Ű`¤ˇŸ+“1př(/ŤŕH†ˇĎ´3œ`Nrkk°övsá\;xňŘŢX<7i–ŠƒŞ[ŮéŃßŐÉ­iŐîŔçϢ0Ë΍ƒU ĺ{°?WaŞő/ˇLŻB@k0Ú3ČTq1Uš $NŚyٲw+ ž8CÝ]´L82óŠŠjŕ¸ç&?ž4ĚÜ4…2ƒeԅB!„ŻMŹÚ˛łČQŁ´„01 `ägQčë`tňvT œš$¨F:&ąĐĂc -ÔNZ0c#œ}ŤŸP,)ZédXßÍą˛BĘ\C4oĎ@:¨l¨ WäęŮ&ní=8­ó—óQpÄyĺüígˆ)m/fS`ďŁĺÎ,ŹÉô@7Í=ÓXÍL*śyęč uČ$ŕËçH–2̘ Îâ*vä@ÓeNőFgžA:FGUU´Ů/ŚÇŠ(dfyç}ba0>:ÉÝŹ™C‘ó2C'a€Őë'Ű>wŚšXhfŚŤ˜ţŔbk=/G”žî1ôĚ*< Fv–‹9Ew8)°N0Ô7J;yŮóŰZ*eśœşB!„âáľšŽľ ł,č“AÂ6;3qa˜ń0Tçfám 2ľćÓRžÂś”ĺëu`גĂMU`vnLq:q)&ӁK<™Ä$Ď™Y3 PPçĹUw‚<ÓÄŔÄ0“~Ž*3Á”âŔăTPě~˘`Á=‘™Ŕ6ž´Óx|nngöuoR–Łšu‚캎+ ˜fljšŃá!:†B‹źvČ`¤ă#ËÜĺRb#tGˇQ^âăfűź_*œ 3%8/cf$BČTđ:l(çÔÓ}Ël™u!„B!ÄĂjSŤZfůV°äVóÔąęšż4˛(pö0ZŰ+}Wq=ÇśúIŒôqíĘ$SŃ: f–s´Î{Oúžęě‡oú8sm˜ĐBéQ毴ú &:ŽňŁAů9äř}äĺSRRDegŻ5O.úžÜ5ĄOŃŢ˘ŞŹ€‚žŔƒÜó¨ !„B!6‡MŹŞdçůą›n^îf8i"Kqçąť.‹˘\ˇ:Łk÷̟b§°Č-ÜĎ;;Mşł×ĄŢ˜šá0ASÁëuĄၯcF˜›ŕQ‰ŒĽ6˝ťfá)zť§čí,śěŰAcqyˇ&é} y3™ę`´˛‚Ş‚čÜz3„#:J†ˇH^ŃŘáŔĽ˜D"ËX˝xƒŐ…B!„ÝćyfUőP˜cĂ ŒŇ>8F˙đÝŻžîa†*™š™ĚŹŇL$H `ˇYď;Ëy˙´Ęěmžóh>ŞŠ˝÷ŚŁwŇŔ–WL•gŢo+ë}2´b1&Ńm9ԗ¸î­lՆ۾˛šß”ĘWľ`Őćý,!™żŔԜ?"§˛Žƒ;ëŮQŕXőj3MhţšG÷KkFšfkm!űwš´ …HhNňKňÉ ‚mŢ#´]ď¤p_%Űě łg˜Ą`Őć"ˇ ŁíܕuOÎô@/'Ď„Š­*˘Ź°”"›J"fb¤“k¨ÎS˜Ö‹™.+ĽŽ(—Ć\Ş' 1Ú×Açč oNNĄ|Í؝^ʲň¨ĎˇbŐLâá CmÍ4ľqϢČˆ>6Hg°€ĆůŤëŽżJ´ŚŒŞ‚2v—)$"A†Ú›ijeُEŻu]!„Bń>˘Ô×כŃčLTĄ(ʝŻŰß§ňŻB!„BąZ\ŽB!„B!֛ŤB!„B!6 V…B!„Bl8Ź !„B!„Řp$XB!„BąáH°*„B!„bÑ`U!„B!Ć#ÁŞB!„Bˆ G‚U!„B!„ŽŤB!„B!6œ Źj <űÔnśx•őΊB!„›–\W‹÷ƒ Ź !„B!„ ÁŞB!„Bˆ H‚U!„B!„ŽŤB!„B!6Ëzg eŞ—ĂrŸčÚ Ž‘P$­¤•´’VŇJZI+i%­¤}ˆŇšK&bSÚ4ÁŞę+ĺąĹx–ZĐĚçüMtş$­¤•´’VŇJZI+i%­¤}xҶǖH#Ä&ĽÔ×כŃhtćEšóuűűTţ]-ZAßáäĆŠ‹\ ĚűxČęŚ ËyŸč:ĆřđAMŇJZI+i%­¤•´’VŇJڇ(­1÷§K^W ą ¸\ŽMŹ !„B!R"×Őbłsš\›ç6`Ĺ᧺؇mŠř،Đ×1ĤUŇJZI+i%­¤•´’VŇJڇ'턾D!6ŠMŹfRS}˙{öĂÝCLIZI+i%­¤•´’VŇJZIűĽ•`UźÉmŔB!„BźĎČuľŘě\.—źgU!„B!ÄĆ#ÁŞB!„Bˆ G‚U!„B!„ŽŤB!„B!6 V…B!„Bl8Ź !„B!„Řp6ÔŤk„B!„ByuB!„Bˆ I‚U!„B!Ä÷żý3üÁo˙ĚzgCl`Ź !„B!„Řp$XB!„BąáH°*„B!„bĂąŹçÎUw65Ŕ—R“;Î _;KŤžž9Z˜–ż/}˘Žŕɗř×ËŒőÎĐeőĺŃXSDyI!UŢžýŻďŃł …Ľx*řÄgR9~‰ţn3Ăćʡ)֑b'ż˘„š˛BęŞr}ý<מzǗqC<,6t[_¤ŻWž7tY!çąŐ°Öu,u$ÄĆ´ŽÁŞĹ“IYEťŞ|XăAl뙙%X2łČs8çşQŹwv6,[Fe•ě,ó Mb]Ľ7Š9”z­¸]yä[šŽŻÎvĹ:ŃÜ–•˛k{ šV -˝†"ă†xXlčśžH?śx2)]‡ł×xŸľűľ'×iŹŘĐm}‘~lÄÇÖ!;šŹä<ś:VÜś–Ö´ŽÖ†ňžŽl!fʰş ˜áQÚ:{č]ßKNgá6ž=\ˆý}žĎ{Š83 ŘšŁ„mľˇmhëĄOuS˜ëzŸäĹľQƍťL èY:v•ţ~uÓĚüŚbíĆ,+ÄJČyl#Xz|XË:Z=…Ő:_ůdŒüő(ßţOQžţ q~m—w˝3&ÄY×gVçSÝů>ź‡U~ÜF˜Î^}ىś`ňĽ”‚+żšÇŠŁžŔ…]U1"“´_ťÂ+ďö1i€âđSWWF]U)ŐöNţőűý”?ŔŃjŒvđҋgš2aŚ´-Œ1N>÷ÎÜźz 8tx;ťË2pYTĚČ$mÍ×xíÝnƖ¸ VőpčŃíě*÷ăÖ0" wľńÖÉk´ť¨ľQ~đ(Ď(Äo¨ăç~ł€Dçţě;ˇ˜FÁ]XËck¨/ôᵚDtÜźÁďv04ç“ČTŇŚ˛ĎĽ9rkř‰Çśą-ßáÝ-7xőt ý‘ÔëR+ÜĆĎ~t+Ľ>+ŞŢÇs-=Œ„ćŐą­“;1DĺáݨÎÂŤDénç7/s}"išWuQľgm-$߼Ą(:ÓĂ´|”Dzůńľń%gŔ\ů5=XK]Ž ÓÔ°¤łé2/ŸëgĘHľ\gň^[[Jme 5Žžór€-Çv°łŘ™˘łů*?:ՋYž•'ŠĄ:ۆĺĆĽ‹źüޡťƒęÉa[}9uŐĽ”ÇšřÚ;&ŰBc›b Ł•×ßj˘uúv˙I˝¤ÖžSě?€%وƒŮQžMŚSEM1nŹÎ €Œ)ĂV˘<>Ľ܅: žá4 {Cť˙˜JľW8V̡*őGjm=•}-küd5úqęcƂe˜FßIu\XzLTđ•5püđ6vŘAŃuŁ•S§/Óśďi`Oaœë×F¸=f؋wóóŸÜŻë,˙ß÷ĎđăwoŇjsüč6ę•~.v‡Á›Çö†jvÖfáqZđ”ŕíoŚ)‘GCE>Ĺ đnG[ ŰZpĐײ8öSOpÄÖÉ|ëuNœjćĘx‡žŘË~ď[,xÝŠeóOăý<÷ď?ćšwŽrś5Nĺ#űř@ƒŽŚ>&9˘ńmAüuůd„;ůáŢĺdS—Z‡ %p”ďăžÝAQ°•?<ÍKg[h™rąí‘Ýš“üá÷ř—ďžá 7iwÔđáG¨4zyŻ7’rÜÉ{]^—ŸÚJcWÎqâífZü™‹Áę2öV[¸qň /žncČSÁŃýu”Fťš<Ĺ,ž<ęŤŘY‘Ó飪ŇËŔéˇř—/ňnŸFýŠąĐy­ŸI#őzOľ}§R e×óšOf{”7NźÎˇ_˝ČŠٍEÔdjŒÜşFSşł2n¤4nX&v+Řóă<ŇhŇwÉĆ`̤|g”jÝÂůV CUĐuPü ö4LľYIԆů؇";cK‰I°ĎÂXňUŐ n”Ç#9ĺČŁ1voIPŕTÔĎ˓âÔŮu,“OD8v8Ęžqę+t! }“wĎ%j:y˜gÉ1+šÁń”ĘqecĹj×_Zm=Ĺ}Ľ?~ŚŮoçŮ:IÓš.FfOŠŽ÷–aŠ}'ÍqáţcâŁă#ÜěHPśł˜Ls×žw†ŚŰŸÔڋ9zʊ Ç4WŽÍńSNśnĎeôÍřťW{™ ĘylľÎc+i[úăĂčČ0- ÔQjíd^™¤Ó݊śóŮ'jŠ*ł1đ^'ĂKŒĹťü÷}đĘsVţä‚Jű¸Âđ”B{ˇĆ{q“O0šŚŃŐođtƒÉPŤFŹ.Áď}$Á—ë| ĆűTş“ĆQKE‚üů85ŁŢťűsßś8_˙źNFˇĆ…Ů5ľLƒ§ëMşT2w'ř˝%řÂ~ƒý90ŘŻ2”t~ŞiÚŔë§//~đâĄeľZ7ÎmŔŠ˘Đ}ęuN\`hb’ŽK8Óo`+,§>cöBFńóČńFň"mź|˛—‰`ĆźrkA•źmľTXŔďⵗĎpnĚDąfă>Ç÷ÎuĐ=• ‚Á(fŠŰZˆš]ʖl•Ą–6şĂ& 3=$j*¸s2ń,ĂŤŢ|Ş˛4P-hłĄ^|˘ƒs­a;ŠŤŠĄ!:z&š`&B ô ŇŃ3HçH]ÍâĐcuä}üřĹK4™či>ĎwΎ`-ŢÎgo J9í}öyżú´Ú™źň.ďô‰:Ó}×xůŇ$śâm­śĄ¤ZţFœŠţ.ZÇçŽŕsęXs¸ôß˝ĐÇŔř]Mçyť3šYƖź™2U%<˛=eş““—lj˜`„‡yçB/ĹIccţâ+ *~k _ŕä[łŸâëƒ1L4ň 2ąĽQ3y— ă&ŠjĐöćkœ¸:ČĐÄ-ď^á괂/ËäÂóođFË(#ă#\~§™NĂJiCéE!â#źöŇEŽGM‡›đ•SźÚ bčL÷6ńâ{(Ůu<ÖŕDI#)ľďTëOqłçřnŞÎüčçÂ$€Dh‚žń<łzťjdÜXbÜ´˙|€_ţĽżřlŒ Í`׳~ů—ŚůP­‰Vĺ§1Ŕ/=ß´˙źýaŽŞÜĹ`ÇGBk0˜¸nç՗ź}ÁJ_Ü ŞdágfSÉĂ\KYfŠĺ¸˘ąb+Şżä"LĄ­§şŻtÇĎUéǰď¤4.¤1&šÁŽ÷é`ÉŁşčn&­EETŘ@Ë/Ľ6)î’ňA.ß̜+ĺ<ś:çąľ­ű\Ó,RG鴓´ű`L Óˆěbx‰ťk‡Ágô˝kĺë sk*W“-ys˙Žę@œŸ/Txű] ˙vUĹV˘óOéŹpŽiç‘O{Nźeáë—ź5 ţgÔ.ЇÓI+ÄB6LS1ĂÜęŠÝí€f„ŠiNÇ̏ÔěRsTŒöaú’;ľd<`˘ägRčSh3ÁL›`LŇt}„8&˝g^ăŸ:,ŒőNBööÔˇuOfT 늚q[Óf “W^ŽăížóIß|F`€Ť“x2,¸Źw7Ć@ńârh°ŒĽXÔěęłTŒž>ZCÉż1™ččeřH.ĺՅ¸Ž´N#m0íœ$1ŚhëJ^Ődd`”(UTWćbĎJŤü…ĘôNĐÜL*šé(6œöŮť22Éľ€9˜3‹‘˜ 0˛łüř”žëNÍ*Ą!GŢ+ŠĚb#}\k2|ž—xv}zĺjƉÄL0ô%ľ{#ÂtČWŃÉť ˜‘0A—َ˙ŔHĚ,(b›äfÇtR˜Œö1mfRR–‹}ŔŸzIĄ}Ť9ŠőĹV˝ŒíĹŒŃv.öŻţKeܸϸĄkœű‹ëšIĺá0ŰăvNœŐĐ3â<~<ÁđŰN.‚U $íßąň/ߡÍö+ŁÖi>^Ÿ ÂcăŇě'ěfČʋ˙l#ÜžšlôƧůÔÎ ™VÎŢţ”ŢĄSYdşîäÄIËÝťÎŰQՅsŸJґj9ŽdŹXÉ~ď'•śžÖžŇ?}+ďÇiőĂ{Ňé;Š iœ Í0ˇÚFŃËrŠ(ĎÁŇ:@’ĘBœ `ÉĄžŇÁť—Ă˜Ř(/ËÁč=Ď­9ەóŘJĎcÖ+],´śŇŠÚÖ<óë(­viŐ'€9ÝÁwţžăžůňTęěUUţö˛BP=Ÿ~<ÁG+L\q…óUâQĎź‡q3#żó=~@ŁËăo0ŘăŃ8ąÜ7Ş)ŕ hü÷ďktč3Ű=Šó'éüTĆ˙u-)˜N!­÷ła‚Ő…Ü}Ňn†–é'K­|?żńË{ç¤U5ƒX(Äôü•́ټěÍX€Žî™[—ł­YĆh—y˘°Ď˙\17[špľ•ë×[žď6}ŒÓß˙§ďwŕiŇüdŞ™żjż2i@~ćLšXiƒ+XĆ4ŒNÍ݁Ž2ü~/YË/˙”öoδŸ;wŞßw<\ü$ŚfúÉVÁœ’|HŃţë|ç{3˙ˇÖŽ^š.–sö€<#ČÄźň6C!ŚMđxÝřŇŠ÷Úˇ%ĹţŁĺf’§AldœŽV…ŒÉF{-ŒZlńÁŔi+í]*Ží1Üq o5YčJşúť˝ŚČŔ-KŇóƒ ÃFŁĎ w^›P$e\QAU`dPCWdxŰÁŞąŘsu ]z’.úŒEúCJyHGŞĺ¸‚ąbEű]†ům}ľö5üÔ˛Wޏ—Őg-ťď$Óěżwƅ´Î…&“íÝôÍŁ¸Ź|u€^2Š)łŇ~ľƒě­”UăžÜ´%‡Ş"…ŽS˝+űŔ9ÁÜó˜Gš;¤$[IŰşŸôÚÉŇŰş§>ÓPYdbҸT“g2Îłv•ýĄ…–„ÉŁ$ř°ޝ÷wˇnŞ $ĺŤ}PAßb’ëayăčííÜTéJúÜjŕŚĘ­#ůÎw IDATe&ÖkƜî—VˆűŮĐÁę|ŤˆˇžâĎNt§x’24—ˇ­YĆ8'Ÿ{ óř>×fRšm•Űś3Ńq…ďžx•ÎĽÖ<×\”7Ö˛Ł"›,ˇŰ‰×í@YÁË-fŽĹ$–Đď=V]'( V%˝´+™H†13ŁbąŕXIů/ƒ9>Ć` ˛2|dŞp{}k†Ÿjcb‘łŤŐ6sżźŠë‹ŢţüŔĘuŚŠ“˜WŢŚaÎ|JŹjŘliäOżűNľ˙8JíX0 „cé^⯚‡yܰŘM4@+JPbŐ¸6¤`łT”ë0hgD1ą[bńš—‘ĐÜ‚g—5@›łBŚIv]Œƒťâ”ć8çœM”šicΝľP|8ʧžcjDcpHŁŻÝĘľ6uÁARËCšR(ǕŒ+ŮďŞY‹sŒcĺýxÝúΒůI}Ě6'{š1ź›ŇźBŞüé׊¨v qćô- ĘĘ9P\Bł…+ţ*lÜlŻú˜÷°ŸÇëú+j[÷ąŢe2Ă$×gšT˜4A+ŇůPŽÂ‰oYů^˙LŠŚ1(űŮ{<š{Ëp\Ÿë­+|pdjîˆb†FâĐč1ń&Ϛ§VˆűŮTÁj">ł¨ją ÁФ•nË rňÄ œőćҸľ–ƒ;+(ŞŘÉgž˜ć/ŸďXřUŐÇţ§Ÿâ#eĐ}ᯝd8%c߇ůňÁĺ/:žˆ'0P°X´{?­´hX3‘ nŚ—vEt㞢˘Y°(`FccŤW—Š0Ł=ź}a„šCĺŮÓĆĐů˘ŽŽě+Áîç•ó‹ćáv[Q4mŃź>°rMƒbˇáPŔŒF ĆŇËßýÚw,Ĺţc賍.pBŇVu¤îĄ7´O~)D˝őî|:Ŕ;ßEřů_‰` 8řúżŰOj›f íÔť%̧>˜ ÖaăÔKĆŚtԒ(ĎÖçÍ) ]pńOˇtĘ+ę”UGŠÝeŰ{.žůŚĺžŰűRÉCZR,ǕŒ+Ůďƒ<Ćt­F?^—žsŸü¤5f›n´Mđ‚ ŞËÜ\ˇáhĄez„ąÖ űwçS_î /Łw ˇV:­ş€‡ý<1Ypvy5Çř…ś˝îe˘€Ý‘ŘL ióšřM…[I+š›…ś äĎűӕdkšqd:c÷ޏóâ}iSŤúäĚsYn˘+hä+ٖšSĎ'łsö{—é sůô0W.÷đĚOeGq…Z- |ti)ŰÂą2ąÖ“|óÍöŮ |Ë?Œ™cŸd̀\ݎ“IǢz=d¨wÓ¤“vľi^nĹdjxœéIתŐejtúĎźĘ?wňÔĄ§řÝCŃH˜‘ŢfžýŁŤ4-1U˘O7 ŰíÂťH^׳\ăĚÉÄŻšL O0=îL9Š´ďśű>dÚTpş¨ô††×c{ ď|hÇ ]ăĚ÷Ý\Q >ŚfÜÁ‰÷TȉóĄŁ:?vp} ĚŘÜçUS˘T5&pLÚxîɏ1ú ĚEë5Đhš˘Ńr°é<ňlƒ[㔽cĄe?ąJ˝—?VŹlż+ˇfç˜UčÇëŃw–ĚOÚcśÉhk#dQTQÁ6k}7ű˜6uÂ-˝LíŞ§˛Ś’~‡—Ţ[=é÷ŠÔrýPŸÇB‹¤YÍ1ţžmo„21!š›e&€Œ‡ŠIŽ˜œMc…lÇ2ˇoĚôi˼ϝ|nsŃUXs}&jŇýŠÓ$Ç ‘€rĎk ÓI+ÄB6ĚjŔŠ0Fűh ˜¨Ů…TÍ_ţOľăJă-đ+ٖâĚ ´¸€‚¤ż3Ă ÍťŸţ-ŔáuăPLŚÇ§ćźK+őWÝžFSqĆX7Ć Ôź"Ş\srJVE1šj‚Ζ~ÂiŚ]jŸéÓ(*ÎÁŞOpĽy”ř*ÖeŞť›ÜœLüąţăżÉ˙üŰďó÷/\¤iŠ\’ÜV ¨źgÉV Ťe9ĺşĆ[óąS4Ý%žFţRiߊö}xŽˆ‰5/‡üädËŁŞpţ'Ő*Ůőťůřă[¨tŽ^Q<źă†ÂXŻFĎ8< ý­Vşz,LŞŽˆĆ­zz,ôŠËš‰XpBÍŞłcŤ~ďízš‰}ţGŁ1•ąŔZ|\ąđ˜•N9.wŹXČĘÇýőßWzýxaëŃw–ĚĎ2Ćlcʇă&ÖŇ­ĘăFŰĚ­ž‰ţ.nLěŰ9”7ĘőśŐżřNîâóŘbŸG¤×śŇťŚYó2ąřŮůŘ!>ş3‡ĹcM…‘)ˇßÄ $úTޜ4ř‰Ł:vP,&'ءĚë&cZaԄň|ƒ;7âh&‡ŞV+ę ʒú‚ZƒZšşć?œNZ!˛îÁŞćöᡊ‹lżőîIĎę!ŰŁ€b%#Ó53Źsęt!K>l/ťJüdgfRQżg?÷1>ťÝç€T§—,‡Š“œ,Ç˝OilkáŒgąuK.Yn§—Ş˝{9ŤÓ{ľ}vŐľ{…Gƙ42ŠňČT42Ť÷đŃ>T<~öĽÎúć4c“&Š+‡Ş"ţ\śÔćŕ4Ć8ýć-FÔ"žřđNr]¸]J÷ń‰ƒŮÄ{ŻđJshćä™NÚĽöšTٸË8öH€‚#ż‘ă 6ÎżË;CFZĺŻyüä8P\äĺ8ďÔergű“>Ý×\dű,(¨xýî;KůŤ9Uߕ‡ĎćĽa˙^>|l/O>şušd,u>ĚéSÝ-<ţŃ˝ě,ń“í÷SRULJ>ń1ž°Çšfš*™;Y~ŰÝvëZř˜Ź^|(V7ŮޢĹE^ž ›Ş=ƒ-ĺń“óg99h¤_ď÷kߊÖ_Ź—“çGˆűŤ8ś#cćD¨ş¨=źƒZMÇDÁ“ᙊ#5“݇ś°gçNŽÔ8–ź–q#őqCË×)TUzűŔ¤°ŘŔ´0°’Ĺ™M•Î6 =#Ƈ>eז8[vFůč§CTĄŢű€7ÎÓ_œćOFŮť=NCcŒO„8^m2ÝbĽg5gUłĚ4Ę1ĽąÂ’Íџú$ż˙KOqźhńdĹő—F[Og_iŸéôc@syɰŠ“Ě ËĚś@ßIk\HwL0ĆšŃŔ´Xцşš9=ű[}„ëm!LŤ kňϓł/籕ŸÇX…śľÄ5͂u”f™¤[ŸZA-ďŠf˙c[¨Nzdcžś>…DžÁv'Půˇç-\ÉĐůă_ňďżăg= 7—1*ďŽBţŽ˙ĺ1ěŇůĺgăŇyŇ݄°Wç{:Áǡé|ěHœ˙zĀ! ßş5÷Ů´Ň ąĽžžŢŒFg–ˇPĺÎ×íďSůwšuGř͏TŕšEL3Nűk/đ/E|îóűŠvÜ^1Î$xýMţüĹn˘XČŠÝĘń=Tćypgjd€+.óö ˘€VşŻ<Ӏßrűž{ƒŕ­Óüőómó?ť˙ś,4[ ťŘU]@Iś§Ş3=6LóĺKź~ytŃ[UŔJńŽ|d_1™z€ŃNlŹ›łĂš|âe80‰ő_äŤßlbhÁŹŕ­ÚĂ'WS곐ŽsëŇ{üčÝŚ‚ť¨–cj¨/ĚŔc5‰&č¸ŐĚg;ŒÍÝN:ißçYÔJxö—`žyšž‚Fv9PLUŸ˘ĺňŢjKú2…ş,;Ŕzśߝ3Îŕ™—řjw%ż–TÇŚ™ ˙ÔKüý%O˙ěśťŐ;m'Ňy–żţn ńâ]|”,pBˆÜäŰßy—ÁņN Ů5[8ž§‚Ş<N%A`tk—ŽňÖľŃŮUS+W­tżţL=™ĺNŢNżÄ?ôTň+Ď6’uű˜HĐ˙ÎK|3°_z˛ ÷í~bDšöâsüǍ(ښĎGžřA¸Ă xłœXÍ8S#3y;Ů<ž4ÒZţRoß)öĹAéŽ]<ąłˆ,%F8g´ő*§Ł[řšcůh˜„ťĎóŐoˇ“űćyś6Ę;ßy‰7ŽŢdÜHoÜČ}$Čg4žý5}J‚~1DÎß<ŻŢsĄ •‡ůňÓqşOř8Ńr÷çέ!žü„Á•o{x˝wö‡ŞAĹž(‡ś%Čń˜$Ś5:ŻÚ99ç§?š íy//śÎŚľël?ŁĄD'Ókŕ°(DŚTşoŘ9őŽĺÎB1içaá’^dĚš3•rźF0…ąâ&5üĚRm1™şô ˙ëŐÁEf~–_éˇőrRŘ×?źăä3O§3~Ţb‚Ôúń×/góůWâŃnç9FŰk'řĆĽiĚ5ě;ËŇ9ÎЊöň럮'řÖř‡ó;}ČR˛ŸŻ|ކ‰×ŸăŸ/çô-9­ÎyĚQw˜ŻŹ¸m-<>ź2XĆŸšˇŽţćQŒ4Ęä+iŐç-&Ý<ű™ƒTM^âkßn^äÚ‡Áoý\œâK6~˙ôÝI—ŰÄŠ+ŒEŔë3QĂ q°T$řűgtŽź`çoÝݎo[œŻ~ĐäĽoŮřjŇ8jĎÖůŇuç›Rxﲅo…uţ艹i­U ţáă:ď˝lĺFŠÎÓŐ~SĄ˝Măkoj4%ČRMűżý33˙ţé7iˇâaćršÖ7XâAQsśńĽĎí˘0ŇÁw˙í$W&(.>ű>đ((ˇ3ůŢËüĹëCkžŘÓŞş}’wtňďő6×W˙UŚBfňÎ +Óş&k‰Ż VĹR\.×úß,ÄÚSČŹ(ĄŔb2uë&×nO ›:Ąń>Nžé`ŇTđć’!ŸżńKgŹ0Qěú×nżo.ĹF%籇]˙e üžÂŁ‹ó>Ąs ŔÄo—ˤŽxćyV!ޏdfU<˛÷}ˆ_;šM¸é5ţ×K}sęˇVⷞŽĆŢuš?űNËŚ_ÎĺXƒŐŠ„B!ÄCď?˙ęOÝ󳵚—™Uń0ťŐBkÜuťx˛>— âĘ)çÉGËq™AŽ^ęIű]}B!„BˆľąŠŢł*Är™“-|ëßÂÜWGăŁOđ›OZP#ft ˝u•wť"˛2B,HĽäńOđë‡3PÝ|ëĎ^âÜ{‡‰Bˆ‡•ŤâĄŸčĺíWzy{˝3"湲űÓ?Ăç4Œ‰ŤüŐ_œŚcŃÓIťźŸíýAqÖńĹßyŒÍ`đ­çř“×FäůÓE(Š‚Ş(¨ęĘR‹đ{ż°ƒÜ¤{ťĚX+_űŁ×¸*‹ë!„H"ÁŞ"5JÇżřI>VŹ˘÷žĺ˙ů‡Ë ›€Vʧç)ö;"W^ć|ˇss­D  ňĚo|”ĂI+“˜ŚN,d¨ˇ‡ó§.rŞ3$AĚĽŕŤlä`™آét ˝ňů÷S'OSAŐ,hŤö@’‚ďŘ^ęwŘďžßŇ0ĐĂQÂC“Œ_ée°32ÓŐ Ęv+ůޤŔŰ4Đ#1"㌼×ĂPoLîśBˆu&ÁŞĺťwňŘŽ2*s=¸Ô8ăý=œ{űݎL/ňţČ÷7EѰť}”ÖmĄ¤şˆĚo|Ÿç;7q´´éęXÁ[Ńȏf˘ę=L^`u}t˙ř[ü—ŻÂ–úÎó§˙ó< RűąĎň‹{]+ßčbTÍíÄSéÄS‘…űĺË´ÜX䍎ŠŠćtŕŽ,Ä]–ýű—éęÝx=C!&Ź ń°łfqäSć'k\(ńiúúúéS=”×đĄĎć“óĎńďÍá‡d†Á$xéţđ‡}誕̪ÝüĚłäkěßUŔ‹Ý›oÖ¤ŽĹĂGŸ ë[mLšěE”ÎĂią‘šŻ÷­Î9‹é%Ž7sů LUĂVZJÍS859>ş{ÇĽ_!Ä:’`Uˆ‡šƒ-y’ŸŹq0Ůü_űÁuz"3—fŽâÝ|é {Ů󁭜źyŽž´ŽŘ’fL’žEÓ*ĺ÷ż°… \úŻóŢţî,ŮĘç?´“-šV˘Ł}œ}íŻÜ\xćď~igű5°Łşâl.Ť‚ 1ÜŰĂš“ç9Ůž÷Ö^C'‹Łg ů͓ äg)Řv,@bšŰ]ˇcK˝ŽűŤăż}ŽăúEÎŘk8RŞŇţ/VňĚĺdéœńžsmsĺŕ,ŞçÉÇŮVęÇgƒX8ĚÄčm—Ţăů‹c3Řkřůß=ÎÖ䳓V§~÷Ë|jŚ‚h˙ѡřŤ3;A„ę-äČą]¨Í#ŰĽ›ŁĽŠ‰—Ţne0–\Ş6Jöŕ'URęƒÉŽ›œxurŇOgť ůGŸćˇ?ƒŚ÷râ;˝ŢJcžcr€S?z“—Z– yJe–v9¨řĘxüŃ:KüřlĄÉ şZZyűk´ÎžÇSq×óĽß:J˝–ô§z7ßü“ÝłŔŇrűĹÚЉO„ Ç!<B+ÉŚşZCÉpá´B0y–ŢĐŃă:&:áś!&Śóqf(¨ö™…řdnU!֏ŤB<Ä´Âm|d‡cđ=žö˝kô$]ŔEzŻňćÍí|Ąą€JŸBĎâ×ôŤFq”óô§=dťfž#łç—óÄOůĐžö}Nt'ŇNŤdUpüŃ:rU0ő8ĄŐéĄ¨ŚŸ,ËDýęóź1˛HŽXČ(Ż Ú§€ŠÓß3Âíëýĺlw˝Ž-:îŸŮ27LTMŁň‘Çů˛ŚŠ 9s8đřŢm>K—‘^9¨Y[ůš/˘ÚŚg:Cs{((÷’íâGw/“DSMfŇąű˛óؖ•…ŢŐLëí’L“D,AĚŠŚaQ[^iEýmM™w"N…Ĺ@ĹVœĎŁáiyN]!֙ŤB<´TJˇW“§DšôÖză î˛í<óÔVóíÄGz¸Œc*v\’‚U­ř˙ůżXő)ś–süݏťŃ+öňš§ĘÉĐ29ôH9ŻwˇJ3­9ÝǛ?裝cˆÉ: z*ů̗g/—ýŰłykÎęŻ îÝć˙Ţ=ű­ z,@ŰĹó|çĚĝtéow˝Žm,˝:ž˝˙Hßř‹sř?ýS<]Ąşú2řş—_řĘ!Ş2˛(p@W(rPȨ­¤Âf˘ŸüŐykÜĹ‚Ż¨œ}ůÁťłWŃVžńG­€Jńžĺ7f˘}|ďĎ_äĚ=/BśŃřř#ěöŤ OrţÄźÜ#wĎa>w´WÉnžŮ×Î˙{jCÍäࣼx0c#źýÜۜ™Ěŕџ8ĘĄ{‚—4ś;çďTFÎ>Ď_ż6‚sď‡ů˝cwÓXŞqéfşósi”YšůU\•|ěĂUdŞ`†yëĹw9ÓBóeRQ_GVRVÍĐMţén*ĽO|’ŻÎX4Ö[NżXsކ˝¨ü˛™Ša3&:o–ٲu+űˇŢýތE\ëŚă’Ü/„ëM‚U!VЇň7Jź‹km1Čh೟ÝO˝=Ę@k7cŽey۝3QhŽréŇĚńĆ{†3‹)T-xÜVô4Ÿ4Ę,ÍüÚ++Šw*`ĆšůĘŤ<%8“ˇ‰)úť:—Qł9^q[EZ6Őżr˜ę9?Ô ^dږZŘ,4+l·ԅâýC‚U!VŠ›LŸ‚99ÁH\!goľv“Ţ7Nđ—oŽ‘P<úéOňlĹ˝jŒ4ó­ľ3ij.Ç>šzűĘłd†Fé4oCß@łÜ‹ętâ՘óđŘýÓZ(?ţ1~ńhöE‚mĹfÁ IĎ&ÁËŻňÇ/ö˘ŤV|U|äăŘşë _ô$řÓmfÜ\Îv×éؖYÇŚa`š`šłÁši&†i*š^9šŻqńp!{ý*á÷!ž ýć-Ţxó*7&Ň2PńřČśĎܲ9Ň?zˇźIză˜vTY*Œš]ĚźĽÄ`°ěNqÇG4ęńiËŰîHrśÍáčl˝é‰;qÎrßKšj™Ľ—__ŚŤ´v…ViöpyýâÁ0Ń'§ťÜEĎĽ{7ŃÜ̕7'1UkN%Ź łą’z—ÁŐ •éU!„X7Ź ń°R4Ź0§ăÄLżßƒJśŽ‰™‹l3HkÇ$FŽÄ˘ł­wö=Ť*ť “ĹKŢçýҤsU¸tZĹQÎąGf.œ@'/|÷ çz§ ë~>řĺgxŞ@xţNŽÄЉnkâĽ÷ji<–…ł˛šFď NŖšÝő8śÔń{GQŇ/_3Řɡţî9něŤggu!ĺ…x\~jwí§şŇÇ?ýÍ[\¤‘0ç̆>˜}.ǃ(łŐ:üe÷ˇľ2ťđDĚ@ljǖ¸ůX×ID˜@˘ťŸŢkyř¸ŃJrđťœ~P™B1ŸŤB<ŹĚą8(v;v‘&NÜN•™űŕ\.;Ę2×Â4ŒŮŐDU v  ƒŐíÄąÔš˛(ô*´L˜ü˙ěÝwp]×}čűďŢçŕô‚Ţ Ń˘°Ź`鷺­bËś,[Ž“XNâäf&žď˝y™›š÷NîKţÉ{ś'™Çqb[–lŤR"EIĹ^Ŕ ˘˝§ăô˝ß‰BÄ9$DH\ŸŔ:돽ö>űŹß^ ÉHfş Pýcxfăi%ť•d-€Šˇé GŰÝăG˘ł’jŸk“Y%Ş(ă zIŮ(!éăĚ÷~Ű<žcÉ{=(ţaÎćü´f VmŕŰťňąŮ YQpœŤÓÇ\N•łç§ú܌†T 2ŠYÉčqáíäf$ Q§‹QTß2‘IĎLDC?@›žBşžq“ô¤fZ1H@ÄĎࠏ›ěenu[yUÜ5”Hqž‘Ă#wßťĎő–e-ş‰űÄ˝1žp Ž˝yՉ{’­Aď~˘!‚đ%wťY‚ |™Š^†*’=‰LƒBK7ôTmYĂĘźdrWłwš%Λ„ŠĎ_HE“Áňi¤Ś°k].şŰÄs’&ƒ-ť+(LśQP˝–­$ Ř=@o4ś´ę˜|nĆÔ’'†ŽfŻ^J…á6…Đ$`4č0¤ä•˛mY22 F}8=JÜůޗc›Çsk=hňŤřʆBr­ăہ¨ý=N|*L-žöĄń Jś‘Ÿc¸šœá~.6/‚c([ÉăËÓH˛%RśŠ– 2¨Qş:UAő Đ>< '-_ÍŽŇ$’Ó Řť˝xú|Őó—d(ŕ‰ď}…żüţWř‹ŻU’5ËI˜sĹXŢŕľv*H ”íÜÎ#U¤Ů­däćSťg/-žédÜQ|Ÿ ‡Ă‹˘š –UÚIˆůď­^‹Ć CŸ•NÖóřă%DČ'UA„űIôŹ ÂƒJăZ‡5?“ĺK̜9WÇňüĆ ž}ĄÔ0ŢąHœ=.*C­] oI!C6Pžç ĘQ ú„T-ˇšŢŞźD ÖńĂ?Żü]ÔÁ‰ÓV˝SZ_'§ý,Ž4’ż†ýy)#a#):Ô(ˇ¸űI˜—íŕż-›ůf ŽËWš2*ńä{ŸŽmĎącýJćtÖl/bĂv•Hȏ7¨ÁlՓ :ÖM}ç̕lTœ]Œ*¤ÉVÖ|ý[ŹRŽxŸŸö˘âęÇ'9żh +쉬zâ VMy} űčşyIÎ;§ősńÝýčĆÖ˛Ľ"ƒTŤ ŰpÇŢj"źv;fëƚšżŞ pŃ\…OőL•ńĺ{Ž-Ćslžm•Ě[=(­|rNŚ$?•TŤŤE&ę÷ĐŐŐÁńĂ稛e^`´çŁ3qîůΟXę,śňŞŒ^ř˜ŸşŘąž”ň\;VDČ뢍­•S=ŸwIB–5h53ŽiIBs˝[WÖ ‘ îĎ…Łß˝f䉭‹)I7Ą×hТN;ǟ5&čđânîŁď˘S,,‚pŸIeeej08ž6Ÿ$I7ţ]˙y.˙ ‚°p˜ ą,ËŤ%wóĂü`K:ŇPo˝u’3}Á=0˛1d)7 IDAT‘,Ł—žQŃdűâçXA„{ăÇ/>sÓďţîŸ~3/ďe2™D°*_6ąŤ€d¤tŰNžŰ‰(žá!z!$Ł•ĚĚDLĂçřéż×Ý4ŻRřçXA„{ŕóV5ŠŠŠNěŐ&‚UAřÂKĐĆ:ş?ÂčľδzˆjuŘR’ÉÎL"Ő$áíďâěšVš|„Ä:#_`â ‚ ‚p÷6ŹŽźéwŸœ¸8/ ćŹ ‚ ŕíiâýž&ŢżßEć‰8ǂ ‚ |ąˆ­kAAA„GŤ‚ ‚ ‚ ‚#‚UAAAaÁÁŞ ‚ ‚ ‚°ŕˆŐ€áK&öՀď?MÁţâkHi˘Éyű%icI íâ-üݡ’5x™KĂ ?_aĄ“HŠ}œ˙öÝ hh¤ÍwżËłpi jů?´‹2OuýwłßŻLé#ßŕ˙řĆZvoŠa÷–j6؆8ŇäF|ňa ]"‹žUMŽÁÉPOčsyKiQ)5Ď-Ć4܋ĂqűOd,içŤ ó›oÉ{VRą"_°”X X„űN’@y󔬬ýęnś$wóĆ/OŇqWpufi hI-Ťdűę–äÚą$@Ŕ1Ŕœ§Ůwzą{P-÷šlĎe㖠†=WŠëˆF×}í8É?üý)P˘w}.Ɔűi4:ÖŠÜÓ`U“‘KéăŘd?ÎŚ>FœQd‹[q6ƒŒŽďáť-\JDĆ^jGÓ>q‘M$—˜P# bŔÝ€>™Źe&B m8÷ť0.ud€ÁŽ­ĚÄÔÚĹؗűY×]ÁŞ <č$Eë7ńx•žÁĆ_vŕ Ę$ćł~ýfž1ćĺÓŁˆç~ŸĹĹą—_ć#ˇŸ°”ĘC?xœôYďŇ ,Š]JÖŧ/íçÝŽ‰Póě5†žůUž˛qUç?âÂÄSÉRĚŁ{Ąk?ÁOw™ž;žLg[=‡NznœOǁ7yťmň&l*ßċ[lœ{?‡z§ßœ%} 5ۖ˛ş(ł`°łO5Ň9vóWęœŇ&$ąźś’ę’Lr’-X pŇzů|vÁ٢(CžXÖ%)XÔ1z›Řđ"­ŢÉ|5%›ůŰoŃňęŻůÍŐÉVśšz/˙÷ىœřŐďyŤC‰9_ˆŕqM4zo×C!ŰČÍÔĄz۸Ú3Ľ‘Źz¸X?ČăE9TäkšĐ$ěĺe,яňсzúÂZ]šh˜`ôvM ƒŮŒŽ^_x–ĄÝ2ékśó­j8ůĘźŰężqí´ľwÓ>öšĽšĺgp6ş˜ďýőFŒç/â*(§Üâ§áăĎ8nXÁÓë31ůz9řÚG|Ú7q,1ž7ɔÁúí5Ź+M'Ő,ńűq öqáŘi>j/—œÂž?y‚é“ă›S{Ž|lâ‡h/Ż˙dÇ=Óó­ÝVCíâtRM!÷(͗.ňţgí ψMR Ů˝ŤššEvŒ×.Öq䟙šć{ý:k}g Y+ŮR‘AŠ>ŠłŤ™ýďžâ˘#ţĆ͜ę,ŽzĐ&ĺąiSŐEi¤šeB']--|rä ­ž‰œ%3ëŸű:_-ź~>˘4žó2ż¨›Ľ÷>žĎń=ŚY”Ej"ę:čžQďŃ ׌­dŹË'˝ĐŠŢ Ąx}¸›zč>3B`JI%T?–†űĐe\éůd–X1čU‚˝ƒtÜΨK=­ĆFţˇŞČtréÝŚL=_­Ą qˆŚ_ˇŕŒŁî”žœ™…$çip´*˜JRŃő÷ŃëÍ!ijÂÉŐY¤Ř1Űu$č!ę݇ł#fꎜ˜BÎŚ|Rs h"A< ô˛YźVŚç• ôލń×Ůţ“´´Nž7mEŐŰM žq–Žž)d´‘ą.ôB+Ł„ v1zރŢÎs;cJ{﯇řčH,ś!yűq݃5bŽ_˝…Œ‹Č,6“ †kď§űłÜł|ĎĎ)mŒ×Ů\ó÷c"ÝN|j2‰ĹV:{\âáÁ-ˆ`UdúÖ×$3ZwˆĂSŐq Ł ×čX˝‚źT™Ë]ż–´Xl’Ś´×$‹ţÜL4,ZˇŽě‘.Îż†bËŚfiO%jxĺÍ+ôEbO+™sŘP›‡ÔŇÎŮFŁ>°ĺQťa;/fá'żkbúZďŘÁ˘VŽlDIĘgýšUüQŞ–ůĺYşâî<š×ůĘhd ˝)ˆŒD˘ %žfAnt˘ !//ŮÓBże)ßyz9):$%Č`ëUöżŽ+ΙALţΧřťÝdTÂŢ!.=Á;§&‡őJĆvnJcččŰ웨H( Ÿo¤ek-EY2gťÇóĚ+N˘áČ9|+Wąn÷^ z9tpˆň-+Řľą€ÓhĹOŒçM˛RűÔ^žČăĘŠł ĄąXÉĘ+ r‘…OZÇĆëHqsęíý´č@N+çŮ˝‹p?Ä{-J5ČĐÔ1Ë éěţÖCěH÷Ó|ćGŁX łqÓ Só“×Zp݈ť yúŰۨNáĚŃtř VŻăY›ŒŒwzŐƐď8 ĹŰ6b8ž×^:Š%<üp_ÜKĎŻ.3OëfŽuGyľU|ďŰk)–FšTWÇąá ˛%™ĹUËX›{•ÖëwT?—ěcŔ(!§Wđ=ˇî’‹ýs|ŻI˜ólh 3Úé˝sƒRk%÷‰J˛“#¸.u10˘“NĆŞ2ʓššňţĄéąŐ– Šď˘ýívHJ#okE;‚řŢč%kÚ¨‡áF?ŤŇHIéĄgjPbK%%S"xywźA~ÄÍč5…’Ň$4íA’KtxëF §äLOgL$Ł:Šc„á6?A?$d¤’žr ĺŠÍÔż78ylĆd ž(#M?ĆH];nŸKy!EV ‰ŮŠĽÎćH2ž§‚‚ŹŽ ôFLLŮÉ$ĺęéë MžűXŇÎëőŁ+Ö ľŰ{űa§’†ťĂÔ/‹öśĎPçFĆžĄ Ëđ0GŔ–Lúň'Ë\}ľ_$Ž´ą\g1—ažŽm‚ß‹×ÖlɅ_DŤłÁŞ <ŔŒůkú9Xď" HćLÖo^NMž}ŘCëĽn˘! ý”Őv´Ůěz6{ÖüîjMAIBçmĺ•÷ęRÚiŰÂw×/Śś¸•×1§U˝­üögő8}Sž•Ď7Ńú*?XSAMJ3‡Ś=]–Ńťęůß/×ŃhćŞ÷!ţËî*vVÖóüq>ůźÇů*^†œ Ң˛-íîëŻÖ’ŸŸ‚Œ„ŮloXHFmZĐäđĐSZœÎđŰCcč2ŠŮśaßţŚ–Ÿ˙Ű Zݟ<5Äđľ&.ˇ 1ě ŁľĽSUł˜•{"ø™Ök,)Ą\ÓĂgÇç­ÉÖ\v>źŽ %vôa §Ž j0ę5× Íđ•ó|T7„AÉeőă´œ8Íą…ĄŹ2JĽ&ˇŇŠÄvŢ$cĺůZ<ŽńŇĄž)soĎ"ËҔŠÂ8zűpšh>aTĆFhkŸm.ŘŞŞŮ” ížĎż˙|P×BWôI^XQĂćÜ6ŢéR™ěŐ5ʰú9ýĘ~^mo¤žş2Ę×°“•qç;Ię:ĎKˇ?(čwđ^v/Ž.`‰ő GÝą_‘sŻłË+YYˇw%šöýň}>œĚůŘą Ř SsVpôă4ę"n×>Œýs|ŻiŃŰ´ úzîœ:aqŠžŁWhŞ›řl×ፎ`qE>™™ĂtöMźCo­'&ćŽŃ™žBů˛dÍ˝ L{Ţ1—´*ţŚA|+ H)łĐ;|}¸§„ą4ł ŻŃ}ۅŇnOÁŰĺýăW9sŠ…Gń‹_|Ä—–ÜuŐ,ˇČää§ĄíëĄŐČÉlýÚNśŚŽňńëűůů—qW°Ě"M[pĹç Cţ a5ˆwâ܌…Ŕ¨Çx=m çM† FŔ˜™MeúWš˘Ä{Qj)(Ę@§ RwŮ5Ľq˘ůb.,”&ށJfŠ íHž..´MöڍţnęZfÂ1ä;ytľöMYäLadă"›I˛Ĺ×Ď1÷:‹­ź’­€ešĆ/q|pFŤKńßr(ÜĹü9žÇ$VUAšăŹy64Š›‘ŚŠĄ"¸G ĄÇ–gœŃCĽŕërM ŘU‚ÎČzt–›ďQsIŤ:‡éSї¤aš~+M$/6ĂČ#ƒwwĂVú‡q†Éٜ†śwçlç6š@H˛Œ¤˙ŔޤGo˝ţś<’ßÁpű”}ĐÉHÇ­‡XęlŽ˘Q˘QФٹšŚçĄÎź—Ě9í|_12$ • ¸CTuÓ÷A-ű§ü;2|w˝ş¨řš‡ńG'´ŒŕU4XňŹ3î}sL;×ë,Ž2Ě׹]§ Ş Ń’ ‹űżôDĎŞ <°´ŘŹ „Ü^ĆTł Y‘ęçܛ§95érhH}véô—)cô´uĎŘşĆĘÚuyďŞ<*n÷ôšrŞß‡; 9f# &§wÎ5m•ËŮľŚ’L&í”ŕI ŁŐÜÜt:}Ӟ8Ť>Ž0,˛š1IÄ”ßű|}őÇřU’–g7WóüWőősäŕeň­&1|˝1˘‰ЇúúŠ‹) 7w1¸-œÜdä =ˇ|bŽŽuóŮE+7eR’­áL“–DťŽ€ĂWM~ë2}űĎĂ|ŇziҒůĂŐÓkAŻUQPP˜řqü÷˛ŒćFĘÎ[°‹÷R¸s9úWĺ8†čꌽš…ӍâZěR2`ˇh!čatĆrÊӃS‘Hˇ›ÉL˘UBqy˜>…TÁáđĄLm†Ć’ď *`hÚľ>PĘh4ÄgŽucyĺ$I˛Ęđ€ăîFYÜ$ÖĎń=v=H•dd­ˇ!iI0Ë œqńŠî!EÂhŃÁŒu˛ŁÁ韾ń€GBžĺĎ)­d´ÁIîŽRsÚńt*HiФ$ŠxÝýpè‡Ńś0é+prŒś¸)‘ăâ\r–Ľ`K3 ŐN=OQdÍD]JztP=‚Ó>C*!wőƒOcŠł9 Ňwʉe}.K^Č"8ěÁ7äĹŰ>ÄPŰŘôűă\Ó~×ĂźP‚x[Gfl]c"[˝ŰŔA%äž1ĺČ ŤYVbʐ蚌ăuWćë؄Xˆ`UT’–-„Că[whÍ&LŠ‹ž‘Éo'Őë`ŔöűWĘIąÜäU‰ÄŰxńą-Wřŕ­^‡´ą\gą–a^m‚lŔ`—P]cSŽ{a&1gUXaÜŢ0ť#íď¤Ţ“ÄĘÚBŇőh͔Ž-§8ÎyŠo Ż*“–ž8ůTLc§ŹĐ~Ë@1˝8Ô”H,Î#KŠĐŐ=2ăF?—´ňáÓ–ştÖW§ß˛ YEdh&NŠ($OÓÖ:xŁ ŞÇ‹[•ÉĘI™rlI,[’|WůĆćća úŹĽ<şŇŽŇßĚšŰ)ô5w1Š…ŞeŮS†ęiČZ’Oş˘Łct"ˆÖ’˜fĂ0ă^“TÂśe6¤ąnz „ÓƘdĹ DťZ¨s¤˛igŮ )ÁJՎ”ëâ bŤçh˝%9Ÿők2Ąď‡ŽN6(”Ń.ęW˛kĺfžWŽŇŕԐY^Ę"ďóŤć–/H¤.Žby†I2ąČ$!IiŹÚXM‰Şęoĺłć‰/=M&ýńZ’űúéw‡ŃÚ3¨,Ď"Iäŕž+ôMůfŒv_ćŔŐbž­Ůßęę9Ý1†.و +“‰ôœĺŁŚ‰žUIOĹŢ'yČ>DS§ƒwɒJyE.éş1.ż}–úŔřńôt­ĚĽÄÔŔšą>řĂQĚ_]ˏţf=(QF[:éôŰćvąL;ˇą7Ů^Ć÷žˇ„pÓ5{\xÂ’ JٰD‹ëb+­ł-Ŕ8ÚOť[˘vu-{|Wšć‰ ŞڇqN<Ýv_ŽăČŞ,vlŰË Öz. Fą,fă23ކĂéşţ\ĄďĚ9ꪡłę‰˝p˘‰vż‘˘ę ĘäĐMĐšç/™äüB–/–˝Äžú›{cŠł˜ĘŤz8ţţĘż˝–‡żó8šçZh"[’(Š,"zä÷üvbë­5…ü”ńŕ^N7ĄE”’AѢń^ڈg”Α j\Ÿc@áRƒ‹ľËyv7œî  ¨~ş{ЧŁ.ě˘ű`ćÇňÉ{jÖĆa<Î(’ĹŒ˝8 Οçę…ńc 7u1°ĚNvm%‹-}ŒŽ(č˛ÓÉX˘#ŇÖLßÝ=Žˆ…Ú7Ĉ3‹ěŇdđ 0Üů9uߨA\ןäÖfQôĘ@ëQ‰ÄŠtŒP™úTeěR'ĂĺKHŰQ‰šÔ{LƒĽ"›šŤ@Nu:pŽä“ł´”Ľ§GÂTœŽEźé^-Y2){&Ľ}gżŸpDFŸNF‘L¨qO$ž´ éz€Ž7ęÖDÓ$<w!ĹRżă/P‰Z3)}TË@ËŞ=™Œĺv줡%{Ú˜ŽłŘĘ0ŻÇ6A››„Y 1Üz›Ń‚VáAćďč eýZVU%ŇxĆIx´}čäC“]4ˆ7FŤůN+ÎFqqúĐYŹ[*X˛t)y~mWęx7°˜ç7ĎÄDi?q‚ŢœeŹŢP‚Iń3Řv‰Ž5ŃSűj.iUŽâ?5ëŘSSÁc‹5„Ý#4žű„YĚyjś}Ł4úˆÎEŤŮ˛§‹2FOĂi^=p‰îŠU ŒňɛŸa¤šĺkVQčsĐxć/-ĺG$ß/2iĺ+Řł|ęPé ÖnÍT|uĂmž‹ŠxhkóQPVD‘MA}ÍçŮřfśĆUuo˝GddۖVđHeʘ‹ŽsGy˙ăznt‡čnhŁcy‹–¤QŠ—Qƒ~†zy÷XGŻM.ĺonŚ~÷V6­Jáâ§#„‡šřÝżśđ–Ĺˆ>Ŕí“Ý„ěCL‹‚ÄvŢT_?g/§S˝¨„­ĺFŒ *~ç-GńÁŃÎ˖Lˆôqŕ“vV°nďvśie$Ľ—ײăׇş†9đŇ~źŰj¨­ŞáŤ&‰ ŰAËg‡x˙H;NujÚyíןŕÝ]MÍŚZŞĂ^Ž]<Áďü•|wˌƒ!ßůSĹXŢČŔe~ů ›6-ĽzY5U&™ ×MwËe>鞜`­¨ĺOödNť4Źëwńƒő*îłďó÷ďőës Ľăđ!^Őo`×ň5|mŒ¤ôńćO{ ÇWÉŃž.~ď#sU6)…YŘLđuő3Đ5ĺ3ńĐýÖeÂëňI_œÇ"ƒDÔ;†űL#ÝgF>ßEV#>˛j̈́Z‡ŚQóKĹ_×@ł\HnUů‹dŻוfšéT=4c6ť”ގ‰lĘ'uM1)ឫ×hďČańZ)ţ9œŠžƒ-čśĺ“ź<Ť ׼6ÚŮTnţ Cőťn˛’’›FVqZ­JÄíĂ}Ś‘ž3Ó{¤cIť Ž Ôҏc]ɋ­t¸ď.HŠĄ~'^€ëhŢܲ6f˘UÌľśsíł|7}ĎĎ%mŒ×Y,e˜×cc|s™y¤‡ĄĎőĹTVVŚƒă=’$Ýřwýçšü/ÂÂa2čcH-‘Tľ‰o×iüđS\‹wQáÁ#‘şz/?ÚićÂëűyŁŃw—ĂWA¸÷$ 5KYZŤĽ˙Ő:şî˛'íó%aŽ­Ś˘:Hű/Ż0t7“ű…)$LŤ—Qą<@ŰKŒŠz˝/¤Ô<*ż–Eŕ`-Íw1/ű>řń‹ĎÜôťżű§ßĚËˇĎ˜ IDAT{™L&1gUl*Ž+'yëR˜˛Ý;ůććRJÓ-˜őZôF YŮöťÜŽFřňR>ó ż>bůÓ_áĹGŞ¨Ěąa5$`0ŰČ/HžŐMA>/ idř.÷V_ŇĚŠlŔ–g€Q7žů^Ňű˘2vĄƒáP2ŮË,󰂷pg $­ĘBßßM÷lsU„iDĎŞ |ÉÄÖłz†ÄüR6Ź,˘4݌n˘Ń {Ř÷ň1ވ'ŻÂ-iI)­d×Ć%TćX1\żvíźňł97ë8\Ać“dł‘”eÂXœMV‘ׇçinXŔ{cHF˛ž(ĂęĆŃ;FXMŔź8‡ŹB Ž.ĐÚ˛€Ë.˜ĎťgUĚYˆâělŕ˝Î4:#6‹ÁëňáűÜć8 _LFš/đJó4z3I6z)ŒŰáÁ# Â}ĄÉÉĄxgŞßëD#×r   Fëő“XšI^š%4ě¤˙ýNz[xŮA˜W"XašhȏCLbâ úňÝ9Ą ó*rő*§ŻŢďRÄ"ŒëT#ŽS÷ť‚ ,4bÎŞ ‚ ‚ ‚°ŕˆ`UAAAXpD°*‚ ‚ ‚ ,8bÎŞ ÷Ś` öPmźĹť×nż[çÜÓʔ>ň,źŇ4ą4żŠŻîţÇ;ÝĚś?÷B )ŮĚß~و–WÍoŽ.ÔRމDJícüÍ ţë›|¸ ˇËAa!=Ť‚ ÜdÖ]Š$+kŸ|Š-ĽšJ.ç;ú ľ#Í,/˝?zN~ÄĎłŸýmmóű}vň’l9lÜ\MMŚxN)‚ ÂÂ'Z,‚ ’•˛niELZşGhşx‰Ă—Gř˘Ž <6ÜOó0 ŃąN…Œ{šť–Ô˛JśŻ.aIŽK\<$ęLAá.ˆ`Uh)K×ńX9\Üwť‚7zŰşzč lćůU”]ůŒË1vŻjňWńÇóé8đ&oˇMÎ-5•oâĹ-6Îż˝ŸC˝ÓçœJújś-euQ"f5Ŕ`gŸk¤sěć>ŔXŇΙÖʒu5l[–KN˘)輝Ľ‡.Ó꽞ŻLúší|ŤNžňďśúoÔY[{7ícń—[ŞY~ögź -ßÎ:—Ë|†łh+Ů1F}ô4ŐóŢÁ+´ĎV^…ň­kŘ[MşQÁŮŐĚţwOqŃ1ŁžLÔnŤĄvq:Š&‰{”ćKy˙łv†#׋›Âž?y‚é“ł>R{Ž|lâ‡h/Ż˙dÇ=1ć;!!ĽÝťŞŠYdÇńpíbGnq­Ě5ßësw[ßŮGCÖJśTd˘Ţ˛bËą!%˛ăűO˛‹süô 'Kˇ­ Ś0Ť&Šgčďýţ(ÜăçO›\Ȟ=5Ź,°aˆx¸vá‡ýU|oŤ˜ť+‚ ńÁŞ <Čô9ŹŻIf´î‡§ŞăFŽŃązyŠ2—ť&~-iąŘ,$M‰$‹ţÜL4,ZˇŽě‘.Îż†bËŚfiO%jxĺÍ+ôEâM;Gr"ľĎ<ÂWŠÚĎ׳ď˜l™ÔŹ^Í÷łÍüŰżŸ 5’ą€›Ň:ú6űŚŞ ĂçiŮZKQ–Ě™ć땔Ŕҝki?~‚˙<ä@M)dĎCkřŁŻÉüóŻ/Ň7m>­LÎĆdyú8óŮiHYĆUU|ýq/=żşĚČő7LHg÷ˇbGşŸć3ç8:ĹZ°˜›vP˜z˜ŸźÖ‚K7§ŢŢO‹ä´ržÝť×ńCź×ĎG 24uĚň\ó$s!O{Ő #œ9z‚żÂęu~ţ¨kĄ+ú$/ʍasnďt)@Go@Í'ŒĘŘČmíYçŹÎ=_™ěŐ5ʰú9ýĘ~^mĄ§ŽŒňőědeÜůN9+]çyéăśńůżýŢË.ŕĹŐÓë!ń”@NJA=ř˙vÂyc%éƆĆëĽ$sŐJjěę^ÝĎ+WÇëőô•Qžöƒ]ŹÁŞ ‚ ÄMŹ,,™ôĚäĄA:€lgíŢZÖ&ş8yđS~¨o~ eć/‹sęĂăźu`ňßŰÇşf푊Â`k×D€ âlëŚOՒ››<ăÉZ,içÂHyE:_'üČZ ډę@͙܂ ôČää§ĄíëĄŐČÉlýÚNśŚŽňńëűůů—qW°Ě"ÍXXĄťĽ‡)#mń]ëŚKŃS\˜:ce…ŽúkŒÜ8ś˝=ŮL’ízŚZ Š2Đ)ƒÔ]vMي'DóĹ\X()LŒăCž’™âB;’Ż‹ mĄŻęef OyşZűŚ,îĽ02â™Qótl3¨ĄnŽ×9gßňH˛PR”„ěëâ\óäqŤžYęAA„XˆžUAx`iąYš˝ŒŠ g˛"ŐĎš7Osj ŇĺАúěŇé/SĆčiëŚyJË]Jś˛v]Ćť*ŠŰ=6­qŻú}¸Ăc6bŕƴјŇ΁l%-IF˛”ń˝˙Z6k’¨Ë€QJ ŃŽ#ŕpăUA“_ĆşLÇţó0ŸtG^چ´dţpőĚWăńf”׏'"Qd3كiA™Ď75­J$Ş "ŁšŐJě-=ŒÎXvXqzp*évŁ1TBŒůJf­ŠËĂô)¤ ‡)ž|§w šVgŠ˘ÂÔz˜Żc›Au9şŐjY’™D›„âvă˜Í*83ęAA„˜ˆ`UT’–-„Că[˜hÍ&LŠ‹ž‘ɡęu0ŕűý+ĺ¤X‚Ď8ťł”Á+źô^돽ÄJЃ-:-„‚ă‘‹ÖjÁގŇŮ?ĽÎÜĂôxU’§˝ZBž%f™íwę¤;nދš@ęAF‰ÜŚ,×Oă)Ž ‚ |iˆ`UTj”p4Z őHvl& ŽĎÔąâĚ_QˆĚÔš›F“ţ}M6› ύFżd0aKP {ýâN  ˘¨0clzv(Hé}ƒtÜr&ĄhĆoßcR2‰V %I0ażŠ‹Y&)ɂŒk˛&l6’4*~ĎXěs}Ő.or­$›`ęřb9ŃJ˘ŹârÝ<Šw¨bÉWőátŤČÉV’dşŻË$%™‘§î4oyďĽů*ƒęĂq‹zHLœQ‚ ‚ ÄDĚY„Vˇ7ŒÁnĆDű;Š÷$ą˛śt˝Z3ĽkË)ÖŗťâÍʤĽ'N>ÓŘ)+´ßâĆ#“^œGę?J$ç‘%Ečę!wZ@ĂĺC˛Ů§;úšZßGČ\Č֚ěŸâiM$Yd „ÓƘdĹ DťZ¨s¤˛igŮ )ÁJՎ”ëfž‰Lve™šÉŸÓ+ ɕC´]&öX"t´ ’ÓŠŽ˛O™óŞŁtYvź´´ťnĘW …Şfłá bČWőŃz͉jÎcy‘îF~’1—ę’™ůÇWŢŘh)\ż•çžÚĆŁÖYŽožĘ ziis ˜ó¨)™|#éłYvS=‚ ‚ Ńł*,…Áž”âLň mÔ†9úÁ9L;–óü Ő¨Ş‚Ťł^ż%ŽÜUW-Ł•lŹ\ÍJ+m ŠEäjüłĎăSUB–bž|8s­n{6ŐKSa¨žă­ÁřÓ(#\jpąąv9Ďî†Ó˝ŐOWcĎÄ\Dç…źWö_Ůóž×H]ť“€ĆDJZĽeŮř>ţż¨ ĐÓ9H´2—SçĆřŕG1u-?ú›ő Dmé¤ÓoťŠŽƒś žű =Ÿ]q Ś,bÚ4˘˝gů¸qć–Asăž\ǑUYěŘś—Źő\Œb+XĚĆefź ‡9Ňuór@Ęh?ín‰ÚŐľěń]ĺš'‚Şhƍ5_…ž3稍ŢÎŞ'ö‰&ÚýFŠŞ+(“C7S<卍Lr~!ËK Œ^b_˝çs*ƒJ˙™łœ[ą“UďE9Ö@‹7‚ę*Ťť ŔAáÁ&‚UAx€ů;:hYż–UU‰4žqmgß:ůĐd@ ⠂Ńj@ÄąqŠââôĄłXˇT°déRňü.ÚŽÔńn`1ĎožĚDi?q‚ŢœeŹŢP‚Iń3Řv‰Ž5ŃS KÚńô‡ńŞ~ť–Żákkd$Ľ7ÚËPx"¤‰:9ţűˇYł‚-ˊŮQf$!ŔĺpĐ~á4g'Vźő77Sż{+›VĽpńÓÂCMüî_[xËbD ŕöƒÉnBöO]‘'LÇÓWź†Í{Ę1+cô\=Ĺď\Ś'Ţ-<ȁ—öăÝVCmU _5IÝZ>;ÄűGÚqÎGú8đĆI ;+Xˇw;Ű´2’ŇËë?ŮÇqOěůŞžv^űő'xwWSłŠ–ę°—kOđ;%ßÝ2c¤xĘ{ŻÍSÔąN^˙ÍÇřöÔ°jóV„Ý´?ÉŤ-KůŢVEDŹ‚ ‚ŠŹŹL Ç{"$IşńďúĎsů_„…ĂdĐǐZ"Šjߎ5Ňř᧸ć‹ÄܑDęę˝üh§™ ŻďçFßm{Ď´ĺŰůďOçpńwżĺ•Śťí=ž8drˇ?É_Ôúxý˙ÝĎIąÝŞ ‚đ%đăŸšéw÷Oż™—÷2™LbÎŞ <ŘTWNňÖĽ0eťwňÍÍĽ”Ś[0ëľč˛˛íwš͗‘Ęđ™OřőŠ˟ţ />REeŽ Ť!ƒŮF~A2Śű]Dás&!Ďü6•m”ÚP‡úék, ‚ B\Ä0`AxĐŠA:NćW˝ĽlXYĘ#_]Nžţ§ö˝|Œ+ţŰgńŔQý4ÚÇ˙×YÉŽ•<űÂ: ×ë,ĐÎ+?űs"@ypHvś|s;…#m\épŕÁ@nĺ2śfůšřz#ýb¸‚ ‚ ÄEŤ‚ Qœ ź×ـFgÄfŃŁ“"x]>|qLW}0DižŔ+ÍĐčÍ$Ů čĽ0n‡OřÎŻžDÔ =.–T–óđr#z9Œk —ĂŻžćPĂü×7ůpđË>4ţĎ…Ś –˙úüß}™_ÔěÂQ•UUŘěvş{{ąŮl BĄ~żŸhtü( ĺĺĺH’„ßďŸ6ôW›đš•UZTJőŁ)¸ö˘ľíö÷žš§•°m[Œ*ݍßDŽ\Ąî#ç‚=g_T’Ź’X&Ľ2€Ů8٤6XĄpľŠ$Ťh'O&ƒ–äŠŃ„ˇ'hPô° ˆ`U„›HÜ4mK˛˛öŤťŮ’ÜÍż<$Îąp х1lâśFGF°ŰíH’D$AŻ×3::Šß?űcˇPčć9„‹,M'c­Î'Ńč§˙‹töF§ýM—˘GYh÷žů•ĐIӇŒgémřŁaÚüŁř˘ Ş ­c#XľzŠ)¤$˜ y°Đ( ůą , "X„šDĘŇuărŒÝŤšüUüđá|:źÉŰSćW™Ę7ńâçßŢĎĄŢé-IŸBÍśĽŹ.JÄŹělăÓctŽÝü…KÚ9ÓZY˛Ž†mËrÉIÔ!˝tˇ4pŕĐeZ˝ůJ2ŇLHfšzf†wQÜƒŽ›ó•Ůńý'ŮĹ9~ú†“ĽŰVPS˜ˆUĹ3t÷~” n’X^[IuI&9ÉŹ¸Fi˝|‰>ťĆ`3xěĎĽvđ0˙ów-ł÷ˆĘé<ňâŁltĺď_jƸf;ߪ†“ŻźÁť­ţ縭˝›öą‡řË-Ő,?{€łŃĹ|ďŻ7b<WA9ĺ? ĆqĂ ž^Ÿ‰É×ËÁ×>âÓž‰§š”wj5˜2Xż˝†uĽé¤še"~?ŽÁ>.;ÍG­căĺ’SŘó'O°3}rh\ĘcĎń]Żâ^^˙É>Ž{Śç[ť­†ÚĹ餚$BîQš/]äýĎÚžŃ9–RČî]ŐÔ,˛cŒx¸vąŽ#ˇ¸śçšŻŚd3ű"ZßŮGCÖJśTd˘âějf˙ť§¸čˆżßË ™ů˙Ů{Óฎě@ó{/šgbß÷…ŽWpE‘˘(•KŞ*Šş¤rUľŰ.ŐxÜś'Ú=1S1‹'ě?]]aíŽr•lšT‹v‰”HQEqŽ @,Ä$€Dî{ž÷ćG‚Ř’H”(ń~ "ç{Ţ}÷>ÜsĎ˝çnyá9žŽźö<:ŢYxĎjĘ6,Śż-ˇÇMZZVŤu:jęvťçČ\;Ş ş@ć_^ˇäňĽňŸČš˙$]Ý3÷Źoh ń! co´Đ74ďţŒ6ňwWPPm%M‹ęeđł!| ˝ĎR‘],:Ľ.ĎŔâĐ#Ţ{ žŃ+é1g˘cxóg-TbŽYIśRňüОgödwmd㎊ЇŢ_]blö~ ÉLѡ)ڟśa2›KČ.ą`Ubnďu1Ň,d5’]žŽ5Ý@šߕ![\Dâ€l§ě…UäMvqöÝąë—&“”)ýî*ň}ݜ{˙ňdŞŔ١d6|KEփ,I¤I:|‰Q5#ŒśäýQ<‰0Š–lšC$Fϋa¸@p+D/îgŒĹliĘb˛ő‡g9ŞIT&ۯҡa-Ľ92Śž–ôŘ62g;%›ńźLtTlŢL‘k€3ÇŻ˘:ŠhZľ’g3tźúć%FK•]$rÍßúPĽŇ{ś}ǂŕ( iĂţ¨ČĘ˙řĹ şŁ€#RŔ”O}™‘+Wç×ۍ‘Œ%<ůĺ¨Ů˙†›ÎFEC!öŠäŁ’ľ˜­ÍĽH]˝´tx™ ‚٤Šć­ńRţ~ú›+¸ŐIz‡ăl+ÍŁPî˘{D˛fSœcĆ ™Ëyb{.ăGßfß,G@Beâl]6SU(Ó2 SZIű‘3×­g󞽔upčŕ8ő;ÖňđśrN˙Ž›đbí˝V d§ůŮ˝?z‚ž°‰ĘĆÍ< Ě­Äô&ŃQ˝sŚłgyí•SSĂc­äš' ˝|×Rüˆ{Á-ĚĹűpš%äźžóHŮ-.X¤ ‹íoKŕšcjˇŰ‰ĹbhšF 0÷ůšLŚéŸЏęő $Y’t¤Ľ›0ÍöÓlzn?EŽLúÖ:l8:Á‘Eޚrjłd.˙žŸ`bО‹-ŢLŢcŤ(/Ő\eŕL Éć {u9ľůŽüî*ž )Ä#*dęńޤ05Âř‡—đĽŮT=MźľŢk•— šÁľĆLʞ(@ëfđ@ˆ„lÄž,4ĂÔ!Ść ňłú\Lô„‰†!-?‡źuËŠĎé¤í˝1˘jżS!żČ†EáĐ\ŮŠŐ‘ŽöŮ.’ž“2Ăm2™Ĺ&;œÇAKŚLĂnƒYcüŞÄče‰ó’—H"~>'řǤ{>o€@p/ œUŕ>Ć\^Fľn”ƒm^@˛°ĺ54•Ů1Ćýt_D‰é0g%€ĐńđóE ęť­„ü’„!ĐͫﵑÜÖÔKOhßßRKsu7ŻwD–&ť¸ÂI_ť™oÔH\~ű^> 9śšÂéŤQţüxdí%ţţ¤8—O^bxŮZś|÷ŰT÷ôŃŢ;Jo˙ÝC~"7|șŮhßâœđL'Ąęhď˜ţ˝čćß~ֆgö†×łWčŽ=͏66ДÝÉĄ‰ý.´úJ2$ş'5а™$˘Ą(q tšÉ. z1ÖŹŁ^7Ä-“(€l/a÷c›ŮZ“Ž1îĽýÔUQfăľH’ĘÄĽł|Ô:ŽI-aÓůt8Íąv•ńÂ:–Ud“+wÓŻ.ÖŢd…HćBęËôřĎă•CCł‡-Ȳ‡Gp:ĽŒ8!—“žŢ…łĎ:V6˛˝z?|Ÿ_OścZťPžák›x ¤‡wT@ŚhCkíaNżşŸßwĆЀS—&yîGťYˇd˝łZŃŔY^ů¸'íuó^Q9/m(gšýG}ŠJď@ĹçĹ贊E ęomC*ý-uźšŚáp8ˆĹbÄb1‰š–geeH$…ff?fg–eyÎŢVôYT|7kÁ2oku´$ĄóŇţÎ!` Oh+ˇQźl„+—ăK“]$†úJJËÁsč<]—ŻMž9ˆłâ™BŠëG𝋠žł#„ĘKČjށI<ƒ>Ă^|ÎƜ‡Ľó$5 „ۏďşŐ( TGşíČ9:ÎÎLŽy{œ3Ą ş_!žU`›b-ËW’9Îđ¤Bp$56Źv ŸWŽ4Ł„N j çÚąČq&G–žŮZo€şƚ4,v‰tƒ "Š‚Š<őJÍ­ÔČ­ÔHכĐ%ô\î ŇuTÂ7&2 ‹A8ŤÁ}‹L^A6ňřeú#€œÎŚ˝Íl2ŒđŮÁVFuëWąÖ ]ł/S&8őq'#s"Ť%ěhžÝŒ“*cÝLLëŐđô 2ҜKIIúŽáYĺTdƒ™ú†B Á.Nś‡‘őşéC¨5çţ•l,ĎÇxŇOˆ |Î˙÷óIŘÖ@cM ;jjyPӈz†8úÁg¸XpđŞĹ9ŢęšńŔ6Ć3ËpYÖ!ËŁĂ“(R!YL¨ř†ĆpŃ@Y&d­ßĂ_íąsę_ËëW5ňŠr0%&čŃ(~(ýČYşĂ€œĹƒßŢ̓Ś~ź~Œ„ƒŐl Ů&Ń6kÜ $oąp”¸%0匆B101KŠŘ›jJœhĚE”ŰFčž=Œśü IDAT•…E]ňž-=ĺUůÔ1Z/zgŐkŒÎó}x×ÖSS™<0‰*YŠŽLG ^á\OlzpŞ…iíŠĐ´f‰zgî‘YÉČT\.?Şl'Ó!Aʎâ˝`ĂRXŒ ŠőˇTI: AŇÓÓ œ››Űnˇ“žžN,ăęŐŤDŁQ˘Ń(ńx íZ[”¸>bŞřůpxnň4[ĽŰrns0Ľěœ ŹĚ|ŽtšlIÇVjGž<ű§"ť d,KGgź;ޤ“gîŰĺĆ,"ˇÄŽî\PGú¸üť ë É.ĎĽ°<ĹëĆy¤›ĄVšÜ˜›ąśđő$bÄf˝w$Y ÂΚäŔh&!îôĽkž ^ăŞVo31ţV ˝Ś|+:%@ŕ6’>5};AőúäĎfYĎ2[ăą ƒ‘°†+˘(׊Y—FžŃ†ÉŹg˛&@~†%Ú?™€‚[!œUŕžEĂžFĚ ¤\XÉڜ0gŢ<Í)§Œ1ŕ֑óüŞš—Š!†zç]cgÓćŰuV5|žĐœŠâ‹CąŐŒI‚™mlŠČ.ŮNnڌdŤă‡˙šnAĹkÂ,19ŒőpŕőHzššTUWłuK-;żľí—ońţĐő.Šćő0~ÓŔBů+ÖđđĆJj XôŇľ‘ŁGŻK~Pǝ DWQQœ…ŽÍKuU6ąˆJuUňU?EEëŚ?’FEşˆŰG@]Y› ‚űŐa>T€azĆőüxĂ+ŽE“4UEENš˘Ş*Č23ťůg/Ń>>˜`Hґ–eĂQžC~c>EÖĂkçtŢ^–%Í&rÓŮFćÚŠWgăČ5Ą×ϞVPuÉĺšËO VŒ=߂ÔÁQjE‰j8J-HQ,yfpMXârsI†Œęl_Q-'&×`EŃTN]qăöC]ž‰*K&:IŚ+41}}ĹzU8ŤÁ"ÎŞ@pż"éIÓC<–<Doľ`Q˝Œ¸fFbZŔ3é_ž•3¤2[âÔž:v‰WŢ랷pęwQ?ţ…ôj |c#œá҈Â˙ňb+r984z]US7´M"cíN^z˘˜H×%>xk§?†˘Ž|ôPތ#OFM×ĺ`7šYVäćčg>6Ž(&G?FYŒ˙˛“IôÔę!MzČzť ť6I˙čŹgě›`( ąđâƅ̼fD ö`čÄ~ţćr>u5…T”°lů*V5Ž`ÓÉřف‘Ľ9Ź)p×ăŠ÷ÂţłŻ Kęo‹Äĺr‘M(ÂétN/ď•e™ÖÖVŞ’@b*‚úԛ$]Ť]Z śĽ";ďJ×ݏ/ččjąč°Śwyqšź¸Ťž. ťÖƐÓw{Ő9•E÷FękŠß•Ň7ÂŕAá ‚ŚT\FÝűŒ`"@`\#;ĎFšÁ€#?ÄŘçar–e`ŇűąĺJÄť|D—Zg vޤ­ˆa1éŃëdƢ ’ ż[%ŕŇ i„-qĆbA|‰¤gO¨Œ9Ä0\ ¸5˘—÷+šB<‘Ěz)J8BDJÇa™ľ\PoĆnşŠ–ŁŞ(€N'ĂôÂ4 łĹxƒ„$‡‰™}j’É‚#M#ĎsdR‘ĐP5ŕFƒEŐτ[EĘÓŁo‰Ů6n\ŞDŠĹzŇÉBĂębĚî6~ůŰSLç!A"łxf™d’ýƒ^ؘKyEÁ!Ÿóˇu9uePbQčpĄh:b Ч%_ő‰`ˆ”E†]b:óQš…ôĽ„ÄS˛w†˜×Ʌ'Z@2ä°űĹÇy¸q95pq~ÔůVco-‚7€;Y`V†`9ĂN†ŹáőNEŕľ Ÿ†œe'S†ńi{e23­Čłó*§˘÷nń…Řp‹~qˇ¸Cýíf¸\.֔–â÷ű ř“•§Ą1ér!M-ń˝kw­jh€4{ezˍ†\F‡‰YK_Í& zPąy[R‘M˘ŠÜäÝ%âӐ˛d”q?%> Ő"˘JŘL ÜŁŚÝšž"Č\žÎ;•}˝fÍóĺyĎ4N`$kě؊l!Łí!Lë H/ŤI%0\şmtżk%ę ‘ŰĄ˛ČA@‰q%4Şjř\ Ä$Fœ1ć‰érĆÜa†ťTúX—Z˛@p_!Ö÷-q|8Śt+f@í§ÍŸÉşćJňŒč­,ŰTOľaiÚŐ`ˆ€&“›—13+ŚK§Ž2ý/™źęRrŚ)‘Q]JĄ”``Đ5o–Š, …đúÁ”•ŽcÁ1[˜Ëm#ÄŹ•<ؔqý,žŢBŚíZaŮe™ç+’ÉXVF‰ŹârůRÜ7–źţÚ˛Ů9ƒ'C[óćՙĘŘŔ8!C.7Ąô 1ćĘp&+7—‹ŢĄĂăcδc”.ZÝ9lß]G‘IBJłłr×Zę Kś§b/ 3`ž—`U‹ůó&kj! ´XŒ¨&aľšnŕX$čëq“óh\™>ky˛eŤËI'@WŻ7ů,´ ÝW=hÖRÖTÍL&HćkćëOAď’ŃSšĺA^xv'7ظż/Ŕ†[ö‹ťE*ými¸\ddd`1‘ААyĄ˝¨wš`”˜&aɡÎô…Ź*ë 'ę,Ër0ëf>›ŞłąÉ ţ~˙źgœŠ, Ĺˆ‡4tfîć1<]>K6…+Ě×ۧ3`´ĚŹŚ0–da1͗’0Vdb•5"žÖGÄT-éŹß‰ĚÉs'ŚHł“ˇb~?ҏřI¤ŮČ]“Ž6ŕ!öáłŮ˜‰™ ëŽŕI¨OG9űîUMĂ3 1 dš,ÍyG†Ł z؍‹x‘@°DOî[TĆF\¨Ő”™zh‹Lpôƒ3Xv­á{?hDÓTźý# ‡mKŇŽyGčš\ÁśxJíŚÇŻ#§Şœ]xîţŔé 4bśjžy,3Ý>Ôô"WĺŔxÇçŸa‘Š,€ęâBť—mÍkx~œŽ ja:†ŚöjxΝེođ<ÁŸ–vĐÚë!˘ł›Ë˛ş"‚˙fęlI‰œUđĂçăôu Đ3â'¨čÉ(.Łą>“Ż‹[—ŕDh:ŽL°÷Ązž˙ŚĘgín˘Ć –7ÖQˆËqeÄɐZG]e˜SÇÇQPéěöđôž$÷ú} 1Ô?†˛˘„K;gBN>řÝQŹOoâĎţÓP&ťúé;Rľ6e{ĺô:~řĂĺÄŻ\Ľcȋ?Ž#ł|[—ëńžďŚ{˝źęä(˝>‰ć Í<źĚUM‹ŕěŔ35Ćô]lĺČúBvíÜËěm\Sp”ײmľ•@űaŽ \ŒŞŒ|~†ÖƇX˙Ô^8q…ް™ŞĆęäŘuѕĹë]*2Ye•ŹŠ•pN^`_Űő™oďş ˇě ˇgS–tîĺ< z$,ŮůTU$s'ü“ôťRMŞ“J[N‡#=Č ĎHš;h7WĹŤ–QŁŽâńKXŞó°é˘h7x÷)ö–=ŽÇŮBKĎ"M:Œő3Ü_ş,€d˛;B~c UŰaÜGÓâ{<ÓűBc—{¨\EůöŐŹ(tâ “ĐĽaʲá¨Ę qź…Žś¤nSm ľŤú&ńEH¨: yYd×ŘĐĆiť>ÚŻy|řˇŞŠâĐ( ŠŚĹ ˆĽÚ„ľ(ŢŤJš ŠzTĂŮB1XČhČĂLšłŤÚ¸ šOFIŒń34T|ýa*ś;Ŕ;Äź–„•đöé‰ä&0őSçŻęˆ+*éŐQÚߕɪTČŹPđcŒľëˆL|a›Č‚Ż<ÂYîcÂ}}tmŮÄú•t|î!>ŮËžßőóĄĹ„A‰ˆ‚ŮnBžyś‹…Q˝œ>Ԃ}GËW­˘4ěĽçR+ďFjůŢ 9G ˝'N0\źš [k°¨aĆz.đÁą+Œ^7 IE6)ßwřż7nĺá5ůöFIáÍ˙>ĚxüZÖÇűŽkŮąşš]ufҔ^ˇ›Ţs§i™Î Ť2púďÇŤ¨Ż,ecľ‹^#â÷0Đz‚O´Ń™Rv§kh8âWşÍ<ŇÔŔľ:â>g>áŽZţâŮšç[já1zÇUę2‡é˜rZÄN˝Œ¤óúO÷qüÚ˛Řř^ŮO`gÍ+›xÚ"őšéúěďéĹŁÍśĄ—×ţĺ{iÚŢLc<ŔŐó'řMxßß1ďćSĐ{׸ë6ÜŞ_HŘšůăG ć4 ű–‡ůŃ _Ëűüő{CŠݲčţś4 ŕÖČpxńŒ&_ŠąaՁaÔOčö–G\3‰Îˇx:cddJ8;tx†Á`×Qńˆz•O˙! SşŒ¤ÓžÔß{Ë‚ŻR]]&#’$M˙ťöy1˙ ‚{‹É˜‚´DćĘíźŘlŚăĂO9pő&Çž˘HälŘ˟íśrîőýźŃźÍĺŤÁ˝Á`ŕ˙üż˙^˙ýď9uęä—mŽŕ>Ľú ‰¨L߁Ľ­PîEţęĽo]÷ÝOţëżŢ•˛, şœœœŸ(Jr:N8ŤÁWŸ4}j &"㣌ŚłuërjŹ‘pŒhBE6XČË3ŁřŁ)žY*¸× 1h¨`Ϟ5Ô;4BĄ‘¸Šl´QTd%î sÓu‚ŻŞŞ˛ióf&']twwŮćîS‚Ăi”l"ë5‚Ăiˇž@ ř °uÊëžűäÄůťRVZZšX,Ü÷hQúNćĺáel]ˇŒo<˝ƒ|íWCěűő1.…ż\ˇ‰ŚóĐ>ţ[˙ Ţś‚ç°Óľgéĺ՟}ș×á _M4Mcrr’ĚĚEĘ$Üqb™Î×Ô<ă#˝"Nűo ‰@@ ÂY€‚§ż÷úŰŃĚ8lF R‚€7HP„Uż&$pužăŐÎsčŒV2&ŒRŸŰ_„U_CŽ^íÁbYh¨@đĹvéšúžœú(’Řj#¤ˆpVÁ”X÷¤Ľ~Q˘A&ĆSÎl"|Ľxß>ą]IpOH#0 – KAœł*ŕk‰Ś‰8–@ |•ÎŞ@ @ î9„ł*@ ‚{ągU ,]Ůz~üX}Ţäíž;wZ§Ž|#˙ÓŁĹô|đď^˝šŢTdw ‰ěć'řOťt|řoňá˜XZy#tĺÍüçď-gěÝ_óóÖČm$S‘Yöçůë,$w]j[?ŕ˙zgĺ6m”Ękh|"ßţ“tußš>$U,ŁńńlźűNŃ}‹÷C*˛@ ¸ÎŞ@ ¸I‚ŻĂV/šp=ůďגÝ•CŻńłŁ^n6Lţ*ԃä(fëÚţîđřW¸_ *ĘíŽÓ,HŹ„ásŃ/Ű @ |gU ¸Ż‘Č^ľ™'ęáüžƒ|<vč† Eŕ{먝ôg‡uVŞ7Źb{}Y& ˙HŸ>O‡ofQíöˇZęˇóŇgßŢϡṋp%c6M;WąĄ*ŤaŹż‡OuĐşŢÍLE$LV+b‚ńöüÉäm|ˆď6ÂÉWßŕÝî™e…=˝ƒô†ĺ?îhdMËZ”Z~ř—Ű0Ÿ=ˇźžz[˜ö?ă¸i-ßÜR€%8ĚÁ×>âӑŠ%ši™Źi^AcMĹY6ě&ˆx'éžx>ťĘŘ<ďW˛äłĺĄ&6/Ë#Ç*“‡qpîŘi>ę%풳y䏟bwŢĚşČě'^ŕoŸ˜ú  óúO÷qÜ?WoóÎ&škóČąHÄ|“t^8ĎűŸő21oőpZv%{n¤Š"sÂĎŐó­šAx}ązu5đ_žSE÷;űh/\ǎ†|˛ žNöż{ŠóîĽď[\T-Ąô™Ľlßž’ĆŞ\rŹ21ż‡Ž.>9r‰n˙”fÉʖžăéĘkĎCĄăěYMą=ÜUtF26•SҐÉŹcđă^&˝3VßhŤžĄĆ‡,Œ˝ŃBßĐźť4ÚČß]AAľ•4-N¨w”Áφđ-Ô7S‘•dt:âĄŰ\ ŕŢG8ŤÁýŒą˜-MYLśâđ,G5‰ĘdűUú6ŹĽ4Gćb˙ľŞD~Ófrƒă\:s-٘ŚËxlgç۝x–<‚ÔQąy3EŽÎżŠę(˘iŐJžÍĐńꛗI,UVŚl÷łüdx`œsGOđΊ™e˝’šœÝŰs?ú6űşçî“P™8ŰA׃ÍTĘ´ &u–VgŇ~ä ÁuëŮźg/ĺC:8NýŽľ<ź­œÓżë& HÖbś6—"uőŇŇáe2Ž’*šˇ>ÄKůGřéoŽŕžV d§ůŮ˝?z‚ž°‰ĘĆÍ< Ě}d)č˝öÜŞwnĂtö,Ż˝r rjx챕<÷d€Ą—/âZJŰYl-Á^}ţJ~řâ&ŞĽI.´śrl"Šlˢvĺj6•\Śűň”f-ĚĹűpš%äźžóHٍÍMĽ=ÜU$,ëë( úo郌lňWQľ+Jđa˘KśA&}kś‰ œGŕČ"oM9ľY2—ßO0ąTY ۖľ4m—‘5ŕgňĚUúĎů;ľŕë‹pV‚űsyŐşQśyQÉZŔ–ÖĐTfÇ÷Ó}a%ŚĂd”a:‘Œ-ŇË/÷u’ †ő2‘ö(ĎÔSeíâL`‰Ł\IÂčćŐ÷ÚŸŇŰÚÁ÷ˇÔŇ\ÝÍë‘ÔeľWŻpągœ‰@˝#•MľŹ{äQňÍűřűŠe˝ćšęuCźŃ2‰Čöv?ś™­5éă^ÚO]%Őa6ęŚ P™¸t–ZÇ1Š%lx2ŸŽ§9ÖŽ2^XDzŠlrĺnúUĐÝüŰĎÚđgEĎ^Ą;ö4?ÚŘ@Sv'‡&’u&™ Š/Óă?wŒW Í„ˇ ËŇŹdPqÜĂ#¸RFËIOďÂŮg+Ů^˝žĎ/Ž'Ÿ5­] (ĎđƒľM9ŹŔlźČĺS›&JÁWqÎŞ@pß"“W<>FÓŮ´ˇ™M^Nü”ßę$PVCuţu*#݃xŚG‡ ÎqŞdĆa•nĂ•ąî&ŚőjxzŃô””d͛Y[œŹ:zž_žň)ďżĚçş8qô?˙ůG|îŐS˛š‘5śd=—墢; ČY<říÝ<˜3ÉÇŻďçŸŢ¸ˆˇşŐ6 iÖíIÇ0ŽעڜP(f#ćk˛‰đÇD–učőŁĂ“(’ŹŒĽš'šsAĺśšŻgU]Ş٧ź*ƒ:FëEďŹ%Đ1:Ď÷áĹFMeFňdĽş2)8ŔšžŘ´ăŤ…iíšď§ wć.處°KĹĺňŁĘV2Kk;‹ŻłÔě•ĺŹ.Ńę¸Ŕńąyî§^x™ębHĄ=Ü]4]SŽ*€BČF“lˇcƒF°s‚°2ó9Ňĺ" ę°•Ú絇ĹÉjăCtžŐĹŕ™Q&:ĆkéĄăwŒűdŹĽdYnĂ\@ ÜӈȪ@pߢÇaO#ć Ň@.ŹdmN˜3ožć”SĆpëČy~Őźë4ÂáŘ,ÇECU’Q9ŽŰ@Ă盻żP ńĹĄŘjĆ$ÁLĐ6ŮyĽ„ů켛uŰ ¨)Ňńů=é"n teul.rěW‡ůdP†é×Sđă sô¨jr”ŻŠ***S“ßË23U‘FţŠ5<źą’šý,§W‹Ł×Ír ˘||x˜ĘÝkř“?ŻÇăg`d‚ŢÎ.Nw¸™[^<’‰t›˘~&çĽ3V=~<ŞD^ş‰IŹdŘ%Tݟš[HUÜî *ŇŇôNىĆć<ˇ¤Cymgąu–˘˝rڃLYcÂé&Ɲ$…öpWŃH„ć:áÉ~,!ßf?Žůćm)Gˆ%Ŕn5˘— Ś-Eva7Ύ098ňe&ęˁ@đľD8ŤÁýФ'MńXň¸˝Ő‚Eő2⚉9i7Î ¤ĎťTű2MĽČ›ĘŞüaT)łI’ƒbŃä’C˝Ý†]›¤Öšo‚Ą€FÖb˟ö>$2ÖîäĽ'Љt]⃡†qúc(čĘ×ńGĺ͉ÖB‚Ąűů›ËůÔŐRQZŔ˛ĺŤXŐ¸‚M'?ŕgF–ć°ŚŔ]˛wź€ťWgwŢmLľ=ÜenăYHK2TKĄĚ[ÉjÄ1Ŕ„~Î6@ |ÎŞ@pż˘)Ä Óë%!"Ľă°Hpmď ŢŒÝ´DýŞŠčtł’f‹ńN€„ĂaAbćˆÉdÁ‘Ś„ç9ŠČÎG&#ӆŹĹń ÉÄ OKžÁ!)‹ ťÄtŚ›4 éć”k$ Ť‹1ťŰřĺoOŃ;í˙Jdën¸#ćurĄĹɅ 9ě~ńqn\NÍÇ#\œŸ-ö–cúŢ@JěÉ咳2Ëv2d Żw*J­ńř4ä,;™2ŒOŰ+“™iEž}Ňl*zżnYg)ÚŤz|LŞyůđqGLYb{ Uƒ/֓BŐĐiNÄWBošŃđAÂč0"1+Q™Ů„AJ 6o?o*˛ ”“nLžÇB⏠@ řş"öŹ ÷-q|8Śt+f@í§ÍŸÉşćJňŒč­,ŰTOľaiÚŐ`ˆ€&“›—13+ŚK§Ž2ý/™źęRrŚ)‘Q]JĄ”``Đ5oŕşY=šLóĆ÷şĚvŽv …iRosŚ+  tŃęÎaűî:ŠLRš•ťÖRoXŠŁ O/ëœă´ňŘҘw}=č ˜Óć~ĽĹ|ŒyŐŠťź-#ŞIX­ŚL$čëq“óh\™>ky˛eŤËI'@WŻ79 éžęAł–˛ŚĘ0­O2—ĐX3_ z—ŒžĘ-ňÂł;yźÁžđý-şÎRłWóöqaPÁRˇŠÍyóÖĹĘ&ěK™źHľ=LßPŻLYé,qkďŇ F‰i–|ëŒ}: YUÖN:Y–ĺ`ÖÍ|6Ugc“üýţyía1˛2†,óWGKéy.7#E´˜0(QQ0ŰMȑ%œd¨z9}¨űŽ–ŻZEiŘKĎĽVލÔň˝rüzOœ`¸x5śÖ`QÌő\ŕƒcW˝ÎçY„Źc°˝‡ž5ůT,Ďe…QF‹†ęŕÝc­˝œŽň„;;iŰó Ű×gsţSńń+üćťxËfƨDđ…Á’nAÇ!Ľä3Îă‡ř•n345đD­Ž¸ĎEǙOř…Ť–żxvîyœZp”–‹y4VÔđ`˝sšFŘă˘ëČ!>8ÚOhĄ"#xă$ŚÝ lŢű;ő2’:Ěë?ÝÇńkK]ăcxe?M4Żlâi‹DÔçŚëłCź¤wÎٸZ°—×ţĺ{iÚŢLc<ŔŐó'řMxßß1ďćSĐ{ˇHŠÎR´7áźČ?˙ÜËöíŤh\ÝČJ‹L4ŕc°ë"Ÿ Î,mˇ74óǏĚiö-óŁ-ž–÷ůë÷†PRl3(ô>Äď[yxÍFž˝QFRGxóż3żË•Ź9؅agYkʰ‡Cx/ôĐ)bŃ 9×*ŢŁW””S¸­˝'ÔÝËŐφ^׏!Ť)„şÇ ,w`ݞ“iĐbq"N'ý-8ݟDÁ×ŠŽŽN‹F“Ó’’$M˙ťöy1˙ ‚{‹É˜‚´DćĘíźŘlŚăĂO9p5|Ÿü$r6ěĺĎv[9÷ú~ŢčŠt-@ óřŤ—žuÝw?ůŻ˙zWʲX,črrr~˘(É)LᏠ_}ŇôŠ-˜ˆŒ2šVĚÖ­ËŠąjDÂ1˘ Ů`!/όâŢ"ŃÉ׃ĐČƒ† öěYC˝C#ЉŤČFEEVâŢ0wyĹĽ@ Á=ÍÖ +Žűî“çďJYiiib°@pߣEé;q˜—‡—ąuÝ2žńôZ ňľ_ ąď×ǸţrMüBĐÂtÚÇë_ÁĂŰVđü6cşV‘^^ýهœYpŽ@ ŕn œU@(xúŰyŻżÁŒĂfÄ %xƒę4 \çxľó:Ł•L‡ ŁÇçöăaU@ ‚/Ꮰ‚9(ą0îÉű!”zs”h‰ńŕ—m†@ Á}‹8gU @ ÷ÂY@ Á=‡pV@ @pĎ!ŽŽžf¤ztM*čĘÖó§ßŮLÁdî;w"ŤŽ|#˙ów6’ëşÂĎÍőŚ"{ˇĐ×îŕ'?~Âą‹\˜¸s6¤˘÷nŮ ř2Čn~’˙ăű ĐŢAŘ*}CtĺÍüoö0uţvZGo'ű›Ě˛o|‡˙ő;›ŘłŁ‰=;ŮęçČßmŸ5-•×ĐôbV×0“wđ=)U,Łé…Z,øoĄ7ŮťĹݲáŤVÁ× qt@ řґ$ĐÄßőűsa<ŘŔŠŇ ěz…€ËɅS-h`vę-CanŠ˘˘ “œtiZßř([ÎňáŮqBˇhC_…v&9ŠŮş6Đ• œš-çHpoĄ2tň#ţé˛äv?ˇ–ü/Ű$ÁW ]^>%› É,4“ŚW‰ťý¸Ď÷3t)0çlr97ŸŇu9Řr-˜ěiȚBl҇űÂ×$îńw @đe#œU@čČŹXĆćUĺTĺ۰č!ęsqĺü_t!rß?čň×đĂ?\OYlŒÓ'N2ғWWOóăQlz—8>‰2%k,,Ł!Gbp —žËQ˘’‘‚ŞJś<ţ j˛ßçď>%2Gťžœş<´Ą†ĺ%éŘŇ âvrţäiöă^<ĆVN/aێ&ü—iMÜvÔMp{(}'ů›ż>ŞrŰĎ"41Jç 3°YC8Ť‚E#ĺ”P÷t9ք‰Ö^‚SUy;Wb1ž§ýLhş}ęň˛ČČ„ŕˆ WEŇc.Í!×*™—¸|Ô7ýN×#œUŕ~G2Qľe;OŽ42ÖŃĹá‹nźQ™ŒŇjśly€o™óëӓˆcFďŇXŢźŠr˝—O_ŮĎťSń–ŤŒ˙ť§ůƒmkYyö#ÎMÍ^řĎä˙=3OĹÇyŕĹgx|ĂjVĺók¨dfůž˝ź°ŢĚđůKě;=ÁdTGvU=ďy”bË>ţîđ¸hg‚[ ˘ˆ‘˝ŕKEGFc6}˜‘ˇ/10˘&żž8AäÉFĘו’ŮÖÁäÔL]üŇeÎ]š§BŚŕ)[ULćbFX ¸!ÂYîk$˛Wmć‰z8żď D§gƒ† Eŕ{먝ôg‡˝tVŞ7Źb{}Y& ˙HŸ>O‡O)[Ϗ+ŁďŔ›źÝ3ó˝Ľ~;/íppöíýV™dĚŚiç*6Te`Ő"Œő÷đéąúXOş(Ů´LÖ4Ż ąŚ€â,vDź“t_źŔŸ]eěv=#S.[ŸÚȎĺŮŘ´Ýíě?xžîŔŒ şšř/ߊ˘ë÷˙Âż^že[÷ňż?žÁ‰—Ë[}jĘzS’]l=ČJ h.ÍZČŚů9ß6ƓUĹ4”é9×q“ĺ°j—OR é‰äZ`™źńÝF8ůęźŰžng=˝ƒô†ĺ?îhdMËZ”Z~ř—Ű0Ÿ=ˇźžz[˜ö?ă¸i-ßÜR€%8ĚÁ×>âӑDj÷6…dÉgËCMl^–GŽU&ăáÜąÓ|Ô= ‘ły䏟bwŢLÂě'^ŕoŸ˜ú  óúO÷qÜ?WoóÎ&škóČąHÄ|“t^8ĎűŸő21ŻşŇ˛+Ůóp#Mé˜~ŽžoĺČ Ť‹Ő{­użłöÂuěhČ'ۨŕčd˙ť§8ďV.`,ŞÎ–PúĚRśo_IcU.9V™˜ßĂ@WŸšDˇJłdeË ĎńtĺľçĄĐńÎŻůykäúčęÝîóŠ 3’ąŠœ’† LfŘđƒ÷2靱Z*ŻĄń‰\|űOŇŐ=óŒô 4>daěú†ćÝĽŃFţî Ş­¤iqB˝Ł ~6„oĄu÷‹‘MłŐXHvy:ÖtiFPü!|W†lqšÝ:[„ _ŠzMXsőhĄ źÎYýJ‹2Ůĺ§ź4ƒĚ"™Éž›ô95N4 BĄƒY‚°Xł!ÜᏠ÷3Ćbś4e1ŮzˆĂłŐ$*“íWé۰–Ň™‹ý×ţđJä7m&78ÎĽ3Ń2ŠiZąŒÇvqžÝÉŇsé¨Řź™"×gŽ_EuŃ´j%ĎfčxőÍKŒ$R—•ŹĹlm.Eę꼼ĂËd%U4o}ˆ—ňđÓß\aé97tÔîÚE…ł›Ł;P3Ëزq=˙>GĎß˙s KŢޘŠŢĹÉ.ždt2 (×-KK$ŇČËľ!wx˜= әŹ8L2:ƒ…Âe+yŹŢˆćëŚwŞ1HćrvoĎeüčŰě›ĺ¨H¨Lœí ëÁfŞ eZ“v”VgŇ~ä ÁuëŮźg/ĺC:8NýŽľ<ź­œÓżë&œŇ˝’ćg÷ňTIˆK§Z82CgłSXZΊ Ÿt‡’÷­ú8őö~ş çÖóüŢ źÇń^W,ŠG‹2>{ň&-=ß}”]ya:??ĂŃ1{y-Űśď˘2ç0?}­ ď´ßUÉ7_ÜIcš‹Ďž /l˘˛q3Ď;dds+=˝×ÚCőÎm˜ÎžĺľWNAN =ś’çž 0ôňE\Ki닭ł%ŘŤĎ_É_ÜDľ4ɅÖVŽMD‘mYÔŽ\ÍŚ’Ët_›ÜŃÂ\<°§YBÎkŕ;”ÝŘÜťÚçSA²žŽ˛ ń–>ČČ&UUť˘ß&şddҡÖa›˜ŔyÔ Ž,ň֔S›%sů÷ýK5gß˜…Ôçb˘'L4 iů9ä­[N}N'mď}Aö~UęAB’Eež;Ş%T4I‡)ˈÔ3ď]g4`0ĘHi,E”ÔčŃ~>ᨠ7C8ŤÁ}ŒšźŒjÝ(Űź(€d-`Ëkh*łcŒűéž0ˆÓa2Ę0ýgYĆéĺ—ű:Ikz™H{”gj‹Š˛vqfĄčßb$ n^}Żń)˝=Ą|K-ÍŐÝźŢIYV tóo?kĂœ5¤8{…îŘÓühcMٝZr&]َřu+# @'—ň{V˛{Eż<^➺Tô.NvŃő ÷¨HŮŮ$z§QzĘʲ‘‘°ZMĚÍ/S´ő1ţtkzň,4M%8ÚɛgjhŽŠĄ^7Ä-Éýޞ˝„ݏmfkM:Ƹ—öSWIDu˜ş)*—ÎňQë8&ľ„ OćÓuâ4ÇÚUĆ ëXV‘MŽÜMżšÚ3–Ě…Ô—éńŸ;Ć+‡†f%AiA–ĽYĎ8îá܀N)#ŽFČ大wHŕXŮČöčýđ}~q<ٗhíb@y†Źm⁒ŢP“uľĄ‰ľö0§_ÝĎď;chŔŠK“<÷ŁÝŹ[˛Ţ¤łźňqOr˙福÷ŠĘyiC9Ëí—8ş„Ańâë,E{%;›÷ާFçdß?żĎ'c3š;‡Ă4[łŠĎ9ŠĐiÜĚżšť}>$ ‘1.ž3LD#lh˘ś6‹ ë0ÎŔ­Žż‘Z ”öw)I˝žĐ Vn+˘xŮW.ÇS— MĐýňąŮŃ˝6'ţÄZ–Ż.$;sœáÉĽż×mďÝŇ{§ëAńiH%6ŹL?KÖ"+ ˇ¤Áœl–u+iXgžzj$ĆÇčű¨ŸČŰ&ÜqÎŞ@pß"“W<>FÓŮ´ˇ™M^Nü”ßę$PVCuţu*#݃xŚÇ‚ ÎqŞdĆa˝ăŹTĆş˜˜ÖŤáédDÓSR’5ofm‘˛‰đœAŤ,ëĐë5F‡'Q$Yˇgďp[NećłëňUÔ4*Ťňnc&0˝‹”]t=„i;ŰG@WČXUč ##‹şÍ;xŚŢ@L˝^Ç\T&Îĺĺß~Čżž}’Ďş&ńřCcڔc'S\–‹~dˆî0 gńŕˇwó`Î$żžŸză"ŢęVŰ$fŸ† $ĂX8J\‹˜˛?ŠŮˆůšl ĎXSâD`.(˘Ü6÷ϟŞ.ՁŃS^•AŁő˘wVD:Fçů>źŘ¨ŠĚHţą•ŹTWŚ#8×›v|ľđ ­]óáôÎÜÝ#ł†Č*.—Uś’éXZ[_|ĽfŻä(gu‰ŽPÇŽÍ­Ťá…—r.†ťÚçSA#Đ51ĺ¨(„œa4وÁv;6h;'+3Ÿ#].Ş[Š}^{X¤l"6ÇA“dIagM2b´ß†š)Ů{ˇôŢézˆăns—Ó)Ú]Ffž ƒĂBză2*Şu¨š„Ź›g‘önşŢk§ëP/ÎŢ ą@ŒDLDU‚[!"ŤÁ}‹‡=˜/@Hš°’ľ9aÎźyšSNcŔ­#çůUóŽÓ‡cłÖŞ’Œéćű1)ĄáóÍÝ˙Ś…ƒřâPl5c’`&hťXŮ4ňWŹáፕÔ8°čg9DZ˝îöœU'8'˛¤ý¸ăPaˇb‘˜ˇDónč]Źěâë!ŘvŒ—3ő<˙@#ßű(ÁQŽźHéădÄŻ„LJš4žüůÜšnŸ}š÷‚ĺŸ>ĺR(Œtˇ€ş˛:69öŤĂ|2¨ĂôŒë)řń†šľ &ďJSUTTŚ>&ż—efšZ Ď8:ŔLJ‡ŠÜ˝†?ůóz<ÎqF&číěât‡{^ćâE"™Hˇé!ęgr^:cŐăÇŁJäĽ[˜ÉJ†]Bőú™ť…TĹí˘ÎŽY§˘wH46§_$ĘŰ蛋­łí•3dĘN7ą%šś0włĎ§‚F"4ˇŻ$ߓňmž'cžy[6Âb °[č%ˆiŠĘę0זPź:GŽ ˝~v)Č: –œ{9{ď–Ţ;_‰Ž:ë¨ŢPʲçJ“Ľ„}ŒÁşłcüúýŞĘ¤÷Twźxk§?†˘Ž|ôPޜHޝľUťĺůĄK*zzŻ—Mľ˘ô=ČߞśQoÇL„ą7Ą˘Íü•Ź]ç__nˆ‹—†yśžŠÍľ§h;§Ă ‡X4šÔNoˇa×&éŐÎ| 4˛[Ó§zo †Něço.çSWSHEi˖ŻbUă 6ü€ŸYšĂšw˝çÜńî^Ýůî÷%öů…¸g!-ÉP-…2gd őľÔďĘ@éađ ‡pPAÓ@*.ŁnËm…Um͸wë!A ĺ2ç/1g›Đ'<"‘WÉjbţů9 ćĂ}ŋZ“Cne/î6‘] ¸˙?{oÇu%č~™ľď؈}_ €Ŕ}Eq%YRK–méْ-MżnŰÓí鞈ž7ń&Ćż:^OźˆŽq;ŚßŒťŰ[ť%Ëś$K)J˘%Šâ&Š„¸Ř b+€jß3óý@€Ź*’)ä ŤęäÍsĎÍ{óž{î˘:Ť**ËE"žVƒHáÁÝ,ŔőľmZ6c†éË2 Ń$Żw0™ KtRěv3ţٗź`4c×)Äáâd3MkJ0MľółW?Ą_šť6ťDsÖ@ˆdgYńÎĺÎl#[§őçŚbJŒŽ+!`ą.\ű™fşŠĘfh9`dđúb,‘˛şR˛đsa$tË~ FŁEDÄd҃#–­núu“† 9dŮfwşŃ™q˜n‘čbd˜ˇ˜×ĹĹł..žAŸÇŢçżÂž–•Ô~ŕäŇÂ>ă­ú˝Jo Ľ6rĚ@ŇÁb–,QÁ띱™ÄăSsld‹0>ŤŻHvś1ů¤ŮtŇý¸ĽÍŇÔWöř˜”ň ˛Đă#z'”̸Î+Č |žžě ňôtya^ÄW@k^Ş{&`°HZťn2˘×‚ˆ-Xϛ‚Ź '{eŻ“Žƒý’vV3ˆw`@!E}ďS;(ą(!çő§WŔR™…ž“Ž[Ď4ZŁÔCťTT–D]łŞ˘˛l‰ă Ä1:,˜it€v6ëˇV‘o@kĄns#5úĚR—ƒ!ŠČŠüŹšQ1ƒ†*Ç H~Mył? dՔQ$$r/č|¤"+ÎNů›×Ą×çł­%˙Ž8ŤEMŐhć>ç6UQ&Ćéë›ŐWńđ)"E%šIvČfÍƜ%íJşŠËŚk‡§ŒŠVó•őäŃnÎÍ7¤cEq6ć… hsزž-Q\ă!bxźqLŮ6,€4ŘCŰT;÷6Plt6VíYGŁ>“nqšyÓč1éćĽÄ|Œy§ó´˜J,FTYlcŠë$¸Öç"&ćӲʑ4=YOݚ čéŸLP‚ô^ő XĘX[­ŸMO0•ŇRť0ý4ŇÍ-UŰä[_ÝÍWšl‹ç/e›Ľ§Żâ˝ĆĹ! sĂjśä/xŕD#śL/2­óJŻŒ92\ڛ9Á(1EŔ\`™ÓOc&§Ú˛ä žš.“fîłą&Ť(áđ/xR‘8ˆ3člä7/ńL¤EŠúŢwv<śš%”Ż2ٌáťţj0˜ŃŢĐNZČ_•…¨Ä ťďěDx•/jdUEeŮ"3ćt#×RněŁ=2ÁńĂç0ďYË /ś (2Ţ'#akFŠ+^'=“ÍěhŢȓr/}~ yŐ”jÂó×ćÍ^ łÖđôŁ:ÎőúĹ´ŹÎƒńvNöFӗUtvMpŕĄFž}FćăŽ)˘†,Vś4P„ sFůšC&ęhâ;Ď8Ţ>…œSÎśM…ŕ<Ǒ+s›ĺȓƒ´­gßúxAžB‡GCac•š ʢݰÔŇMY6];h yü˙ÜLŽs”Q_­Ł€ćĆ"˛ĺ1Ţ;xç\—ćGžbżÍMĎ57ăž0q˝•ňşJjłľ{OóáĚvŔĂcHͥԚ;8rqř7Çą<ľ™üÍ6%&{ŰÓ/‚4ó&:x饕ĻŽŇ9ěĹא]QÇö•Zźzé]$¸!OŽŇďŘşq+Żp՟@Q"¸ú'đĚD_|—Ú8śĄˆ=ť𢭝‹cöŠzvŹąč8ĘąÁëaç§çhkyˆ O€S]ô‡MTˇ4Ń Ćnˆ’Śžnڈä”Wąś^Ŕ5y‘ƒíţtHÇfiéŤř9ůΧ4>ż™GżýĽçz虈"ZłŠmŽF:ö*˙6stÖ–Kyî´s/ć›Ń"`Î- şrş“ŸđO2஢dZçe7;źěŘş–g÷ّ˛f°s˜ńťđRy*˛ Ž“Gřšf ˇ6ńx˝†¸ĎMçšůw=ýŐĽĎjL ‰Ž#d r#ťnÄ*‡î8Ăoß˝ČP˛šäI>|ăcľ°vÓŞ‚St~z‚—CŤůÁcY™§›˛lšvýôőŠh¨ŚÚއhg÷g:zžóÉ=w%D÷™ ä7SQ^AUŁqüî1ΚđO™œéƒ…ťťiß˙ ;7ärá#7ńń.~ýż{ř˝Ő„AŠŕ ƒŮaF Ç!­ÍgҲĺěĽ|Z*ky°Ń„I§ö¸é9v„ĂÇ-v‹„“w_?qo[<Än­ˆ đڏrňúT×řďţęÝ­l]ŐĘSf¨oŠžđÎąţyg+Á~~÷Ë ěoĄuçVZâŽ^8ĹŻĂÍ|ģׂ‘îÝ"-›ĽŠoÂu‰Ÿţł—;WӞڅUf‘hŔÇPĎ%>š[:`kÚƟ=\8ďѰmŰÇwˇ(řΞĂßž=Œ”q—¸vôż5lgßÚM|}“ˆ ;yăFße#ËAœďő ß]NÎÚrláދ}ôEŠi~p1çZĆ{ź‹@iE; Ń*qB˝ý\ýx˜ŕ íd*˛ áśşĹ*JWQ^)"‚x/wÓ5•ĎŞGR^IžTSÓ÷~łƒĹ?ĹZ•‡ÍށXŒp˙CŸ ážL”‰áť8ŒąÎľ8[­Q‘ˆ{üŒaäüQŐWUQš)BCCƒNG"A˜ýťţ9•UTTîĚFCŇŮŤvňüVďÄťW3=TEĺfäm<ŔöZ8˙Ú!^ďźĹ&M*******÷$˙é{_ťáťţýżŢ•{™Íf4yyy?”¤éQ ŐYUQš˙Ńiӛ0eTWÂöí+Šľ(DÂ1˘ Qo&?߄䏢žYŽrť„œĂ é+Ůż-v…P(B$.#Ź[ˆ{Ăę#******÷8Ű76ßđ݇§.ܕ{ét:u°ŠĘ˛G‰ríÔQ~1RÇöőu<öÔ:ôâőŸ†9řň .ŤgŔŠÜ.J˜î#ůÍěŰŃĚł/nÁxý9‹ôóʏßçܢópUTTTTTT–+ŞłŞ˘˘Hx:x{ Ţ„Ýj@/$xƒżěaUą€ÝĎŹŁ*…ľ’˛§—ˇŢéÁ­Î•ΐîîóźŇ}ÁBśÝˆAˆă›ňăWĂŞ**÷.˘˘ĽŘRh'ß8UŰI•;€ęŹŞ¨¨ĚCŠ…™š\FĄTŮĹŻćƒ/Ze† 21ü˘ŐPQQIهó`;Î/Z•e‡zÎŞŠŠŠŠŠŠŠŠŠŠŠŠĘ=‡ęŹŞ¨¨¨¨¨¨¨¨¨¨¨¨Üs¨ÎŞŠŠŠŠŠŠŠŠŠŠŠŠĘ=‡ztŠĘ—ŒtŽIMůţâš-NvŇ9uçvĎĐTlâ/ŸŰÄ w]ž›§›ŽěÝBSű˙íßďŚtü"&îœÚú]üđűR4v‰‹ˇH7Y•;‹@îÖ'řoßi‚ŽNúÔĽÇK˘ŠŘĘůÁ>ü´ŢÎnu"u=Ç~n3űwľ˛W ŰíăëňÝłgc •u´~ŤóÄSˇx_¤#{żĄÚAĺˆztŠŠĘŽ €˘ž'UTćq?Ô Á^Âöuů„ş.r#•{ ™áÓä'W4 ˛÷ë(¸É &ŠžiĄ,w‚îŸt1%%ý”[FółĺşŻpîÝÉ{Ö)ž#¨v˜FГ˙'¨, F)‰qOoç0#ç=DĽ›\Ż˘rPU@Cve[VWP]`ĹŹ…¨ĎMׅ‹˝äfí Ź˘’„–źŞŠJ– IDAT†fÚXËĘRVDŚ\\8}†ƒgƸ…ĽěŘŐĄ˙ mى/wÇú>@şvšżűŰO@–nť,BŁtO=[îŒłŞ˘˛r÷iÁz–ęämo‘ßMűáqbjâň9˘:Ť**ËÁHőś<ąĘŔXgG/Mፊd•Ő°mŰ|Ít”—ĎL˘ƒŠ˛ŹLŹÜ€om01rá2ĎL0Ր[ÝČžýPb>Č˙<:ŽÖ •[ #Š‘(•ű %Š÷Ň‘™Ďg]u-Ľ5ĽäçM04ŽzŤ*ŸŞłŞ˘˛ŹČ]˝…ÇáÂÁ÷ř`0:;ú?8âb8ň/lh˘áňÇ\J#i,Ôl\ÍÎĆ|rŒ ~ç5>:zNŸ<'Ržď?ZÎľwßŕÍžšď͍;ůŢ.;Ÿ˝yˆ##2Ɇ\ZwŻfcu%ÂŘ@čd tă‹1%Y]6kˇ6ÓR[HIŽ›"ŢIz/]äđÇWť]OCcĽńÁMh)&ß$ăěćĐ>áÂT’jŕż>WMĎoÉż^™ëľZZđ%‹Sżx•ß_›oŒ+Řţä&v­ĚĹŞ„éîŕĐ{č ,ŇAHEönÚAČbϟ>Í>ÎńŻ{X˝{­UYŘ4ţńŤźýęqÎűftŃÚXšĽ•ÝkJ)ÉŇ#D őtđî‘KsúęĘřÚ_î§Ĺuœ˙çWřćŮť€Çż˙śůOó˙ţün%űŚ˘"ů›â›-pú•×ůCoxś^ôőŃz„˙°Ť…ľgßĺŹTĎK˙qŚĎ.ŕ­h¤ŃŚăƒ9i\Ç3Ű 1Gxďwä#g"ٞĚl{¨•-uůäYDá0ScNΟ8Ă{CÓz‰š<ügO˛7nĎÄÜÇżĹ|ćƒ4Âk?:ČI˙ütˇînek}>yf˜o’î‹xçă~&ĚÖĺVą_ ­•L ?W/´ql‰éŠŚ{˝Üzß:HGŃzv5k­C钒Í2°€6ťŒ;WŃR˝‚<‹HĚďa°§‡]Ś×?“˛`aۡžÁSU×ËC˘ó­—ůçśČŃŐťÝFÝa„ŠZZ_ďĐizzçĘHŰÔDËCfĆ^?Ëľáš4X)Ř[Ia'Ô?ĘĐÇĂři×S’Ő™Éi)"ˇÂĹĄGgÉÂ×5ĚĐY7‘ĎÁfËÎRď`”’#ŚlƓF`4F˛ZĘ(Z™…ŮŽEˆE öť>12§Ż.›ŞɝčĺÂď]ĒÓÖŘ(˙ćj ‚ý\xm„¨’}SŃAĺžEuVUT–3†śľć0Ův„ŁIŽę42“Wšśqey"—Žż0 Zˇ°"8Îĺs—P˛JhmŽăŃÝA\ov“ůžG*ˇlĄŘ=Čš“W‘íĹ´Ž^ĹWł4źňĆeœ‰ôeK ۡ–!ôôsśÓËděĽŐlÝţß+8Ə~ÝEć{Xˆ”ěŘC‘ßɧŸÜJśoXĹ7ž0ü‹iG*S;ÔďŮCĽŤ—ăďu"g—łmÓţ]ž–üéYéËŢ];ĚÜĂPĘĎ­DîžÄĄ×§iŹT6a3ĚˆYlýÚcüIľL˙gí<{!­7ň§Ĺţé_NŃâNÎw…Ř°ŚŠ&['§üsŠiJŞhΒ8ÝĎd&úڍƒ`Ş`ďÎŒ“ƒIŽ*€€ĚÄgô<¸•ę"‘łC"e5Ůt;Gpýśě?@Ĺp'Gާq×:öí¨ŕĚoz “fY6ś~őO–†¸üÉYŽÇĐXm•UĐ\iĺĂŢ€ěă“7ŃŁqE#ϨÄ{ňo÷Ět •(ăɃMş|öóöä‡éţôÇÇ$lőěŘš‡ŞźŁüčw=xgýŽ*žy~7-:7Ÿ?Ĺľ°‘Ş–-ĐË+oˇ3>“n_hßŮVĎ֚^^댤-Ťzůˇˇă &Ei>ë˘7ößÝÔDkn7G2ŢIWÄîâď_žÄ„ Đͨáëź¸Ş‚•śË÷ežŽÁŰÎ˙zš §4î•Ŕ#üőţUěmnçg瓝§ÔdďŽf4ÉÎEyď÷üÓ)ĎŹ3ĐŮŃ9ó?Çş-Q@ĎŠ3œč/j Ž2—b/rze!˜Šh,×â?‚_fŽ?{Q˜K!ÎԈ“)@#•G!ävŃ׿H$°Żjag!ôż˙˙rrşîÓÖĂ ô4/ŽkĺŇ>Ţ”‘â­Źł…9óĘ!~ŰC>š<É7žť—ő§›T*ƒŸńŤúŚ×˙ŽNńvqßۘyJÝfię+ŘŘr`ľúŽÍĽ|âÄyěĆä”e|ŽQ|€FŠäfŰ\}u3%´9T~3gџnkł  ńŇńÖ ! ` O¨™U;Š)ŠsŇu%žžlh‚Ţ_8‰…“ěŇîŸXÇĘ5Eäf3’ŃhŞfŃŮ ô€VŠ˘˜˛:Šw÷đÜłŞoŹ˘ŹČřťÝě ČŠŇ3v16{km.zɇł7š‘ŚŠë rż˘žłŞ˘˛lÉ/ĚEc ˆ6ŘĘć,/§ßűˆWt(ŻĽÁ˛đ:gďžŮ÷•„k܇,˜°[ngüYfŹwpĆńPđô áT´”–ć,YKQ6ž× E Z­ÂčČ$’`%'ëöôlżŠ{6ů#ĂSȢ…lűíĽ;ŇއKšűěžr•AYGUuţ vHIöŽÚa%6ÄÉ6Ď:MEčƒ×8ÝFÔjĐÎü)ŽAşý"Ľ\Â&ú¸čŐPŐTăşjš|Ö4XIô÷r9ف€Tu))_Ö9Losxđë{y0o’^;ÄO^ż„ˇŚ‰5VäÓۂiÇ0ŽW˘fě ĹŔdŔt]6˛P¤8Ń˜ ‹Š°Î]ËrŚP-Őčĺ1Ú.y“Ę+F÷…kxąR[•5Ý9,ÔT9‚ƒœď‹Í:žJxˆśž…ŽpéÎĺ‚Á^gŇn2nˇ˙śęPę6KO_Á^ÁšR ĄÎ‹œ[ŕ~Ęá̧~u3%$ÎĂôJú;6q"s Áî ÂŇÜçH›€ŹÁZf[đ<¤(›ˆÍsĐQDĐ@ŘB lˇĄŽj‡i4ʞÝŔÚoo`í7×PżĹF˘ű]oôă›őŤődŐ9Є&ď#hDę?ÜSř‚–RłCzÎ &ý´s:ŰŽŰČŠÖŁ O0¸Q[“ž*÷'jdUEe٢ĹnÓó) Uą./Ěš7Îđ‰KĆœŇ÷ěę×)„Ăą¤ŽŞ‚,MGa4ˇőFPđůćŻ'SÂA|q(ą˜0 0´MUVGAóZömŞ˘śĐŽY›ä`(q´šŰs*ƒÁČ<;$$ĺśí ăńçE€” ŸŠ8TÚ,˜’Ś&Ś*{7í0“Œ×ĂřRk¤D+˛Ek/ý_ ‹ŠH^#&" qኟíŤhś_á¸WA[^Eł=Aď‡řMᤏƒŽ,‡žČ”€šňś9ńóŁ|8$#ôk)üţĆy×Ęňt)(˛ŒŒĚĚÇéďE1Šł”FYDůŕčU{×ňçՈÇ5Πs‚ţîÎtN‘QŹ@0â°j!ęgrÁvƲǏGČw˜˜ÁB–M@öú™ż„Tfj*ˆœ<92tgQˆDcóęń´Cyu(U›ĽŠŻ˜m'[T˜pMqggŢýş™r”@Ż{Á‘-fŠ•Űí(*Ä| –˜„#Ä`łĐ $í,›ŞŹS})%krąŻ0˘Ő&ŰHBԐéŢËŞŚ‘¸ŢÝÁŠőŒ2ńä(ŽhŔhŔR@ýŸ/ž7ľâץ@RÉĎdo”‚5šd[¸ü ĺ’m•ńÎpÇtuPš/QU•加E§…xlúx ­ĹŒYöâtĎ˝Ľ•ŔŽ 8\Ş|‡MŚsK@ kÝnž÷x ‘žËţý. IMĹzţôĄüy‘ąŒTş 3dtkEIýžł˛wߊ$‘¸…nňŘe~ővď‚u‹3żEýř“œđÁöŤ¸7ŻbÍJ+'N‡¨jŹŔáPw8ĽGaŠ,ÝR´čľ‹Nw´6+6e’Ń¤zá›`8 °řdÁŔšŽMşe‘`řÔ!ţîJ ľET–Rˇr5Ť[šŮ|ú0?~י™Ăšw˝ŚßńÜ=›Ýyˇń󩛟BFŠ*i”˙œŹžąžĆ=YHל ˝ç!”PJĘiŘv;áÄŰçKc%N𚛩€›Š h~˛‚ę>ÚO携ô~°řq6J,:Ď vO][LNľ×ůÖÚ\tq/îţÔ\ե웺*÷#ŞłŞ˘˛\Q$â Đh5€ŽŘÍĚîŢjÂfĚ0}YF4šäőŽ&ła‰NŸ€ÝnFŔ?űŢŒfě:…x ꠃ™‚Ź`ŚiM ŚŠv~öę'ôKs×f—h>ż5’„„0c‡ëJXŹĆ%ě ’eAÄ;g5łlBÔ\pćm ˛÷‚d?S2Bž†ˆsŒk7[Ä7ƒäźĘy÷jlŹ §mŠ5 f˘}}t,<Ü4UűŚŹƒ‘X´şé×c""$äe˜ÝéFgĆaJ5óIdX1Ż‹‹g]\< ‚>˝Ď…}-+ŠýŔÉĽ…}ź[ő{•Ţ@Jmä˜!9L-fŮȟޙY JOAĚą1P‘ěl bňIłé¤ű9pK›ĽŠŻěń1) ädĄÇGfŤëqÝTřBç6UQ&ĆéëťÁˇ–˝ěćJť“˜ĽŠ[łn%՚É^°žy’ í„’*ZÖÖĐdŃyy…žjęöMU‡oSś öĐ6•Çν U{ÖѨϤ;˜fYhô˜t ňó1杹XL%#ŞX,K †$¸Öç"&ćӲʑ4=YOݚ čéŸüP‚ô^ő XĘX[­ŸMO0•ŇRť0ý4ŇÍ-UŰä[_ÝÍWšl‹ç/e›Ľ§Żâ˝ĆĹ! sĂjśä/˜Ł,ąe2x‘iÝTBxý`Ěqp[Ëă3!%Ś˜ ,súiĚäT[–„4×ĺaŇĚ}6Öäb%üţĎC*˛âfüć%ž‰ťÁ˛łCŒÉś1":E­×ßá1<=>$s.EÍŚďŠŃc0/řV2Ů‚‚…œSÎśM…ŕ<Ǒ+ 7ľIAöž°ƒ‚çü)ŢnxŒ?yřqţ˘Ź“ś~™Ü+¨k(&řÁŻœC)ăjďctçz|(]řç{o\-˜ş}S×ax` Šš”ZsçB.˙ć8–§6óƒżŮ˛ÄdĎa{fHŻ,DG/˝´’x×U:‡˝řă˛+ęŘžR‹÷B/˝‹Ěœ“'Gé÷ lݸ•‡ƒW¸ęO (\ýxf˘/žKmŰPĞÝxŃÖÎĹ1 {E=;ÖXtĺŘŕő0ŒóÓs´ľ<Ć'ŔŠ.úĂ&Ş[šhc7DISO7SDrĘŤX[/ŕšźČÁv˙ :¤cł´ôUüœ|çSŸßĚŁß~‚Ňs=ôLD­ŮÔ6W#{•›9şFkËĽ-•ľ<Řh¤S{Üô;Âáă7D™H8y÷őÓ÷6ąĺŔCě֊ňŻýč 'ŻOuńîŻŘÝĘÖU­á~xv{ Ű×ĺęşČšŰrŽTî-d†O˙‘Ÿ\рXČŢoŹŁŕN$+˜(zŚ…˛Ü şŇĹTRŸLČ-ŁůŮr ÝW8÷îä=ëßŰXˇˇŇŘjd6˘ČHĄ(Ą7cg†pť—‡;(”Ő°îÉBt‹Ć‚Âg.péT`ůľĎԒ­‹ŕíaÂ#!ZM˜‹˛)XŸ`抟Ŕőď—źÝ ¨ÎŞŠĘrG0R˝m'OŹ20ÖŮĂŃKSxŁ"Ye5lŰö_3ĺĺ3“¨ÇJŞÜ€`bĺţ|kƒ‰‘ —9xf‚ɨ†ÜęFöí„óAţçŃqőŮQš2ŇňœŠÜ‰pďŁCsîبŤ‘ľű˛ÉŤ12~.źlľř°‹‘3Áe“ßű[K9YŚ0ŁŻ_``Dš÷›>׀Źú˘ˇ…ꏪ¨,krWoáńF¸pđ=>ŒÎžG\ Gŕ… M4\ţ˜KÉ!2…šŤŮ٘OŽQÁďźĆGG/Đé›k‘5ĺřţŁĺ\{÷ Ţě›űŢܸ“ďí˛óٛ‡822ż š´î^ÍĆę,,J„ą>>:ŃÉ@čĆWvJ˛şlÖnmŚĽś’+6#Dź“ô^şČᏯ2śĐ‹˛Řó§OłsüĂëVď^GkU6„ü*ożzœóžéôušUěß×BkĽSÂĎŐ mťYÚ¸‚íOnb×Ę\ŹJˆ‘î˝wŢŔ‚źĽĄƒ`.`ëîVśÖç“gˆů&éžxw>îgbÁœŁtdoÄ@őCóâ6×Ţ?Ě/OME$ÓC|łNżň:čëHöőŃz„˙°Ť…ľgßĺŹTĎK˙qŚĎ.ŕ­h¤ŃŚăƒ9i\Ç3Ű 1Gxďwä#g"ŁrĚl{¨•-uůäYDá0ScNΟ8Ă{CÓz‰š<ügO˛7n_ÁÜÇżĹ|ćƒ4Âk?:ČIf6KçyH5]Míü×çŞé}ë EëŮŐT@ŽAÂ3ŘÍĄ?|…ŠĚ{@)Ů,;hłËŘšs-Ő+ČłˆÄü{zřđŘezý3) ś}ëű|Ö˛ŠŽl 6“[nĹhƒa×Ćýt_ I0-;Ř)ŘRF~Őô”V9':áeňÜ5FbÓ2;ĺß\EAd€‹ż"2ŻŃ0PđT+Yătý˛O<tE ĽĎŽĽ8wŽĚ {6ąiĎĚÉC˙Ď/3–ź€ĆHVKE+ł0Űľą(Á~Ă'Fćę…1Ÿú—jŃ^&V\H–%ŽçTc†RŞZhÆßébt,ÍR´˜rôŃ1źŽ…×ĘÄÜI/‚4ó–n[’RÝ̤ܞ`TgUEe9c(a[k“mG8šä¨N#3Ůq•k×Q–'riŕzC)PĐş…Áq.Ÿť„’UBksîâzł›Ě÷<ŇPše ĹîAΝźŠl/Śuő*žšĽá•7.ăL¤/+XJŘžľ Ą§Ÿł^&ƒ`/­fëö‡ř^Á1~ôë.ۧD0”ňÄs+‘ť/qčő)B+•MEŘ ×Ó­â™çwÓ˘ŔąÝç IDATsóéńS\ ŠjŮÂłv‘Ŕ ˘Ą~Ď*]˝Ż9ťœm›6đďň´üăOĎ2¸H'čV: Ëg˙7aO~˜îOĎq|LÂVQώ{¨Ę;ʏ~×Ă쏚tdoPÄHݞ‡ya‹™Ť‡ń˙(ť`Ş`ďÎŒ“ƒ˝ó#2ŸuŇóŕVŞ‹DΈ”ŐdÓqěÁőز˙ÝyoœĆ]ëŘˇŁ‚3żé%œnš 6ś~őO–†¸üÉYŽÇĐXm•UĐ\iĺĂŢĐt‡Qöńɛ‡čу¸˘‘gTâ=y„ˇ{f:HJ”ńä™4l–ÖóvYh¨Ů˝ăgŸńť_}yľ<úč*žńD€á_\I}KŐfčŤ-XĹKĎoŚF˜äb['&˘ˆÖęW­asézŻĚ¤Ź„šôîA\&1ż‰ç._ZÝ ëńGĐ s1&÷G­ZnŤIÇöŹ¸ŽťŔžCţÚ ęsDŽüv€`"YS-9×ÜLô…‰†AWGţú•4ćuÓţöŃĹlfČŚüńB”ţ†Ţ ‘ Řęčô €9—ާęÉŐ?{•@D‡­ŠŠ›€pścMôVyz°ĂAţŚ´ąÎŤKDUoĽŻÖFé“Íç$đ^Äĺ–Ń•äS°ĄĆěn.ż3NězÂéČ.DĐaßÖDÝ:=ţc—éšäv‚i˘QÁąĐńQHŁ$’ž1ݘú?ŠÂ&™jbl23ŽúVŒâť>÷4ź Fňn˘˘(ĆÔůF'f#ćâ˛K 8fŚ"K~&:ĂlXAnî0ĂÉÚóČ-ˆ^ÇO3]9Âřű—ńé€ÜBŞČ%ŢÖÁ`˙u{$ˆD’e"˙ŃŐT”)ތ2x.†`ľ“ťŚ‚ú=]żšŠ/6[PXĘMx> Ń\AţŽfl.#ČÚTJɆ&Žß¸žôf(ńˆ ;YEZźC7š:ÝźĽCŞu3ÝrťPU•eŒŠ˘œÍ(ďľ{‘ÁRČśÖŇZnĂ÷Ó{q)ŚÁhaöŐ+bôółƒÝLvú™Đ=ÂÓő%T[z8ˇ0R˜*‚€>ĐË+oˇ3>“n_hßŮVĎ֚^^댤-Ťzůˇˇă &u>ë˘7ößÝÔDkn7GŮĄWĚÎEyď÷üÓ)Ďl§˝łŁs6˙Ĺg sć•Cüś{úűÉĺIžńÝ˝Ź_4s"o;˙ëĺ6œ@7Wđ×űWąˇšŸżą#vsŔžŞ……Đ˙ţ;üËÉéňŁ­‡Aéi^\×ĘĽ}ź5(§-;żLLÔď}˜6ézű˙Öć™}‰›jkiÔ óúŮI$@´•˛÷Ń-lŻu`ˆ{éřä*‰¨“A3s…ĚÄĺĎřcŰ8Fš”OĐsę ':dƋ¨ŤĚe…Řˀœ^š Ś"ËľřϟŕWG†“:gE!ŠĂgjÄÉ ‘ʉŁrťčë_$’—–ÍŇ{2) ađ3~őAßôúßŃ)Ţ.Žŕ{+XiťĚq_úő-u›ĽŠŻ`cˁ Ôj\üé;|86—ň‰çą“S–ńšFńĽňŚĂLëńG›Cĺ7sýéś"h‚€Ć?JÇ[ƒ„$€1<ĄfVí(ڤÎIוxú˛Ą zá$N˛Kť b+ב›=ÎČä"3V”cçéülŽMňöšŽ˙ŠyM99–ă¸ĚŐţéRďQýŹ$ďvUAOށőä%}%yÜ źŃÍčŁ27×tőeä ř_ŚŤmFŚ}œ€´ŽúŚr 'p*iËÎWB‡c[ľktř>źDďĺđm9Ş `\ŰĚľ žVbŒ˝ń)ý×§I FVčîb|0NóÓE”4:ńżŢPˆváź@#głbŻ_[?Ž>…p~ ĽŒâř ëKoŽ„ç3'ĄŠR ž\}pϐŔˆŸ+‚¤Ě—M'oŠ“NÝLłÜîÔsVUT–-"ů…šˆăc DŃÁć[ٜĺĺô{ńę‘nĺľ4X^'ăěÂ3ےI¸Ć}Ȃ ťĺvb 2c˝ƒLĚŚŤŕéŠh)-ÍY0˛–˘l"<݃+Š´Z…Ń‘I$ÁJNÖâú*ą!Nśyď€ jŞÁAÎ÷ÍmvĄ„‡hëYÜń™‘ö>ćfɸŻ\ePÖQUżč¨áMu@KEuzyŒśKŢ$™ÝŽáĹJmUÖLŸŽl˘‰•?¡7[č{gžŁ "%ĺ+Đ:‡é b~}/ćMňÁk‡řÉë—đÖ4ąĆ*|ÂY00mŸX8J\‰˜)›P(&Śë˛i”›"ʼn&ŔTXL…u~.d9S& ›ĽőßüľrJ8ˆ/%F悶ŠĘę(h^ËžMUÔÚ1k“œ'%Žv‰ˇ’âő0žTßK°e˝~ć/”™š "/úZ’ńxćO S‚~ŚâPił`¸aîÍu0â°j!ęgrÁvť˛ÇGČw˜˜LO6 ą|-O—äŮŃăMrVud9ôDŚ|Д7°Ľ0ȉŸĺĂ! Ąo\Ká÷7ÎżßĚ.Š,##Ďn:!Ë2ˆbR‡"r‹ňÁŃŞöŽĺĎ˙ޏkœAçýÝ=œéœ"ŁUiŮ7ç!ٞPˆDçď:íPŢF}KŐfię+fŰÉ&\Sĸ“dVď8r”@Ż{ÁŃ5fŠ•ŰíL)Ä| –a„#Ä`łĐ $M?MUVƒŠž”’5šŘWŃj“m$!jfŚÉ.ÔÄ^zmŚ Go%%:ďYżŽÓ햃LltĎěKLôÇh|ś‚ňmn<‡&nˆŔß\_-:‹ą(Ń â‹“LV=JO6ůĹĽTM˙ߴˆ†pzSH—@šô0Ősó –ťƒ¨™Ý<˛ŸnŢb“8?ń`ÝVĘĘ‹ˆNř Žô3ޡŕ^J”ÉĽ{rÉ+éÇ? #ŹČ#7[!p|œäŔ~Z馊hŔhŔR@ýŸ/ž÷ˇâץćf?(ł/eö¨5EQ@2~Š%÷Ç'4črŹŘ+ň(h) ř‘Fř݆\w1V™nÝL§ÜîTgUEeš"hŃi!›eÔZ̘e/Τóě”ŔŽ 8\Ş|iŚsK@ kÝnž÷x ‘žËţý. IMĹzţôĄüyQży—K‰›ÜďŽć^Q=—ôV:ÜuN˝öíŐ{yqĂţ¤ď÷źÜ>3@ hŃk!öŚľ6+6e’Ń¤gÇ7Áp@ańI“‹0[é–[‚áS‡řť+4ÔQYVHÝĘŐŹnifóéĂüř]gfkÜőbşă7¸{6ťóncćőř^CČHQ%ňŸ“Ő7ÖÓ¸' 隓Ą÷<„ƒŠBI9 ۖ Ť’|O“ŹxŚđzĘągaŃLŕ]čŃ|Ńú&BŒîbŞ|%őŤkŠłÔĺ`ˆ€"˛"?knTLă ĄĘąDĂ#’_SFŢěY5e ‡Ü :lŠČŠłÓç˝ôůlkÉż-gľ÷ŞĹRĆÚjýlÇO0•ŇRk\˘#(RÔTMfîsnSebœžŢą Ś%¸Öç"&ćӲʑ4}VOݚ čéżî§#ťąQŢ}óĂúrź‰é“_bxźqLŮ6,€4ŘCŰT;÷6Plt6VíYGŁ>“nqšĺŚŃcŇÍ˙J‰ůóNçh1 ”XŒ¨"`ą,U^iŘ,­çá6Ë"%´Tm{o}u7_i˛-žż”m–žžŠ÷‡$Ě ŤŮ’ż`ޞhĖÉŕEŚőX áőƒ1ÇA†K{3'%Ś˜ ,súiĚäT[–¨3×ĺaŇĚ}6Öäb%üţĎC*˛â‚Îí :ůÍK<Š Dń …PĚŮä”%u–ŮäVꖾî6˛˛qd (“!ÂiW ˙ I´“[ŸźŢT‹˝!=Q|C×ו§#ť1ĂG† ęr(ßSˆńóč]ű'™•ŃV“Ÿťŕ†˘Ýě@sšyÓhĐ,ô­bÂKnž(áë˜ ŚËbŎ"˛Í <“7ž×ŇNˆKČĘ´sśřsĂÓăC2çRԼȚbƒůn7†ŇĚƅ÷0Tfc"žE˘•ˇĚЎ%ŐÍËí@ŹŞ¨,[dÜnäšBʍ}´G&8~řć=kyáĹEĆ;ŕd$lÍ(uĹë¤g˛™ÍyRîĽĎŻ!Żş‚RMxńuŠBĚZĂӏę8×ëCvÓ˛:ĆŰ9ŮM_V ĐŮ5Á‡yö™;ڈ˛XŮŇ@~$Ěĺ dœŸžŁ­ĺ!6çđ€U¸őęžűŞŢďÝ{÷ÖT’ó YSŚ00z‰ĂužYuˆĽÍbŞŻîáä›g¨xj3‡žýrĎ5Ó<Bľ'QRYDôĂçyvjéŁ#…ü”Éŕ^MˇbDÁš’AъÉ€ˆg”Αúb˙Žľ.]qącëž<§{ƒhz€Ž†žůç‚ß!úřă#ůäT—R˘ő3îQ°§c7Ě3ŻS׉:2)}ÔČ@ł=!™Œ5 0ŘIos8ö˛zW›—Ü­Y=Ź3Đâ'o%qU:‚č,ň$:ţ‹]ŒŹ*'u˙*řtpryŒĘ,Ô;q‰kŔZšCVúäxLƒĂNBi26%ČЙÁ׃\ pcŤČŢZI™˝Ńřět2VĆim˘żO[TŮšhÝ´}’@ĹÖŠÖťšrzńË×Äĺd˝1<ëoWĄżůú¨™Á:HüR!šŻĆZ;ˆ{,‚bľâ,ME?}Ž–Šľ9cŮ7ŞIů×2ĐÚGďލ˜˛ÓÉ(R™hĆ3ÇĄÖű†Ď"ť4| wÎţ[ÔvÇÝxź^]DŽżŻOC×ĂzźLL˝ĹD}+]…Őě\MeÖ#Ý"†8ĚÉvœE‰DNžĽĄni˙čÍe%”=ŞáíĹ3$˘ˆOO&ĽÄŽÁ;D_Ýě3 ١…–,îos!Çm9`UˆĎą@GÍŰ6łĄ*‘†3ă„GŰ9üB'ďZÍÄGCxC`q˜Qo˝úlš‹ÓGĎâŘ˝Š•ŐŐä\´Öžçő`Oďš+ˆ‰ŇţńÇôćŹfăöŹZ€ÁÖKźu˘‘ţYŸŸ )Ť3pň(ż0lá`Í*+3vĐpî}~:RĆ_}eţuoE÷ľóoż|ďuÔěÜĘş°—ś‹óŰ@%ßŮ=W֛(GO犍ě>X]óÓsĺ4/ž}‰›-ÉvSáAŢţőź{kŘZU×­ !÷ÍĺÍŰo\ď6–˛sŠŇwňŽ}‘/îǗößq¤Š‰ş{Řš!…‹Œjäˇ?nćUťS4ˆ;Ö+j 1%Ší¸éž~Î^Ng݊öTX°ÄéĆGhţđ(oďœsP6‘>Ţ~ůćýŤŘňĐ>öU­——ţţ0'ŻuĄÍb:nűXÜž˜Ú,ĆúF.󳟸عłšuŤ×QeU yÝt7_ćýîëÓŤśňÇ3o85ŰäűŰtÜgßä?żŃCtŃÇQ:ŽĺEÓv\ł‰'6Š(ZŻüC/Cá%ndÍGß;ÍÄďÍ'yM>Ž€׼VZƒŮTî™+¸Öpoě[@֎LŒzK;mőŕ›ő١˛:óWhR É­Ę"…ŠćőáŞm˘q,Ş‡<“|śŔíŻ4ّGʆBR"!< m´ł(Űt›Ý‰Š{Uv˜ ʃ!‚ýýtœďfpąK{DF|dmľ1Ń24w๘íF]ôźÝŽa{éťËÉ6*§ýľ ^Î 0xřĄ5yd–§’]˘… ťüxę;žk!ó;JÇwŠ•îH*‰yɤĺÇa4čD}|umôîĂí›ăe ١X>K󷹀ăś(ĺĺĺz(4ŮĄ(ĘľW/ä§bů°šM1”VHŞÚÉS[-4źűoϡđşł(¤n|ˆîˇqáĽ#źÜ°ř^!„÷2sM5Ő[ôżxžŽš’¸7Üšăćޑ,łX­V ŠŠŠNŢŁ‘`Uˆ{_œ1śÁĄ~úărŘž}%%6``‚PDCˇ’žn!ę -Ë9 âîó÷őĐż‚ÖPáÔńűƒĂŞÉNvś°+Ŕ¸BqˇdíËĂîëĽýˇ\3Ü+îŕq G–fq\\œôŹ qż‰­gő*‰ůĽl__DişřŠ#z¨‡Ăż9AmĚéjĹ燑”ŇJÜą’ĘÇľÄ"z°çţń]ÎÍ9W!Ä˝Nq:Iʲb)Î&ŤČˆëÝOişrŻ/Ýs˙[Šăś”=ŤŹ qŸY\°z!ނÓn"^‰ŕuůđÝŐĹ>Ĺ˝Ä`˛‘ä4cR¸ÇëŇ5ą0äoŕĎżą…ĚŃĆî\ňCÁ&ţâ›Hi¤qüćۍĽěýĚP˛‹˙çĎö’;t‰‹ĂwŞTJů˙Ç76s`w vŻcťsˆݡ˝ţŽąl7ó§{ȟ̼;VßĺAYQJ͡ʰ÷2v‹ż‹XĘ !„÷‚Ľ\şFzV…łČ}¨IˇjřÎ]ë¨É\şŸ-žSżç_u„?{žÖĽůîY°;ÚžŠ…ŹŻmcÓ÷ËH2ĚřUJUśő’‘S_!„X>î—+,!Äm1´˘”-ŐeŘą!äĄńâ%Ž]áółĚŞ‘ÔňJöm,aenö8Ž pńÔiŸd撡jB.;vŻbŘSĎůţČm÷>.ţá~š†C<[tȸ‹ušŰW!„ 'ÁŞŸwŠ™˘m;ůB•‰Á†fŽ]ĂRIĚ+fŰś]|ÍrŒßœ%|ˇëšÔ +<ġ6Xč˝XËáÓ̆ ¤Uđŕ‡Éą柎 Ý˙í „BąLH°*ÄçšBJőŤ€‹‡ß὎оލŽŢz‚ťxzĂ*Ęk?âňônEƒâŐěŹH'ŮŹăéëŕƒcipk׋äoŕOĺÓńö+źÖzýykĹN~°ŰɧŻáhŻĆtŠ)…š˝Ől,JÄŚělĺƒ túg÷Š-¸ŹŃÁĘ-5ě]KNbz™ďŐ˛*é›öńëŕÔs/ózKŕZ;´śwÓî˜żÜ˝Ž5gßćŒ?…ƒüEö§_ŸE‘ňءřŃcS˘˝źô÷‡9鉵ӊ'ĺąsgëŠŇHľŠLxĆéjnćýkińĚ(o°Sąg­Ë&ݢ1ŢŐđ×?áâ˜6kťKÁ˜\ČÁƒ5Ź/pbŽxhťpŽc*žˇÇŔť?~…wgÔלĆö/nb÷Ę캟ަ+yçâővPŃžK@)(aÝci¸œ˘šĺz[W­bÝ>+ƒ/ŸĽŁgĆž™ědě_Afą8=Œż˝ŸîzpĎqţ.¸ŹÁLâş<˛V&buQ&BřÚč9Ń;÷v…BˆűˆŤB|ž™rŘV“ĚčůŁ›¨NŇ˝ŇFÇƾ伪\îźzÁސQł…4ßľç.Ł'ćPSYĘĄ˝>^kbń9 ŹŘ˛…ě‘.ΝlCsfSS]ĹW <÷J-}‘E”UŮúľGřR‘Fű§u>ág&57ňGŮ6ţçO?Ś%ŠĽ€ý;Ó:ţ‡§Ş“{Ť1üiÍ{śR”ĽrŚÉÍ'ŻĄ9Ô´ ž|hŽ“GyŁybňzˆĄéýëp•1يď=ľ™be”KçĎsb8„jOŚŹj5›sëiП>‘T%gÇdyú8óŃiHYÁö U|ý ^zžšĚČÇ2Š5ŸÇżľ— ć1ΟŰ6mŕSüóĎÎŇ´Ű7ćJˆK0cžŢŒvă˜ŤŞ’°˝űđ0ÇŔ™LúšʒUę_ěÄYDYŐBúĄj ňtźőýt›@ą;IY]@YF</´áž¸íŠ !„˖ŤB|ŽY ň)6ôóN‹( Ř2Ůśk 5ůLa-—ş‰N0›Tŕj°ŞbśóóĂMLvŢľ3÷0—ĺPdkćÜ=… ˘(Ä{[xî:†ŚśŰęßÍwś•ąľ¸…—‚1–UHXť…GJę_űĎ\đNíA#§ŰBüťoŻâŕÚZţů”KI †^>;JPšě?´…í% ˜Â.Ž|ŇF$dŔb2aĆzű Ń|ÂčřGhmÎ1§ráuĐ[Ú@‰a€Ă?{“÷ŻG8'N\ŔižŮ[Şâ 4ňwżšĚ°ĐDżé ž[UŔJG-ÇÝK­*dnXOMBó/ášúÉý?];Ęߐ sŤ*&W˙ň›óôE'ë[ď}˜ż:PĹţĘ:~~!€Sű.‚1™<çŻn+Ÿ”˘`đôsĺw]řكŒű+ŠÚ‘MNiőá˜ËĆW’WăG/Ň\őfŇC]a*Ď"§˘÷…ŕ̚!„÷ #€9>nršŤK× 0ůpę9nü?SżçęóBˆ˜ůƒĄ[ZR*é™)¨Cőt5Ímes|˝sžţ¨ň ŐŹ¤"ž IDATľAó ŻÓčkéfüZÜe`ȍVnĹiS`ąÁ*ƒ-]SA€Îxk7}[ÓČÍMĆŘĐK$ڞ*VeďkćԕŞŃp-ýš>ĐE“§ŠM˜NůČÉOĂŘ÷)-@MfĎűŮcîäí—NĐq˛z×FśÚębţ¸[h<ĹYŔę\ţÚKœŒÜ¸)-€{V˘FW]#×Ú!BoĎÚj;IN–2XUě”%Ąúš8×t=Ôƒ=œo˛~í\/Ňč­ke zýńH}]űł(,JÇxĄcéçGÝô˝Ű‹ozÜoO%oGęmŢ˝Őń5 ˆ^lÁť-{žľ~-ڞń$–&`đ1ÔF1¨×{GĆpű˛IËu`¸ź˝ [!„XƤgUˆĎ-#NGn/~ÔŹBÖŚ8÷Ęi>ˆƒtH}˛zĆët‰i˝\:ZTT 3–‰ŽŰíżĄ÷Lřp‡!ÇfÁ|CꀞŠƒ´$Ĺ^Î÷ţ}ůœďu™ą(q$&ÄsăŐÁ_ΖL'~qŒ÷ťŁ@/­CF2˙tc읤.´ÔAMr’¤ę Œą°Ń>_đ†c‰jčˇ},@ą‘čTĐÜnĆnˆ–4ĆÇ}hsŹ˝úťëtŸ‡ą0Źpذ*ŕZęi˜ZoËČ uVRŹdëˇű…¨3áž1”>d"› Łz ef§ś ĘţdîœĚş'ŁQ™ş*„â>%ÁŞŸWŠ‘8#„'&—1ÚŹX5}#ׯâuď>H˜ńR]ż WÇąźĽWc%m°–_żŃ2g¤…xTҋóH˝öK…Äâ<˛”]Ý#3.öR6@}]śBöÔ$ÎFb´’dW Ć]a,Il@´Ť™ócŠěÜ_NśYA‰sPőŔZ*âgmúÄ!]Áf3Ď€/´SŰsupŠ;Šľźš-é3ĆńŞfsĚ11R¸mßúĘ^]ĺ¸y/ŽîÇĺsrΚ ę^š[ÇĐlyԔ\żĄ˜˛Y]2_{¨d­*"ĂpýqĘŞBňÔ0­-ƒĚŒÇnÝžKČbBW°fŘŽŸŻ+ÉEśyośXKSąŽ?6§`WŁx:=h1—`źŮMԚBVĽeö{â1Y%g„BˆűŰ]lH^AZa"ę|ßłzď•zÜs%“BÜ!ƒ}#hřä›[Š sü­sXXĂÓß]‡Žk¸:űč ŘľuÝŐGóh%;*7ňE­…VÔ˘r šç3ę:öb?Çš7ZB6ëŞSa¨Ž“-ĄE”Őżđ1o”?—>ßç5pž}œ ÁJJZĽĺŮřŢű-?9¤§she.%Ö+œóđÖ Çą}y3?üëm Emî¤3ŕœÝ‚Łý´ťśnÜĘA_=mžşd }˜ńhluĐt'ßĎłőˇ“NG%9ż5e Ł—8\癿çRáŇ;śŽáÉpş7ˆŚčjča(<šoýgÎrní~6|á!´WhöĆQ°ŽŠ2=ČÜŤźj„Vń'MŻCKÎgŰŚLč;ÇŃúŮŮ~oÝžKGc|$ŸœęRJ´~Ć= Öâtě†ú<çoԑIéŁFšýč ÉdŹI€ÁNz›Ă‹*;QßJWa5;WS™5ŔHw€ˆ!s˛gQ"‘“gi¨[ň”TB!Ä]óŮŤŠ“Ź/?IyŃM˛hŁtüK#e;Hţ˜ÎŽť5UˆűS Łƒćm›ŮP•HÙqÂŁí~Ą“w­fâŁ!ź!°8̨ÁEŒAÔ\œ>zÇîUŹŹŽ&/ࢾö<ŻËxz×ěŔ˘´ü1˝9ŤŮ¸˝Ť`°őoh¤V`˛Ŕ˛ŃqN>˙*#›Ö˛{u1”[ˆ‹qŃ~á4g['Ešš¨;°‡R¸řÁáĄF~űăf^ľ[0Eƒ¸`M°˘f‘>Ţ~ůćýŤŘňĐ>öU­——ţţ0'=ąŐáÚ&.󳟸عłšuŤ×QeU yÝt7_ćýîšCŔĽĽăŘQ^4mçÁ5›xb“Š˘őńĘ?ô2žŹąîďäĽ_˝‡ď` vmgmŘMë§§xąššďíQŃfU7JăŃßÓšb#ťV`×üô\9͋o_˘{ŽSl!íťT4}ď4ż7Ÿä5ů8~\—Zi fSšÇ:× poě[@֎LŒzK;mőŕ›uţ.°l4Ŕŕá „Öä‘YžJva<Š&ěňăŠď`¸KĆ !„¸ż)ĺĺ庢k|牳ćŹ.ÉŇ5j2ü'”äÝd˛6JÇżü˜žOąeO”ögž§­3ö€ŐœXŔ͉㍖ŢŢ?Y(l)ě˛QôŸŽŒÓůY^ż.˛wďXēU^Be^ Yɤ;ăQݍ<ű› ǫ̂sœ3ƒU+ XYBŠÓ‚EŕâĘĽ:>nr-0;ëÜârŘ´ŠŒU9‰8M*р—˙üă×nkĎćc5›b(­Tľ“§śZhx÷Ţn Ü˝9‚w•BęƇřá~^:ÂË žyzĹ­Šäî{œżŘęăĽ˙v„S2BF!„¸Ż-ŐrŒVŤő˜łjɧđéŻSX°°,/Vk̆9iФŘКcŢŮ˝E!ÁžĚŁéé<–žHÁ]9‚ ŤĂ˛8Ş•âľŹÍw ¸Ç ÍŠŠdTŻçŔşLlk8uš—%‹-ěĺ‰őɋ† Řň9ôĽ­lË5Đsůo;ĎńćĺrŻ3V{ŠW/…)?°Ÿoî*Ľ4ݎÍdÄdą“•ŔmO“ź'č ŸyŸ_~2ÁšŻ~‰ÔOç\9–„B!čžXşFąäQřÔ×Q~ő[Zۃ7)ÇÚ´žc×éâđ„‚‚‚ĂœČ×2ÓŮk7Ň?˘~0 ‹¨/šer,4çżÁ)o°’ÄŽ' eÎč:žö <űi=ži}jçťyřŤŰŠ^WAyíqjovúÍIÁYRL‰5Bóťp¸éj˙lűböfič!:>>Ć3˝Ľl__Ę#_^KźzőW=ţÍ jgĽi˝éšŽćżwVňŕŽJžüîĚWŰ!ŘÎs˙ř.ç$řş‘’ŔîoîŁp¤•ÚŽ1<˜É­\͞Ź_j ˙óŮM/„Bˆ;dYŤšŤŸńśčľžšÄ[H~Ÿď|Żs˘ł‘žÄ4ž˜–Á’TŕÜ<q^mä=ďÄTp¤VḚ̌`Đ˝źÔĺ%7-…jłč„c}=źć ß0Đgg_ZŰҍ*‘hˆĎ8o syBĹĆ7Ę Ůg óv[#/řg_Š9’VđŁřzů?ŰF_hcůó•yŹšaOŻŹćitšúů/#×翊Fd¤łĂa%ÍĄp×Ż Ó;cŒă‚ĘĆT‡XŽĹRŠâóL˝ËÍSŸâęéÁ5óéŕ=aŞË¤8XÄfł)E¸aŢçrťŠ2Ţy…7:Ż`ˆˇŕ´›ˆW"x]>|ŸŤiqFš.đ\Ó &IN3&%Œ{̃GňŘĚŚ‡čétą˛˛‚Ck,˜Ô0ށ^Ž˝xšŁWüËî,B!Ä˝eyŤŠ[–đé79)Ć×ęş˝.ŮěśąşĄÓëár`bîy‡Š•‡smčZPą›Ęˢťą“3SqŽ—Čĺ˛>nrŢŽfV&eRć°ňLk'Ç'Bt‡@3’Ż˘řŁ3.ÖŇL&TtƃAbʢCXÓ) **Ft"š>đéLč×ßM‰K໅ylŽWŽĹhqńVÖ§YаĹów탴k1–ą‹:ËN6Ťôž9{Őâ¨|ř1YĄ2|ö(?˙dlĆ\GŃžA<5Ŕo\MçD ]^ sJąžÜŸčD€ąŃĎCWęÍEC>†‡–Ëpíĺ*@ăGiüŕn×C!„÷ŁeʚIý⟱çQm֝y˝ă>ţŮŮy:¸ŒTfäńTŠgÄËqW€Nuă’’óřÉiœěëâ™ńĐŹ5ďGZů/lÉ+řŰl;&ƒŐV…30P“™Ĺú8˘>^ëěâM_‹5…oçgąÚčä+éÎw{č †Ńíq¤™âQ’bKde<řn> B†ÉˆôgÖá´qţĽ~PČĎ(á?¤™Qt/Ď6śóᬞ/ŤÓłŮŻ€âdo7żóFÉLĘá{é6ěÖtžLvńŁáZ,ecŞĂbĹňbL+fmŽŠżŁFďâú‰Â=—yí¸‰CKxôńŇŠg#üÍ2 V…B!„Xî~°ŞĐ÷úű yćGŏŽĆ:5wL3Ü,ŁP”ąH˜ĆĄv^ńŕu°Ý -#]°°--…´HdöĐ4=Ŕéą!tÂ~?ĂşEĹi4 AWílpQĐŕˆ/LűGxӕBUJĘ‡ŻŸŚnŢ^Ő(ÝNÓ}“MY‹6đőý)´~‡wťŚÎŽöž;]c!„B!î+w?XUSČ|ř1Ňç Ş¸igęMLxůÇ…Ą‰Ű ݆Ě-‚Žşę“C–ľ‰ }:dęȴÉW"\öL°Ęaa…ŇĐ'‚ł}fbiŠ;OßÉcąä NÖîßÁî §ŸŕăÁŰÉ0dŚtUŽHm˝Ó3ôÜí0CţţôP>ożÂk­wî$6lâĎÎĄő­Wy˝íćۍĽěýKĽô‘'ů_Ö[§>›t|çßâ˙ý]÷ý—é\ąPśs;ŹĎ!ÇA‰réß~É3ľ÷fć/eE)ëMÁuřZnń7KY!„â~t÷ƒŐh'M÷+şĆ眸‘š˙ő‰s.7rsZ$@Ýź™ƒcŮÎ#:ä+:ƒ#íü§Ŕüó,• =:ëL&V:ut?Ż†Hs$RâÔIU  2pąĘőFs÷:ë‘ †5(5(d˜Í˜ áPLX&łňF'B ÇX6–:Ět§ŽĹ’SíT=°“ý9!ÎżőöŢf(ńբ 1 ¸Ëeú1 ńŮś™FĎŠßóŻőP3Ů˙őľd|VoýłVl᛻sp]<Ç M^Â踺—8$W,d}uy)Ă4ýk#cÓŢNIÉŁňÉ|LMőœ{{ô˝í$„BÜî~°ŞćSúWMńÍzV¨ŢQQ/ç˝QÖ: d%góx°—ß{Cx0o˘Č‘Čƒ›ęsŇ'čéčfë€Đ Íţ ĽZ*Ť6ĚčtCˇ‘ W'¨ih€JĂş•L%žlÓu4tšúůť‘0:Q.ôqږËĆ8ŰrŠŮ6íő˙ ύ^ÍÂKŮXę°\($­(eeŠ 9f@MĄŞŚ‚|Âݜí𡣒ľq‡ĘŹ„zŰđĽŹ`Ë s“5†[iš5@%!+—•+T†]|03Xe‚ćO›ČŤ`ŐŢ=ÄĽˇŃ6ŽaIËĺčŰo-ńž/bŚhŰNžPeb°Ą™c—Çp…TóŠŮśm_łă7§G‘eF§Q,Ź<đßÚ`Ą÷b-‡O32RTÁƒ&Çz˜:6$mvŰLćx”H˜Đ}7žY!„ˇ˛ ‚ŐžÖVFĆćœ”DŢ2ˆ|˘cüć vĽĽ˛Őa%;Î@:ţđ~ŸŽůŚ.Lu†‚!BX°˘ÓîEŁÍBˇ›Qôݡ™\)â'}Ov°ÂdÄŹ(ă´!šzxœŸśFčLOcťĂJšBá îa~78N÷´č3–˛ąÔayPH.Ź`çĘřiĎĽ°fc  ăŻă|‡(ŕpZ1 `Í.b{öĚíD¨mš#X˝ľđ@-ĎżćcëúbJWVQŻ x8şřşƒRŞˇđX\<üďMëMîę '¸‹§7Ź˘źö#.Oď*4Ř(ŢXÍΊt’Í:žž>8v‘÷ő“ežů­ÖŠü`ˇ“O_;ÂŃ“ˇS 5{ŤŮX”ˆM2ŘŮĘ'čôĎn÷—5:XšĽ†˝ŤsÉIŒG yénžÂŰG/Ó2-q–Ąd˙÷7ŠhůÝaŽd­g÷Ş RLQĆťš8ňú'\ťZW•ôMűřƒup깗y˝%p­ÍZŰťi÷?Ě_î^ǚłosfę–1šƒkX_ŕÄńĐváÇU|owü ďNe/ťZ‡ćÉŻęŻGgśuń=šČÇĎ<ĎŤąßę2VěăożšËĺˇ>bźh-ëW$`‰účiŹăwjiŸŁ}cÚ~R;wVąŽ(T›Ę„gœŽćfŢ˙°––Ť™Ţă’Xłľ’u%™ä$Űq˜!čĽĺň%Ţú¨Ái‘ýd;”aťöqRĆţ‡˛Š˙Ď1guÇxŠ(%Ź{, ÷‘S4ˇ\?>ĆUŤXˇĎĘŕËgéč™Q“Œý+Č,ś§‡ńˇ÷ÓýQĹBËĚ$ŽË#ke"V§e"„Ż}€ž˝7”˝Vߣ—qĽç“YâŔlŇ őŇý^;ŁŽeđĽ+„B°‚UCĹ?üß(ţĚßX§w¨™ďÝřŹâ˙Ťšóш÷ú|ź×wó-‡=]üĺ厞ëlâOb[űĺ&˘´öđ_GoQ*ěĺ­/ 鿋Ľl,u¸ű4ZŢ{•˝wërďźĚŢ‰uűajźDíMËčŰřý‘6~ë旚)‡m5Ɍž?ĘąYÞ5FŻ´Ńąq-yŠ*—;Ż^„+dÔl!Í7DíšËč‰9ÔT–rhŻ×šXDpfRłq#”măţôcŽĚžÚnńŢ˜?ý”űő'ZÂĄCU|ý ^zžšĚˆŠĽ€ý;Ó:ţ‡§Ş“-Ł1üiÍ{śR”ĽrŚICąćóřˇö˛Á<Ćů“§hńĆS°v _wިó,ˆ´4â¨Ţż™ö“ó‹Łcč)…|xř„Ę?ýň"}‹ěš4fTń˝§6SʌréüyN ‡PíɔU­fsn=-SAˇbËaűÖ<”ćvÎ6¸ő3ˇˆ­Ű÷ńƒŒůűß6rőžĽÖsŸ?ӄAQ)Üy€Ů˝yá"“§ ŽwpZec>Ć1P Ä%˜1Ooű¸%§’°˝űđ0ÇŔ™LúšʒUę_ěÄYDYŐBúĄj ňtźőýt›@ą;IY]@YF</´ážaľ‚sk †ş.Ú_k‡¤4ňöäPô@ßË˝,aÂz!„bÁî~°*„¸k,ůúy§ÎEPl™lŰľ†š|ڰ‡–KÝD' ˜M*p˝gŃlç燛˜ěllg8îa/ËĄČÖĚšĹöd) ńŢž{ŁŽĄŠíśúwómel-n᥆`ŒeÖná‘…ú×~Ç3źS{ĐČéś˙îŰŤ8¸ś–>ĺš1ŕěú”_ż×:9ç´Œ7˛ řÁĆV:j9îÖą””Pačá峣DՑËţC[Ř^’€)ěâĘ'mDB,& “ša=5 AÎżx„çęƒčŔéÚQžřţƒlřLƒU…HëY~ó^n€Ąó<—Â˙ţĽŐě-ťÂłő‹˜Ş8ŘňĐJ ţٛź?-sö‰pšŻ÷2ęŢžýÇ:Ć}Óz†?m¤eâË|Ó*jRš8:59^¸hďpŹëuĐôuôŃ2+ ^Ü1^0c2+ţ yÎ_ÝÖ¨dEÁŕéçĘďşđG÷WRľ#›œŇ>ëĂ1—Ż($ŻĆ^¤šţꍧ†şÂT>žENEî Á镀Ţ.Z>&0ä§3=…ŠŐÉ$Úz¸â !„¸ď-ˇ,/ˇ&w{…¸CTŇ3SP‡é j›ÚĘćD§Ţů€ç6áÍ/ĄÜ6óu}-݌_‹9˘ šŃ NŰíô9i śt1|mť:ă­ÝôéFrs“gÜY[HY Ť˛ˆ÷upęJŐhŔ8őOč˘ÉŁ’[iĆvťZúŚ%”Ňń Š6’œ  ’“Ÿ†ąŻ‡– &łç‰ýěI彗ŽđŻ/_ĆUźŠŐöŠěϊ’˘$T_皂×>žô`盃ŸńǙFwsÓÓřÚşéŇLڞ˜B,BËĺťűţz”p F   * 8­ ¸§ŽbćEn_ӈĂôůŽ ŤižGÁé´˘p}~ĄbśâŒÓ {c-ŤyÓPŇ űé˜1JuQô(0ĆMŢç‹řüř•d ײĹYI°\-ďcĚ­Ł&;HRačZLŤ’˜hCšk4JeŞÍŽV°ŮÍ7 u&;ÄnőYŹ’”dGĹuýh8$t˙˘Ö~ÖĆ݌j é‰Äăfް–Šx…FÝKsëZ^5%&š&‡s*ŚlV—˜QfŤşÇ‹[WÉĘIÁxšŞÍ’X˝2yv`{íE~\0''ŕTş˜g0@%ť˛ˆĚSçéNľáŞBrŐ jۆçXűŮHáślĎRŻ?Ăuł“éŽ.uoŕąňjś¤÷pě†,˝fŚ žŔä{]ć{Ă6âÓŮś.uŃ銖â/‚/ĄŽ`ͰĄ6ş'ŰŇ`%šČ†2çmki*– W“&)˜‹S°ŤQ\žÇb!e'ovݓBVeî 7fŠĆÉ&t›K !„Ÿ5É,Äç–Ć`ßZq&ůćVę‚ĂëÖÖđôwץëŽÎ>zöEm]wőŃ_ߪ6ÂĽ+.vl]ÓŕtoMĐŐĐĂPř†‚„œŤřÎ7L|T;†ž˛‚í›Ňˆöžĺ˝†™Ë¨$粌La`ô‡çVŃ=œ|ó OmćСż@îšfš‡C¨ö$J*‹ˆ~ř<ĎÖGA÷ŇĐ8ĚCű*xňŤ]#dJdĺşr˛đĹşŕ#0ŁKpŒQ‹ń1ĆGňÉŠ.ĽDëgÜŁ`-NÇnÍ}Üt¨#“ŇG 4űŃ’ÉX“ƒô6‡Uv˘ž•ŽÂj vŽŚ2k€‘îCćd;΢D"'ĎŇP7cŰB!Ä2'ÁŞŸcŽšˇmfCU" gĆ śsř…NŢľš‰†đ†Ŕâ0Ł1ŽPsqúčYťWą˛şšź€‹ÖÚóź,ăé]Î9^ĽýăéÍYÍĆí%Xľƒ­—xëD#ýł:ŢX6:ÎÉç_edÓZvŻ.ćr qŃ Žą1Ú/œćlëDĚAL Š‰ş{Řš!…‹Œjäˇ?nćUťS4ˆ;Ö+j`20ĐýźôŤ÷đŹaĂŽíŹ ťiýô/6Wó˝=*ÚôˆUĺýW>"á‘uŹŮ´Bß gNđ5?|$qžEé8v”MŰypÍ&žŘ¤˘h}źň˝ …§ď]˜+ďžG_ń&vŹŔŚůéŠ˙„çßžLĎmŹĂ¸ĚĎ~âbçÎjÖ­^G•U%äuÓÝ|™÷ťŻîœÎŔÉŁü°…ƒ5ŤxŹĚ@Ř=BĂš÷ůéHő•üĹW` ŽqĚ4}ď4ż7Ÿä5ů8~\—Zi fSšgŽ@\ĂuźonY;21ęaü-í´}ԃoÖąX`Ůh€ÁĂ­É#ł<•ěÂx-LŘĺÇSßÁp—Œ BqďQĘËËőPh˛'B™š—z5)ÄB !–Ť9–…:’ŞvňÔV ď~ŔŰmÉšrK Šâ‡űm\xé/7řćB{+*šűç/śúxéżáÔ/ˇjŹŘÇß~5‡‹ż}–çok…P!„Bˆřƒóf­¸-VŤő\gUqéŒŐžâŐKaĘě盻J)Mˇc31Yěde'`šőF>gt†ĎźĎ/?™`ÍWżÄŠ˘2ljÇŮć$ż yĆ Vuć'­ę¤´Đ‰>ÔOçďd°ŸwzˆŽńLo)Űחňȗׯ^ýU‡s‚ÚXŕźß階ćżwVňŕŽJžüîĚWŰ,ŘÎs˙ř.玥JťżšÂ‘Vj;Ćđ`&ˇr5{˛\|Ё~éĘB!„˜“ŤB ĘxçŢ輂!ނÓn"^‰ŕuůđÉTˇyDişŔsM0˜l$9͘”0î1žéylô=.VVVph“Ć5ĐËąOsôŠ_†] !„BĚCćŹ qŸ‰mÎŞB!„‹ˇ”sVŻőŹÎxJ`*Ä˝eŠ>0„B!„ř,I‚%!„B!„ËÎ ÁŞôž !„B!„XÔ[ ˙]čóB!„B!ĝ2k°ŁB!„B!î6$@B!„Bąź¨’íW!„B!Är3g6` `…B!„BÜM Ę,AŤB!„BˆĎ’ĚYB!„Bąě̚łzł!Ŕӟ“W!„B!ÄR™sÎŞB!„Bq7Њ˘Ü´—TzP…B!„B|ÖćL°$ŞB!„BˆťÉ`ąX朏zŤyŹÔ !„B!„X ˙?ß äËw"IENDŽB`‚mastodon.el/screenshot-tl.png000066400000000000000000007617451501733112700166250ustar00rootroot00000000000000‰PNG  IHDRŤ8ďˇJćsBIT|dˆ IDATxœěÝw|\ç}çűϙŽA݃AIąH%Q]´\dKr+VŹ$NöƉíŹwŻ“Mr“Mr“ÜťąľšÎ&Žł›ul˖âŞbuJEQ¤XDŠ$Ń{ďŔ  €™9÷$˘Ě q(}߯_ć<çiç™ó;ç™g €űďżßdĂ0˜ĎBŻŻÔŘŘؚ¤+"""""×'§Óy­ł ×ĐkŻ˝f÷ÝwŸŮÝÝ}ůĹőTEDDDDDDfJMMĹ23P0Msޝz]DDDDDDd5uuua1MóŞ@TŤˆˆˆˆˆˆ\K–éB XEDDDDDD֚efPJŔŞ VDDDDDD֚f zÂ*""""""×Úĺ'Ť‹Ź"""""""ëi֓ՅV=m‘őtŐK DEDDDDDäZł,œjj°ˆČęyŕ‰'x˘čZçbő<üÄ<˝ÖGq˛çą˙Ä_üˇođwó_yÔX^*ë“×ŐąP^?hýGDDd)óNV`*"˛úÎŁľ×:@Ň˙ÍűŻu&B˙G|f‡…gŸř+ţúďżĂ/"ůíië5búˆˆČ™™™|ĺ+_!..îŞm111|éK_"###ětmŚibWnUO˙>÷˙šz]DDf°ţ ňĹf.^¸Č…hÝx÷nŮ–-ąüăßţÓ5ÉRüoşĄěš:|[ăç\÷0t­sł¨5Š×ě?""׃x›ÍƋ/žx­ł˛nžůÍo.şýŤ_ýęšűӟţ4………|ń‹_ä[ßúĂĂĂÄĆĆňĺ/ÇĂC=ġżýí°ŇľM˙JđŠUD$LQ9|!†˜˜ţƒŹŸĎŁép çßňb&€}O<Áć?ú._|ˆ›ňă08őłćEçCüöÇvł!ÉĘpËY^ú§qĘ?•núGxěÓ[É÷¤’ŕđŃYu”§žó­S›3ďů<Ÿš­„Ě8;ÁĄ.ę.ý˙ő“6ňžü×|%Č|bň) ˙k|íbŘýđŻsďÎ|Rlăô5œç­Ÿý”ŁÝÓÉĺţ/ü*űŠ=ŘÇŰŠ8řď´\UŘĹӘ,ç˙Śĺw>É-ŠŘÇťŠ>ö#ţ÷Ë óV]Áo˙g/ř"O<´Ż=1yœ›>ýyöoĎ#Ţ:J[ůa~ňƒ7gä'´ź.–Ćž'ž ŕkAůç~m÷ŕüůňǍ ×ůbőş˘ź†ĐDDdśx€xŕňőZůîwżË—žô%233ůƒ?řžő­o ůýß˙}<­­­<ůä“a§kMKKűKŕr:ó˙šŻÍýš´´”/ůËÜu×]tttĐÝ}ůŞFDDƛiŹŻĽkóç¸kč_čČźŸĆď}—ƒľ-§vÉŰżŸŰödpöŮďđłWŽPe˙üʍܚÓÂ/ţí'źx°Œą}ó+{sŕąÉ?Í!qä0Ż˝ň"ŻŽ!ćáGůœĺjá/žTĚkßţďüřĽˇ9]Ůăľ4śÁŔ‰ƒœŮżŸŰ|Ż}űޘL.ő7ţ–/n*ă§˙ň4ĎšeÁţÖL„–Ćd97PýĘ÷ůé‹op˛)ž?ň+dż~€3óT]ßűďňÖÄ~ö˙_űÚĎ8ptňőÄ_˙[~/ó˙öí§yárˇ~ž/ÜRɁăýb^—J#o˙~vÇßAňŔ/řŃ/Ţät—žĄ…ë|Ąz]q^Cč?""rĹt 0M“˘˘ÉűWWW_㜭˝éýŤ_ý*ŻžúęĺÓŻżúęŤkvěńńqΝ;Gii)‡M›6qË-ˇžžNkk돧­áiĽ…öůĚg>C||< |öłŸ űŕ"" żĘŸîłńÚ÷ęřćńX>ögŸŔ=wŸÖ˙C5Ý z{¨~ĺ “îo ˘c€ĄţŢţŸ@ň-WöźĹŰç›čcl°Ž—Ď÷LßLŒ ‚>/>ß ]Me>ľX=üÇ­U˙íĘÚúč üőop<~÷&€\~7ŞžţU=C ´pć'˙xe9ůŇ˜Ňőu^ťÔF˙Đ Ÿĺyŕ†MáTf˙ůFƒwžyˆşţQ|ƒÍźű?Ę!çwI&Ôź.•Ć$÷Śo󯞥žľ…ÚąĽę|­ňJhýGDD.ŞÁ`§Ÿ~š'Ÿ|’@ Ŕ<Ŕ'>ń‰k˝<Ż×Ë?ţă?ŇÖÖFffćĺ'ŞË T!ĚiŔ""˛ ýŻńýWĎqŃ~ú$/ŸŻcdî>ďfüŇ Ŕɉš/] Q,îäWîßIaz4ր‰él`OóŻGžÂăň˙pǚßsř 'ęFÉ฀ĆfžfňĘÜýŕä^ŹŔ‹łśˇp¸)ä4Ś^:8{âj'ŔôʡĽ_çëż1˝ĽŽ?úŁů>×r'QŔÎ˙úlżüš°“ôJ^—JcĘsőłŽźxĎg5ňJhýGDäCnf úÔSOqęÔä]Ú'Ÿ|’ÇœűîťДŕőfľZąZ­Ëţ{ŰôSÓé@5œ…•~üăó裏^ţYDDć3ŔĹ7Ś~>Ǜĺóě2O,éżúĽ);ůó/=Hűż?Á7Oˇ3j=Á;ڎ›T<ű?řł7‹¸ůö}Ü˙ĽżćŢŁÇ˙űL×é-pŁŇfÄЁ9›Ç—‘Ć|埏ú‰ÉϦΓú“ox˙ţ÷Oóœ-ž?/ž×ĐŇŔ;ó—Ľę|­ň !ő‘ą…U€łgĎ*`]'3SjmmĹjľâńxŽZt)ś™żĚ .öÄľźźœżüËż ű ""˛ÖG‰Ľ•ż:Ő~ů%wÁŐť™ŐКăGţžřłŻb}ć˙"ŔTp䘚ç[Œr3ŸtÁż\Ž˘ > ć/Žä&>jƒď^Ž ăŘJ8i„`Ź“ÎÎĽvz›1vłßâĺćŰJ^—Jc!ÔůŐőşy‘ĽřýţyŐi3Vżá[Á+u-Wă 'k!&&fÖbJßúÖˇ0 ăŞE—ĂJ÷ňGc–únU}÷ވH„”ŠÜ?ůŤťřţĐ5s‡ű¸s[ž„(ěÎ8rś¤e—Ÿŕő4{n'Ýí"&Ĺ tňߏ(ú/g‹'–¨˜6Ţű5˙u  í€Ň?ź˘¤hÜqé”~âkłďv.™Ćjiĺ›çƒäüÉçšľ0•ř¸RrśpŰ' §ś‡’×ĽŇ˜Ç’u>_˝ŽF^EDd)oźń_˙ú×ç T§={–o|ăkşČЇŮoýÖo‘‘‘1ë3ŞCCCüó?˙3x<{ěą°ÓľÁŐOO—š ,""×ғüĎĂ_âłüˇě÷M0Öüßů/_ýëéíA ď{œű=q8Łżĺ/|ă߯üůˇę˙ř_ůŤOěţţüď†č˙é_đýO=ƃż÷§¤Dék:Çs÷cŞŚţ¤ę‰âő/|†ßř/Á6ÖAĹÁć›ÁŻń§3rľTŤĽëűĹSŸú,÷üúWy(Ć΄ˇƒÚ˛q$Œź.•ĆՖŞsć­×ŐČŤˆˆ,­˝˝}UöY‰őzr‰Ç˙ůĎÎĂ?Ě÷ž÷˝YÓ}˝^/˙ôO˙Äă?Î3Ď<vşFII‰9ý55 }mÍ|_k3ó‘Ő4k…|Mő‘HŇgVÚŚŕVDDDDDDւĹ4ÍyƒN˘""""""r­X–ŢEDDDDDDd}͏ꊪˆˆˆˆˆˆ\KK>Y¸*ˆ‘őpŐjŔĄ¤ ZEDDDDDd-é3Ť""""""qʊˆˆˆˆˆHÄQ°*""""""Çŕóů0 ăňżéßCů_DDDDDDdľ¸Ýn=Y‘ČŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆc e§(§Ă0Ŕ0000&˜|]DDDDDD$D#žą%÷ѓU‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8 VEDDDDD$â(X‘ˆŁ`UDDDDDD"Ž‚U‰8×O°j؈KËäĆÝ7Pšd„žmľőAeq”™ËÍ{6ąÁý!)łˆˆˆˆˆD,[(;í}ä“ÜœhĹb1°X,X ĂWĎϟ:Mƒ9˝—…Ü}áÎá#üđô Ó/1E|ös;ČľÎH0ŘÇŰ?ů%ÇúLBaËž‘ßÜ_H’Ó¨ěżÄ…ŢŔ’Ű–cŮéYŘóŕ>öĆ÷óö ďp:IJ­{šW1HŘź—ĎޖIźÝ€ —ău•ԍŹÁĄŽ'ëR÷"""""˛žŹéoÔcŚŻ‹w_}~ę4őÁ™)œ—MZއ¸ćĚĄj~úýWřŃĄz‚0ŢQÎOž>r  ŕo>Ëž9EĹđճ؜ĺđ7ŸăϞŚb$Ěô˘’É÷¸pD§QŕqŹJ^Ö$ÍŤ˜ô—ç‡/•Óśü˙ƒg]ę^DDDDDR° źŹ…ž ś Ţn/ŁÁŮűąiäĹXS3Řŕž˝-06Ds÷( ľźŠzo¸Q‘ÉX+ľ=ó‹m[ŒƒĚ’b ăćNy 2Ö×Bmw˜évQŐ4„ˇŻ•Ęśń0ó˛ŽiÎÇ 0ÜŃJŁWO/[ŻşÇ :#ŸÝ[<Ä[—Ţ[DDDDäĂ"¤iŔÁކ‹I‰O"?ĂFY­Ööč,iŔ’LAś“3c3śÄe¤Ŕe­c,I0¸P0ľŘśůY“ šw_ŻTS38÷oĂOŕ §_y…ÓáýŐú§š SąęëU÷F;śswž…œ‰—xśj-c‘ëGč ,űŠkĂÄFvvƜ(×NNNŇÔk6rňŇpÎٞ•™€1ŘIĂUáúłĆfqßý›ÉXƒ'Y‡ç*/[ľiJhÖźîÍ.žkfÄ“knˆˆˆˆˆDАŸŹB€śŚN|[ňqgĽáą´Ó2=ؖB~†ĄžŒ¤xܙä؛¨ž˜ŢžLŽÇĘpm']s§ť’Řşł„íRHŽq`őűčioáô‰2ÎuM°şldܰ‹ÜœCšÓŹlđÓlŸ*_ĺëĎó\őÜ)Ę6’‹Jškg9 v‚#4T^âĐŠVú§wu%˛es.Ůň2bé}÷~t~äJčaŚđĆRn.öŕ‰u`ńŃŰŃFٙ‹œneN•Ź]š—˙ÖM^i ť‹ÓÉHˆÂÉ=^‚îůwŠąämȢ(?“˘ôqŽ={šÁŰ¸}ł‡Tˇ•‰á~Ş*8|ş…>?`"=7“˘źL6ćŘšôň[”E•p˙­EäĹčŞ>Ď+ď42˝śUČý$”zYjŸĹęţŞ|żMyÜ&îڕO~’ |^šk*8t˘ŮÝ×JRA ˇnË!/9š(›Éřđ - &faďŽâ˝úŐîď"""""ׯ0‚U˜ho§i<Ÿw*ůI-SŸë´ŚzČuŽSřÁŰ÷˛-*•ęćÉHҜJśs‚ććf…‚QÜ˙Š˝lwvóΛoň“ÖQlIyÜł'y0ËĎsf•ŸÄŽśóŢŃAŠv—R3AÙs\č7“ÁŽš!žAňÖŰxÄŕô{Ç9>î˘`ÇvöěڋÇőßťƒ1Ŕ°ťˆ‰'+#žhk>cćç`ßuŸĚ÷qęÍC<ß<‚ÂŽ;÷p÷'R‰ń ~ŮâgŽľH{"{>ş;2 ZϟáŮ×;蛰ŸžĎw&_˝ˆmdOŁ´8ŸâŹXřŘzĎ>b-|í<­>™7ěŕ#;÷’x’hŔ›ĆÖŇ"śdÇá4ü —î`S†‹şŞbvľe'ˇ5śňB?Œ~J˝X—ÜçÍÁ…ëޘ•ďţ=ˇ˛5fŒó§ßă˝Q;Ů[ˇqűś›Hďh`ȜěG [nĺswx0Z/ňÂOŤiľ’R´ď(Ą`ź…—\FłbU‘Ë›ŕ8ŃMmť,ąäeE3y oœ“FŹż‹ÚćŞÇ1 ňąNmĎH%.ŘKCŰĚĘƆ›w˛=1Híń“źŰ4ÄX ŔpWoí"ŕLcĎÖdVwŚŽŸžĆĘ*Zh÷™@€ŢŚĘĘë)+o˜g! q–v^xá§j;innäđÁK4,$R05×ŮôśqüđQޚďɘ;‹í…n͕źS7ČȄŸŃţ*ZF0-1lȉ›ˇÖ"M°ąóföe9Ş<É3Ghđ122D[} ­Łs÷˝]5źüâQŽuÁp‘ßÇ/”QŃ5Œ×ŰGĹą“ď4‰Ůp{˛Ź˜ý źţâAŢhđ6ň‹cšđÚťź}ޅމÉv0,áĺ!¤z ac‘şŸo+žř!^ţ8ÇŞ;hnićŘÁóTޏó (‰ r-)ěÚéÁmqöŘ%ęǙ˜ĽíŇYގ0\6çšćm1‘Ť0?7NSc/~,¤ĺ¤ `D“—K ˝Ć1?MőřLƒŘ܌É—p=4úf$ĺHgkĄ#ĐCUĂĚ(Éd¸ŤŻi›ĺ!ůš~V3@CYí3bsdŸ Ö(â˘f>í âóŽúÔĄá°ă2Ŕš”LĆĺo@1vSÓĐČ隁EŚěŽršś4ś—Äb rţ\WĹŚs…ŰFćĂŁSŰ먝š––9Dmă A#ŠÂü¤ŠŽçghď‰ÉHm%çúƒŕďăüÉ Nž8ÉázXyĽ^̐ënţşgVžƒt”WŃ0łœăƒt{ƒ`D瞺€'ÚÓKO˙ĚÇééóab%-5n•öˆˆˆˆ\ßš 0ÜŇNGŔCNZ:šÎ:.ŮRÉO†öcŒfK 㹔ĥł!ĄŒśÁdrÓ ú.t1sFŻ%1 Ěá!úç,lúĆ5!1.–:WXȕć†}WV͝űĽ7ó1˝˝´ ›d$lä‘Oť9uş’ł5ÝôTžĎł•ËËÓrÓ´$ڐĺ20Çzhî]zzőňŰȤ§wpNŔl200L˘b‰˘‹áɗ“ţŢA&ď ŒŃrń<-ÓyH #ĄÔ‹u•ÚcŞúóôŕÔÔ_c:ˆˇXŚ‚óŤW\žţÝbŃ Z"""""3…ʚCÔöÉI›\TŠÖ–NŚe€ăÍŁ“×ďăTˇLPRGAn4'ÚSÉrř¨m™ý´Ďˆrá6ŔpçóĐăŮł?ËjŘpYŔg,”ˆ0’ş8ňVű7‘‘ĹŢ{˛¸ĺ6/uĺ9]O›oŸÉ]fš†ŰM´ĚĄ‘ŠĎR.nůmd2>6qŐSÉŔ„Ÿ `sŘq0XOĂŔôř8uő]ŒdâÉÍ ŰšJěD7 ó_Š›ĂźüÜÚćŮlNŒ3˛Ŕ:AדŃćó<ýă6JˇndűŚ 2ÜąlßMކT^|î$ĂáHËJÓbL>á ™ťć1 ÜXN™ó|iŤaľ`Lm ˇÄĄć!”zY‹öXT “SďwQr[*Űvm â­:şÇ bsˇpSś o%ďVŽč‹kDDDDDf?XŤťąƒţ $f—°Ëfg¸Ą™ąčhS+ÍţL ŇóšÝG°˝š–9kŐLOátXabÄÇđőą’aĹ퀑nÎëćÜ 'i6rÇŢMÄĺrÇśŞŢí ďŠÚrÓŸ`Ü›Ő:OĂŰpŘgż˛şmd… 2bdVBŠ—cý8Vť=–.=çňىRîÚšßü­íL,ŘńŃVs–ŸŤ˘q|U(""""rÝ[Öĺ‚Ýí4 ›XâSȉöÓĐŘ;űIÝh;Őí°&™Í]W-ćěď§Ű†ÓMœƒ,KĘfűÜ>v'N=ś ŽŃYSĆóo70dÄĆF…ÝËM380HŸ Ft4ąswpŒäšýhuuŰČNfFD–w]켌y|rÚâDuís&•š>jëŚŘ —Ć–yŚ8ú:¨h™k2›6¸ŻZŹČęvłfkÎ,X×c V#šäÄŮĎ2 ‹ &ƒƒ#Ë{ЎŒ4Íájş‚ŽňRgVŽAl~sëbŰȚXŔŽ\;ŚŻłŐĂĄOy 7ĄÔËZ´ÇR˘˛ůč#ˇqKJ/Gßm˘wt˙ź•`!šôVžđŘý|ź8:¤EźDDDDD>ˆ–1  HkcžÍy8:Úi›ťÝÄŰŘJ{0•ĚáNúćť*÷Q~â"Ű2śQpŰí|Â]ÁĹöüv7iŮ9l/rS}ŕMŢjőŽř4˛â-€IBz‰ íôM˜Kl[€éŁťw3ÝINQ9ŁX“ŇHŠăTÓř"éYp§ĽâŒ(<™ńD ö3[L29I6 bRSHrŒĐ3>+ů[6ąq¨™^_gbˇÜ–C”ŻĂű ŽV=MÓËŮă5lýxŰoÝBíŤi˜ĚM|lG,cc&‡ƒO<Žî~|ÁpÚh&ƒÄŹ,2ť:éőAtZ.ˇÝž… źœ?ô>—FŚJ}Ľ|ąéQő´ÎÍy¸yX˘^œ™!ŐÝbuouĎČwÚĚmΤT2Ü`'%=‰˜Žn†@Źv ŘÓšűĄťšaČO0dÜ7BW[ Ş:đ†‹ź˘ Râ,$nLĺÍĘἿbHDDDDäČŘ´i“966m†qůßôďn—sňgØzŇc`¸rřäc7sę?:7ϓ2#–=ďçćţwů—7[œöéHĚćć]ٔ•@B”s|„ÎŚNžWAEßdb۰‡/?ËĚY ŚŻžgžs⏢ůßy/–G?YLÂĚ'|mźüÔ;”šČ*.b{a:ŮŠąÄ:-|Ăt´4qę˝ *űç_AʒžßůÔęŚ9Urb27rűî ڏ0ü~FűŰy˙xÁ›ďgöÔ7 śŸĺ{ĎUŇk†ÖF“œlýř'řhށˇŤ‡ńč\~ß0--œ;SÉĹîÉ'ňĎ6~űĄM$Î,_p”÷_z™×›ŻľCʃ%„z aŸĹęţbÜ<ůžhă姎PŸ;żsWúŹžčšŔ~v‘ÁäBřČŠcç{Vj2ŢUÁ3/œ§q̂gÇüĘŽ:żÍĎĎk•`ůŕń]őÄsˇŰ˝‚`uęšŰXh YůšVM*_žçŞš[đ!b$läŃOßHŽmÓŻ◍žÉ€Ýî")cwÝ]JŰ¤óä|˙˝­ ,""""xĄŤköŠP0ˆÉÎ$ӁÎ:Ţkň]Fƒ>şË9R1D Ii |€× ‹‚U‘5eb'żWÖp:‰şj"‚—ËŽÉřčŘ<ß+""""ňá¤`UV5&OŒÄĽ$âVď`¨Žš‹ƒA,‰EěßW@n‚ §Ý†3:žümťšˇŘc=œ<ßĹbŸ6ů0ŃgVeUŘňvóĹ6Ě PCŐüěŠ÷iĐ AQI”n+˘47…Ô8.ť~F†iomáÜŮŞ]KDDDDäƒC ,‰ˆˆˆˆˆHÄŃK""""""r]R°*""""""GÁވˆˆˆˆˆDŤ""""""qʊˆˆˆˆˆHÄQ°*""""""GÁވˆˆˆˆˆDŤ""""""qʊˆˆˆˆˆHÄQ°*""""""GÁވˆˆˆˆˆDŤ""""""qʊˆˆˆˆˆHÄQ°*""""""GÁވˆˆˆˆˆDŤ""""""qʊˆˆˆˆˆHÄQ°*""""""GÁވˆˆˆˆˆDŤ""""""qʊˆˆˆˆˆHÄQ°*""""""GÁވˆˆˆˆˆDŤ""""""qʊˆˆˆˆˆHÄQ°*""""""ǚ’’ň—@Ă0.˙›ţŔnłMţlLmajÓĺ}Ö'ˇN’Ň3ز%‹o˝c+H˰—–ÎćÍy$űşč q›H„łĆçp×ý{ůŘí[šmG &=m˝xŤř‡áÜř •q5ÇL‰,IYlݒŽŁŻ—ţ‰kĄeZÎůie´ü||Ća‰źsäşď_˛ =8†źŒŻu^VfÂżřĹŠÝnÇVŠÖhŠśmfçĆ42â]ŘOť'H IDATL?Ý]T”]äD­—ĽűžATj7mĎŁ(#ˇŕŘ0]-͜:UNyŻÁżŒ)ž…ĎߙMŹÍÓÇŮÖ ŞÍĹgI`σűŘßĎŰ/źĂéžÉýmŮ7ň›ű IrZ€•ý—¸ĐXrŰbiĘ Š^W‡-™Ű¸‰‚Ö#|ďĽN‚9;yüc7ňˆu”}Ł…•Ä*Kžëm úLĕq–5fĘuŔ aó^>{[&ńv‚^Ž×UR7r­óžđϡu({XăJ´Ĺđ˝óšŽĂ†¤œ|vn- ĐVĎ3/TĐ5'°'dą{G%Ů $şmÇFééhĽěL9gŰ|\ŢݒÂ]ŢÉÍńóMb Đqâ—üŕÔŔ•ý1p§°wÇŠ<ąDۃŒôQWYÁŃs ^—AIœ#sŹW˙ šŸś„\îܡ…-éŃŘ&†iŠźŔëǛč[ [ŽěR>~_.݇đlů(×˙Yż¸Đ§Ű¸éťřÄ.śś*^ý/­g 6‹ŰößĂ#Űâ–L̝ż“_ř&öäÚi+;Ă/^y—×ĎőăĘŰĚ'ž“Ű< ÇÎC•'řŢsçi9Ç•LžÇ…#:ăňËţćłüŕ™ST _Ýź‹m[,MY!Ő몰g˛5a„ęŠNFLŹVl8ŁÝ8W8 bÉsc˝­AŸń7ŸăϞŚb$BʸË3ĺ:`Ň_~œžTNŰőyĺ˛đǔu({XăJ´Ĺđ˝óZŒĂŽĚÍ<ôŠýüŢoŠßůřě̍#.>÷œý˘˛ˇńšOďe_Ą“î‹gyáŐwyýLFF÷ň>ZĹĺˇZ{ É1ăCtöôĎů7H÷ĐČ Ă nă>˙ŠlvőńţŃă‰V?5ożĂ+ĺžÉ×Űh'šßړĞ[ň)űE5óÖ|ŃîVn /%ÄҍvQŐ4DR|?•m33f2ÖßJmÉŚčš´ŘśĹŇü0sY’OTk5Ë}rłŚőş ůť.$Ś%ŕÂĜ*ćÄ@'Uľ0tą‘•}‰scM,ŇvkŇg‚ŒőľPŰ˝“MšŤ”ä5łŒ1SVŃŽ;f€áŽV˝%dÄ­nŇëkcĘZ—=ÜqĺZˇĹu}M˛Đ9r Ćá‰:Z[čjmÁp§qăć˘ćîcOăś;‹ńŘÇŠřĺŰźP5uŰĐJݐ•/ܗÖ۷RŃt‚ęq0\NÜF€Ú#żäľ‹GjFBż3›˜Ţrž~ĄŒśé‰† -ÔßÁă{ˇń‰Ý=üŕx/ ĎAŒP×úšĘ_˄ŮOěŮÜ7ĆĽC ôLĄŻžÓu[řLI9ďőR7Ťë$oÝÎî/§žŻŚçş|ÚžƒU™IŘP×ÔÍ\ž#čkŁn` ž„D2-Tv,Ts&A0ý LĚz˝Ż˝‡!3‰¸”dŇ,Ő ,rN›á4LpÓŻźÂé…ň\čb‘m‹ŚůádM.äŢ}EtžR˝ü‹˛5Ź×UÉßuÁŔĺt`XlÄFĐeč­çőőŤxŒĹΛշhŰ­YŸYß2Žľ°ĆLY5k?î\š)u}[Îůś†e_Ö¸r Űâ:ž&YüYßqxźŤwť&ś¤l*š:Xľzr(Ž50}mœŻóÍÚ6Rß@/›­îLJsíTWO`DšˆbœÖŃĽĘa%wk1ŮöľçŤŽŞé˝XIՎ[ŮRZLљc”_—kDÚxľvý+ź~â'!%'Ăô^>L†1]ń¤ĹÔőĎxţ›ĎÝ;“)?ĚńŽyT˝BœlÁn5‡ăęřÖ43¸xÛCœ}űß=OYĎěý Ť+`ř× ďXNœŤźîńZ¤y=˛Ćfqßý›ÉXĽé)Ť]ŻŤżH7šŕ™•h÷ő?,ÔśÓš(‘ćĂ6î|]oăĘő–ßëńqÄş‰2ŔžzÁÂ@?í˝&`#-uňcq†ËI>†— V-Él̏ÂĐ4ßÓń‰nť‚ÎtŠłíŤTY+áőťĂ†a˜đ_ Výţ `Ă9Ťšü@3oěXŃ$כŸŹNĐÓ?‚™KŢöRŠ[ĎP54YІ;‰Ě8ƒŕ@+U=‹Ÿă=Mœě™űރźÂt܆ÉP}3-Ą>°¸Ů°k+űJÓIqéďĽúŇEŽ^čaÄ\‰lٜKAś‡źŒXzß}…YŮÜîŇ4˘’ŮścŰňSHŽącřÇčî¤üü%ŢŤóry˛F‘ž›IQ^&sě\zůmĘă6q׎|ň“\ŕóŇ\SÁĄ t-śr•5Šôœ ó2)ĘqPőÚQ2śrלLyŠúůâˆ%oCEů™ĽsěŮÓ nÜĆí›=¤ş­L ÷ÓPUÁáÓ-ô…2ďČĂĆí[ؽу'΁Őô3Ô×MőĹrŽ^ęaÖűő˘u2gŠśkŽ[ƒ>3oĄH.*宝yä$Ř Ž ĐPy‰C§ZéŸů&´dŮmŢů>ľŮmzZJpœîsGůţť]“ŠyôĄmäL}°Řœćěë8Đŕá\ ŃRcćĺz ýx!íťZcÝĺc.ŃŽWoq'fyCęßaŒ;á´ŤŐM^i ť‹ÓÉHˆÂÉ=^‚s?P7ťÁIܰ™ŰwQ’âŔ ČPW;ŐeeźQ>ľ¨‹+GŰLĎ Żq¨sŞ8“ŘśŤ”[JÓI°91š×_ăľ˙ ĆĘĹŰ`QK–ÝB→Ő)çĄă4Ĺd-~Ýf[Źčü]ę˝cąk’œwĄŽË+[čçČĚż i^i}/Á?î'Řě6ěĚęćCŁ“Ft´pF9ą™c M˝ůYl6,A?ţ9ďÇF\nüĂô Í÷Î䧯߇™ëƓ‡ĽŚ‡ŕrŻ+B}Ÿ^ɸ˝ŹńjNŹ÷ľ4i;îćћ“qMßô ŒŃqî?<ÖIŔćáŢ_ÝËÎx;`ú}t?ÎŽu2ˇˇ†×OL&Ćý˜†ťmzg›Íř›‘gGv)wZh8|ŽĘënő╠ńŤkʌxM2ŠÓIŠIbSqI†ž ĹwěfgÜ0'ßx˛p–*3ŹD%¤RzÓnîßÇxŰE~ńV݂+_Mţ“ěͅäGƒ-)ƒK+‡˝Ďáł-ôFeł÷ŚM;z¸Ř4L0*‘‚ÜLŠ7$k5ń6ŐPÖ1+‚ mă&Š §ś‚ň^sÉmĆiŃŮ|ôĄŰٛ gÎrđD9çę0=Řťł\ł‹ňśÉAĈĎbďîbś$çtâˆIfű+ľď_äŘĹ6c2ŘV’OIÂ0kXđŁŔńYěÝľ‰m…)$8]ÄgdS?ÄŮ8QՋ-łĽšä¤f°g{"}/přýzšƒÉlŰZČ žqŞ*{™ŐďŁ2Ř˙Đ>nKóqć­Łźpč<§'H/-ĺ–-IŒÔ4Ň>fÁé˛ŕmďÇLI%Ů1AÙ÷9ZŢBU}+őmý ş2g”с‰›m[bi­îљFfş‡¨ŽjŞĆâoŤŠüܞ>ƙ7óüá Ż%sÇ Ü\šŽĽŠŽĆŤ>(żtţĆף͜ßs•XŠ:|”_ź]Ćɚ~\[ء3W{=uŢůϛpň‚# šŇȎˇĐ[ţ>ŻŸŽ§źś“ößź+u[“rŘť˝-š DŰí¸SłŮÓÑC§9tډN{ťwSš8LEíŔÔ]źÎ#ŠÍ÷ÝË'K4=Â3ožáČů6pÇMĹZ;špů tŠ:i e‚Ĺű–5a úĚ嚙*ŁŃŠlIŸŕŇ鋜,ďd,1‡í%ůšz)kž|“ ŠěĂt7TsŽËĹĆÂD˘ĺüŤŻňÓ2ďäűŘheú‰ß”CR˙%žţéQÎöC<(„5ffÔ[HÇ qßŐëBm×&[hăNeőr˙mÜ Ťží‰ěůŘÝ|lK<Ł5çyő­÷9|śĆaYy)Ä[Çi)ŻĄaxne™řúť¨ŹóáْE˛eŒňˇňZ͕9y›š§8…ŘŃ6ÎśL!Q:ÚĆI˝!—äžržţéQÎôW0V.Ń‹˝‡TöjĘ[:WĽœg}Kź…Ű+:—~ď¨÷/œßeŸwĄŽË.[ˆçH¸ăđŠëű #:›S‰ň÷qá\ŰĺuTLż‹ź-$¸Źô×ÔŃ_`•—u^ Mg:Ľ\ĘkćÜmń÷rŠÖKКŔ– 3*ÝĎЈ“ ĺU4Ě ÖÇéöÁˆ"Î˝Ô v%ŽšFfŢz'ďĘřűhœľaˆŢÁ XÜ$ĆÎčŽtśş1=T5ĚYL†ťúđšąY’Cî9Óy3Š­ä\ü}œ?YÁÉ'9\?=4/PŻötn(tc¨mš1˰cł0ýƒÔˇ/:•vAëĐf†ĂŽËkR2—Oƒŕ`75 œŽ˜?ďËĘŰ2˜c ˜ ×5P;ł<浍ƒ( ó“?Ž„ţl)ěžaĆžŁ ›`wľÂ:šĘZ÷™ eU´Ď8m̑Az|&Xو›*O8eÇڞڗRó3H¸|j$će’čâRýÔmŘU=C3Ă9^Řy[…ą.Źv aÜ § á´ńRÂ9Ž-í%ąX‚ƒœ?×Ćňf~S_ßÍqŮiWÚĒDAöätEKb…ńÓů7HĘN%.ŘCeĂÔSȍ•Ký ťěŤPN`Áq%ÜüŹđü }œ\ě:'Ěó.ÔslŐŻâ8ź.yňÓtěm~únýą…|ňWä?ý‡‡ř˝Gvą‰š˝&`288‚‰I˙…cüŰSŻđƒ7Îó^E 5 -œ?uœ¨Ľßˆbă­7Pä‹uúýaj!ŇŤ˜˜ÓŤY,ŘěË| { ł˙ŹĆxuMŻĽ4•7Ň4pĺäQ8c•-GV&yöaŞjű–¸~§Ÿţnżr’Kśbý‡ůýOmÄVu‚gONŽülÄćs÷Ž$F.ĺxG{Ć /AâHHMŔE#W6ĚíúӃ–Âč+é\ő˛šĐ lW^ˇXޜŔ–Ä$<0‡‡čŸó¤Űô1jBb\, t†­+y3éďœjŰ1Z.ž§%„?ľ$&âąţ!zgŢq5yď/pÖœńĄôđŹG›™Ţ^چM26ňȧݜ:]Éٚnz*ßçŮĘ5Č۲™ôô΀'W¤ ’@tB,QtąŕĚ'oţě— Żsv:Óý̘~?^f„j5űLpž6ž\žé—Â(;˜ Ô5Óś'…ě” b*9ĺ5ÁpSŸ@ ů=jF§ËąšçâŇcŚ+1.äău/'o+ëÂn×%ĆKJeŤNťv'ڐĺ20Çzhî]Ţ80ŇŘBł?ƒ ‰ňb.Ń5hbII'?j˜Î'ŠÉńĺÇpŹĎ‹i¸Č͊'Řq†ęŠi++—;ö‡_ö•–s5ółŇówŐĆÉ0ÎťPĎ1‹g ŽĘ8ź&×.ó1}49Î÷Ϟ":.ˇ-ČčŕCdńÉÇóÁôŃŃ949F˜ăxçyÓô5WsŽ{w¤fPœiĽ>peąĚýŒăT)§?–G0ˆ¨y}c9ăXXýgĺăŐ5ż–‚]ő\č.ćŽ4Ľ˘¸xqšůŢz*ťB¸N?M|ЉƒW%äbÓ-ĽäšyńdcŘŘXšOâ@ /Ö1„ćóľ4߸“ĹєŸjňő.´`ՒŔî[ IąôóîÉ&‚`c´—ŸáÇ͝Ü˙ŕ­Ü˜˜ĘŢ]™œ˙eËâŸ9š+ŕĺěńnĚŢBĘćBňßëŚjÉh5ČđČÜŁ˜ř'&ďÔ..yJżęŒ('nĚńńyWč Œ3a‚Óĺ"Ę bç›Q.Üî|z<{öĹ­aĂesdœą/ĚfZÎ2áF” ˇ̉ Ćçţš`b_8ś.mčâČ[děßDFB{ďÉâ–ŰźÔ•Wpät=m tŇőďO&ăcW rŠi*6‡‡Á‚SŠ‚žAZÚ 1ńdĆGáŽr›J†cNgYf„j-űĚBB.;`z[(ďŘJvfEš.N_…č ŠRÔżuĺnôꞋK™Qao-lj…,ˇ]wÂ-C8mźd9B­gˇ›h ˜C#ĚťîJ¨FŰŠn°!;‘ü,'ď Ž‘”“NÜ@?{?†‡îÍ!-?ƒř3^úŠäĽ™´kť|̕ŽGËű—Sö–s5ółâsdÇÉóÂ9v-Î˙ĽŹ{žL?Ă—oŕ:ň3Éľƒék§Şm‰•ĂĚ!şzýj#)> łgŒ1Ü6ۂĺvťƒÉsmÜżüžąZăŘ|Vcꊈkisˆ ĺ]ěMó˝1›¸KU XSؘcg ˛…öpŚň­¤ŸÎœRî,°Đpř<Ł€%ŽĚT;ÁžAúŚó1ćĽoÄ`Ť'Ă!<đťţ„ŹZRłŮoÁîĽĹk2ă™ćp‡NśP˛?‡¨ŒTŇ,-4/Ԑ†Ĺ4Żz|ěíĄ}Ü$ŐGjœąäŞÂ˜ü‹= šxgaGíU`7ňňsh›§-͉qFÖí[ŠÉšť&Őˇ:m>ĎÓ?nŁtëFśoĘ ĂKÁöÝämHĺĹçNRÂ]ýľĘŰLć<ŕ Ťerĺ;sésʞ”ÇÝwnăƒńţ^Ú{‡ľÎ;}xmęärŽ×˝Ď„SvĚQŞjz¸+3ĚütÜę0r3É´órăŐˇúVĺ\ cĚ ĺxÖ0ö]=kÓŽĄ–!Ź6^ĽăZ-ĆdúÁŕU+NN>m ő`>ję{š';•Źěĺ}lȍe á͍nęÇs(Iͤ0ڊsI˛Œ^ŽÖ†ń>ş'ŰrĘž–ĺ\f[ŹäYŰqr>ác‘spód¸Ů|C&n#H×Ĺję.G cţŠ˝~ŤÍJĐ;Ä  Ѯɀ{žஹ\9vhp?0žĚžąÚăŘ,Ť5^-j=ŢŘMź5őÔíńPœžËćřjދÉ"ß5ĚĽ%§/bÁ~˛[2ˇÜšťŤŒŸ•O=15œDGÁDűČ:ö36V— —‘­XHÁŞ5ÚM´ř'ć}j:14ÂHœv; }r՚ZÂŁހg´’Ÿüřܜ€Ö$0B+W)?c“ůqÚ&Ÿě­jÚëŃf†W´Fş9wŹ›s'œ¤mŘČ{7Q—ËŰj¨zˇçŞÁ/2ú“Att 0<şřL‡‡ť?z7Ćú¨Ţľ'Vť]Ă*CŘmźJÇŸ|ÂełZçyłśáů+Mź ­´ßšJfڇěX'ÉŁÔí'8漢yœ’Â$ŠrÝt&¤b﬜55öšŒGË*űĘĘššůYń9˛Ćăä|B=Ç"í:áÚćÉ ŚpˇfŰ ÔpđlŔpgóчoŚÔŮÉk?9šY œN&##c{i1ÉpG“mŔŕÜ>i#!Á…ŸöŽA‚ËíŤ8ŽÍkƍȸö|­œŤóąą$‘ÍisĽăl m đźćď' ł˛u;;źœzޚžP{}= KHąaĐ7Θ ¸Ł‰›g$[ôÔŁ˙ááy—܃˜Ě ҝVƒŤO ¨œř˝ô,{Ž“ABB ´ľöŽűcđ`_`DĹ’äšťŐ )) &ý]ëűYÚpűűéöƒát‹‹MçŰÔ žšiŻC›YR6óŘçöą;qz.á5e<˙vCŚAllÔź'adô';™ńX ŇŃžř9eÍČĽ$Ö ŘSĂ;ĺŢE÷]n„j-űĚ|Â)ű4s¨•ňśŘÓ(*Čfc†ŸšęŽY7×ţ\œ=fŽ…qźk1NŹvť†S†ĺ´ńj780HŸ Ft4ąsO W,IŽĐëÁôśQÝĈňPrc&éŁmTw ęk:đa%ł ˜ÍYNÚëÚf˝—_‹ńhše_I9W3?+=GÖzœœO¨çX¤]'ŔľË“3} Ÿş#›˜ń.ŢyýőS7-i™ÇY1lAücs:™%Žôd+hlƒ`/Uő٘–xr3ćÉź=™Ü4 ćX;U-ţe÷ŐÇćłăUd\űři¸ÔȀi\źŰó] Ô5‡7x†…úÉBŒ¸|¨ŇeS‹bÚś+[Űp8 0ęcnWű iŹ twĐŕ31él+ŒžźŃlޜŽƒ 5-LÎྐ\z+_xě~>^=y÷¨Ď‹Ď#:‰Œ˜™)XH.Î#Ëj⭝łé‚ć™N`MbC–FZxżzdý§ˇsĄÖ‡iMŚdnْŮ\‹%ĐυŞ˙Ÿ˝7ýnăşó>?UŘA‚ ’ ¸/â.ŠÚeْ%ۑă-ąă¤“žd:Ýótfé9Ď93óf^÷?ńœ™óôóô¤;ôćŘrËňŰÚWJ˘HŠť¸ŻŕÄTÍ .I@€‹\Ÿs”Xp—ßň˝ˇęŢşĺHęĐ¤ă\:ţ_eĄŚÜ¸áFĘh$}MԄ-­­ÚΙđ›ś)ÔMž IDATg‚Ž‘ˆfj+7žnD‘9ęţ€(íŰ)Ÿ iX˛Ö6REÄĺÓŕ"–˝âI•UÁą ˛wœ–Ţčí‹5*dpíî •m$•‰É& ĆÖśc&>âî;zűěPS~˘žŇŕ8Łëö§Ĺ‹ŃˆA3ăŠ/Šm‹‘dű5Ž>Äďă(ąG˝˛k’>ť„ ĎĄ47ź"SY!śxňB^¤o`IHŁž.ßŕčęVIßČ(>ĐTpČě {`Ýş z”pߡÓĎdś'9’ČŘąbÍą¤ä’ç;ŽIj,ŐÇůĺ;uŘBS\ť|ƒŰög.-8—ž)ÍĺŻ]R4” Á žĄ^Ú2b¨ľ›‘€ŠŇĆJŹkě!USE•^fş˝›Ţ•9rą‘ŘX;IŃŤ=0÷Y!49@űŹ„˜‘CĄŃEO"uF“ČčŠ}Ą’ĐWîMŽ}vWr2>@4gľbb]:Ůű¤ăš|^@•““óˇĄ%Ĺ@„Ő?+Đ^Ś\iT”fc+)ŔŚ“ L+‡NçLŠßh˙q}”E  ԝ>ÂÁľƒ‡=|Î|9ĹTfgR\’‰*BÔĽQTÓȏ硝ʧę&ŞW^pŸŽ!Çf&4mgÂDV)?yœs…!ÚżšĂ˝éĽBÔé944”Qb‘źFđ„´™ů:XBžBîYÇ]xĽ­>‹VŚÄœÝMfY1Ę­˜CÜ!‘´Ź|Žœ=ʉ<ąűˇůúŠg5ŘUĆ.•%űôO‡Nvc_É..ĽŇčd|!„*-Ź~'Łăó,Fxvnsť†˜™ QXeٍ8ŸźZ ŁŰDŁŃ ÔÔÔČ>ßRTovąjÔ띥˜ă‡Ę¨,Ě’ŚE%YœŸŁż§›;mS<Ó둗ůŮątŚî\叭ËGd‹Jj9V•OAśƒÂăœg¨Żť-ĂLnľ~-˜8ő“ šşĂç3šœj,ÄŞƒÂeăуNÚěţĽ'ç7ń›wŤ1‡ßÜ ŒóéďŻÓ™Š˙üFɚçkeďţă=K6˙Ź?wó2ۖđ šŽÖŇXfÁ’ŽA ú™Ÿž¤ŁľƒűOŤwłDë!ţú˝šgwFVËşÁ@Ů~s>MB3íüîƒ'L­KŚÍĘůěwđ˝ô6ďЄ‡ĹÂă+ü÷Áb~óN%áďG^écßrĚhłŠ8yʊšB3fƒ Ůďfjx{÷ťčš[{GA0ńÚŤÔ[ÓĐĘ~#ÜťÝFŤXťąm’‡‡—?印‡–ŁůjĹŽs!'ŽUQˇÜžĎĹÔČ0vÓ1=;7k_‹}É)őهOŃ8@Se>Eš&L:‘×Ĺäč0Í÷ťčvDżĂsŰ"ŮPrrçâ\™Œ–W:ß~‡7KœöüifĚz ×ĹÔč(uódz)§Ôĺ›çF_H Ł´œ*§$CŔłčĹëvĐÝڇˇţJ–nІîó_?Ç\›M6-U]Jbfó>ŢgáđküĹÉŹ5ĎâFšůťOúKběűĺţ°×˙čhxó-Ţ.őóđŇç|5Y°ăÉĹ ÄĄ™‰ÔËw“Ľu+lĺ׈őEНřúG|/űx+݉ÝÎéUœ9^NeŽ!Äă˜ŕᝤ“x˝hŠŁÁ‰~{ą›¨oŒłxůçŻqJ×ĎżoŚ?Ź]ĺiţˇ Lßúœ?lňúƒmieDהmô=Á~n=Ĺߞ„óWÔS¸…NFkÄó.Víܖ6ąyŽ´§I@‡Ÿ˛˜°˝ĚĎňë—ňЋë×ddÓüóۙ4Tž|žő“´´öĐ>î‰ňěĄKyÇë (Í3‘Žđ-.0Ň×˝–!&6œÚ+`ĚŻŕĹ#ĺTć›HWK¸ćčďęććă VR'†ŘŘŹŸąęŘťoâĎŠŸäčU*çe¸oâ?ŒŚ;a+řł_%łőţţöl+ŤńÄIj çvž#ţv~wą“éˆŞČŠiâÂńbližŮqî_Č˝‰¸ŢŲgp{ŁoŠ5ń]Ź",ŸśĽLHÎń^ ťÂĘĹŞL÷Wsą7&9UPPPPPPPxŽ,őüĺOKčżř%W6ťƒšĚú2JxóőJŻ]ĺęä÷c>ËĹjŸÜRPPPPPPPPPPP؇¨ŒŘ ÓńON1ă°”’íĺ‹ČKœIG^âÓ†v¤ŽýD˛ŔPPPPPPPPPPPPŘGXáWo6Q›.€ÚÂĄj3ÝC Ÿʐ”•U…ď1Şô,ŹË§sgäda|:[e…ďAĐPZ{)­’&íŸ>™ßů7Œ(Ź!śÓ€Őjĺ™U…ç uéqţćý&JŒ n+çX­Žąś ćeVPPPPPPřŢ ăœsĄąäRQQH>ÓÜúćߏgGw‹¤ŸŹ\Ź*((((((((((((l—XXRžYUPPPPPPPPPPPPŘs(Ť {ĺbUAAAAAAAAAAAAaĎĄ\Ź*((((((((((((ě9b? XԐ‘cĽśś‹oši/kžłk¨tdçۨŻ/$Ý9ĂlôçtvAMF^>uuĽXźvěž$—/jÉśŇXŸvnG ÉĺďZ +­hxb}uLŞíš(JN*읥{5RLš˝Ÿˆ×JĚÇÎ^´Ő:ŠĘ,ćü…ÓźuŚ‘—ŽTPa–™ŸĹíĐÖďKź$sŒyžě˛ b9 8Ś÷ŹŞ ůŐkdëUˆ˘Lß|sťŻÎéŐ/đçŠ0А˝´ŒuŃł źsc/Ą.:Ě_˝^IśNBt;:hŸMÖ1ŕćşÓüâĽ25HNîôwÓďN¤( ŮĹemŹ R=Ŕ‡—ş°‡‡¸ ĂVSÉÚŠ,FŒjŸËÉŘŕw›űvŻ;ľš„sgëŠĎOCp1ÚÝÎWw†™Ű¤ëÚ˘ŢţA ÓWžäŁNϖďôJ­]çšĚIŃĚŠĺtڃŤ—Žó`n‡úł[őîKśŤŮG^ĺ?˝óv#iö żżĽáíě˝<|,őüúg XŁ:Hfžő ˙ýş  1rüČj‹ĚdŐH>3“c´=ę¤eÜK¸Ä§Zł÷$›hL´ń%ecĎnč]ŠëÜ{ăt :ŠśpćTŒÝ෗§ŠňëˇóžĘĂß}ăâđ^‰—'‰óMž'ťě 1ËÁąvţĺ“z<{KŽťďňۋ­ úwť% ›iáw6ÓĺJEěČ8:ďđO—;O0Çľuź÷îëüÍ_żËoŢ>Ěђ 22Ó0†I0Póęküň•*tݸǟßçć`[Ă~ţ“Ô¤…í0PçpöÍăÔřťřĂo?âż|ÜM ę?9žůî*›S/VfďäJwl“žŕČc~÷ŃşÜJNŚƒ…2ŤmZVíó_ďždűZ°DąÇ÷řčňUţĺâˇüë};!@˛wsńŇ5ţřů-.}ŰŐo)ďB{4ŸKB ů\ĚĚ.0˝ţĂKI2`(:Ä/zšł•:ڟ´péó[|őȎ`;Ŕ…żĘ›•VU{4{O˛‰ĆDˇS6Śď†ŢĽ¸ÎÔÎakÔUŇhvÓŰ5…[–AĽB€.͈θ‡âeÇIÖłÄ^ĂíUbź‰,áwŒ30ł×Œ*á™cp~÷Wy6CĆçăiŞbGášcș`ů7“cŁş[™ HřçxĐď'ťś‚bŐúŇ,M7;ižŃËLĚĄ,á›ĺ鴒“)Çc§gxçÜÝă;xž[őŚ-ľŐTf¤ŕń‘íj {F¸uw€žĄI†Ć§wŮżČŘč}ý#ttśsŤwĺeŻća*IĄŁ {˝xd‰‘ťßń÷˙úĹş?_rąÝ‰ěĺĆĂiš<^:WUă§ëĘU.5Đ38FűŁ{|puˇFý™F*—çŰ;ŁŮťEmŞ1ŃĆíé[ę] â.ĺ›âůO"DŐIŹ<3zdäĺóSô<äfó î=/ťABcĚfqű};'ŚmŔKČH’ ěň3ސ÷ü`ń}g%vRWžœ`ń~ű ˇěK˙-ć ÔÔć`X÷uډ dç“kŽf N¨)ĆTœOŽhg\0çd˘ĂĹěęöW™ůy˛>“<“@żăY‚ŠŒWŽZpw^ăÎdźˇëRm×ÄyŽrRZŕÁgŸńŕűRo QY*yíěŚ>ëĽ/%ŰĂ×€ŕÄ#[>ƒb|l–`ţł:÷jŚ‚Ôűp><7žiďƕLc1/ÍfśőOty@UTLľI@öŽÓÚď]óU÷Ŕ }Ţ"4”hčí î fďÁ ¨Ńi­ŁúÔAĘB#|wo墽¨ŐĄŰĹÜ­z“ĘTČ.Ôa۰RľYěoăró$ąŹŻřG;řäÖĎÓ‚XŘUJNz۟ňtƒŃ5”8Čy„[móH€ÖdÄ €ěrm<&ä`bVÔäĺf >ǚŤżö’ĆDjKŞăn/őˇY:4UEšqómъ˝bcoyű‹8VV×ţĚRYĂšŁe”di= vwpĽy GřŔ N§ŞŠžăUVŹZTrĹšizŸtrłc†5ŔŞŇ¨<ÜŔÉj+V“1čcvrœśGOx0ę!Ś9h¤üX#gňÉŃI¸łôv<áfű̚흂>›ĆŁľ4•ç`Iע z™™ĺÁÝ6Ű×ŢVéť*ů%(- ŞXCǧWę́áüą2ʲőŕu2Ň×ໃأݵßPÎw´jšđâJM!ě˝­|v}ˆ•g°ăëG ‡ki*ˇĽSĄ%íă´4ˇ3l=Í/NZĐŻˆOČÇäăŰüÓí)Bj+Żýü4G35€ôbo˝ĂďnOŠZnÍcî€G ž~ 2RÚPËńę|lf:ĚĎ8‘Œ‘ËNŇÔţxy‘Št}‹k{¤ŇkŃ ƒ,Ísdţ ˛ BŁ€ĽÝjľń…uG[ÔŔšJ‘ÁkéŢö)pj,8´”błÉ=Żäd2rRŸE}] EVJm&fo}Ćż´ş—âzul™7)Ť7ŰEŃĄ˜âIíŕ1~x˛˜<ÝŇD¨éG?Ľ €Ý_}ĚĹŢPÜql-đ;&éőË}Ñ>ˆ1‰łŻá¤jœˆšďŹ1ú0eȋtÝíÚhŽÜjÎטjî˘oůę1č"j͊ Ż–ăcŃłt!š–ŚCŘ5ÍŢ&Űő×HĆ泣mő mŞw1jG"cUŠ46.bˇÓžuŇXTÇŤGŠ(ľé€˛s?â˙>˛ç)˙ţÍ hŁŘk;$:ĎŘCś‹Đ¸˜Çźđߤ|ěŘÇ$pą*}đ4ď‰N5ßá^Ŕ@ő&N;U¸ş|ˇQ0P÷ę+źS í›Ť|ütŸ:Ę“/đÎËç(6]á÷wfX2ŤŽęóçůq™—ćoŽđńˆ9-‡cçNńĘ;šd~ň5 nŃ.…§^˘hžŸo.ˇ`÷ë(j<ĘϜŁ$ă:żż9ľÔ.ƒ I7ÍőožáßĆ<¨łKyőőŁüđG&ÄŽńheŠ>Ćď Ś<P_”N<ő"é>ZÜçžGCQă!Î:A~:üöËA7Éîľĺq5ĄĆڧżg”ôŁÖ弥1.őë‡~šk_~Í˝1/rz1oý䯞“Í­‹_ó˙ţąŠ÷ÜH‰.DßŐ/ůcçňÖŠŕ$úçŻpüř ^5 ňáÍôyc+×pńkŽMmqIO?4Yœzó,/Œľ>⣯&™ ¨ÉĚ/ăÜ9ËńąB8Fú#l}ąćgĄ‚3sLK2Ži^ňČĘXrś@fF‚wœÉ•gÔŮźđb9iö6ţŘš]Á°4žÄűÂ<îßáŽ_Żäd˛rRŁÇ”žIĄ-“4•Ä\ŘŤşŽ#†źšîIa˝qŮ.Š hbŽ'˙Â÷o.pŕxŐé=ŚÝ!2 “R\ívQ ˘cĆŰ×őľ¤dœŘ*ßżĺQ,>Üi„4_¨"×?Ę´ĎŻNlƒSvƃE”˜ň(É[sĘŤfuľTTŠwEłˇËöýMŰvś­_óÍÂćmŮZ;ŤR˘íńÇxœp{âĐI߂Ž'‹8䣜.Ö0ŰůëC>ä  ťÝ^‰“ŕöďʎAžúä[ž *Ź™‹|őńn÷N22:Âío[éö Ë*¨5mžŕkËQSVm˘ý‹[\}<Š=°|‚_۞}Fš›š3ć]:Ýrqš‡ Ş *KL§{— QQX’ƒ>źaÚlŠ,Žž~úW.Tc,7şßâ釈íčIÎjYěžÇ‡7÷âv/2>0ĘŘnÜĺÖäQ_nD ŔPß8ŽĺŒôÓ6ŻŁŚą‹F@k.ĺHš–™Î~FBK}Éi<ĚąŹ•:TXŞó‹˙áÇüŸży—˙őý“‹ëdB‘ q‚K—š•œLvN:Çšsí&ß lź[™Xąĺ˛zăľ]Š9ž‚Ě ŇÖ5ʄWBĚŇÖ9@[çŕňaű\ –ŰSĆŐ׍¤dœŘ2ßӘŰ҇;ž´žÓ…jć:ťé {4UvpŁmž hćÔŤMÔZôhÔLš…źđú+\(]şO ,­Ŕîźfo“$ř+šśíl[3˘č] ڑŕX•|m“8ĆăÄÚŸN†ŚééexAd<3t÷Đ=8‡KŽnŻ„ItžąÇlˇ‘XĆźpvfěŘĎ$pąb¨˝—‰°x•Ý ĚxePČ0,;;čĆá–AĂńƒaďŽ xpůeĐÉ\ţŽ Ő @•mÁśŞ÷ŇÂ4}ƒC<蛏aËĄŒkhtíá’“ÁQ7˛˜Ime&˘6ŸĆJ#Bh†žAĎÚßÚçpĘŚB+ˆçťKfŃDFb˛ł‡Áđ‡Yü L;% dˇś•rdÜOťyě 8Gë˝.îݽǾ`|mÓäs°Ňˆ Íót8ěn° A-†ƒ Œš1Ü9ÄŹ$ /.Ľ2ě”!maĽ=Oçžů!ćrŁO?Ôy4՚ĽZłŰ;°@ŔŇPG}ş€ź0Č˝ž°™RpškŸÝŁC]͟˙ĺOřßß­BÝs—îÍdů€Ž#ٸ;Z¸3Bc;Č{ݰxďţË˙÷9—GLœ}ó(uëOzڔƒm=JNŚ,'%źŢĐ&+)qÖWŢ$ąŢ„mE‡âˆ§-Ů×Z°BŒyˇ/"‘Üq"9ůžĂˆY?Y‚)4ĂŁ'sŹÝ)dřöUţýÖ0S%?ţůřżţç÷ř›÷QĂ #Î厅ĺÜqÍŢÉóW4Iąˇ5ąślĎIÔŘx‰[?ălOJt2šń’°ďöĽí˘ą“cÇţ$ĄgVĽĐúđyv:Öjx§řćƒ/é0ĂÜÔš€[ýîň—eç,ă.›šŠ÷j¤ůA7-}ÓĚt?äŁîX[%33ł°nŔ’q.z‘HǜcFŸ•U ˛kÇş“dŻ Y&ĚLgeÇüÝŠgŐŠ`ŸĽż„ĺ;Ţ[vqĚ.,oÉô1ú¤•ŃĺĹœŘŰ6•…U™ ż›#/p˙?.Ѣ’V•ě´OWórž•†rOžxQSRfEë ŰţŹ_bĺn†‡§łr(Ô ČžFfw‹ƒ˜YÁkG-hdíˇž0´îfch~˜o/óí†_ęŠyĄŇĐŸÜ›Ä‡šŞ†2˛ćűřäé" FZŸ2rř(GŞÓčlqĹ40(9™âœŒŢ͘ëHFŢ$Vo˘śŰ\‡ öxڊýŹáLJ ů"I'Ś’’ď"ZƒvéŃd"‡đzŹÂ+˝ŞžŁŮŢţ>Ú#m{“˝ ?şĂ?´4“–‘†Q-áYXd‘B~üë2˝LN-ŽĆmr5;ĹśHŠżv†äŒ%ťT~*Ǐ8ĆăDÚ#îa\!aß=‡śŰŃąc’ŕKą!yĐŚgRiŔhГaĘĹŚ]E!;7žëÂöz 6s!§_-䅗œôwvqăÁăŢX‚EÂĺ^ŽŁL0°´ß]Đk1ôŒeź÷뢾ƒŸ F/‚ěöă@ˆăťŠbł#­ăi›`ĐcAđŻ/N@^¤˝ÓÎé<+EUEdtô0ŻĘĄŞXĂ|÷(ašWš›W?ŒFŇD݉=’LT™œxĽ‘2Ě\ű}žyű™şâÎUˆ ^kĽËˆäjć˜[ąŻĎɜ[ Ńš…ÉܤĽääźI¸Ţmíhý˜ă)‰íŰSZÉŽădŒ“ďb.Żüâ,MąŽŚÇČę/ás91‹#‡óŃ㣭s,úʇÄ5?żú˜†śŹ€ ČŢ zơ>*!ÍNľ-’˘Ď;DŞŰşŸląŽdég$ö…NnĂwßGŰ=s DIéĹŞ&ť”WÎâ U‹ß1ËÄŹ‹E*âŢcĎH+ř×qŤhŞąa3š¨h:Niy.Ÿ\źG—k‹ˆ‘CŁ­HHňę •ěâӋíŒGŘ_ ü¸ƒŹîůŽĺťťElýX~ŁJ,%âě ˙”•ęüę2{šŸ^H™ŢEGř`– Œ˝Ü-jĽ˘°7’´á;1Żŕlĺ/ćŒMwô1ߜˆ}‹ˆÚ /–a´ˇńAçňŠŠ #́‰đ•ƒ >?¨ôzô’(–JNî6ɲDHśí≧dľoďhÁöŘŠ8Žľžmçť4Çý/ŽŇŠJ˛B֟G˘)ޤ1KDöNĐšĺAoaFę`$ěOzéßęN`˘š˝śŘśżvTˇu?Ů"œdëçö‰N&ęťďłíö÷(1RwąŞľňʛ'8lňŇ}ĺK.w8—VˆÄ<.”’ţl‡ BŸŚ÷4oOóřŽŽźň*^>]CEF /ęŁçÖĚĎ`DzQŻ€nůŘżŰƒŰkÄ#ƒVˇW”W–ÔcůîNOŰdßŇwuj 1ÝpňŽń¸ßKUmuUYŒëó1. ŻŮœPšŰěţĽ•(ľJ!hŐh5~“tTXŸćGő&Bö.>ţ˛›Š˜EA$§ą‰Łf'Í{™‰%ž’-ˆJNî:Éț„ęM…í≧dśoOhAâěTÇUORňÝĎĚř3ÉíFDŠĘm¤ ˜˜$ökUôĘCźX¤AšďăۖőĎšnŹ'qÍNą-’âŻ"ŐmÝOś'‰ú‘ý “‰úî{jťça”(){ We+ĄÖ$ Íôq˝Óu+٘SÇŻ~y–ăYËJ/ů˜ękă㍃,Ę&“!Á† ˜Í鈄›Ĺçp0Ag$c‹ƒű¤8žťÓÄÓś•ď˘NÜËě8Č`Ç󲀥ş‰3ezćűGÖlNŹÜmöc~9„´4LëƒAo"[Ÿę™żHVí)Ţ?•‹8ÓĂǗ[ônýŤ„Œ2^ ; cهË­:…3<• IDATě75Z-„<^|Iź!ŹääźŮN˝É´]<ń”ĚöížlŠăxęI]ž§!kŽ™…ŮŘăN—_Ďť/‘îˇsýŤÇ lńôĆ^ĐěÍŘOţJu[÷“-ÂIŚ~Fb?čd˘žűžÚîy˜%JĘrXÔ¨Q űƒŹyjMĽFŠV! KÖÚ{‚(".ŸŘˇő „KóŞlĘ ľŕĺaŻŮ;I×hTjʍŽTF#é+m‹çť;M\ý˜ k$˘™ÚĘŻ’Qgd`^wë(49@űŹ„˜‘CĄŃEOżcŁý(w;ý]“ôŮ%}Ľšáľ ˜Ę ąm8Ť[ÄŇđ"˙éWxť:m›‹”™Žógç ĐŘ;ůč“ú=ńĚHôÔžĐ@Ih„+÷Âޗ 9Ÿ š3ČZé–.lƒŒ}ґTVrrŒźI¨ŢäŰ.îx"Dhů5 Şőůşo´ ěTÇ[OLůŇ;… #my˛›/ŐXޏóËw氅ڏvůˇí[-Çî ͎Ę~ń$a,٢Ű.ç‰_?ă#~Ü%đÝţą]’óďy˜%ˆ*''çoCKÖD„Ő?+Ш5h3­Ź/&ß y O¸đJ *ŒÖŽÔ呩đÎN14ăĹď×QRg#+Mdáéc^К 9sá‡ĚDźł“ Îúó8R—Gžfçýj-Yś ^=s€ý# xB:KGlX4y;ƒSŤŹ8$-Źż“Ńńy7<÷OŰBĚ̄(ʞQTœOž*D@Đ`ĘÎĽşĄ‘7ÎV Ÿ˘ß. ~œ*+M%F˜ŕťť2ľ\mf>‡–o€{–ÁńĽŘ‰Ż~ŚtTUĺSbœf> ^PËۧóѢF§ßě$ýÓ^‚¨;}„ƒ9,j{l:=5dääQ]SJľŐˆFyÜ8=^<~ Ńvˆ_˝QI– B‚ŇÚ;TľáO˝ŃAŰčƗĹëJšx÷„™‰[ˇ¸6ž~*#ąŕ5P{¨˜ Ç‘‚#‡yÁ2ˍkOąo:ó˘ŘUTr’äĺ¤:=‡††Ľr$݃Ń•rŠ#ö|Ln˝qÚ.’ąÇÓŇO%tÖ ęótčd7öE‘ěâR*NĆ|{C V1˜sŠŻ/ŁŇ˘Ceźó‹Ěť|ř×̞âĎĂ`œžˆD˛Ç !-Ö|ćĂ­+JjňŤ+(MŃB ÷L0ąj]v§ĎŸć­#‚C\úü!ís1Ş”ÍNÉň×ć-ŽŁ}–x[Łé]´~L- UÉŐ؈˝ßÔVńęgÜí‘âÔIÔéš4,Ł8]„Ŕ⒮„š‘ěx‰=Ž×˛m™hů'íĘŘą Łk˛FŁA¨ŠŠ‘}žĽhŘěb5ŁćEţ—” DQD˙˙Šç‘đ'łÖěëŒ4ówŸô#–4đƒSĺ”dx˝xÝş[űđ֟ăBÉŇm†ŔĐ}ţëg㘍ĐT™OQŽ “N$äu19:Lóý.şQŚ‚‰S?šŔĄŠ;|>“ËŠĆBŹ:É!\ö1=č¤Íî_sĄÍ*âäą*j ͘ *dż›ŠáAîÝď˘knm]ą|W´âŻßŤyv— 0ΧżżÁ@Ů~s>ŸđűĐL;żűŕ Sëâ)b9’‡‡—?嫑ÁO?4ćBNŤ˘nůť!Ÿ‹Š‘a>ěŚc&ÂčjŹŕĎ~u”ĚÖořűŰł›Ţ™ÜŞ\uů)ţó%kú/{řđďŃЎéUœ9^NeŽ!Äă˜ŕᝤ“x˝hÉpÁ‰~{ąÍá—ůŮątŚî\叭 ú `>x–_ż”‡^Œt^&0ÝÁÍüŮŤ[<ŕ-ăî¸Î˙óÝÄÚç ÔÎ˙ěÉ2l{Ÿ°ŰÇb)¤ÁRĎ_ţ´„ţ‹_re˝+ȐQ›ŻW˛xí*W'wjĺAAAAA!ÍVPPPŘ9bšXMéŤkö*#śÂtü“SĚř,e…d;Gů"ňme…‘†řôƒĄÝn†‚‚‚‚B (š­   °ˇxNĹUˆëą3üęÍ&jÓP[8TmbŚ{hĂ)Ŕ ;˛˛Şh4jACií¤´Jš´c|úd~ĂaA ;˛˛ŞHŒś<âިŸÜ†FŽ™çšţĹş<ťÝ.…ď+ĘK ;J,,)+Ť {ĺbUAAAAAAAAAAAAaĎĄ\Ź*((((((((((((ě9”‹U…=‡rąŞ°7ÔdäpřřA˛•CźVQéČśqědUűŔ.{Á˘–ě‚NžŞĄÜ¸lڰ;D‹Ő˝Ç{‘˝n—˝Ţ>…dđœĎsöç{VE3§~t–Ó™Ž^şÎƒ9ĺm Ďę˘ĂüŐë•dëD DˇŁƒöŮĐn7+1’ŤéŐ/đçŠ0А˝´ŒuŃł°wc÷ý(`Ž;Í/^* S#€ääN7ýîlBŞP40ŠD‹ŐݏăąÍÚëvŮëíSPPPŘ>Ďń<'Œýš˛j°PfŐŁMËŁÂŞÝíÖ($™ŕČc~÷ŃşÜĎÁ<‰ąşŘ}—ß^leП¤śĽ˜Ý÷ٌŁó˙tš“ńçmŽŞh`R Ž´đť›érmŒŐhŸíkśC{Ý.ťŻ? Šć9žç„ą?/V=vz†q΍Ń=žOfîű-ľŐTîęS ßÜ(O§ŸƒIƖą˝%<Óc ÎKÉneŠŘ~”C¸&Çr>ąNJ4p/äţn!ăsŒńt&RœDűlŻŧێĄ˝b—Íú¸Súó}ΛDPěľ7Qü˛oy^ç9aěĎmŔŇ>űŒťÝŽç•Ľ’×Î`ęł^úvu‹ŠŒ$=‰ˇEŹ&boyż\Ť{Ï2ňn7!٤@÷NîďŃbu/ÄqüDőiRbh÷í=nSß>%oâCą×ŢDńË~ç9œç„ą?WV—ľ:tűş{ •А\¨ĂŚÚí–<DŠUĹŢ Ű%Y¨ÄâóGŹ>ÝĎăčnÇín׿ßŘďö5ęM&Í"Í>M"öż_žâZYtYAo[_wÎ#čKy˙WuĚ\ú‚+Sˡ€tŮ:ÖŔ ů˜Ő Ü<ţę ž /[ĺ@珖RlÖ šçěîŕJóŽuÍJĚ>[ÄI,eFBŸE}]I„XM†˝ŃHůąFÎ6䓣“p;féíxÂÍöÜr űŠN§ŞŠžăUVŹZTrĹšizŸtrłcO,w÷„4Ž˝űC^łŠƒ^ŚŰďđ7§¨Ň¨<ÜŔÉj+V“1čcvrœśGOx0ę!ę²ĘHiC-ÇŤóą™ č0?ăD2nҌ-5 ‰qý§+´`OG"ąi\Eňyňr?f˝ÜÔ7[ř5š™ŒX­‰ŇňB”p ßĎ폰Puˆ3uVr*.ƒ=]\{0Ę\0ÎvƔÓcčęśđéHĆć1´Œ Ď˘áp-Mĺ˛t*T˘Ä˘}œ–ć6šÇźÄ”ćąjJÜ9Ÿˆ†Ć8ŽÄä‹íixLśM8&ԕx|–JIÁąŸ1ę™ÖœO]E>ĽĹ6Ę­Aî}đ57ge@MvQU%V*ĘlŘü]üĂ;˜I`ě]"És¨Q}Ră89~iăćH:îTňŽźÂŸŸ´ _š—ň1ůř6˙t{АÚĘk??ÍŃL  ˝Ř[ďđťŰS„‡ěDŢĆ9ĎyPĺääüm(´Œ‚°úgĺďľÁĎkďźČé?@ǃ'ÜëœÂ—ULSmôł´ şXŐű„ě=Nb-3‚!k“X݆˝Eu•”Ľ:ŰF…8ƕ+šÖ2ĘŹĄˆÓ'j¨ÖÎđd؅”Š~ ę~đ?nĐ1tó~óˆ­ŁĚ›ËyůD5•Ş)Ú×ůŠaćił2 "çĐ)ŢŞŐ0zď˙öůnş–ăDGőŤŻň^­Šžk7ůŤmÜës Ż¨çěŃ"ôô;7&4YœzëŢŞĎÄÓ×Ęçß=äZË C.-…Ľ9dŞüŒvö1čZ6eLŕƕ¤¸n Ůâ֑řâ*uš^FfkżśäjfRb5–ĎÖ˘Ę.ćtS%ő%fŇ4ŒšEÔ§ĎpăĘŽ<fJcăř‘j˛\t=ÇG;cÓŽ>źDőé‚Ęźi Ťzp&ßÇŁoŽńńľvîôx(8r“ ůˆĂý šäčv‰Y;ÉůX54Îq$f_lCĂcą­[Ÿ`L$Ž+ńř,esŒTŒáˆ]Ď š…ÔU—R[˜Ž#Oň‚ŽüĘRŞ‹)ÉTƒÇÎă'vÜ1çéúö%q5§Kn'Í/yˆ=ˇ¸ôŔ˝C}tăœčçá`ˆ‚ydŞCô]ů‚~4żTŽä˘żm_A%ĺ đáż\áŰr˘ó„ľ<ŽźsžłŁ/Îh4šXˇŤ)=ÖÄAłĚŔýfnťđ…B¸ěý\yź1Č蟡{‘ńQĆ<ëżŸ$#ŽёHÄŽÉĘý8m‰ü*$[3ˇŤ‰˛÷ńé'7š=- Ç–9ǟžlŁËîÂ霣ëö=îLɤ—äTĄ*ŽvƖӡ-}-†žéŒ47sgĚK§qČ Ę ˛Ä´Ĺä!MI(çăŐĐǑ˜}‘¨†Çhۄc"q]Ůý9F*ĆđHÄŁg2‹Ă]|ůŮ#şźë|*{čŘ̇7F6ěĐŘVű’1‡Jj§Ŕ/;ÚGđO÷rŤ×ƒŒŠÂ’ôáöÖfSdpôőÓżâăDç!)ĎŰxç9Ďą]Źjó¨/7"„fč ˇ†ŒË>‡S0ZąŹ–dŃDFb˛ł‡Áđ•'˙ÓN +/Ž•]t÷ÍB$ˇĚ†yUO˛J Č Ůéđ†"áő†6ن´RˇŒűi7çh˝×Ĺ˝ť÷¸6]> ĺz„Đ }ŽľĺgéxęDR™ŠŻ2‡(Î>­ű˝oˆđ×҂‡ çZóÁ"ł ˆF˛LaîŃćÓXšäƒžÁř iř˜&€@FQŢłöˆŮTé1ËFećJ˝ŮEšdH3tFÚZb°­‡‰0Éîfź2¨ d–ËIŘ>Qâ$î2#-VˇƒŒkh”‘đšŚädpԍ,fR[™šťIîgЍĂ-ƒ:‡ăłŸĺGŔƒË/ƒĆHŚał˜H/;ÂĎÎĺăzx“‹-ÖO•­˝Şl 6íłßI Óô ń o>ňę:ŚZ˘´@ëăqśÔě¸5 YqŹźŒE“”ű éĺZb÷k5s[ąşMd.€ŒŤ§á>y:´€$¨,ËFŒť1ätLlCš|V¤yž‡m 4¨Ĺrp1WôířqhJÂ91Ž#ŠŽ™Xm›pLl#çw{Ž‘Š1<‰č™ädzɒtČë#ňćŞDó4 cM2ă8%~Ůé>†îbVĐ—Rië^aĽ=OçVu&aMJuŢĆ;ĎyŽˆé™UќEždŻ‹ůuY){}xdČĘ0a`jőƒĽ˙ …ÖťTfép>!ěΒĚ|˙ă§r(ĘąQ‘ŢMłSÁHE™™ĐČ}úâńŠźô?ŽŮ…ĺɰŃ'­ŒŽô''{Š?.'łŢ?ž›s"‘9׌ž9ÜkʍľOkłĄył“ťžýť(> j1+Ťd×"Ž”ř y¸‡F Ú(ϲRšŢ}AFĚɧĚŕbjFGŽ%“eéܞs" zJ 3‘&ŃťÉűú¤í_ąŃęýŚ„í=Nâ.sǐ™™Y ´îߜ‹^$Ň1ç˜ŃâŔťôĎ$­ŸÁ)žůŕK:Ě07ľ°F°W}q Đ4ň~uiŒOŰŚ#đ˛s–q—ŒÍ\Ĺű?5Ňü ›–žifşňQ÷ćÖłr(Ô ČžF˘lŃ\ýž9~ HZ\ďD^&ąŽDlľá[ńř5IšIÂąšLdffÖMldćç]H˜I3›0ŸĆßÎ-rz;ˆYYX5@p‘ŮđByű˙q‰•D =ÇâŇăs>^bGR3ąŰ6vl3çw{Ž‘Š1 >Hž z'B”eQV¨ăţ‚ěâ|2ć‡ůŕa:ď˝VL^™ĚGNÚ\JódĆnł¸ ;oÇ>›ÇÉ^śš„Ë˝ţVŻL0°tˇVĐkŃ žs)Yý”ź ŒNhÓ3)Č4`4čÉ0ĺbÓF3„HIC%>_YgăĹcyt_›ÚřüTČ΍ﺰ˝^ƒÍ\ČéW yá%'ý]Üx0Ŕřú­X+Í4IA^tÇG iŔ.Äő^ )z™ _ˇKbąšLdüžŔ†ëďP ˆ¨ľ´¸lg*^Ë"ôE6<•!‡İp—Św'66#•1mw:vw{źKĹšžŸ˙ŝ§Ik’?)óËN÷Q^¤˝ÓÎé<+EUEdtô0ŻĘĄŞXĂ|÷(á׊ŰŻRŞqÎsž'â: XvđĹĺN&$6Â$ü¸cÝ}ąp=}3œ/ČŁ ,c{?BIśĐŸ%ëĽ÷ą˛Žř"#ť†řôb;ăö lŰÉBöŇ70ËŤEšĺ íœŁźÄÄü`3#CFüĹÔćP™ŢĂăl+…Â,7<›-¨ÄWu ěł'm.‡F[ݐä¸ík?5ŮĽźrî­ZüŽY&f],zT[Wé4h˝ŢÔźÚ Vś[hW}°Ű-ІŒspŒ‰s)(°RdŇQańĐwӁäsŇ5â§ś2›%FŚĚšhŚş7Ýs)°ĎŢśy¤-‘:ÝŇÓű!ˇ'ć؍ŤŸZ+Żźy‚Ă&/ÝWžär‡si›˜Ç…ňBň ›ýPbźwˆ™9™o[Ęů›9ńbí—z—žC\í‚ }šÜÓ<ž=Íăť:ňĘŤxůt %ź|¨ž[3Ÿń/­T¨UŞ˘ŚFťî Ä4`çăz/˝LÔŻŰ!áXM5iiD äňŕÖě­vĘž%=ĐŠ—V}*#MٍŘ،ÇL̶݅ŘÝíńn§ęßóżmŽ5IŒŸÔůeúčăqż—ŞÚ,ꪲ×çc\^łH\“RˇqÎsž'bşŘ—ćç™  5`ŇnýýD‘Çč&ETقôőNnýţž8‘ć㘠€`0‘­_˙Š@vś ‡}ů™ż=€äp0Ag$#…>H˛sœŢi Á`Ľöpůžqzí` o/* *ŞŠ+Ô1Ń?N<G"öŮo6ł9‘ăcł/ڌxúО•Pkfú¸Ţ錹Ž°Ú˜lyĚămA/WŽM@1§Ž_ýň,ÇłVöű˜ękă㍃,Ę&“!˘hIó ĚÉ ¤ĽaZ˙˝‰lýڙa˘°Óq˝H†^&ę×í°ýXM l™¨˜œ˜EÚcí\ŃÔi˜ÓťZGSv#66#Ő1Ťmw#vw{źŰŠúÓłKo×ŘšŐŤíŒ5ɌŸTúeçűd°cˆyYŔRÝę2=óý#kˇ“¸&Ľ\?âœç;ԔŸ¨§48Nçh ö|ř'hęEVY¨­L[Űľ…ş bČA{cgîćƂwré¨o•…šňTů ÄŇ+wET›˝%VäEú„4ęëň𠎮nńŒ2ŕMA‡ĚşÜŰß*™ ű¤ÜćŰąw„AS•MyĄÜŁ<ěĂŚqôSÔ¨Q űƒko"ŠÔhcľ…’›wFpĄ§ćT=Ľë@! KÖÚű†‚(""ł°ŕŽ˜“˛k’>ť„ ĎĄ47ź!ڞBlë훨ět\ďQb1Yz™€_ˇCRb5¨˛*8V˘AöŽÓŇëBHY;Ôď]#ÍÔVn|E:#óV{˛âŐ΄c#‰c‰ÄLœőÇhŰ]‰ÝݞcěHý$Śg’‹GD=™Śđ†Ť°–䑞Šk„mŒ5IăTúeGű¸ÜÓÉÚg%Č .zú7ˇФTçmÜóœçˆÍçĽçAŁ~e/œć­Ł%TćRZVʉ3gřŸ~~†ăůϜŞ2Z(ÎV# `ĘË!{uż‹€.;›Q4ääg“žÎ¸Ža†ZƒßŔ0CnM¨ÓŸ•Ÿž^>¨ŇÂęśZÉ7Dęb€žťiŸ)>őo5P˜6$\Ű IDAT“I~a)gß8ĹąĚ ŁÍh;m+‘>ЌŮ­ś3—ÝĘoÔd۲É•‰B›‘•Ő{ľ)—‚ 1ç瑥Yů—ÎťOöŠŠxé ď+Ľ2Ů>˝LĎú‘-ĹJ)ÎÍŚŹŚ–cĹ:Lzý ţż~›Ÿ2ǰ\fvpŒ DÁGßŔěł=öž şG ŠČS#ônX~ĐfćQ˜)Â:;ˆórČŃ‚kA&K.ŽÓ>1ĹI|eF"ZŹFľ÷V:Νćd~é]…*#ĺ'›8d\äń•zźŠégprŠą¨r ¨ÎT-ůĘ\ČšˇŽQŤ@0_^ĐeĺSl^ŠçŹ‚|,Ëýwőľqk,€Q΅sU”giןk­Źž†Ş|3sĺuźsŚƒw‚{O6>[˛dK'-wú˜‘ŇhząžRăRéľźuĄĎ'ƒ %ǚšÜśř5`š˘mÄőö´1œ¨˜ěÜOŘVzżĽ_“Š™ńĆęćšíł­Č*,¤ S^§ÇR\ÍŰoÔcĂI땇t¸ămgŹ9˝•OŁĹŽ;í úDl'^⽓ĺ(Zփ—ÎđW?=ÍQŤf ťÄŤ äü–}Œ‰×ńkxlś;&’˘+ť<ÇHɉDôĚOoűó’–Gę(MAe ¸éo•ÁBcĹšúŐ÷Ž'Ţžk’ÇŠôËöqľĘÚ;g ŇÂŘĆ-ŔĎzˇ&ĽçŤŃľ‹ůMüćÝjţöî;<ŽóŔóü÷­ęŒœ3 Á,‰ (Jśd+[–,9ŽăxÂÍîÎsťłăšŕg÷žynćyvžŮť}6Ěî>wž™qZ[–eKV°$[%Q3Á ’ @€ČčÜU÷Gƒ$4)€AlJżĎcČěŽęˇŤŢŞż~CÎ+˙mŽćgxn'Âţ_˝ÄkÝóO-,aýŚfÖ6”P’ëĹJĆęçXŰ1öœ™źřËČľěÓvxxâłóóňwťçqž\ćő •ËÄĄíümgż˙™&ň.Ë3gyîvszŚ|Eľlžc9+k ) Ú¸ń0ç:Ů}ƒŽÉŤĺSŹeuE>7ÎX_7ťß;ĚÁŃ2žřćVVůŔlçG?<@†*˝œUÄ}_ü­ţžýÁ^:f5’ű›î揬fhç+üđŕĺ×:ó4śňǏÔ_śézŘĂĆOńőÍE—…ĺD÷^ž÷âŚÜ먟Ťœ' )3ăî_ĺ\=<3˝őë{đ ßM­Ÿ{uťxe¸ŒÖľ5Tř!匘<ρ}Ç9<Ç˝iűiČ_ҧ[ŠĎ7DŚ˘DĂcœl;Mtő'x°>ýQčÚĂß-çwçGbgůŮOŸĎvi _{z56€ËřĄí|oç$U+–ąžŠ’Ú˛<ňüŠč4ý=çŘťç'ÇŽÖӐ[˝œmw6ŇTŔ$“DĆúŘżŤgóƒđ˝É[XĂ]w,gŐĚűA*6Í@÷9öď?ÉąáÄUާ÷yľsăjŽ´Gr7^ĂçHVýŽĹ˙űŤŚŻňüW|_@Ý^÷9q ď+ܲď3őu3>Ă3Yüű™MQă*>ąŠžúâV"B˙Ůvśż?²Ď>Ŕ–"¤čÚń ?\ơŻsűŇ;zmŸ5‹9zß´ăň!îăEĄĽ|᫛(hű ÷ŢČüŕyÍďIĆëváßsţݍźö×MŽ^}b˘P(´¸°Š™™ÉŽ›1Á’d;+9_úĘj&Žóƒ˙іqV8šV]Nžö ž?uĹT+"""S˛šo>SOÇóżfű•~ľ‘ÍBÂęGŹĄXn&ײńŕ2ŢŮ{Ĺ_eEDDDD˛‚˘Şžœ?€Ą¤Ą†âÉNf¸tžd'…UY ?K7.Ľtâ ŻďĘp'‘la¨¸c_}t=Íš<%Ź[‘ÇđÉŽyłKöZĐuVE06žÉ3<˙ţ :˛ĺz>""YČÎ-˘bfŠĐüŇ"Bg†닑ˆČ‡Ěŕőz0Ć˒će89MŹ÷çĽŁăˇŃlý˘1Ť"""7ˆgɝüŃ#„fő[JMâŮě§SUDäCerŤůÄýëY_$5ÖËŽˇö˛ťďŞSʇH,‰ˆˆˆˆˆHÖŃK""""""r[RX‘ŹŁ°*""""""YGaUDDDDDD˛Nö†Uă!żźš wŽĄĽX“8‰ˆˆˆˆˆ|œÜÚëŹZ…´>q/wŒńÖ oło4}Ő#OížőPĹ~ HqrěGFRˇtSEDDDDDäĂsk[Vƒ%4Tđ唳´Âwńîd÷Aţńš˝œ˜Ö%{EDDDDD>ŽnmX Ň~nŠÉŃóœě}^—ŘŘyÎ +ʊˆˆˆˆˆ|ÝÚnŔÎű^~™}ş8ŽÂވˆˆˆˆČÇQVL°důüřłbKDDDDDD$,źeŐątÝjîZQAEž“`t°ŁąŻ'‚3łš –°năJÖ5”R’ëĹ$cŒ pźí{:&šŘŮ7PÄęUő,­­`IU#;_ćÇmaԖ*"""""" Ť~šśmă3KâŘń6/ö„!ˇŒ;>ŃĘ'/§ŕWŻóFO“SËŁOśŇšäčî˝üśgФż€eÖ˛őá*wďŕ'{GHĆ /ˇ€šŞrl‡QŁËӈˆˆˆˆˆHÚÂ:߆ŞXŰ"uţ;ĎNN¤ˆŒős˘'ŒkĺĐX—…—ŚÖ´8œŰő/ěĄ{hœžž.Ţ~ő=öŒyŠšcwÎ\3՝ěe׎wyólâfˆˆˆˆˆÜ†V×‹ß€]TLĺĹ+Ěœ‰!Nwcßéq%-Lj˜ă§§/ďΛáؙIťŐË g=ŠC4šR×_šĚ‚şťSŁôOťT4ńäS98pŠśŽa†OîçůötKŠUQLšÜéIF˘óJ`tt‡| Ë 0Jřˆˆˆˆˆ|t,Źpjˆ÷Ţn§?îâ-¨Śő“Ÿŕžö0Ďlm¤*Ť&č'dŔÇ‰e*"'Ⴀjxވˆˆˆˆˆ\ł/=”Ÿüěm^;ŘC_$…ńç˛tÝ|ĺéťX™łôŠ„*"""""" ł°Ů€?LJ‰ sřýaďńSѸœ{ď^IS~÷­;Íé3QÂ.ú|ř3aű˝x ¸Ń( R‘ŤXPËŞU˛‚/~a+‹fZG8gŽđË]Lš†źź ŒŽ2ĚŁ80ˇCqq.cƒcĚŇ*""""""2˂ťcBڗßeYX¸LL„qâ}9ĹľKhnĘšźÓݧ„UKó°RciĂšÎM.iŮʡżú ŻČQçb‘ …‡Ul–4/gYE!%…yT74óř=ľŁýě>:ŠC‚ÓďďçȸE]ë=<śžššŇ*k–pď#­ÜQ¤gď>öŽ\ęěÉ-ĄŽŘƒÁ[VJąďBô4ř ĘŠ)°Cae9Eޙe&Ŕ’eU”ćŇźźŒy¸""""""rŰ3+WŽtcąôü˝Ć˜‹n„BT/[ĘşŚJjËňÉظń˝Ýěß{’“cÉKKXżŠ™ľ %”äzą’qƇú9ÖvŒ=g&‰ĎŹgUŽç÷Ÿ\Aá츜č弟ÍńĘVţř‘z|łšŃł<÷ť9˛¨ŘxŸż#—]ońłś‰ëlŠ‘S8šé2—„BĄ†Ő€?ýocfşÝ̅†NŁŽ¸""""""˛p Ť‹č,""""""ňáPX‘ŹŁ°*""""""YGaUDDDDDD˛ŽÂވˆˆˆˆˆd…UÉ: Ť""""""’uVEDDDDD$ë(ʊˆˆˆˆˆHÖQX‘ŹŁ°*""""""YGaUDDDDDD˛ŽÂވˆˆˆˆˆd…UÉ: Ť""""""’uVEDDDDD$ë(ʊˆˆˆˆˆHÖQX‘ŹŁ°*""""""YGaUDDDDDD˛ŽÂވˆˆˆˆˆd…UÉ: Ť""""""’uVEDDDDD$ë(ʊˆˆˆˆˆHÖQX‘ŹŁ°*""""""YGaUDDDDDD˛ŽÂވˆˆˆˆˆd…UÉ: Ť""""""’uV?j,ĹŐőln]IcČÜşí0ňËŤŮpçZŠÍ—‰ˆˆˆˆˆž…Żj”ÔłyC#MŐmÜx”Ąž>ŽśŕPoçćmçmÉŞXËď>ŐLI†Ÿ\'E,<ÍĐ@?ǏœäPw˜äź i}â^î.ă­Ţfߨ{•g3Žş›/ÝSM×€3ÉŽŽ“t„oŕ-§vßz¨‰bż¤89vŒ##Š\&"""""r]ZZúçŠT:,c.ţ]¸ ŕőxÉmÜėnŚÁ?Éńśvö=ǙÁ9uMlŮŘHE¤—ƒqާ>nÜé´uŇ1b(Ť+&ϚćŕŻßŕŮí‡Ůy¨ƒÓ#.ĺ+V˛y]#ľŠNôÍ üĄśÝ]G‰?ƒ§9:tőP>Ďń^CÝň2ňLœžă§éœžŠť˜‘3ŃϑŽ0EKŤ)őš Ÿ9Áń÷—‰ˆˆˆˆČÇC"yőlăőzŘ ŘWÁÝ[ę(H đ›w˛˝­‹S]ç9qě(żzŠ.7HSëjšź7bł?ZÜř4çO÷ĐwÁM™œ&O†é?{‚_>Ěš”şť6°Ą`N—ŘČ í猘=ĎÉŢřž,Ĺt˙yş&ouřs‰çĚpŚí¸Ú2‘´uśK+X4¸}œvKĄĘňűń0^?!¸I[úĺŒwsb`-uŐĹ4ÖřŮ=ľp‚}/żĚžE•čâfEtqœ+mČՖ‰ˆˆˆˆˆ,p‚%+ŕ#`Ŕx}řç,3î4=]ý´lçt4ăĂž1^Ď6ČÂëýˆÎĺĆGÓÁ-ô‘iş!ËçÇ˙Ý}‘LÔ˛š G™vĄ°¤‘ť—uóR{řâŘÔÔXoźÜ5ď1&XÂş+Y×PJIŽ“Œ1>4Ŕńścěé˜äB§V_a%Ť–V˛¤ŽŠĆŠ$ťŸ}wG\ŔCqm-Ëë+XÚPEUü˙ýgÇv;He}5˖TłźÎËą—Ţäp°™ˇ.cI^ŠÁSmźüvćí1"Z64łžą„"żm9L örpďaöž^Ü(fíŚfÖ7–R’ëĂNFîëaßű‡94x“šŒMź™Y{ŁŃYc~EŹ^UĎŇÚ –Tĺ1˛óe~Üž|L°bIK3wލ¤Ş0ˆŸăÓ8Ą +X56łíÎe4—ú08L öqęđa^?>žXÂÓ_]Ĺ𠯲}`Śt1ëîhaKK%…pa˝ö*Żv&oM‰ˆˆˆˆČÇ΂ª3xŽcKi- °üžOđĽŠăź}°‹îŠĚƒbMN->ŮJKh’Łť÷ň۞)’ţ–mXËևŤhÜ˝ƒŸě!Á—W@EM5ËŞsđ8ăXš—‚˛k¨Ëˇq†ĚĹVW“WÎږeŹŽÍÇo’LˇldeU€Žör7-Ľfő&îé:Ď IVńŕ“wł>0Ď_żÎîóQÜÜ:ű\+|ژŕóŻłcŔš´žˆˇó~r>‚§x <´‰‡ŸČĂzv&fÂܢfé˝:oy#kĘ-H ÓŃťT‡ŢyšÔTc;Œš9mŽŢ"Z˝—űŞ çŰđó×úMx(¨lŕŸ(špäí8 }Sx~g3Ë˝qÎź˙żîştÜ|5UÔúr)j(dÇŔh:ŔĆF8ô~;Ő+*Č9Ώ^8BoÜ]\‰ˆˆˆˆˆ\‡…u.Mńţ›mœ™vŔ P˝z#_ţňŁ|őf–ÎÍť^šZ7ŇRŕpn×;źt°‡îĄqúzşxűŐ÷Ř3ćĽćŽMÜYl—Šs'řőË8rÜű÷ňÜ;ÝDć.ëäľËëIŔCÊ<Žźş“ˇő0˜HŻl,›7ąžş÷îe×ů()Ŕ™˘{Ě;ŸŚú<Ź‹ë9œŮľ›çڈĽRLvđćÁARţrZז`Ď<ż •ŇXŔ—SÎŇ ß˘*<]€M0ŻˆŚľ›řŇŁ+)3qş÷ŕŔŘĽu'{Ůľă]Ţ<›ŠľŇ˘jÓfî­ń1ur7Ď˝ÓIĎx”pxŠŢł=œĚY=Ňˉž?őľEłşMm}~ E ՔÎ:Ź’ ęý=ÇO§'‡Zd‰ˆˆˆˆˆ\_g55ÚÁ ĎO°ţÎľ´Ž,ĽŔë§zĹ>ˇl9űßçW{˜v%-LŞŸă§§/ﶚáؙIŐË ŮľkŚ%ω‰r_*#óĆĘB’Šp›Č™“s€QÚvŸ áŔŮ$xkYÓÂ8#œ97Ť ­ńâąR¸É0gĎOăř*Yۤúhô\ŚG™tË)¨Š ÄbŔ7<ŔńłŒq|!łô^`ĺÓúĚ3´336Őa˛ç4oě;ÁÁL×YĹ!Má΍€žrÖ7ça9´ęen6/ÎŮłC$ŤČŻ-§ÄbĐŹb–Öú1€)Ş˘Šŕ(Łé ´ŠkËČw†ŮÝ9ÓMz‘u$"""""r=VÜčßŢΑĽŹ^ŰĚć–*J|§ŮΏ÷Œ*,ŚÜ îô$#ó&\rÄ!ŸÂ˛BŒžž­wÓ˙™˜™„8FĎŃ6zf[%ETxä#ł/çâN°ç—/pĐvH$]ʊb*|ŕNO1›óŃŠňó(40ŕLpŕŐW9°číâĐë;Ů?Ἠv÷ßUM(¤ż?SP˝2Ť¨”š€Á Ó˝Ŕk”†ťzčNVŃXTÁ’Üc N¸XĽ•4§öSVRŔ˛†\ޝÄ5ęk púpjڝyÎE֑ˆˆˆˆˆČuXTX˝ 95LŰ{ďpôh Ÿz¤•ĽŞ6ŹĄĺřڂ~BÜxœX†ÇŚbq.ř‚Â7`ˆă•.ƒb‚B¸‰ńšŤ¸)ÉYë0ĄžúF-—Ä5¸á8ąLSő.†ëg`Đe``ˇřaž\žœű×tňýý,´*L(DŽîT˜Š…>(ŇÇŠžľE4ÔřŮ3ُޒüńs<ť?—§>UGyC&󕱤Üĺü{˝Ë˙ĐęHDDDDD„†ŐPE+ücꞾěţÔDoźv„˛/ʧÖ[B]šEŰvý0ÓĚLwŰ>Ľ;ÝĹKĎĄ7Ă>¸‰8áĹ4~ 8§œc|Ůr*[š¨kŰO×Bˡf&›rćOqe˜;n”ÓgGx śŒšÚR|ÇGiŹĎcźs/Ý]!ÎĆëh.ŤŚ)ˇCĹԘŢ=™ ?Ü:‘ŤM°TŘĐĚś5eädXćŒ÷svĚ,|^7%ě‚ńÍż&+€í÷â5ŕFŁó&NşŃÜXş{Şńxń]%°^čÊ ‰p”é áčˆ™ęďäب‹É­gcCŚÚş‚řLKąmgřľÁƒĎ›éA.“çésŔW]Am^%KK"œîÉős˘;v1ËęCT֖áčžŘn]‰ˆˆˆˆČÇÓÂfŹÂJ2­m<řźÜ8“ÓIœŃQ`‚yć­Lqq.cƒc\Қ"™J/ĎŘ*xœą1†’€'‡Âœ+|a=ă‘ “ű^3gŒŁíc8ĆGSK=… Üwg|‚QLNysI â@ć‚ÜÉ^N 9˜`ÍŞŠŒôrjĐœ=ÝO›ęĽ+XUă§ŻŁ—ŮĂ|oY‰ˆˆˆˆČÇ҂ê ”˛¤tţ恚%ŹČ7¸“Ýďs ŢǑ3Q\ť„ćڜË{ŕzJXľ4+5Ƒö1.śĂ9Ó ĽŔ P7{ć[›ŠúrrŻ5ŔFű8ѝŤćŚźy;ëÉϧĐDűӗvąKXŮš×kŘ…ȝý`+Ÿ ?Ä~q3-ůדŽ]FNur>žĘĽŹ+[Řáp§ű9=褏Ée1ä5ÔPuĽëǸSœ>;crX˝ŞœXgĎĹîźąîÎĆŔ[˝”u…cœ<žź đbëHDDDDDä:ŘĽĽĽžJĽG>c.ţ]¸ WÝČęę|*ŞŠČ÷űüää˛de m]Bqj„ŻďĽm<8Œ†)h¨cYc…Šá”ENQ%ďÝÄ]ĺ†ó{Ţăő3‘Ka•ąV-+Ľ"ßĐŰ5ĸ nݝ<˛ĚGÜ h%>?ČŔt°sJiYÓ@}ž…Ÿ¤§wœŠäÜ~Ĺ)†‡SÔ,Ż˘śŽ’r;EÂxÉ+.cEËZšw)ţ.:&㌌:Ô-Ť˘aIĹ&IĘň‘_RÊ5kyäŢ&ýœLoąÉŠă“÷5P‘“gř4G‡ć˝ŔřBT76°ŽŠ„<ŰŕÄ&Ž;é0`U-eYa€âĂčđ‘$ŕÉ-ĽĽ%˝NtŒł=DRq†&ü,_^I}‰Ąˇsˆń„!ˇş™ÇďŽÄ‡żb#ýt E™]-ŃDŤĘČ5QŽžßĆŠ‰™…ŠŚŹ‰•%œţ“ź~hxÎYÉEԑÁWPÉş5őT!Ąłwš¨Ă,‘ƒDňĘ ŔëőbVŽ\éĆbéXrĽ° äPXSG˲jŞ‹(Éőă7áÉ zťĎą˙ĐYÎM_ž6L°„ő›šYŰPBIŽ+g|¨ŸcmÇŘsf’ůW'ľ)j\Ĺ'6ŐS_ŔJDč?ŰÎö÷GXöŮŘRd€];^ᧃËřöS+)šÝ’çDŘ˙Ť—x­{~ęńÖp×ËYUSHaĐ&›f űű÷ŸäŘpââzž˘Z6ßąœ•3ëšń0ç:Ů˝ç'FgÍdŇúÄ˝Ü]8Ύv°÷ —ąĘZřÖÓŤ™ß íĐýÎ+üčPú:´Á[ůĂOŐ̌ńuŢű˙˝Ťžo?š‚ÂُMôňŇŢćpŔ[˝œmw6ŇTŔ$“DĆúŘżŤgóƒJBšu%)ęKR,)sˆľůţƒ _Š'ŽđDľCbÔË?ž䝉[˝Ĺ""""""ŮIaőÉkóŸîOâußéC:ŹÚ•qŠq”$x¸ÉĎÎýέÚ`‘,vÍ݀6„ůîĂ1>Y:s‡ä+O†ůg[Tš´uˇ‘Éă!ţĹ >şŻ>I›ţÔĚ ×Đ;–ą""""""2ßľľŹ‡euIVUťtLßeĽX_™¤Úöđě ÜŔŰÉŘy§ăqjó—9Ł>ţís+\c6űÎaՓⳏ‡ůlÍó/‡xqđf?ĄˆˆˆˆˆČqmaŐvXZ nÜćÔHúޜ˛•Œ Ř }Œ› ŤěűÔ°‡ĂéŰnzZu I “dcĽĂ‹ƒšOKDDDDDn×Ví >pl:’éű–”§đ`ččˇHÍZ×řškS4”¤h(KŃTîräőž7qžś9Áş"—É~/ß3ŔžÉ™Y.ËVÄyxE‚ćR—|ŻK*nŃ;ŕáC>~}Î"yŮ^8Ź]çÁeIšŠň<‹Xtž÷ňú>űňŁü§GäÎéžöóWĎúiˇ’üŃ×Ăl €\×pdGuÄJçÉ(×ČŐ[IM ĹŚ†tԗ8,)uˆ´…řWťmŻCSUІŇ eMĺÇ~“Ă‹&ÁÓăl,wČÁpžÇÇĎwúŮ=>ż|o^’Omˆłľ.EMŽ‹×5ŒŰíđ0ę€ó°łSAUDDDDDnfĺʕn,Kß0ćâ߅ۡ€cš<đh˜/UŒíô‚q IÇ` Xś‹×‚TҐtÁ{ř›9\ĺ˙|0N]0ş:=řŤR8a()tńáŽŰo„ IDAT ˙ň/“ž=ákKŹ„Í›;ýěsŮxW”ĎTšŕXź÷F˙ůÔĚ,ťţĎ<ćŠJâ6/ţ&Ŕť‰$_{(F‹?ÝúűƒçrŘîńgŸąbf¤‰“!ţĺ"jÂvřäCÓü~˝ĹóυxvpŚXţËŁ€•ä÷żćţ`şČÓďĺňçű-ŹŞß} Ί|÷btďÍáťďŰXľQţÍCq*ý—ę§żĎĆWî`& ä8xŇËR>ţŻgŠ]:€Ţ’8öŮ(Ť@ÄĂsoůhˇS<š-ĆŞŕZl9‡ďujŒŹˆˆˆˆˆd‡p4vŐĺĄPh,‡ęż×Ĺo§Ă“ąHßöڃ*€í™šąt Ńŕť? ˛+zЍş řőóš|çGšü}Wş7Ź?×!ϸ,ż3ÂW—8Ř@çţ ˙툇=^~şÓKż ĆrhmŃěpYˇ%“•éŘ,Ŕł6]ç=´OĎlś/Ĺú*—Č€Wť.śÜŠ$uł÷Ţ8,-u‰őxycčBl\xůW›S*Ůëç/ž °+ĂńHtřłŮ=kYIĐâ§?Íĺ˜ËŸ<ď§sfŇ&;?ÁC łžË8Ü{wŒŐ3-ÂÝGüü⌇śv?˙pxŚ…Ű84פëSDDDDDävąđnŔއď˙8Ÿ‡'Ÿžćó%6?ůi/Žěę(˙îłq şüó}ĚíŠę&,úÂŔĚÄC#§|ź1lŔ8ř,:ęeŔ—äŸŹvŇĺXěşÔĽ85bӝ‚JXyIî,ƒăcI>˝ÜI'n×ĐŢc_ě<1¤pIŽyys&¤:ĺaziş;°•Ÿ¤ľNöŚ×Ő%¸+Çpŕ]/c3‰ÖWţŐ¸ ‹ŕϰ,nq~úҲáoĎt-Ž{8<ŁĄŔĽźĐÁÂN׋˘ĽňRxí˝T_}#6)Ň!ľ´&IĽąéVÓŞˆˆˆˆˆÜ&?f՛˘.ܘE×ĚÓÂb‡BCĂ6SWxŘ윔LšôőE]‹×^ĚĺŻ!ť6NłďÂ,g–2L'gśŘ8ÔšxšŇ‚¸†p<ýĎ@ŽC΅źe'ůĆďLň;łVő͌7u‹Îđş/ő‰˝,ÔL…çt΍Űěę2Ü˝"ÝYҘ`ůN›cÁ÷ŐšôňrlVœE–˙a‹[tŒÁŚ—ĎŐŰĄ{ńŕF‡-úŻpýW‘l´°°ęMň{_Œq‡lř-°+˘üőˇă“§j€÷OńwŸHĂüÎ+^&?°ŕËYłł_ĘĂOŸ°;>=×1ŒNrŠŽňřŒ ‡O{˜\ž ߀•“¤ľĘe´,ÁJcóÓöea{ny\ţ‡Ěľy}—mÄа Š)Am‡>;ŧWŚđnĚćűź„oőśŠˆˆˆˆˆ,‚ª•ëPíOOŹd[ćâäJ>ŰĹ203i0śíbŰ05m]S8Š„ 1Ŕ ` ›ÓxîúCââú.šƃÎíńr šŕž éŽŔËăÄËS${ź3g°íľ”˙a›č đ/Z|Š5Nk}”żúvz&+×1œďôńË]~ŢžĹ)"""""˛H ŤÎ¨żřo~°\žüÜ4OĎLŽ4žę˙÷“q {ü‹|Œ]ÇĆ$mÎ$Źó&E]!\q,˛éH%hąăPWěbú>`˛Ł„Í{†{›Ó­Á…+b1Í?[Â7éĺ­łCӆ˜Ć¨ŠˆˆˆˆČmlQ,Y%)ęmHôٜKOçKCšƒí:Ž<šRAYŠĽÁKˇs˒4çZš {ß ňë’•¸äÖEůËŻ&8=dHx]jKSY{ß5DӉ–]oYYáÁ_EŒď>é°˝ĂfĘvXޘ`Sá­ˆ‡ÝÖĹçŠ÷zŮNđ@NúvďÉË'Vš˝=‹)ż 2EíŹ-ŽH˛4äăTŠ*’—ŐAae’Őů‡' ůWП@Q’†ĐŹeĺIÖX´Ď̨ŒKyaş•ŘäÇůÎ7. ňMĆ-ÎŘź{ČĎŤ†˙Šˆˆˆˆˆd%ť´´ôĎSŠtĚ4Ć\üťpŔëń`ŒĄ¨&ÁĂK\†Îřy­×Â5.wnHвůí.g2¤!Ť(Ćżz&vé’4€/?ĹśĐ~ČĂŔÜć̤ť“^ş“.šČĎu¨*tȡ çĎůřÉo‚<Űi]źŢ)‰ôúgăôšĽhŠMѐĂ=>~đ›/÷Íi@v,â î)w!eóâv?'bW¨Ą–oWEůŤ'ăÔÍjy %ůäJ‡ÓÝđš+ź—×Á=Ť]zĎ9|ësW¨Ÿ“._ůr”MłĆĘúňRl]í0pŘKW ňŤ|zYŠŇ ?;XśKAžC˲őS^veŰ Q"""""ňq”H^ý:2^ŻłrĺJ7K'ľ+…ŐPŔŸţˇ1xEŘ Í„;c  Ŕ%1~m“*Ý2ĆáłOOńd4Čw~ĺeôVoĎ5° âüoŸŇâgŇËřY=‘ô2ĐaĹĘ(К¤Ä‚Ô¨Ÿoü8 gˆ‘pôJ­…iĄPhqcV’Q‹Áčě{ ăˇCPő¸4TĽ(›iÝôUĹůdŠaß1ĎuM u+U/K\l‘ďôr riY,bŃv0ŔoGҡ­\ b‘ŰǢĂęíÉĺîŚř˧ŚůßďJa‡{6&(đňZ†‰•nÖŹŁĚwɝłÜř*fĆť:c“C-""""" ‹š`éśe\ĘňғĺU$xňŢ×Âî7ü´_˝ŤtV;wÜÇî•Zó Pĺ_=–âs# ä8Ź^–ஸq›—vú>¸@‘,ąč1Ť3K˜YtqlWPăî‰ÓRčâDlöîđ÷mvöw_ţĆďpGsœ-ő)‹ .> ’ Ăč¸Íéoördňö8N"""""ňѡ1Ť Ť˙řOŘ&ÝíÔśŇAŐśŇË­t†•ŰŔW˙ë­ź ʈˆˆˆˆHÚBÂꂺćŤXXüÇżýĹm۲*7_"‘ŔgŰx=6öœó"ĺş$’)âŠ^Ż÷ %ˆˆˆˆˆˆ¤}<ĆŹĘM•JŚ(Í ’W˜‹×cc]ě.~‰ 83u2gh*‚íą3'"""""˘°*×ÇMĽh(- äťzkŠ,cđř,‚>/šĂăXśŤˆˆˆˆˆĚg—––ţy*•ž÷JcVˇÝՂ1†]NÜđnŔžú˙ĺ+Güź?z]E}čěę(˙ţŤaÖMűxwh~=Źšo’÷XŒgîJ˙=˜kóęY‹ŒW<ľ’üî×§ř“%†í'm˘™ÖÉ2ŃXœšÂ<ňƒţE?ÖkŰxm‹áÉ0žŰĄ…ŐWÁƒ_~˜ű}´Ţ ËůYűřS|słÎ#ýLŢ k(YŐřŸžzÓg8:4wşk‹%÷}†?|l=ŰîjុVł1w„˝g§2ď“U΃_”Ď-‰Ńvr”řŮď!CáúřgO-ƒŽş#üˆĺęçĂíÇŽż“?ţĘ*GNpbôV^xĚĎĘăëk]Nśš]݁vľsGDD˛K"yőϯםؖU—{™â÷ę/Ÿ`éČ[yüŐŃŰđzĽV’o-Ě'§ü/?÷їiŹ$řÍ0÷ŒřÓ_úZÄNž=âߜq1VЧQsĂ6<;}ňƒ~\÷RĽ¸.Ěë|qaz2Ž Ťä|}žŰŕźą(_ˇŽľŢóüŞm”…|e3fŚ.˛ŽC˙ĄüäŒ V)[]Eɭޤk˝ő+1Ú÷žbËçWąmiż˝Š’y—Ĺvč}ď×|˙ämđ~)""ră,şđŮvĎ ¤[V}eI>ť4c;áíÁľ8?&ϥؐ1ʚ€C‰"ăs–§ÎřÓďp2~˜ł92Ř.¸|äÂjŽß‡mYÔWĐT]I‡x"E<‘"ĺ¤Ď ۲đym|^ŻÇÂuŕôůQÎ Lë÷1Of,:r}íË9ÁŔu=ţ"5›×ä3yr?§Ž¸I6E Ëٲv K+r y 61ĚÉCml?öĄU;""rŤ-2ŹΝösnŚpÎJ‡ĎÜćaľoÜ`ĘŠ˝@†Ć­—býcVĆľh˝ţH xmňsü<Úş”Ş’Üô)7=‘’ëşżX.´ÂH˙őĹüčő#Śíyau:%é^xä|ŽëR]U ŔůŢžtšŒ‡cx ä\C7ĺK šMKYîŸboűpćVU`éÖ{ůě?'Nąýđ(ă1‹Âş&śn˝/ˇóŁÝ#$2<ÔuœľÔ.ŽK*őjšŽúřȝY%J{{?ÜßŔúĘăź~ţF|şLž;ĹÎCÓYЊŞsGDDn­›6Á’ ŚřôćŸ^’˘"ą)‹Ăí~~şĎC_چ4Űaă]Qž°*EuFz˝üx{€÷'fml}„ży,ÁŃ7s8XăńŚĺžĚë.ÔŔ˜…c\Js€Źż’?kv9ůn.qĐÂĘu(2†Ž1“kj\|b’oÍj&=řf˙öŘÍčí˛Ş5ĚżÜŕpę˝˙áŕŹąŹśĂ†ő1>ł2Icž‹‰[œéôńł]>Ž…çcž|fŠgđóźnqWkœm5) ,Ăř˜—˝ཊĹmY4ÇĘ Q’¤8?HĘš|ďM†×˝Ř]’¤´ ÄšáI˘ą8żoÎ6[ăńd8E]/ÝjZVV‘ńBżÉd’ńą2ˇy/†ŸŚĽĽxŚĎpf8SY†’ľ[xbzé5~{îRëÇšóýôDďăwŽf呷9NŻ_ąů!ž~G>zúš'ůáŇsá{ŽUÂý_šŸ #ťůŻ/wfżló‰/=Ŕ“{ů^ě`ÚŮřÄcęZˇńô†Îż÷6ż88k,ŤĂŇő-´ŽŹ "χ‰OÓ×y†wvľÓžS&Ÿ-Ď<Č6ŽňŻO°˘u-5ůäX)ŚÇşyó•}Ÿbaő{ěeO.˛Îź4Ż_ĆęúR* B„|Ÿ§Ťý$oďďfxVúľëďäŸ>VOכorŚl ››J(ô9LôvňÖöCœ˜¸<¤x kŮśu5ŤŤsń§Âôœ8ʞ+Š^g.,â|XôžÔrĎ=ŤYS‹/Śçäޏ.登lŢýéëěšś×œ –˛qój6,)Ś(h“ŠEäř6Ţ;™˙Jśshşk-÷Ž*§8ŕ2y…í5Á6nnaÒb ƒ‰Šq:ۏłc_Łł>‹ěĽ[řçWŇţö^ĆkWąŚ&€Śżăoî|Á >’„#‰ë+ÓßŔçży'˜Źjbi(FÇű{Řď_Ĺ#ĘDx÷ľ÷Ř=8S7ńÜYô1^ˆEźŽaqçďBĎšynNXő¤xćń0OńóęV%xxS˜ć ˙ú5/sżĎ4nŠP?młcŸˇ0ÉĂ-qţč~‹Î_ú蟳îęÍBÇýüí‹~(Jđĺ{ŻźîˇH˜d:ŹŽ:4–¤U]™ƒ‹‚<ŻkŃ71ˆ\ÞwrčöťŘ% ţé=7Š=Ǹ´´†ů“őÇß ńۗĺđŠGŚůV­áÄq?îˇ 7Éś5Qţ×r‡żţy€Ł™fÂń%ůÚă.N§˙ń†Ÿ)ËeES’‚k¸ěŠlcČ ů°íô—š”ă`ƒeY—c…txuÇuą- ŰśČ ů°3„Ú™ŕ÷űńů|óĘ˜‹÷BĄyƒ1Äă7h* o uĺɞ25šřkŘşŠ˜‘ýo°ýÜÜnz#Ç;čźkuĽ‡ťŔeôřnţGˇÁK㖻ŮœSŚ3NĎ@’;+‹)ˇ:éĘôźÁ"*ó\FÚG¸1Úßy‹a?˜’e|ćžę˛űó?KZˇńšőAνóż<<~ŠEÓĘcĂ#ŸäÁZ—îă§ŘŢĹ䖲zÍ:>_äٟ¤+ăyYÁ/Ĺé<Éö7&ˆZ!jšĘČń˛đú-žäô"ëĚËŮ´ž ÓŐĂᎠĆ#†œŠ:6nÜÂWJöđݜeâ˛'´¨ß|'ţăÇxőĹCP´„OÜťœÇ˙—íŒ]X7XËĂOlaľg”ĂűŇóSןÇr s~Işu×p>,pßŐ<řÄÖřĆ9vđ]a/Ő+/ěŰutĆ69lřô6>UĺTŰöŒ$°C9”VUłŹ&ÄŽyAĆPąi eӃŮwˇ°†M-ś×SĚ=ßÇÝĹ1:cďHŠÜŞîŘt7ľ…ďóŻu͙ŘĚÊ-ëé>x€Ÿż7…ľlťw=_(°řÁ/OdîćĽwęŞJ)2ƒ‹š× 3‹ę-ó?ßcapILpb˙A~Űv=ÝÝ-*ëň9˝÷‘ŐkXżő>ŞÎđŢΖޚŠ{6UÓöjWúGž›uî,ú/̢^Nj9}ČÍpSÂjáň–Âɝ!ţíÁ™îłÇźœvŚůNsŒÇ*ź|żoÎc˘^žű’>ŔKˇwŠ?]‘d}Ž_Ďiő3}~ţć}/SC6?*KňŻ×f^÷ƒ¤&,]—’\ăKŃXhhë˛h.IQmyđçşX)›ółZmG‡mF›äÍézh\Ön ó/Öş´˝•Ă>f]ö<ĹÍQ~§öżâßż0ť°—í݆ż|2Îç›}üĹ!kŢż]ŕŔť9üőA‹ ? 긆¤J:ú˝6Ą€—H4ĘŃÎst÷÷ă÷zYY_GCuŐĹërśç<'şÎK$¨­¨`ő’:rü^ü^;óŒŇ3}ŠçU¸<œfXžń1×ČäćS셩‰)2ý\RO“ÝÇkGÇI&§’­÷­gS}ţÄ$§ŰşIĹm~ fŽT|b„s~ bŔܰJŠŢŢ1œĽETćşĆ]°˝„|†D4NÂOi1ĺVœ}&\q˜d °¨š ]‹ă§aË˝<ľÖĎ١ŢâĹcłęĐןOÖN˝ůĎĎlWmÝ1žńä2ś5ŸâGş6ZE¸ďžÎł'/nwGGÁ ­_wńu>Nj?<ÍDdV9ŢÁšÄC|eí2VvňŢÜŮfűŽńÂűçŇ_k‡&xłŹšßY[ĂҜSě›JOVąv5Ťr"´˝üŻtŚ_š‡NóřďŚĺň ˝)u–v çĂö­lM -šQŽýú-^<ť¸o}q+kŽ'ŹúËiŞň0}b?ż|Ż˙Ňö8‚e™ 3¨[äFĎň÷/ľ3ęœeČű(Oݘ˝˝ť|5w–zvîŕك“érŽuŇë<Ä3Í-ÜUŃÍoúf—nHőćWďw§?_Fň+o!đŔJZÎđ♠ďřÎ4#“.VUĹ6 ]O‹››`´§ƒöîQFŚ“ŘšĹŹXÝȚm÷QâßΏ÷\kww—ŃSÇŮulŸ[ÉÚűKé:ŘĆž—᲼4TRduŃëŔÍ9w¸†cźŔ=[đëxqçďâĎšćÍ9xý\VÔŚđ;6=ÎÓpř¤‡ZjyO|ú´‡~çŇşgmRĆIˇxÎq朇éYˇĆŹ+ŽűARýç9x‹S,ÁfĎQ›‘źKü.Ĺy.î”ĹŔ‡56Ő¸l¸'̟Źs8ś#4/¨‚ËĆŚ$ţˆ‡ßžą°mđÎüšĂŽLCcuj~ţܸ‡×YC×bmh*çŠ{VPňő2,ăýc]źyŕ4űÎö0KŚÇŞSą$űÎöđćÓźŹ‹é`Q!9>žÚş‚ Mĺ7`‹nđ4.Ńh"ĂŻţĺ•%XƒtEŤ€ÖGpœ]Ż˝ĹOŢhgŞ~+}^şL 3FUĽŔPвň͇řdŠË‹đ§Fčš13ş|0¤éžűřÜşçvźĹ —U?MMĺx#ç9t&†mŰxfţÜá>:§-*ŞKđe*;Ţǁc“ž/Ś~ŻĄÎ’ŃËžŕ+ýz#iBćÍýĹĽďÜŔŹŻ´ccÓ8&H~΅ky…¨ŻÉĂDú8Ţ=ë•íăh×ܖá›Qg×jaűś¤6éăHçŹ.ĄąLűśHN‚x ĽĺԄ.˙tpœL%;ôžîfěâáKŃ?8qůö⥺śŸ3ĚąS“łÂP‚ł'{˜$D}mޜž˝]ý—}ž„ťűču|Ôבů"[IbąX>BÖÂ9C'xîĹ=źuŕ4‡Ű;9¸??}n'm6UëWł2t­%ťDÂéc”ˆĆI:qÂp‰Fâŕ÷qíÓŃ-ŕ܁k8Ć ´Đ×ń˘Îßk9wDDäf¸ń-ŤĆĽ(äBÜ08ç‡vgŇb؅Ş\‹ËŻ7:šź%0•J7Žeşg8~ůřĐ Ÿs×tšÎ¤Eß4ŹĘu).q(˜°iďľ8ë$i,qÎuq&ŹĚ]@oť*ĆďŚç˘şĚÁϜ°j9Tム%řÎďeţ=9ĺ’c`îp7gҢ÷łšsE5ë—U0:fɊ$K§y÷íí$“IÖm}”ââɑ.ŠŤYˇľŠc§ťđx<ŹÚxKŠsH Q”bh:ĚŃsˇŮEvđŸç%>1EŘŤŞ‘ Ľö=ż›÷űSŔçFmJżźvŃ%;#ĂôĹWRS‘uzŠúÚBq‡úÚBŹîiĘËra¤‹Ţé§vU3VŚO¨’˛|L^ŢaĺP”o0ĄFžů˝ĆŒe¤Śü Ä杗ŒdňB6n|šą9ŸEîä4ŽĄ87ˆĹřŹĐď0=='¸Ä˘L§ ľ9A7ád˝Ąuv=ąo7žRô|‹ď)ĄąžœÚŠR–4Ž`ĺęĺŹ?ř6ßw€šżËÜČîţłÍŸ]<=űý•ł¸‡€ß'NřŚüx䞎⒋ßoĂ5w˜WěĚ˙ťW١…–ľcąřcüÁŽíuœĹ9""2Çu…Uż7ý[d,1ëÍß5Œ† T¸”av*+ĎĄÄŔؔuŁ>noC˙¸K’Ü„ÎC6I×Đ1`xŚ:I2žlÍőmŻÁq2NZ;OjŔË/:-F{‚ź\=Íă˙?{÷Gv'xţ›™ĺQđŢŢĐdÓ5Ű{7Ýę–iVn4šÓhoçvobď&..ânţ¸Řۍۛ¸ąifŐŤi¤nŠŐFí=ťÉŚizÂŢűň&óţHÂŁ ¨ ěß'Ý+™ďĺ{/ßË_ĺ˗w{š2čŕčÔĚşJ˙$¨ŕÖhŮ  Ď^ëcoe™)vBîqBž ”84ŔL°ˇ~fŤéű܄{ëŠH1žÎ 0ój›‘I/ç[ú—HeăSSŒĄ*5 3#sżý7ÂC ™4 ěőáSRIq(Ü\ŃĂd'yUóëüôőťPvfRP¤Đ3ŔéŚ 2ëĘ)̓<ťN_˙řŰĽEťlĺDÇŽž3œ)¸—ýwďăúŕg\žaéĆ& ” ˙đ˝ąh—Q—oeŚŘ¨ŹÎĂ6ŮÂoßšDĎÍřW!5W[ýľťáeŇm ¤&‘˘ÂčÍýޤ¤ŘQfŻS2‹§%M!9yŢą­Rpj„ćúšës:G~ď~îÜZFÉéAŽE[>F€)O%7‰´yc‘’œDŠbŕryçC*ŠŠŚnŽiJRКßí[ü ŐIzŠ‚>>1ŤLbI%9فb„đx6˙}ź˜Öq4ă IDATçq4íwUmG!DëƒŐ!2PŠďI¤`u:5œ!śĽ(´MßĹěÔP BTŞ ýk|-Ą0ć{ŞNZ¤WÁA—>˛rÝâ›÷(¸YS ZMříAžÚŞł`y$Í {ŐĎ5EîlK˙é…ă´őßŒvt=ŒŽO_¸]FFĆÇíň,řEĄ­œ˙ôÂqÎśôĹ?ĂŤĄkPǔI΂ł%Ȥ+ˆ-5 ;îď¤a*}‡ËČą*`J˘ęŕV*Vő›ÁH˙(^sťvćîîgČ7DűP*ŐťsÉbœž5F7†—,ŠÉóÎíe‡9ţŃUĚů™ťÝř5+oo÷đĚA˙1ÉÂéQH/ňhľÎdťˇěFÚ䄊G”€FëĚŁ“ž!n%H•ĄŇ7k%`sR˜ŠÔé;ĘZځpŚ…ŮZ !JËřźŕV×8ŐŚňč??źŽ)č†BkťiŮgHƒV~r&Ä˙yĐĎę4ţŻłA`䪍_–šůÎ7‘gćł Ś““fgi˜ÉÓÎ8˝÷ő›ŐĘŕ„ĆŽa*ňÓç|Ś* VŤ…đĚ3RVŤUQڟšĽąk˜Á 6Ť5Ž9]+?­mC„îÎĽ,KĽkÎŢÎ`ßzE[lm4ř†9ţÎ9îćŰX‡ačLtöŃëuŽ*ĺđĐ0zĺ…>.^CG§ŁkЇdŁN4ŃëžUžŚ¤4ňSÍӋZeÚŃ[Z&[ ڟky&čŸ7ÉNŁŠÍĹž=[yňN¸<Ŕ0|ôľ,ű:r?ßĚk§ąg żf#5#ŇŇź§ßŠň˝ŻŃ—oÄefxhż>Î]+yňQƒłí“Ěɔo-#7‹/Q ƒÁ+ő4Öfçƒ÷ŔĹöéW×l­˘LżHW<ĘlÚŞÚCÇ6tĽžúÚ;Ůq˙ÝčimtxĚl­˘”ĺXRIÍ/˘śTex˘™OZŽnŹ$—ó•çĘ ]ď˘m` wX#5ż”˝e&ښťč\ĺ÷2Žk œÝ~/‡Ţ͗“Zh “TPĆŐvÜíŸóů‚Ő\uÎJž}ÂĚš–ÉéWâěLGŹçÔőĹËË^”GžâáJŰČڞ_T,TÜý÷:Giď›`Ü@ą§S^‘G–ŮGóÇWh‰Çk“ç‰OۉSGuG×~Ło;B!â!Ş`ő˘×`kU#v# ŇyÍĆŤ§-tĎďłCżyĂÁÄ?UůůŽÍŔçÖh8gçĹsfFěëČđ¤Ę Žö™Ť cJŁÍ•&•ţYŻFLŤđńż Ď)¸Ô=ţ÷=ÓŻwđď?1-˜.ÖrĆÁ?Y˝)z÷íçΏř¤?úçßţ€ą[9P]ĚáRšŔ59AOÓŽtG˙ҍ¨Ë7â23žřݍ{¸k[÷—h„Üă´7œćĽńRžűČjƒUŔŰĂ;ż;…çČVśí­c[ŘMwÓŢôWňěóîŸĆĄĚVß"ŕëĺ˝ßÄ{×vvÜą—Ú ‹îŤyťłšŻěWWýHŻá˘ţZ[ K8XnĹf2đMÓqîÇÎőŽ~‚qh„coĹ}`;uUŰyČŚtOĐqëYä9ám'O2T´‹;ŽTb×˝ ś^ć­ĎšXüś*UU9hŁM\\kđbéo뤧&›Â˛ Ş,*zŔÇŘ`;žoŕ\ĎęŢCřľřÔq”çq4í7ęś#„"”ššĂďŸţşVQ”›?7~řóű5TE察u&üPn>çŰŔ@l6ĄP<ž—ű÷”˘( nŻ—×Ÿ {pđćTUQ(ÎÍáÉ;“dˇc_ęŕŢ8‡É´đű—×GHWHr&ŁiZÔh ‡qš§0cŕtŹţĽ ÓT˛÷=ŔˇvşxóW'š:çŞJ!}ÇÝ|밝Ś÷?áÝöh.(­ězę)MšĆ/~u‰^ů˘~k)_ą>ň>Â7w{yď_>áâş­F[Zů!ţýŁš4˝ů;ŢčˆědT3ˇńí/W2úá;źśˇ=EÜíW!6#oůąÓápÄáŐ5â Ĺd2󧍤%ۨŤČĂałńŘĄ´÷ő1áš^•"ՙDY~>› Ă0¸Đ6Ŕ G TŇRSšóČ]X,VŒyĄ‰Âô{ôf3t}á´B?Ÿ?F(°Ö‹HĄË—š\{„C;Óšöůěg× ĆęOńŞóĎ<ňYW9}ľŢ !ŐFFşĆxďÄâŤIŤN2Rtˇwń_k*_ Ş:˝0×Mj2ĽENë˘wík,m"VŞ÷U6ĐČkm¨nŇ~…bł‘`UŹ™ËâGݟă+wŐrĎÎ-¤:ÔUUÝZM“éŐ˘˝ţ ŸÖwń›OqűŸDf˛Xůć7żÉ=÷ÜC(´pęl  ąń*ďtxâ°ŰŮşľ‹eá*F&“‰ň˛Rţĺ_~N8¸Ć‹ÉŔďýⷋfřé8y”î­âČž*ž|vőĆG=źůËϨŸ‰ŚÔäljň¨¨8 +ٓŚűRŻL)[Nĺ+âLIf˙“)ďćZďŹäUÖ°?ËOÓűm ĄÚąŸŤďţŽŤ 9iżBąéH°*bÂóßŢšŔŮÖ>ŰWAua&ö™Ľ˝ţÍ=#ź}ś•‹­˜L Ö0žI× >řř><úé"Ÿ*„Ăa&§ŚĐu0PU•”äéé‹˝=Ď0ŒuZy:ĚxçUŢ輊fą“â´bQB¸&ܸgĹÜŚźj°aŸ‹Ž §xˇaá‚3bžČĘWęág ĎEyE9÷Öذ*!ŚF9óîeN´/|ďŽ EÚŻBl:ňĚŞˆ=C§˛ Ź”éwč Ozhéeĺ×p¸<^ÂúĚkiZ ÓSU C' -~‘aLżUGSœŽ5,˜#„B!„ˆŠHžY(XuŘŹÓV V…B!Äš×?ýłÝşÖEoo^,šyXň QÓ71t‡@_~ěF|ĄÉKB!„BÄ؎ňéŮb­=œ‘ĺÓL8÷ ˙đěĽĺ¨Îd”™…5PÝ5…÷zŽÇq=-üĹ{ŚÇośb+ŤËҏÇE$Ä×֊u­ëł$( V…B!„ˆÂ٧ßFü÷KŹ˝řEŚ•˙ŐŻ“´c÷Íu6ĹbAÍČ$9#çŽ:ÜW.2ňë_Ąvwl@n7FŔžDîýçŢý Ţr-C×qŸ=C˙ó˙€ŐăŽQÇÚJG!„Bˆ/MőłŤĘţ­*š˙ťYZv%Ýłƒ*gâϙUjś‘˙§†sĎžEŐۛL8÷ě#˙O˙ Ľf[Ěň‘čefßşgÝ>M›^`e ?ŠŚ‘´wÎÝ{7ú°âBîŹ !„BˆÍIľ’łĽˆĘÜ’-*!Ÿ‹înšúÜă”duąJEzóύ›í†`œĘL/*!˙{?Ŕ’—żěv‹­ĄiÉË'ç{? ďoţ21ď°Ć¸ĚT‹T-fŮSL&´”举ů$wV…B!Ä&d"§Ş†}%ŠhSC4ˇőҰQ\]Ăžb{Ü.r÷oŐH˛+$Ůöo]Ŕą>âSf>ÍDćWžžh jĚűI5i˜eÁŤ-yůd~ĺëř´Dť—ś1íLL“ňB!„›ŽâĚĽ&×Jpč:§şiďéŁţň5Z]*é[ É[ăş5‹Qńshű­ËçCŰUT6ĎÂ6ń*3çž$íÜ=çď ŔŹ($kÚͧŚňTV:?,ĘĽÜn˝šÝ I;wăÜw`u™ˆ“őhg:6Œ|Ř0FDŰŢŽíŤ !„B!V ŕĚLĂŠéîż.ęş\”W¤—ŚŃ;ŽiŞe… 5%ˇ&ąÖ”(”*›dUŕř”™×€üĂGn­öËtzWZ2w§%“jşu÷ٲĚ&ŇM&v&Ůyol’wFĆ…Q˜y†őđúN}– ŻľYŸvVjłPă°ÓäńŇé `UUö&OżîçܔżŽ/šííL‚U!„BąÉ¨$;m(ş‹ ×Ü{L>—żáÄé´Ą š1–ŘĂbÖGvŠ8í úü;ZşÂŢiłíIs*|óQçšÂ¨ęÜíUEÁĺ58v)Œ×oúc/>efÉÍĂVR6+x,3oćebSU‚†1g7B×Lł‰IvNNL16ŹŘJʰäćÁ`˙*Ž1ÖâSf7€SSů~Aťœ.š<ü—Ž^&CaŚ$ńďŠňřŰî~>›$Ť-ŘÖÖ<|;‘`U!„Bl2&ŹŒ BJQ5űKĚ 65qĹ$€‚ĂjF¨‚ˆ)Iƒď=e˘ +˛ŕéťL<}×Âżď2řűßqy@KˆG[ăSf–üB´ä˜ůwš3OfŚaQTŢçĄëć”UĂ0x432›•7FĆůt|’E!4ó倖œ‚%żpBŤń)łŮTě3ŻŻąŤ*ęLčiUUĚę­?/ˇíílCƒUEQP"(ă_lÉśˇ÷ś†ąÚÓ\!„_(ŠŠŚ†ŽŠ#فդ‘ć4ُ§ŸçSŐč/ä5ÍĘ['ĄšËĎřš™Ă;´ˆŽcfÓu8~9Ě_˝˘˝ĎŒ–( ĹŠĚTťýć`Ý0Č2›Čś˜čôűya`„Ą`hzŠďĚö^]ÇÖé ٛěŕąĚ4^ĺšÇ‡ŞLOVívb;{•âTf7wL…ĂüŹoˆ=ÉI\˜r3Ł* ''\7ӓ.TEYtŰŰ=\ݸłG+âé?:LMß4éŁÝtŚQ*ŰŢĆŰ6đ__¨_yC!„BC'ŹŠ‚J˜kW95 â÷`ŘRQ]_ý—ŕ­=ţ—żóóGO™ůýM$Ů#űwSƒ_źâŸß ăZV~\ÄšĚüşÁŮ)7oŒ3 SlľŕĐTŽy|4{|7ďŔţa~y3/Ža,úR› śepÉíĺ’Ű LOŁV€Ép˜W†Ç`ćwe‰mowʆ9úňűœŠdŰP˜ é*-ś%ŰnŇm}‘l%„B„đ pšą˜ŔxţDą˜ą`ŕ÷W=5Ŕ°ň˙˝čçj‡ÎŸ5SV°| ŐÜĽóˇż ńŃš0s"<Ł:_|ĘL÷z1B!‹Uë>?ŮُIÇ3Óx23vŸŸwFĆQfnSkŔiÉŰ,tů ƒ¨3ŸĄş×ťĂ^“řˇ3X<čœ Ž´íílç%şýW°B!„ąŚ3ĺňadŮIuŞ0zkń›ÓUŃtůÖD˜MV>8 Sž ˙qŘX]^ƒ˙ňó Ž™ą˜dÚďń)ł@_áŠIÔĚŹéß ƒRŤ™ďä°#ɎŞ(XÍJuŢü7*`R|şÎŰ#ă ĎLOMčë!!ó]§v vW:FžhÁšB!„Řô \#㸠3šyiÜźŠ:(Ęu˘„&éÝS)`ł, Ř­ Ůi‰,ħĚýř:ÚoţŽĄ0WÜ^F‚!`zJk‡ĎOçĚĎuŸŸ3“nţŽ{€wG'ćěĎ×ŃN` W‚x•™ÝZÜ%šÔutďí9K1QżúB!„bI†k€ćLöć•r`›î GV[œ:cm=ôc“Ž?ŕçΝÔenńh*ŮĽňúq?VK"Nž2ł+ŕ:qçŽ:“ …yq`„Ó“.žÎJg8âŐĄQ”Yw˙üşŽß0ćÜ93B!\'Ž'Č;V§ĹŁĚź×šń^kĆQť5&yôľľŕžr1˛Gď6 V…B!Ä&bŕZçüĹTćĺR“ŠňščşÖMSŻ}ĺD$?SawŐ­č)2řđěôŢاb6Mś§R%/Sal*F ÇE|ĘĚuö4îËqÖínMHmóúůQ÷vMĹžťw……S<ݗ/â:{Ű*óą/3óř(ý?ú+œ{öĄ%'c( ÉűaÝRLŸŽógA×o>绔°Ë…űÂYĚc#ŤČIâ“`U!„BlNşŸë- \_ťŤTň3§ĂŞ‘ ƒçß ňÂ{ÓS?˙a?|ÂLfŞB~–ĘÎ •O.Ä//1‡2ł…CŒüćWXň °äĺßü{ĐĘŻX ô÷1ň›_a ‡b—ąX‰C™™ÇGńüž@KN>Ö-%řŰ[é˙‡żEčx_ˇs@'ĎŹ !„BąŸßϝ;ŚßľyĽMçĎŕ§Ż‡Đą˘cĺ§Ż‡řó¸ŇŚcŇŕŽ]*^˙íůěŕJÔîúcý} >‹$PüéQť;⓹MŔP!Đ×ËŔó?‰*P˝ÝI°*„B!Ä"rŇś—Ťźúiˆ?űëç›ÍŘ­ˇ&ŠÚ­6Î7›ůłżđę§!ś—ŠäŚq/ŻŚúţć/q]8‹ZůŠ áşp–žżůKŒŚ†uČabR…PƒĎ˙eÖbU´ŹŹŹż‡§§2(ŠróçĆďf“iúĎʍǢnLŸ^iľB!„›QqŽNßüăďBxýK/œäők˝ Tđúat*v/^Q“2¨Č61Ö7Äč&xëŁ29Ářç§ôö€ICłÚ@3˘€a`ƒ„'Ćq7Ö3úĘKŒžňĚc1ÍĂf+ł`(„żłW'fSbź´g=CËŻ¤l6›Qjjj żß,Ź:lV V…B!ÄJ(ä'Źń żţ€M“)qW^O^,šyXň Qt‡@_ţ„ZőWŹ?Ďżěç‡#˛`uĽ˙ !„B!„ąâp8ä™U!„B!„‰G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚U!„B!„ G‚ŐH)fRs‹¸ăĐnve*‘öEđE?~!žˆ¤O\?Ş…Ź˘Rî<˛Ę$)ĎMí‹R—ëŐ|QĘS$Ž ż@ăŹ)’Ôœ|˙ËŰČŇTUEUTUAQnýL3?˙óń áXĺPIᎯ?ŃÉmüâ§'i ĹjǑ3•ÜÁŸxé#Nëq´âń !ŽâŘÂ3_?DŮŔçüôÍv&˘ě–ÖÔ'ާMß˙*¤ď¸›ďÜ[LŞEAŃ'9ŢÚH‹{ŁóuYˇ6żşTóęřˇżżŹEn?zŸÇÍP_ő—9Űé&ŢgăŞű€¨ębýËÓĐĂü>&ĆĆééîĄĄą–Ń qíUąKÄžŇAĂľNę›;hč‘˝%űX''Z§bvň*ÉĽŃÇĽV•EäX †Ž5P?˘Żř€’TĚ}÷”msŔ`3W†bĆ'„•Ž_‘x´ěJٛGŞÝÇľ =ŒEŮ­ŽĽO\OˇC˙ëęćJBiM)ŠŸŽúfÚ\ŤŰÇzś‘xŐĽáęçĚů6ZFrKłHQ]œ}ý-~ńÁ>9ŰJóˆNŢÖ­ŽŤ˘4ÜOCŻ7v7ĄOôsŠŐCfU!ŮQôŃÖE\ËóB-Ă yeY$+n.}đ oŸď šg —’LŎ­Ţ[IĽĂÍőŽ źqş4MÄ>,ó´Q6j,L¤q6ŢĚfsäӀő€›žś^úüA†ť;ilé˘áZçtŔzń<Ÿu„0›MóvjĄxűVŞSWw‹:iK!… ŘŠŞČŠěVpĚřFťiZŹ!,÷žAŽvL19ÚMcO žßŔmˆĺ_ˆŰ›‚ł°‚ĂťňI×6:/‘ÓÝŚtĐ]Ó˙ŢęűÄő´ńýďÚĆ?Œ0ŽžnŽOÝ~ŁG"X×6ÇşÔ.şŽuŃë7Ŕă™ráö‡đűÜôľ6đŇŤé [ŘrčöĽĹ{Ę Žo´‹kƒŃőQ×E<ËÓď˘ëZ/!Œƒ\ďęŁšŠ…cĺ'?{ŸŁ} …{îâ;•˛–S|š~băű°…1OgŁĆÂÄg×C c?­í#„ËL˜€ŕĚßjY5<ö@5ýŻ5­âލ…Ҳl4ˇÝNry1…Ÿ Đą!_âčKf™ĎôqNżú*§ă”ŤÄ°\ŮqSTÝą—GĘ5Jżĺ…Ť›cŕ6\“Œ rÇ'Łže;Ź "Ë ŢI:›y˙Dó2˘Ř3ŠŰżƒ˝Ůä$[QC^†{ť8}â"ç–šł3?ÍWŢçBŇ6ž¸§†ŠŚóźúQ;Ăá5Ś3'Ídj÷íâPmůŠVLFŠ‘!š._áč•a<7v˛–ň°e°{˙vöUäaSѝŠÁΝşČŠn/7&IŹéxLNŞ÷íćHmyŠV´áž.žšĚé.ڌvTPVZHenˆ˙ú&GG ŔDfI [KóŠ,/ ĐßŔO~y…!#úú˜Í‹ô˘(ăšea§ ¤ˆę˛"jJŹ\}ý(íu<ꎈ<‡‚w|†łř¨a[ÉV8TEMŽĹ?E׾Ť|x˘…^ßÂÝF\?+ÔE8âm"l›Ó‰’Uľ{ëJ(ËNÂa2đť&éjďe"ŤóĐUN´˘?–%hÎ\öÚN]Y6™•ŕä0ç/rNŤăť‡ÝźôŁc4†WŮ Ţyf˙$ó'Ĺäź_Aôi˜¨~čižşĂyć‚Đ:”:€‘š•ď|m/[l  ]œ{˙3:’‹ďŁÉGÔçÍÇ?Sĺťśs¨ś€Ât;V%ČÄĐ$á¤X•ĺtâ7ÄŚOÖŠŠśÎß|×ŰBíQŃQôĎë^—‘PA8Űd IDATě¤$)(x˝ţšűŠŞ/Œź~g%@vÍ.>PFiş…°{œöĆ+źwŞ‹ąđ­}.Y7wEyFyLŤڎs˙'śœ|J퍌z"M{ĺ~â×)+—É"â9~DTOsę!Šó(Â:‹öšľ1BbŽ…‰ąďő›`UËĺ‰oŐĐů‹O¸0Œ÷rň“qŞíf[röłç¸8j}‘ĚăU)(ÍÇ1ŐÉľá0ýZ7cűś‘^^Dîńazgő†jZťj+Řş%+^ę}g¸‹w_“nŻ…â=űyęŔ=lÉ<Á?˝ŢƄŠs Oőť“ڏtâďvşŮҨ١‡{ž*˘âÄüüÔČÚV‹Ôä4Š‹Ňpj:#Ę­ŻÝԔ|ęv×°sK*6%LčČ˝ěIösáô Ny,lŠŤăž˝‡ůvŠÁ_ogňĆIę(äÉŻŢĂ^ë żó?ďö`Ę*ăą'ň{ĎĽ ţ뇜YbşŮÜ4C¸víg[‘•ÖŤ]¤ěŻ˘xç~î˝ŢĹK-Ą5Ľs“bg磏đle‹ď|ČŻ[Ćń›’Š:|7Ď=ř%)đÓăCbQśA>|ýMNöx1’Kxć÷ďâ‘g3ą˙úm>ěŻńxll}čžRááô;đb‡ #9‡ƒŢĹ#Ďć’úňŰ|ŚŚ‘_\DmĄ“>ŽzăŰFĹBzvĺŔ¤jčCĘÍé ŃÔÇź‚ĹšźÖô"/ăEŰŃŽZv”¤bWtl=ž@?Ÿý„÷CNvŮÇÁG¤ j’Œ-§ĎńÂą )ťxlďAžŠń/512k˙‘×ĎJuńowi+oÓmЏm‚BĆÎ{řĂóQş/ńŇ/ščôhäTďăËî *ĐĹË˙|Î@´Ç˛ÄiăÜÂ3ż;Ô~>ţŕ.ö°ĺ–r÷=÷óÝTš~cšËŐľƒižą<óӎĹyż‚ŐĽ˘ůý—ůŤÖüáÓUd*.üîwźÚ>óŔÉH#˙ý§S<óí{ŮáşÂó/]¤×Vȑ;ďŁÉGôçÍĆ?s&GžšŸ‡ŠşĎŸĺWoö14‘VPÁCfǨ,§Ĺk<ˆiŸe÷˘Ű#ŁŁéŸ×ż.#aÉŤdOފ˘ľkÖtŐ(Ćéhęw֑‘˝ç^žŽŒóů‰c 8¨Úż—ťŢMží#~üažę"ęňŒň˜Ö"<>ɘZ*š*x­ŚA?ąR™,"îăG”yŠřÚĆż}—ˇÚChäĽMń每ńiS]{çÚĆ6ŠK­\ţÝ{źzś“öž>.űœĎGÁVXC]ÎěýG^?+×E j$ŰDŃ6Ѳ9x Ÿ$cŠsŸ^Ąu<@0ŕĽçĘYŽw…Á–ĎÎ2űĚ´şľž;f*ÝÁŽäőçÓśq&<Úř퍗č›3youí`ią9ď㗆ëzgt ĹFnścÎŚ8ÓÉu„š~š™ŢŔňýo4ůˆţźYíř§Qxŕ0[™l<É/śŃ5îĹ힢§ľ‹nďüíq<ˆuŸ]G;śG>FGÓ?Ż].EQ4)™Tď9ŔˇžŮFŽ ëô>Ÿľüw4ătäő;›JšÚÇK/âd˝í|řî:Â*i[Ť¨˛˛b]D[žŃÓÚ>ßô?ŊӡD‘öĘýÄňe˛˜řŃć)Ňó(š:‹öš?ú!ŃǍÜ÷ĆX]°ŞŚpřË_ćĎřUţü‡Ďńƒű qÄ:ciůT¤ůimŸ™ňŤĐŘćFWSŠŠH[˜qÇË;ý”Ťľ–ŮÓ )ZŽO˘+vŞ+˛ĐŹ쎴Cxˆ+ÍŽšSVB#\š6ĄĽłł6#ő†ńú–šňdĘtúŽ\Ľ}VžŔƒS:¨RoźčÚZ@]ľ%4ÄŐöً#¸F™0Rˇä“˝lŚo¤iŕiiäܘĄQ.œŹçÄgŸńa[0Fé€r3ć1Ŕ”ĂĄ=Y7O #čĹĺ7PLI¤ÚgwžQ–‡Ľ€ÝUT}œć볌Ą(̚Žš ľ{ }ÇŁĚ<—ĄefS`˝ńˇ*á‰AŽľˇóůľ‰é6¤űń,ńU­îółČĚW"ޏĽŹ)˝ËxIAŚÜÓűźvţYŮ OL2ŽÁŽ÷ÍĐô)F&Ś÷Ÿž:Ť°Ł¨ŸHę‚Hę+ŠśŠ$eŸ¤€>ÁŕœwźřńN0šŠÓ}ĹZĎK>ťŤě(ĄAš:ćNŐ3Aü‹ý›UľƒEÄ輏k†‹Ť×FĐQÉ-/äÖ˘Ś éĺE䄸Ň6{żKôżQç#VçÍ2Lšě۞ŠŚOpá\÷‚ťŢk?†ĹÄx<ˆGŸMŻjldŒŽ˛ސşœEMĺŽoü˙Çř˙ë=ÎÜ_IĘp3o˙ö ţyތą¨ĆéHëwNf´]źJ2< y “ƒ‡2gŰEë"ĘňŒţÚcőŒ°NŘP0ijŇ^Ž}ÎłnăGy"9˘.ˇhŽůŁÝ~3Œ…ľď ˛şiŔ†›Ëœćü¸˘šH)ŰÉťc™-…”’BrCCœÖ°Y§›íHW?ŽşJ˛Ę‹Č:9Ćŕ˘_ë OĚ{‡˜Ář¸ ƒt’ŇSHĘH!Ď<˝"ćđ‚o8 FGŚ“Fzn:vFX÷݇ĂúźoŠ t@A9?ľŒLň-€{Šąů=ˆĎ‡×€ŒÔdŇUč_q5kƒŃ቙U›}t^ş@çĚ'ZNŒŇ őóöżžÎĺt…Ńţń9ub€˘°Ôӑ”‡:SFhŠ‘ŮKלřőo8ŤéBZţڎGŸŚÇeP”QË7žžÄŠĎ9Ű<ČpăçüŞq™ăĘŇő/‘”ńŞĆ"Ď,ÍěfP×TfZDTí:’ş0ER_‘ˇMEU§ËØůlţś€:3j­çčt›V0ŚÜLŽóĘGąí_╆ÁXKÝG˛Ů’SDUr#§& P’¨.O#Ôy’ć#ƒľĺ#^獚‘Cą]Áđ Ń9şň=‹DăŇ'G^çZFfœĆöčú獭KŔ˜âÜ[Ÿňů¸™Œ’­÷ÂŐ˘§#sç ‡çeÚ¸5D0ł5ęň\ËľG´ME›ŮW8ŹŻkÚómäř™ĺΣՖŰĘ×üvpEą}RFň& 7fße•Ájˆ‰Ą:g~ď3ŘRQť\aŁź4ÍŞńěoYřqV5éW\´Ó2đűNOC„“ŐŒÍaĹĄţŔ˘ß4…ü‚Xm6 ¸dZˇbŸÎŽ žöÇ%sO6EĂŽ‚á^ü˜Ł/ąću,ÓŃ˝tyŹÉé§Ůq8줌äPhY{o­:ě$Š@ €ţĄaĄOh€Łď5Pôä6 2ŠšçŃbîşo’Öú>>ÝJOŒŢžT}ÜŸHę"ÂúŠ´męŽ1ú=E'™Š ߨ'i6tÇŃmmíf›†bňTǞ| ţązGÜLy´˜˝3I™ůO$CŔZŽÇÓyžç˙Ľ‡]{jء­ˆ‚¤Şö˘Ź<‡ßţú Ž/f K‘ÖO$uÉ6ˇÍP?'?`ű}šÔŞ áÝV*Šeť8\b"<ŇČ'žšSŽVŰ֔ů !͢ŞëňŒÉzô/kJĂđpľyˆ‡Šň(*Ď'éR+JiEĄ>^šÝ ‡ë՗FD™ŁÂú˘ŻZęnL"&âÔ'ǰÎ×EBŐe€k—Ž3VSKÁîjJ.|NűźýD3NGSż1łŠňŒ÷ľÇ Zz é*Ą ĆôuM{?Öbľĺí5¤Ű'üX¸ű^oą}u *i…ů8Ćzé]ĂşŕćÂBJ´1ŽŐ÷p}|î~z­}ÜSQF~E!ig'‰dF($%ŰQ°ËƒËcÇc€ĹjÁşČÖ&ŤłÂ­ç„áóă5ŔŞAĐëĹɢĘ™Ž%ŸGŸ9Ěž/ďżÁËW&§§hyEĂ{sÇ9÷™•źĘZź{;•ie9˛:7źž„Ű­.C}m\­ážŒ2öW\âzӏ磧#­ßX‹ś<ă}íq‹Fá–\Ź@x°—vĎzŚ˝ĐFŽkÓr›{Íżň Šy1‚׹IĆÂőß÷F‰í=jűŘϞŒľœĹeyXÇű]51ŘÝÍő¨šĹT'GšŽ™â‚tTÂôőŽŕĄ?Š#…,űüm2łRĐ0hJŮzŃGÇ ś$Rc´’]<Ó1–˛=EAşĆÇő3O éŁc …@ќ¤;—[˝vmÇŁćěä{ß}ŕÖęĐşŸţ拼řA.C!%%ićD ş1Ím]…őN/>˘ŠŸHęÂÁ6ć¨ŰfÁŽ^úÜ!ĆOđĎżÄţť—ůoď4r}ÖH¸ÖśŚŽ1őDĘźŻÁÍi¤/ÚcÇŚŹG˙Ť4 Wő=!°äR[]BmAˆćŚžČ§źŽS_ }|‚T§sAÝ+ś2ç]i&âxĎ>9’:'Č؞puŠqůę(aĹBŐî˛Y‹TE7NGZżąmyĆűÚăfÚÎŐ8P ˙ôÝkcýŇ^ĚFŽkŰr›{ÍżňžćÇ›g,\ď}o”˜Ťjf1Ői:ŕ‹ˇ0Ą0€†éü-“Ş-V\]ý .2_×đĐÜ-“ÚrGDSQ´Ě*”™ÁŰĂŮf†ż—‹×ź ełŁÚ9ˇLŮěŹJA réęXBM6|˝4tAËb[ĹÂcג’HŽÁ<XĽŁZ̘ œűü„fĆŁ|Öw0´ śWĽ.˜âbNM#ÝŁăQ“ČΘűŐžŞŠ¨LNşfVŹv14ĆP¤Ď)4ňJsYćm0ŤłŢéĹIÔőI]ʰeŰT[řŇ×ďăHö0ŇÁˆgú١5Ë"˙žą+ŚLJňfohĄź2—Eǝľƒőč_b—†—ŚćA‚˜Š8´“ňP7ő]‘ĎiZŸž4şńĎpőqm0 śĘrćź …”ŠbŠćí#ǃřöÉÔy‚Œí‰W—ĂMít‡Ŕœ_ĹžYyŠfœŽ´~c-ÚňŒ÷ľ€ęČĺž'î Ć“­gyçęôŞŤŃ§˝Šëä%läřąVąŹł×üŃnżŠĆÂőÝ÷FѲ˛˛ţ"žžGŹ(Ę͟żßřżÉžBaY ťŤ˛IŃ@7T’łł))ĚaKa[ sŮQWKUŠŸ– -tzÂŘňŤŘ™kĹf¸éwid•”S㘤gbᅅbN˘t÷îŠNAń{˜šňâňřo^*&ŮEEԔçQ˜l&9Yc¤w˜QOů[ˇR›Ś {'óÄLza=ş›JŤ‹óďăŘ@Ń7i[¨Š( =äĹŇHĘĚg˙9œ =§Žńć5ĎĚÔNKZ{w—Rŕ€°{˜ś^ŢđJŸŮ™ĂŽÝ唤hŢ1ZťĆńĚ|fJĘf×îŠéĎ|ł?S°ema˙ŽB˛-˜ mŔC@1<˘SZ[DYiYjˆj!5+‡­ťëxújě˝m´-łiv~ü“tőL0ľŕŞ;št–>~=hĽtg!•É–ş˝`M/ćţ'P—fFU źĂý´űŤ,á0[j ٲĽ€ÓĘŰtOE×6QÓŘ~G)šÖdś”çSYQÂΚ-ԔämיuáÓŁ=wbhLĄ˘ś˜ň3Ł}c¸qP´ó)7˛Yąęăԟ鼵ÎÓ*ÚÁRiÇâź_ţłľ÷a7]*Ĺť‹Éľi¸›.đn‹kÁą-Ý˙F—Ő7эŕghÂFmMeŮ*=탌’‹śóĽť 0cĆfßH-ƒ>BF"Žńí“WŽóhÇöĆčU÷Ďë_—Ş%‰ÂŠ öVg“˘)čž)†Ć=¸3ŤWhgćqŐ¨Ż{Vę'–kŸ ­Ďř]ž";˘/ˇhŽůŁÝ~3Œ…ë3Î&łŮŒRSScřýÓi– VľÜ]|˙ËŰČŇTUEUTUY°=áAŢúďďM/-¨)[xôŃ:vĺ9ą`´ˇƒÇ.pn`ޢj.ď!ΛÚëkü˜˙úv7!lě{îY~ŻdţW}N˙ćŢě6S÷ěsű˜ÖňűůӇ ć| şÄ?ţë%úu°d–pä@ ۋÓIw˜0ünú:Ú9yށ†‘Ľ_ÔŹĺ/’ŚîáĚËŻđFçÂFI:˕MsX!ľ|7OÜYAiš‚gʇĎ=Jăůfź;ć‰2 \?ÉߞLá;Ť-ôbŹeGqé Ý碿ŤƒÓ§¨žUŤ-7T;Ĺ[ŤŮW]Ŕ–ÜTR­*!Ż‹ţŽëœ:Ő@Ăčě OŒĘ<| ”ŇLjŔK_ŰU>řl˜ęŻ<ĆÝ ŚýŁ×řů@MTőą¸5ŚaĎIqąvěáľçáż÷YžZc™őMžÁřů÷řűśRţÝsŐsžĽ˝ŐNŚ¨~"Š‹ˆę+ňśů×/ˇέćé§öS›˘,2›ĂŔ?ĐŔ/{žëž(ŽeöÜJî;\CmA N5ŔPG3ďŸôsč¨ĐŻó⏎Ń8çâ ňvđĎÜËŚżÖó~š>1Şş^‘ÝĎ<×Ęœyé5Ţčš{ľ¤,Ý˙^đDžEŰ{„çMÄăßM ÉEľÜ¨’ęl;J(ˆgŹ—Ď7Ą~œ§fĆż`ďYţáĹFFŒÄnnˇ>yů:ż!Ňą}š6˛čU˙ź~uŠćěćOžą“œsĺÂtýϟ›žťäŘz/˙ÓcĹŘŚ†ĄSońŁĎĆHŽ˘/tąrýš–ěN2qÇăüńsL vœâďNŚđíeĎ×hĘó*Ą˛čŽ)’ň4ô0Ÿ—ńąqz{zihl§et~˝D7ś¸XşŸ¸ í\ą[L<ǏŸÖF•§Čű™hËÍĺ5´Ű'öX¸üľ÷ÚöhGdÁęJ˙O 7"4źůk^lÚDË\ !–š^Ëwţŕśhă|ţÚź}݋¨fYE•<üđnŞ’ úOźÉONŽÇmzĄâ¨äß|˙ĐB!Äânżń#Úk~‰6+‡Ă˙•´…bóRpn)ŚČú@+':ź7ƒQ=čc°˝žŚĐQÉĘÍXü™ !„Bą*Ź !Ē }ú™Ż›/ŸCĂn7Ł`ŕ÷ú} B!„XŰ&X593ÉwŞ€BZvIˇÍ‘ !6’Ťľ‰Kă:JF5O=PEY†›Ů„Í™FEÝ!ŤľƒˆçâŹj$ç¤O?óŤ&‘—cKřź !„Hˇßří5żÄ›ŰmńĚŞŠě0˙óÓs_xމ_<˙9m›~^žbŁŠöLví­eWi6šivlfÂAľśUřbľ/ŐBVa1{v`f4çô6ƒŰĺX¤o2Ľ•đđ÷đĽűę¸oŐC=#LÎ_<ův)w!„BĄŮlƴљX sJ>{ëŞŘ^’EvŞ Ťjđ¸ęďŁáňUÎ\ŸbŠkďX0•ÜÁŸÉńÖFZÜńÎ{˘ť=Ž5aú&S6÷=}˜ŞîŁüĂËýč%řă/ÝÁ74óVž[ŽošÇú\ߌýBą lÚiŔÎŇ}|ď[đ؞Ôţkź˙ÎQ~ůÚqŢš0€žWĹ#Ď>Á÷("9Ž7Cgů§_˘Á%&ó)ö,*ňmXšTĺ[Ř ÷ŕă™gsŢžŘă ˙ěQţĺŘŕšžD‰Íž ĆęóOŻÔÓťB Ëź'şŰĺXĽo˛lŠ˘.ÝĂՆ~܆š†[rśY'Řz—{ŹĎőÍŘß !„›ÁŚźłŞ$Wđ{Ő’oöÓôţ;źxe֔ąöN.^๯aÇŽ;yfčM~qŮE|.Ů |ŁÝ´ élwĆ%MËđ rľcŠŹ´Q{q*˙ŘZ9ĎЎW`ďžJóD4GdĄjO“ÇßçĽsŁř—ŮnĺýGşŻa\}Ý\ŸÚNaęZó~;¸Ž5ú&…Œź ě3Í98>ŔŐ˜şt[M|ýË=ÖýSlöˇÚţE!„¸}mÂ`UĽpĎvŞě Áž+ź]żđŮ&}ރwO–SýPĺśRŇř9×ă6Î@—늅ôqNżú*§7:ŃX!ĎZV =PM˙kMQ^Lh|÷MŽęú˛Ó#ŰdűŠÜJí7Öé%˛ŰíX7şoR°Ű,(މ”$iĺ×[çmˇĺëţ)ű[}˙"„BÜž6ß4`5“íUɨčô4w2žč˜n0ŐÚIgÔäbśhëËےf6ąxIŞX̋7%ŐbĹśÉZŮbyÖRśđÄ;XmS2V TŁŘ˙JűŠľőNo#}‘Žu=L/§át.?5vŁĘ=ÖýÓj÷ˇÖţE!„¸]EugUąĽłkß6öVäi7aR \Ă˝œ?u‘SÝŢé‹ S2ľűvq¨6üT+&#ČÔČM—ŻpôĘ0žŮÁĽÉIőžÝŠÍ#/Պň1Ü×ĂĹ3—9ÝĺYt5H%%‹"§†Ąߒӭ ßC.ƒĘ4Eůɨ˝~ňJŠŠ)/˘śÄ̕WŢçBŇ6ž¸§†ŠŚóźúQ;Ă3‰*öLęöď`oE69ÉVԐ—áŢ.NŸ¸Čů§yEr|‘–—ÉNÁěüżúő)Űyč`YVđNŇŮÜČű'Úʜ5͙ËţCŰŠ+Ë&ÓĄœŚńüEÎiu|÷°›—~tŒĆ0X3 ŘQY@Yi!•š!Nüë›1™%%l-ͧ˛ź€B?ůĺ† PlěŘYFUq>ĺEÉ ň?ťŕ^žĚV,Ő=Í˙ĎŢ}GÇuÝ ž˙Ţ÷*Ąs&r`˜ƒHQ9X˛•,ÉĄƒÝnˇgÚÓÓîééޝݞöîěěžÝÓŰ3;ŰÝVo[ślÉśLĺ@‰˘H1g €ˆDÎ@( ŞŢÝ? "U XR˙>çPP^Ýwď}ˇ.ęW7źç6¸ąO}ęՁIzÎâďwĄ“×ňçˇ°ĆĽP€ĺópö­7xŁ%*¤ú]8Ďv˛7íäKťóHw)Ql}ćël @ő[ŻđňՅ‡í—nGĄ§żâ6i‹Ś°b=ťĘłČNŒÂŠ| őϡ‚C IDAT ˆ^nŢYQť4ÜŠlŢžŽÍ…ФĆ80ü^z:Š:™cőĂÜ8|çPŽ$*ˇŻgkQI.SYŒtˇqvfŸľ‚şUÎ8 Š‚y+˚äđĎN2Tž™{7d‘mŕó ŇxĽŠOśrcŁĺžç—čłÂr™—ŃOGçmŕŃ­ydGĄ€˘žĚŸ>zŹž˙á8×ÂégmQdĺĺPZCYž“+o˘1k3mÉ!Ă­ěŚúĚyVáĘ[ËýťJ(K‹BMŒĐZw…ŐÓ~s'§Ĺű§e´ľ%űťEëĎGĆjż˙—q˝„BˆHň­k”;‹GŸš‡}™“œ}˙#~ůŃEŽ^#g[%wUda´4Đ8ębăĺŮ 'M‡ńŇť§ůč|+ ĹÜż{-ĽfoüątąöáGy~ƒÁ•ƒ‡yĺŔ9ŽŐ ŕ*Žŕţíkpś7P?<÷ťv3˝ˆűÖ%ăĐĂTŸŞ§Ő;çRŠË)‰3°{Ú9ޛŔŢ]kŮR’J‚Ó‰&š-ą´]íǑANVQÝWŠéˇPîlţ~îÉḉůůç8Ůů vďâěĽnFĺN˘¤ ‡ňâTâMjŽĺ|ç"´Š Ą&Ű2Rű™đżkśšœŘűxó—ďńvŁÂľą\xý0ÎśŇĺÓŔtn§čŽlI˛¨˙ä(‡›GđxşŽńޙ.Ž ölJ]`:ěM!•/Œú˛fĺß$#a„ˇ^9ÂáŤ4ˇ6säÝs\ń*˘ JXˇŘ„;;Eťśą!v’ޏ>ápĂ Ccct5VóËýé˜5YO3Ü\ÍűOS5~ËؒŁţô ^ú¨™9żnăȇsŕš/¤hr=hiÇFşi¸Ůg­´n]ľüęŐCéś@E‘ĐÇ;ož§şËĂđp?U‡q¤Ó"Śh{sͰڤrŸŽĐËźÜ~Ú?ÔMM] ÍC@3ÖÓNu] Ő ý7(ł˝úď4řŃÄřůéĎOpźž“ćŚzŢ9ÔŔ.ró\zý}öŸiĄą­ƒ GNqŞ\ŮelNťYO‹őOËik‹Ľˇtýšé[Ĺ÷˙rŻ—BŠBűťĺČ`C‘e Q×pfąšÔň÷pĽq|Ƈ§ŤŸ!­ˆ_“Ię5Rů¨/fĺߢăňgŒ*ëÉ!şG,0ÜÄG/ň֑IeIĘßÍŐć‰YŽô¤oţYk‚ąF-ďón÷†śŤ•§´‡+u}X¤f“pٍŠÄÂŇ]\n^ˇ°Ň 3ĎKZĽv´*iŮŇŮş>ÓâüŮ댭úůÂl—Î,*‹Ł ĐĂĺZĎě÷šżËuCh3‘ĺI3:¨0ĎáȢ˛Äa RŰ´pŸľ*×I{ńŒëŕkŽ5R?ó ĄG¨oĆRQ”Ľ`,ű=żHŸŽ0ĘźÜ~z5ópŁFƒ×żťŽ‰ÎĹ 3hž>š:fŒÖ}CÁv‘ë\콞œ~vţôVĽţ"áz !„wHHkV„D2 ýúG‚ßč ‡9öĘ/8cZLú5ĐÉ;?yƒK‰ŠţÎÁYkc´”bz ŔéĽÍŁÉI*çk_ćÄŠÎÔvÓ[sŠŸÖ,œ˚ţSk`.:źi`›ţ|bnY§Łéďšş—Ÿ—–‹çi™ú™–LŚaŕÖ(Ěëe\CR|,‰t.ňW?´ň…^_ˇ Ź[žĹ׍Fa,ŤIÉd:zd”áŰśCr˜üáԃf ž™ë{RY“–CIl '†5¨hJ đˇ§vl9éŽ.3iuÚŃj¤e$Ľ‘ĽĐŢZú—ë^ÉůBi—fR2vОazçŒęjúűF@bz"Qô1zËĄœĂ˜*ƒöĐ72ăh=ÄąW~~ŁĎ23Wď:ŚˇwhN_38čA“HtbQţşeśÉ…űŹp…u}—ŮOŻj–Şw­ŔŚwCV˜Fp7âp-ˇŸśÜżs3EÂőB!î”Ђը(Ü đM2qëg]`rFĐcŃ:ŽpĆ&’›…ŰE|\َ[ţ˛űť8ô~59Ż#+)—}ä˛÷ŢaŽUUóŃÉk´Ý:ˇtJŔ;WCŒ˛ăr(Xh˘Š˛á˜Ú‰'ŕäցAk{:¨(W°Źî"ž˙źŮo”I”ztré{†Xžëk•î(˘ ŔçŸS'wR8ő ‡[ŠîŘ̚œdĘňŁ8yq b˛)M pí˝6Ɨ™îjZľv´ i1nb °<ٌ„0ʞšyŸ?}g0ý‰ůÓđOLâÓŕtó1şŒťxÜh瓋÷YŤ[VÍÄÄÜŠ ŸŸ`sÚq*đ,łM.Ôg…+Ź2/łŸ^Ő<|–­BýEÂőB!wVS˙Yę#ž=šGÜĚŚL}´÷22fÎ;ßxŹĺ/ü¨ŠMel]—CVt%[vQP˜Ć/_9FľgîVkh„ b 7 1 )RnâcƒÁěŕ 'ěŠOÚÓČŻ~v‘ś9Ék´o’ŃF%C)_8őľ*”Z8mĂXr-îíV=č1ŽÔöđ`N9…™D_ź†ĘĎ!ÇßÁݚfďÜúŠ×ď­Y]…v´â´”,oŔbžC]^Íźß ĄöY°zeľôÜţHSőoGďt›œj™—ÓOŻv>ËVŤţ"áz !„Ÿś‚U=1Á¸—Í΢_ţ;2yäÉÝl§ćŔ›źzy88mÍĚŕń˘\2fžM™DĹ8a´›łGş9{ÔIFq9Ü˝žâ„Ř\ËŐĂ˝s&néáŕ4§Üx'i1-Ăó˘ĘOjŒ=Îőöů™ˇŹŢ`Y&řĆÇń,wŸ˙PĘwÂz}­’éňŮí6ěˇfŮé$ęö8Î/œv€fřZ ­ű2(ČÎĄ0Ş Ł(_Ó'ÔOŹ$ÝŐłjíhŇғ“Lj°ŮĚ9×eÇy˓Ť™÷yó3îeLƒĂéŔ9ĎďmNvÚë}ŤŤpÎá`LƒÓžxŸuťË ŠčŘ( ŕcÔ~çÚä´°ĘźĚ~zUóđYś ő ×K!„¸SBú2ߤ7ƌŽf.Ŕ–Ďú8…ŐSÇGUSÂ:qÚFžőÍűoěř‰5Agí^ţ VÄĹEϟ9Ť—Şz…ŮÄ/č‚\ÖŘŔň´RŐúŸfŤ€n?ŕŠ&ŢňËćĽ|ö0ękľXýô@šŁ‰ťe՞”@⼕Ŕ?=mň6łá´›iÚÓJU›锗ćQžĺ§öjÇŹiƒËIwľŹV;Z´ŹÁ!ú,0bbć\sĺŠ#ů–o(V3ďó ô÷ŃéĺŽ#%ęÖß*’Sâ0Ń tő3gIkˆŹţzü ĚéłnwYÁNnV":Úű°î`›œN™—ÝOŻb>ËVŁţ"áz !„wJHˇôD'WŽO˘ÍDÖĹϙ*jO цÎM>ßěőŚç|óKhR“f%ځfxŘłŔˇż×Ď]ŚÎŤąe•qOaԜi~ʝĂť˛qâŁůt MáLľôśSÝâ3…uEî9i›ŃŃĆ:Wv‰ňépëkho;5­>°%“—1ó$ ‹Ó™÷łĺĄg0€6Ü$ΊvL2ňÓYôN9!ťÝ0ÎŐÚn|Ř)Úľ‘B˙uŞZg_č弝ŔÔîŇć{…ߎNĽmR{:¨ë€+‚´Y7ű!Ž(—œU>ߒ&ÚšP7f*JcfwBśT6–ÄĄüý\ź2°ěKľˇŞ–I´™Äú’…űŹŰ]V3š„voăL­g•Űäň„]ćeőÓŤœ‡Ď˛ęoß˙KžĎ ľrßýÖă<˝6&¤iňB!ĝbڤ¤|?ţšTJÝř7ý8ř3@_ŸEnišk2ɰđâ“SYťi3OÜWBTG#ľ˝vň7f“ä6Žoćú88sšďńlN°c(Íxo'˝^ŃlߐAF”Śwpew‘”]ĚŁ÷–‘Ą;řŕƒšŠ›œĎcr€Ś^'E™—Ž!× Z™¸cČ)*ĺᇶ°.ޢçŇ1^9ÖsăÖ*ś˜4** ɋ3ŃĂ´ś 1âťužĄŸŢ>‹üň ňłH1üř ń)iŹ­ÜĚ÷—ŐŢ@È( YlŠĚ'Ë Ń^Ú=Œ@Ĺ,]žë#ΐëËŻÁJEeQ0˙ŢŽľ2P¸RÖ°˝"›TLuŃĐ5Ć伟ôýô (ŠĘs)LłÓß1Ŕ(nr6năáB;~—§5HŐézoTM€!o4ĘŇČLP´5u3ˆ"oËnž(u0éŠ"JůčťŢEר?¸.of]ĎĚë\–/źz˜ćóäVć’î2˝zž÷ęgŻM7ÝĹóŔ•YÂĆt'.=J§Ç$%ݐ2÷0mCó}N;Z<ýëCŢ0ÓşŐ=C.Ę˲(H5hkěfЧˆÍYĎSwgaǎËŢžęť˝řuxyż]Zôw’P´†˛˘,ýăŒůM˘“3Ů~˙Nv§Cۉ#źU7v# ˙~z{Ź)Ëf͚,2l~|ĘA|rĺ•7űŹúáÉÖ-€Ěľk)OPXăCt LŕĂNbv >RIąÓĂš÷Žp¤ËG Ě6ZŸ5Ÿ…űŚpÚf(ýŘBý´=&M›ŠXkŔä­íƒ3ň~ŰXYD~œ‰öŇĐ:0ľFÓFrA ;J‰RCí´ů‚}P\&›+ Čv+c˝4´L•ń÷úrúŮ…Ň ˝ţë_źôŹćőštłńîlJs“bpúĘŔáB!–bˇŰQeeezb"řicá`5řә˜ĂÎĺŹĎM"9چžŁŤ­…S'ŤŠęőĄQÄVňŘ]Eä'(ĆFźxGűŠ9WËřƇxŹŔD“MÇůďűŰH\[ĘÖŇ,Ö¤Çď4đ{člmâĉjŞű—ľÇg˛es ëóRI‹sá4-&ÇFééě¤úňN7 ß˝03ˇđÝçב”5kT4Đs‘üä₷}ˆJ/ćŢÝe”gĹcLŇÓ\ˁăěúÚŠŹ&^ţ›#ÔĚ .M’Š7ňЎ|ň“]“ăt4\უ˝”>ű(w') @ăÁ×xąťœóÜZ’ćäő çç˝ÉgíćŐz<7^ç˘ňÉ'yŞ`’Óżx7[o†Ă¨ßń|s‰<qkxä‘ÍTdÄŕd’ţöfŽ9ĎٮɅö¤ŠM[(ý3]“a§5_Çć”sߎbJSŁP~cíœúä*Öî/đĹźŠ;ˇŸáżüŹ&äóÍűž ą]îTśl_Çć˘4Rcěţ z:š|îÇę—xď†xGb.ťw–ł!7‰Dˇ‰ĺőĐŮÚĚÉ}Vř×i.'›Ÿ~†'ó †ş{˜ŒN$Ńeŕ÷zčźŢĘŮSŐ\ę™n#+|Ď/ŇgÍ´hߣĚF(ýŘ\fÖÖš}€5Ě'?{7ksŮmĚ×Ćk/a➧yŽĚ1ctP3xî}ţş!Ÿß{ŚtÖŹéň_KŸ'oSďőKń᡾ç–1˛ ú¸T;ĚśńŹ_ŸĆĄŽÎ9#ĘKežâڇ×ÝVśŔŮc)ßZÁŽň 2ăŘ´‘žŽ^şĚĄË˝ŒME$ʕƍ”äfR˜KďÇŻń˙ŸąîŐCéÖJö”gďÄô{éíhăÂéKœl#źŐ­Šöíáî”QNýę$5Ł „E!ć[Yy9”äP–çäʇhĚÚĚC[rČp+ĆťŠ>sžƒŐC¸ňÖr˙ŽĘҢP#´Ö]áĂcő´{çžŢp§˛yű:6Ś’ăŔđ{čé¤ęüeŽŐßyt&eąĄ8‹‚ülŠÓýűÉ[ęӀäź<ÖćgR\˜EöD5˙ŇĺGɗw~e=És˘n44Ë7FՁˇym|=ßýR v…šzţĘÁwyĽjáő̖eƒƒŁámÎ%„B!„řĚY^°ŠŚëjŰ7‘U\HёNŽĚš—Šˆ+)  ĐĆ/'ÉŘ6O*Š<ĚÓĹ>.źű!ŻÔ2a‹Ľd÷Ý<óŔƒäĹ}Ŕ?é =Ž(âcČÍI Ć´čS3WĘşXűŕĂ<[4ĆÉw?ŕĺf:6ěĺá§Ó‰őmŢi uŻA|ů.žŞpÓqě=´,°66Œźq™lŽ(gC^ď–=÷ÓhćRgÜ9l*rÍŢhIŰam* M\›œ?QÎ,* ŁPÖ8CŒú5~ď0WŽUs-`#˝˛ŒbGđX=ÜƑ?ćŔ5ߜŕQE簵čŐ\ĂÁúAF}~Ćú;¨nĹ2c)΋ šfROݟ‹ť§Š×Y§NŢ­ţŢ|ő=ŢiđŁ1ˆń5ňӟŸŕx}'ÍMőźs¨!\äć;šôúűě?ÓBc[ŽœâT?¸˛Ë؜6łv”îŮNe‚Śů“ŘŚ•–žÚ[9řĆaŽŘÉÝš“]É Đ 7WóĆţÓTßRszŒúÓ'xéŁfnýŐâÂ9?€ŸÎsÇx§~ĚDvî-"Q˜¤­+ŚŔßÂŰď-¨Ţ¨{ËC˙°LB!„âónů ő(Ő5=ř°S´n q3â)#š€i\šŇšŕF8Ú?ĘŔ˜[ť6ĽÜXKŠ}ăx&4ĘMư̈œ`Ü;wDMM­a5“SÉşą‰“A`¨›şĆFNŐ …8eTáLJ&ĹĄ0’×°!}áAçđóîcdÔXt×5Ń9#  3hž>š:făÖ}Cnăg\&g•ĹQčár­gvŮü}\ŽB›‰l,Oşyq­ Ƹ–w‚yf/l9ç×c\>xš*¸ó6óDeŽô <ąĂM͇§¨ň„|*ô„‡ÁĽnî+„B!„řĚ[ć4`§žĆť3)Ë.bcbGú5`ľ6ŸTO oˇ-˛ZÔßÉ;?yƒK‰ŠţÎÁYëJľ”B-z_œ k¤—6&'МŻ}5š§j8SŰMoÍ)~Z^yĆęĎđN|_.Kd÷ƒŠűé9Zć^]ĽźOż`ţ`zz7^…i0u3)™ ;hĎ0˝ăs_Óß7B€Ó‰˘UÜŰjEçף͟}0›Ü/’ż÷^ž5ćĆVó1ď^ó†źY’R`Œ2, V…B!„řÜ[ѰÚŰĆĹćI0“¨\›a´ĽRQĂ@m#חŘŮȢľ}t"ššY”•ącKَP#=ŔßĹĄ÷ŤiójIšě{äaž÷'řľ{ŠÉŽ #ĆŠ>tšjĆ–˛–/íNcĄ;îŹJޗAE9q+`b’ůý“ř4(—+x\´ţ oU{Đö8R]|t´9ńî" Ó@ň@ŹB!„â3k#Ť>ęŤ[ń”“\^Dî‰~Ús Y=̙ŤýKîÂkO.ä‘7ł)ÓÁÄ@í}ٌŒ™aGĐc-çxáGmTl*c뺲˘ă(ٲ‹‚Â4~ůĘ1ŞĂˆnôh3ďĘ%ďą|R6í⾆ˇyçúÜáŐŐĘűż,~††&ƒÝ™ÉŽ‰TŸ ´í’4Łí Ÿě7HB!„B|žŹ0X…ÉëÔŒą#6ÍyŐD—ĺŐ[ĂĺŢ%DG&<š›­qăÔx“W/7423xź(—ŒPsŚL˘bœ0ÚÍŮ#ݜ=ę$ُœî^OqBlŽĺęáްn_ăŠ=Ă;Ĺé|š,ŽíVrőĽÓ4ΌV+ďË Ç˝Œip8óŽúڜě ´×{óDdĘ{ IDATö9r~GĆFžÜî¤öL™›óÉŢš‹˝ÍďńQW(WGÓqů ŤQ!„B!DÄ[ů@ ż‡‹ľ#XĘEů֝ě*°Ń~ľ™ĽbU[v>ëăVOU /¸óîRŒ´|ë›÷ßÜ}֚ łö/ЀG+â⢗QČŕtŕ*ĆL,ĺ‹{2q݆ź/G żN(w)QˇţV‘œ‡‰f ŤĆŰţŠáː×ŇŽęůA9Ňš˙árŐ'xýđ ^;?„eKfďCÉšÁ˝B!„âłif­Z´×4Ńm3;‹Ł—Kuž%7Í1vl đůfďlÚqš źhÁĢIMšńځfxŘÖ¨ę4=ÚĚť53˘ ’6îŕÁ<ǍŰóŹjŢĂ5Ń΅şq0SŮP3űÚRŮX‡ň÷sńĘŔ͍›,=ƒ´á&1nfM2ňÓgíä|[Ώ“â}ťŘJŻéŔŤ}4=ÎąŢfęZžŘ†cŠó:Ҹ÷Ů'ůýŻlŚČľÔÁB!„BˆĎşƒUÓKnié6ˆĘČĄ<#šé˝„Źž&.uYhŔ×ÖHÍÔ}0 ť›Źâ|ňce'Ť(ŸüD'&ŕëč¤ŐFjkM@áLĚĺÁ§v°ÎŠ@E‘•“@ÔTí1Šä%ŰE\z)Ι–Âë(ĎJ$5)œâ no;G/ö/xëÓKţş5dقçË+Ë#7ŢqăV4žş3źS;F,[ş‹=… ÄŘTŘyˇE§°f*ď1ii¤şŚón#);…˜ńäfGcŸú=.Üx0HĚJ'éĆĆM>jžâ "oĎ˝<š%—5Љdĺp˙{ّŕăúɓœč›ůuÁ$ľ´”mßHaŒ2ÝämÝËS…0ĺN"?Í55/\áH˜>ż"i%ç7]doÚŗֻh˝\Oűttďëăäé6Ć´Ię–Ý|q}ŽE‚f39—ŠœX’2 Y›&+ƒ…B!„řźSeeezb"¸ S)uăßôc[F%ß~f-ÉŚÂ0 Ľ0 …Ő{™řé%ş,E|ĺƒüŢýI4źťŸŸV{!žœo~cysF5}§ßĺŻ÷[XÉcw‘Ÿ ńâí§ć\-ăâąL6ç/OÄóÍç֒4#Fѓměá ç˝QäŽ-ekikŇă‰wřÇ=tś6qâD5Őýóoßcdlćť_YOƜ¸Ç˘íČüăŠa,ŔHßĚwżzó8Ťç"÷“KxóCĚűń8žńü:’gćÝ×Ćk/a➧yŽěćˆ-hĎ˝Ď_7äó{ϔÎńÔŢkźô÷Ǩ&6ÜŠlŮžŽÍEi¤ĆŘ1ü ôtrůÜ%ŽŐĎs[“¤â<´#ŸüdĆä8 Wřŕh/ĽĎ>ĘÝI Đxđ5~2˛™?z"֚Ôeß™ĎW~gĺvuٌž†Łüůţfr~†Ż­wÎřś$Ř.ţzőĹʕţĎíe“­•ý/ŁzľďÉ#„B!„ˆnˇ;´`uПB!„B!ÄjqťÝr§!„B!„‘G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„G‚U!„B!„Çv§3°ę$$hr“,rS4…éšî3v^nťÓB!„BŞŰʚŮ~ţ暊jöóV&ýŠatöÔ^78VkĐ0ś˛ó­Ů1ɟߥ1gg źuŢäĚuEë¸"=Uł&YłśŔâá2ÍP‹Éľńŕk5*˛ -˛Á× ^=gržŐŕRŤÁĺ~X“Žq)čźfă“fƒÓ—Żoœ ÉĄř¸Ú`ô֌Ű,žž/@áŒc-Á?ďˇóRŤÂş•%„B!„‹°ŰíËYUš’<‹ 9Đp6ř”™hą%Ë"Ç4xé–Ă;šMŞ<Öť‚­Aƒ_|b2<őű¸Ěßű’ŸÍњÍ;}üď vţăŰ=Ë X5t74YÉć҇ŻeńÍÇ|<š §Í9qW‹ÁĽa¨ˆ >ôź|ôfů_L đ§Ďű)ˇƒ=Ţâˇpé“ ĂÝuŘ<Ö2xíÄÍע ĆS&ů­lˆr‚:›M.Řu3śĚ{M~Ń?;oö,‹MQłŸł† >iWřV^5B!„Bą,ËŰ`ÉÔ§€žTÔNfŃéš,úťÝa™Ă&˙íC“ÁŠ×Ľ•úůö­ÓRĂ 5–92ޘôß{.¨.7żŢnƒƒí7ŰÓ-Ší ?‹V˝dŇܧč\¸ĐĘĐě-›== ´Č"Qő)՗B!„B„bY#Ťf˘EĄŹNƒkţŕs…p­Ă °Œ4G x"Pš-›,˛kLŽOQ†Śtm€/ŽľX—މw€BŃŢeđńY“7›ţ…74k7řZ…EIźĆWÔ5˜üô˜É•™kd–űyr}đq6ЖbpPQÝ`ňĆ9ƒďôÁš-÷řřƒMšŘ!˙Ž/Lđę‚˙éCşŔ:ŃY8f^ żb,Œůˇ}56ţ]Íüżóx!Ú ¤sKž°Q7śaą=_ŁüU=2C?§B!„BÜNĄŤ zb‚_ĎRD 2ýüżßőŁ˜f0 ÚţĐ/=L˜üŮ 6Î,AŢ"`PÓ_ŠŚcŚXlŒ6šîlšÇ÷ń­B1Š8pÄÎGý°uˇ§óŹą(~ÇΟ_?0ĚŰćăß[ŠOę ňÜŽŠŹđSžĽůĎ?łQ5<Ž|Ď$˙ëvC+Žžďŕ/ŤśL?˙˗ܗfąˇĚä˙~ŮĆéŠ×?jpôŞf[šEňÔ°jgłÉ…Ąŕ˙ˇ÷…6Öż&ŔC7_Ż2¨ ĽŢlßţM›j|ű%V\¨UlÜh§‚_2ܝ uS;#›ŠŰâŔßnpĆką!¤Ü !„B!ÄíF°ŞÉI—” ”Ę—|<Í´ =aąv),‚SU•ĄÉMƒ–@€Lq;Ňáň<÷SíŤ787ýiŻÁąë°§4p[¤Ÿ6鰝# c@™[ň4Ż_Th­č ćJ™inLF–YF3Ţâ [ç>?ćQ\ďSx™lË đ'_ă[ŸÁĄzĹ}•H.˛ŘřąÁżf[ĄĆœlPh V…B!„$ü5Ťvȋ=aĐ4ľ%mbŞ&QAOZQ73ÝbsęVtĎÍâŤ_šdÓ1;˙Ű ƒńů^Űlăß70ܚ˘ ~ţuĹŇŠŠ1čÜ Ë圸'Î÷ZlOŤÇŕÔä/ż8B!„BąęÂVÍD‹\˝Š–Š8)75ř5÷,osĽiQށ—Vx&Ŕ§‰™žflZüö7'řćŒ×8Śî?ŞŠĆžů׏z}łŸ÷θ'‹˛iÜ€Ŕ¨Á' 2ł,6UHskl 2ŇWP¨EX~čé2řŐŰv†m>~ŻHŁ”íňóL“ƒwÍó" Ă#ŠáEKż˛BߒkMý]&Gú<ŸBpóŞňm…4_3čĐŹ !„B!"KhÁŞÝâťżîgťLSá2ŔĚôóß7€R`łÍŢ\Éßbăßź6ă^ !JOĐ7-ĹőA0âg0řÉË6ŽOÎ}­śýžž%‚5gěŢŤ5ř§~Ÿ°&Ŕď=čgK<`AwAó8—w7ÚĐiĹńŤŠß)ҸŽ×ÝV¨ůi×<›&Íä3řÁ NlšĹł_Q<ł78Úŕ; ÓRœj˜=ę,„B!„‘ ¤0̈Ő丂›)™ĆÍ͕œ&ęćKӛ+őŽ(FĂ͉ią1ëć˝J­^ƒKSLÓˇőyÝ Ľ!Љšq˘×ŕžč§Ň zŇŕ'?ˇó‹Ž`œťőá *VvÎĽLz^ ŽŠŒĹ¸ŚWÉ..ŕ_"PŇ^kru—ŸőśŕhrIJpÍďÉže[!„B!n‹‚UŤßäţeŔ—żęă+ɊŸüŘÁŤ 3ŰĎ_? q…›+%–Ř3ő@ĂŮ FđŤ]Š:?lś†&/XI°:˝śuęáHťA‹ y7×Ćú; >čZѲ԰ĹÄi˘gÄŚ]ƒŤ;⩇ >nƒuy7CŕΓfVB!„BD céCnRN‹˘„஺őS÷MI×$)čě4–˝šRbޟ?ź7x/P€žZ;?¨Ž3ŐŁ&ďÖM­9Ušťśșb+ťfÇ]>ţă>‹„nkjÄYěÁŐŁ LOă¸9Š˘,6/śfŐžQmZBpýŽĽÉ ­ü*ĘâŮÍ֍oô˜Á;ľóŻż]6­8^3cÓ&­8}m‰iĆB!„Bq‡„ľÓHÖä›ŕkW4چk‹ŹŻLÉ °>ććc3ÉâŤ{5vČJˇ¨ČиhżâÜ{ gF¤vňcoĽúx,bóüü?ß Pף˜´kÖ¤i’ ʼnCÁi´óÉZ ˘ß`Đnńđ>?ël ľââ;?ŸÚÄh Ő ŢoQn3=Ŕ<'F4›ÖwŃŚ˘5ůŃĐ75şŤ' .÷Ŕ–Ě`°[|×$ł^áŠŐ´|âŕ?U$çZTĚX{k&Y|}Ÿf$ŃąšőšŽŕëýƒ—߲óÉh°~3×XŹ›ôšŠźŐ¨Z Âł,6ÄJSZ ¸×äÚ(Œ4˜œőZěu5lprę­î$‹Í)3ŽsźĹž5oˇ(Ć>Íáe!„B!„˜bڤ¤|?0uoĽÔӏgţLZcńxôÔŮxťMĄ Řš5@…Űŕý#&őól|dfűůŻĎȡß|N95E™š‚DpYŠćë‡/Řřáű㠐|ŠsWLZüÁőŚń1šěDMźĄ¸Ţbňâ;v^jTř§ˇiîŢj‘e)Žž3Lśxl[€§*,ňlŠćV“W?´ńOWÓYÖăçťɉš¤(Mj˛&ĂçNÚůŤkđ`™ĆQšť+5ăľ&W˝ŠúëŽ$Mf >EOÁ›‡ěüđŠBgűůógÜRţâ,ÍşlMq˛ĆáS\ď48rŢĆß°qlŕfÝýٗ9fźÖĄY_ dĚä`çÜĄd3ŰĎ{.@áÔůŇ-Ú¨i>or}R1™dqwô]ąńŁ…vřŸžéç.÷ěsTŹ Pé7yż=„áj!„B!„XEvťUVVŚ'&&€ĽƒUĽ6—&Yt{o>Ÿ ń .cS%!„B!„ânˇ;üűŹú˝Šî[ŰeôM!„B!Äę kƒ%!„B!„âÓ ÁŞB!„Bˆˆ#ÁŞB!„BˆˆҚŐţÝIL†ŚĄP L#¸Á’Ą@ɒŐĎ­§˙ŤóNgA!„Bń/PŘťĎ÷S!„B!„X-nˇ[Ś !„B!„ˆ<Ź !„B!„ˆ8fJJĘ÷°zӀmů~^řŚâ>Gűokţ…¸í”3“ÇżńEpľsîú8úNgčśÂťřăoÜEFĎj"-wâöQ$m}„?zž ęëiżÓů‰\fö6ž÷Ű÷PěŠçRˇ)>đ ż˙ÔVîŰ]Á˝ť7˛=ś #‹ô .Ö?ö$ßŢ¤ŠšŇËřçđ-şző+„BÜdˇŰCŰ`iĂžIţÆŕŚJ‹m°téCzAÖąN+Ű7É˙ąUßžÖĆÇÍmoˇńIř|ŠX‹ÇÖk< &‡şW;uƒô͛Ůě¸Î/Ďő%?*x­ç<_Îo}cY ‡ůżŢhơÚY]5…<ÍoTDąřťŮ˘ńĂ_ńĎĆ>ŐvźPýF›ÉŽő)Œ7ÔpQ>źŽXtœ;̏ęL0ŇŘ÷ÄR—|—šľěýúî/iâçW˝+~żé›řÝŻn uÎÜ(‹ś#ođ§†ąVx!„"„Źv6™ź2Ś0U0@ĎđXžćúUÇn×Ý)ęj.Ú86üoąŤ<ŔŽŃDżdçÝÁ;ÁĎ>#Ö⋻tx >îVŤ8)W{6%0\}ŠZďBGŮH**çîMů”dÄmďP5çÎsŕ|cŤ˜ŸO‡Ś˙Z=öϸłKؑç¤űJŐýúĆqƒŸFČýŮŤ_#6‹ťJé÷ÔqŠŰ/_JÝaś3üĹ_œ+°âk1ŢßMC?`ÚŮŞ !XŤŻžS­ëx|[ iu—čZ•HR3Řx…s“3ʤšžň`8\ŤYżB!ÄL!Ť˝-&ű[nNűÍÖž-ľ&Ż4ÜÎě}(šęL^o~lňf§ż{ÄâţbÍű§•|ąąĽ%”;G8~ľ—yÇǔ‹’{ŕŮ ]5W9pžÁ ƒÄźRîŮ÷żő>/ë‹ŕQÔůh›ŽđqÓôcEĘöśçŮ銭âăkĄŒ/Ż’ĎeýŠOŸfzšË1ΕŤ<ňp[˛ŞyűújäE3Ô|•Ďy" @źÓő+„âó*¤`uŮ ÍśÝ~žžÁ"Ç˝í&/°qthöa*ĘâŃťiĐ1!(W€?ůŽŸŘ*“Ţœ[݊łGmźă đÝmąc?{ËÎk]S‰Ú5{śؗoQ˜ IpÂذÁĺŤ&?9eĐ曛‡Çöx¸Ŕ"Ó >Ż˘ť×ŕ“Ó&żh^ÝŃş‰ đœJn=@pMđ?>ŕқNţŹîćóq|üÚ÷^qđm3Ö<űľIžŠ˙áĹî=~îÉŃ$˜ŠÁ~ƒ~ÍĆĎTľ%X|í^?÷ĺh˘üŠšjű˝ţdˇćĺźŇ7#]›fë–OŻľ(ŒÓ¨IĹľF“Ÿ~brytn~/żoçlZ€'K-2+kšŻýÚ$ϧÜ|]ĆC“üňĄŠƒżýĄw=!_–y¸()NĂôÔQß3_ P¤lş›/o€łűßä˝ć›#M×;h€ßŮ]Áú‹9?:Ď˗ ˘RŮ~WŰ SHŠRLziźRŇ'[é›/rv%łăáÍÜUœD4ăt5ÖńÁÇŐ4Žę•ĽťŠůUŽ"žţDUU3œSJ‰ŰKÝŃăœvmŕKŰ҉ëäĐ[‡9Öĺ'œú˝']ŔžŔú­eT䧑‘MŒ&†hźZĂÁS-ôÎéRŮą§‚­)$š ^/ƒ˝]T>ÇáćŠuĚF"÷ýÚcܓrs†IŇCĎň§7Úd'oüđ§=łÓ őZŘó¸wßF*rcqůGiŠžČń‰ĺ_ 37˙ţŠ|ߟú´Jî*M%Ńa1ÜŢŔgŠZţWi!ŐŮ2ęŔŸÍŽĺlĚK&)Ę`Ň3L{S#GO^ĄŃ3•˛rłýËOńxîtG ţýWůńĺyFĂlË1ŢŇN›•CYI ď]ď iIÁ’”ÂévăŔÇč˜oEi†÷Ţ$Źú ˇ…ÓvBć5ś%Źáž{+¨Ě‰Ĺ鼼úG˝ĺ|}ˇÉĄßć㾛š¸]}ŞBˆŰŹîđ‘?jđá)$ZŹhřšIçt?ołřę3>žKV\¸`ăÍ>HĚđĹ>Ö%Ůůă7 füM (_sú„‘ ?ß㣟Ó䕏Mśí đ•žnŕ”Űâą­FŁÁG×]c˜ińčv˙%ŐĆżfr#ţPšGóńŰYŠ“çlźŢśhM^–ĹŽ\ƒW›ŐŠ>¸˘4É1€‚Ř‹GwYDOš6cT5ĚzX§ĹˇžÔX&?zGá14ĺešx'ŕ ‰˙ęË>îw*ŸąqiĘÖűůý0oMËĐ<ňEßY5U&?ęb5÷VúůOš˙ü3—nů ˝á.?î*űK:)ŔoŢż‚ö`)>xĎÎ%;ÉžwŸEß;?jœZŹí+ÝpƞB~†żľ—Îy>ł+W.÷ěLŚďÔťhžýMaŃW]Oă]ŰČK38ßć‡~[ ÷>óű’˝4\¸Ä‰žąŮEěÜą5IGůÁ› Ďj6ŠöŢMnO3'_ÊĎaűćM|=ÉĆ?ýěmţĺŚ{;ňk•Oí‰ ŒUlbë=÷“ŰYĎáű(Ůľ{wäpţő&źaÔĐÓ”;ƒ[ł1[špmˆÁ1ELfۡßÍoĽçŻ]cđ˙gďžĂă¸Ň{ĎĎŠ@# €9‚HQ™Ę$Ć“=֌ík{칯ӳť~î]?ž÷îŽűzwýěŢY{mŻóŒÇžöf$Kif”I*P˘˜@$‘Ń@ŁCŐŮ?ş "‘@€lŠżĎó4AtWŸ>őÖŠF˝uNů~(ćŽO<Ęău ŽíŮÇ;]iź˘bŞëQż¸˜gŮď‡`€=?~™Ś0ŘĘ5|ö‘ĹôďŢÎËMšaš.E×č69˜™Ř~úó÷ł1ÜÍŢ÷vÓ<eéú;řL‰%űw-mDzüž{(8t€çż˙nŢ >öčZ>óń8mß;J÷LÚĂTc6ƒú†ŞÖňĺ/le™éĺČÁƒěęNb‹*XYˇ×6Ňt˙›Ł˝Řý§Ă,ZŸ)śXƝyœŤďTć8Y­öřÝgäq(â6űé0ÓÂĺËYc[ya>`‹ëxđŃ­ÜľŹ”hşŸă{Ďâ'= ŁLs°wÉڍÜ;šˇżĘżîîĎĹĄ‰óÁ|iý&î­=ÏZF•i ‘FžůěÚ}€“4}”˙ŕZ\sŒoÎ&{Ó.wNęëč>vťˆş:6źšŚÝ{ŘuŇŃY˝Š‹+¨´§éžV|§^îšÜŕž˙Fú†F­ëĄœI’_Ü\ĎÊSlĎ=›‚ŹY"~ř=žˇŁuÔpđ}X;z†Ţövz/XDG˘ç§/s áÔcf¨Ůź‰ Ĺ ö<ű Ďĺ’ß=ÇzůĚ/ađBŮ؆CtZöÇaĺbGḏ8qÌéjë˝öö0—La1ăNMňŞĽŚŽ ŻŁÓÀ­`ŰO?Čśy˝ě|ńţůĽŁ ,Ťçśâ™L:bń’jÂA'ŽőŠCŠS‡›é§ˆĺKJÇĹ! ­ń Fvô4žĺ|fɒŞÜYŠ™”;őu eӉ$™ É`ÂŽD"Q ĚLâ;•rs‹fcZ­ő… Ł˝ßĨ(˝TŽó3¤2PP]â˘qQfšŔL#fڈe‹K1Cç9t65jßláŔéä¸}sfm§ĺL;‰Qżw÷Ć lŒňľßéÄlző5%‹¸­ÖcčÄaŢëw1H00ÓűÂLŁ=̜Ďp2/JQôÚJ .â[ß›Wv7˛÷hťß{ů֛ěíó¨Űş‰őEW/crÓ؇Ś_ë)ľłšŮߘú66E,_R†:ĎţQű—nĺ@ÓřOső*""ÍiĎęŔĐŘ$'íg‡h†GŽ<󊁔Ą}ܐÍ`Ŕp!€E%ËĽÄĺâ.Čöx^L&Řą+´¤>Ă7lŹv”„Ó7=Ž5eůţť–u÷űüáŻút^°ď0iňxő¤šćŮF;Z-ďL°dy˝Éđż˙\†Żl x˙ËŔ4âp-šs0`hšÜévă¨*† nčw ŘŮ?Ž_Đ:ęJÁůü—ßœźß93ŕ(604Ş %Çś‡ WčLÚÍ?OŚŹ4B˛o€A^ÝJśÎâ˝§ŢbgŤ´qŚŰŁúßm™~Ń&JIąŠ8=â§/0T•Ä0ŒžJÚŃ×?8&..§/ KŠcH3“rgˇžˇŰq]ŕFB€ľx„)™A|Ż^îEaŞë×óĐćĽ,Ť.&2Łž҄źQߊóěxˇ%÷Żçu }:9ßŃMsS{OörŮI˘g)f˜eE&÷ü˜%éë$ýÍ6ŁśÉdzĚžér_¨ăŻŤŸ˛ŠĆlšőľĽ%”[Gwgß,OŞ5ö§\˘…wöŃp÷|–/đŘ{jfc‚ŚžMߔÚŮ\ěoŔ”ˇą‰QVlâôŽ a@˙ĐŹěo""2usšŹÎĹe—-sÜ ó×§ůŁ$N{|ë%Kó ¤„ůüŻ÷OLuNíó[Çś,sŹ­ hXĺsďFŸ}ć÷ß°łz{ ż×˛ˇV/ XéYöÎRćuŐĂ)ߐžÂF™îá˜ßéńľW,“”éR†ž›ü:—fČ "cc<Â!HĽ˛‡ĚĄ’"Š]/ç/umâşit”ďšŇösî* \gWݏgߊ}?ĘÖoă—>VKňôQ^Š ƒ)2źE üüýUăB•Ąu÷+üůńůŹZś€ĹľŐŹXľŽŰ6Žĺö^ĺŢhç2ó͚›oWšť˜Í~3žn{˜Š…Q ~’Á9i0ŽÁx‚€ é „BŮ](3” a*(-2ЗŤM¸’™Œ™sIâ>ÔS1!ŔYÇŔŔиu6”•a鉏),˘,ěH e{#fTî\Ő÷jeÎa|M!őëj)čkä[ĎíĄydĂĘkźËîCŠţ ށĂűÁDćńĐç㥠ŤYął#ă÷Ť­ětbć†č‹;ly1e.~ľ”•1ćTÚ\măşjĚŚYß €žŔPUUF˜& ?m3lŕp.{˙ě)ąĹT–Y‚Ţ>şćä./šöŕŇ ŢüSĐNkťšélc7DoÜaËK&ěoĽĽ1쨁Ěůśż‰ˆ|ÝđK)Žžľ$mŔƒőnĚđ˘†Ű*1ěožŮĎpް1$o&cň h\ÚîR†ó3řŕ)đ*6—ƒßcrUL/AÜĐĺ`邀đHĄŽ{W^[˛ş˙Ź!ˆ<¸ěҙe ¸o™wŚŮ°ťŃ2óůĚFwŠ…Ő3źfj&íÁĽ %ąY>#žéäL{€W=Ÿš MÓן˘ ź˜ŕˇ4q o÷<°Šš¨Á„ŠYťm#kftmZ†ćłHŰ*6֗ŽŠC„ˇ-Ś”AššĆĹÁ˛`ÍRć,l¨X˝”…6Ùłr×)ϤܚŞďŐĚe|-žg˜Q†Ť¸sCŐÄ}Č S0áű!NçŔĺ×ČĽR$!‹^ŚMN#fnÓÍ}¸ŘBÖ/šÔËo ęظl|ůsľG ąôŽm|á÷óń5œŻß”c6˝úşsió‰­ZÇ•ăžÉmĹ3YŸiś‡‘Ś˘ĺĽ”Lá‹ÇÄ*Š+ƒ–ŽkœŮÝŁŹ˛dÂľŁ^ůrî_W‚I´r|˛éËo3ŘߎnŰŘ Ňtś VÇŚeŁöˇčÖ/+¸ű›ˆČ­íĆöŹ=G=žkřÂ}iţsąÇ۝PąČç§×9úN„xn&3ŕ:ĂŢS–/oóůž€Naǖ Ë0dĆýÁ˛%>˙ĺIŸä)˞6COŞ<ą:xźŚ“ÔŽĺk|>S (* ¸}MŔrkxĺ]KŤ›~‚^Ë{]đäŚ żçk˝kť–ó잯ŻOóčÇSď{섾|6Orhçá˙´2ÍWJóÖZśŸ3 zP3/ ae@˙[ţčŕôgćI{ú GăđxC†/y‰Cŕ Íç ăç`™žaˇóŘŁľŹšo9Ý>vŚŃś–N‚ú:–gâŻ=ż‹ŘăˇóŐ߸ŸŢÓç9Ÿ(žPŞ™ˇ„mw—NÜVAGvŸĺBG÷óNĂGyŕžGůRń1Žtú/ZÉ=ëb žx‹wZĆ­˜s¤JÖđä§#ějě#(_Č][ŞĄc?oż4Iȴ˝˘Ů/wćń˝*7ČÉSÝ<ş­žĎ<áŘu˛—d¸ŒUV˛€8ţ¸ŠÁlÉjžüäj2§Îp˘­ŸxĆŁ|á îZ˘˙ČiNOňýôuĐ7ÜŃp çl<ƒsI.œë˘ĎŸnĚíűp`ýl~ěQřŕ$ÍĂ,ÝPĎ*›ž°ÍŐ6Ę.aĂ KGďa^nœŘ‘<˜MŤž.ÎűŻîcÍnçŁ_|ŒşM4ő¤°ąr–ŻYŠżëYžÎÝş&T\ÁÂňl˛açÇa(Ź˜Ď˛EŮIŞüÁÎő¤pÓl#‚nŸŕî­řěC°§=I sţdë¤÷֌-Šc‘dĎńÎkœa>ƚG>ÉGK:9yž—îx ›ÇęŐȕ$8ň“}›ëqéL#žÓ,w&űŰUMk;:öíc˙ú‡ŘüńźœŚÁ0‹6ŹeÉ ßŰsżż‰ˆÜÚnx˛JĆň­ď‡é˝Ďçńú żś†ă†ýťÂüËŽÉŻ‡œŠłťCü‰Íđĺ>ż´RqÞ!ţ¸ŰçkŸ7ˇmÂňúą€|vľŁ8ń~ˁ]aţő˝ w1œk7eXKöşÁdÂĐÜęń÷xühômVڇŔđě‹!Ş>ęłms†uC†=űCüiÂç˙úČĚOŮť„ĺož3đp†GîÉpÚpřPˆż<íóżÜë3Łoxéš0m›}>}[ŔV:"žĄŤĎpôpˆ×ÎÎđ23iˡ^ {Ŕç㏤ů\Œoů믇ůŃ5mÂÎ֑A𯞓÷pő˜ŚQ|ÇCüâށýŻň§Ż´âOł=\âsîí7y.rÝv;ŸŢb1~;?üF]ăo÷cbŹ][ƒ×yˆŽ5yq)ZOœŚůśjŻŞ˘>bqŠ]m'řń{ŘŐĚOfsŚŠ›‚eÁݏóŐ-üŕ›Ű94ćHÉPŮđ(żú`ŒĂ?|…N^ƒÄ[‰â+śj#żöĺzş~ô<ß;6ů}w%ßęś}’_Ý:Ä ˙ ťošż…""×_,ĂŤŞŞú?w?%ŤâYƞ5śŽGśůlLz|ëKß ŤŮâş§dý&6†ZŘs.1ć@3ŃŃJkx ?tkЉD’á´ĂF‹¨ŠŽ‘žĺ[lÜZ_šů°ţ‘űhHä{;ÚĆÜÎKň•ÁNř[XFĂś ,K6ńÚ ްş‰ˆÜ:Âá°zVeăřÜçŇŹëńŘuÎĐëŤÖú|zěz1Ě˙Ó8ĂĄ˝z!*–×óđ]ŤY[SL47[‡K6óƒoźÁţ™[“ŠŻˆ\Gڌű?w?KzÎpô\/ƒŽ€şľˇqߊG_|‘ď7&ôˇPDä:ˆĹbJVe4Çć{2|acIŠ#f łÓňć{!ž:aԃ5^4FYq”¨É0Đ'žŃ!ÍlR|Edî°ňž;ypÍ|ć—5ú;[9đŢ^Ţ<1ŔÍc ‘›ƒ’UÉ;ąX,fš‰“Ůăœ:nŽÄDŁDÔŠ]ˆĹ††Hľž'ŐކK^‡{mÉMMÉŞˆˆˆˆČ4lX‘@áŔI]Ž2[TDńÖť(žw…ËV`‹K0ĄlÚá2‚ř‰Ó§ˆż˝“řî]ƒˇŢ´e^I)ËWB$|mĽÓ Ÿ:‰?Đ?;Ë3JVEDDDDŚáąťłw>pRW1W°j •?ó$EFÔŃL$‚WIÉźJŠ7mađŕ>şžú6Ă'o@moŒPĹ<Şĺ×)žýNŒľ×T– wżOŰ7ţżť{–j˜?Ž-:"""""ˇ’ÜšÎrç:KIlî?ĎŤYËg?ž…ŰJňČqQĂjçw)ŢźuŇDu< Qźy+ľżóť5l™ľzä{Ě ×­§xËVŒç1×ô0žGŃí[)n¸ýFŻÖœPĎŞˆˆˆˆÜœlľ+–ąŽŽœ˛¨!=4Ŕůł§9Ô'5Gšfąeeů˙îcÁ}Ň™Ł˜ŹZCőW~HMí—sŔř2RSKőW~Ö?˙Z~ö°ÎrĚl$֛ľę™PŻ´dÖĘË'ęY‘›P˜Úu¸wE^_+‡›9ŸŠą|Ýî[V4gšwŽó(*4î\7{ Çő171łEET~áÉIU7îQňĂř?RSKĺžÄͰsĺĆ´3ÉR|EDDDäŚcJjٰ°€tű śď;Că™sěŮ}˜cqĘ‹Y™ýĎ,.€{Ö_:|žg˝Ľ¸`ö?gŽĚ١ŢEŃƆ1Ď9 l %ž7ň(ö,ŸŹŞŕ7-`Eatdš‹Š66PźőŽ™UbŽ\vžsxß9|禴쇕†‹ˆˆˆČMĆPZ]I))NŸďbřâÓAœÓç¨_[ÁÂy!šŰfw¤ĺ őK/ b­_jXžĐÜ$łĎMĚL4Jń˝Ű.ÍöK6I˝żź„ĘK( ]ę}v@U8DE(ÄƢB~ŇÓϏşzéÍřr×°ŢťwßʓŰÚ\ŸvśŹ B}ʐcC ÎgG­ĺöÜEŃ ‘ ‚Ë.űaŚdUDDDDn2–˛’BŒë§w`lSb ΰ+ĄŹ¤Óg:idU™aŰ&KqĄ!ߣnŻ7”_JVˋ ?˙XˆŽ9Źťź5†xÂącżOWß´WpĚMĚ" j(Xş|Ô§Ŕă•ĺü|M%֒vnLyS×Ępˆ E…źÓ7@O.Y(XşœČ‚’gĎĚ`gŰÜÄě"{–_­ŤfSqŒýń!ţäL ýŸťK‹říE5üĹš6^ëé§4äMX6îŽţ0Q˛*""""7Ś jŔĽNʖmŕaZdĎ`Š$†˘‚Ś•D 9B|ĺ“!ꪌ–|ęţŸşâóç/8ţżď§‰MŁsiŽbŠ]ˆWR š÷-ˆ„y˘˛œˆąźŘŐËŰ}ń‘!ŤÎ9Ť,gyA”şzŮŢŰOĆAÄ2š“^I)‘Ú…ů‘ŹÎQĚFł sˇŻ)´›K=ŁÖś—ţĽe?Ěnh˛jŒÁL%Ć.7s˜–ýP/;ţ ڈˆˆČä,žG€Ľ¸´ˆ‚°ÇźŇ0āo÷ŻLŚáé×}›ţÇ/†šwƒ7ľă˜Q‚vđůłďf8ԔOWÎMĚlaáČŕŔ9ŞÂ!ćGBœM&ůN{ҙěßÜň‰ `ČhMĽš˝$Ćă•ĺ|ˇ˝›ăCĂX“ l gm­ŻÍÜÄě" ř>ßl˝Ŕć’"ö 2ŕűXcx§/>’˜žÓÇ3é˛ötőĆ%ŤŢžđ›˛~ 5şÎŇTž„•S˜pMËޤËvŕ˙yßŐ!Ŕk°ř´Ůϛ-–îA\aր̋ŁbžĺřPöŠĎĆĄá‘Ř_Ž­Ś&ć=¸IojsŁÍ}Ěö&Ř?˜˛Ă¨ Đďű<ÓŮšßÍe–ý°ťqÉŞßĆËßy‘Si“™ iďa-ű!^6_ĆȈˆˆHŢsi†“JĂ„Á%‡ččĚždŁ˘8’ĂŠÍčî‡?ýnšŁg~ăła–×]ů€Śą9ŕ/ž—áľ|2ţ5|đ\™Ł˜‰.“ÁD"X§‡“|íl!?UYΕĺ4 'ůQW/&×Mí÷•—°¸ BópŠÎt›{Íe2‰Äě­÷ľ¸í &O:G'¨W[öĂěNŃÓŃEύŤ€ˆˆˆˆÜ”ú¸ęĺ%’—zˇ KŠ)0>-ĂלD¤3đÜNŸ!řoż&V0yÂO8ţäż§yë@> űonb–j=?Џ­ŹĘţîˢa~ľŽš E…Xc¨‹†š§Źxä=ĂpđRW/šĄÂţ@?ŠÖó×śŞłćú´łŮ‘o˝ŇłăVKÎEDDDäŚçčżĐM?ęV2rŤS[Ě҅%˜t/çťgďś5óJĄ růd 0j˜_žďÉÂÜÄ,ŐŢĆđ™Ś‘ß Đ—ń98˜ +-Żß÷93œälîqz8Éűýƒüĺšv~Ü=vŞäá3M¤ÚŰf¸Žłmnbćü Ěâ\-.ĂW_đ&¤Ů€EDDDäŚăú[8Ô2Ÿ{ęVń@CŒÓ=>E jYQěÓuź™ółt JĎÂ}=Ž4ŽgaŰ&Ëó;ýě5Žyj.bć’Iâoď¤xÓL(„z3>ßmďbWœOUUЙÎđě…n̨޿dtnLϙËdˆż˝3O51Ko$qź‘ŘÚułRÇáS'<řáœűEÉŞˆˆˆˆÜ„Ň´>Č;ĂËXˇ°– ՆLb€ÓGÎp°yŮĘk+ Ť/%YéŒăŐÝŮŇÝj ‡˛Żm^eŠŠ4œżƒB'771‹ďŢĹŕ}oŮ \z*‘äŻÎľSčYâă˛xĂÄ!žƒöß˝k†ľ˜+łłt[+mőgoފWR‚3†’;ď!şd)M>ă{vCŒ\ç{9~<ÎŕŢݤ[[fP“ü§dUDDDDnNÁ0-'ŽŇrbî>˘aľĽś2›Vuő9žńĂ4ßůIvĽŸý˜Ç/"Le™ĄśĘ˛qĽĺü…|œ]i”9ˆY08H×÷žM¤śŽHMíČóH;G*ső[ʤÚZéúޡ gŻbłeb–nkĽçĽçłżXK¤ş–č’Ľ$›NŇö×ArÔĐę[™ŽY™„5p߆ě˝6ž ř˝żJńőç3ć!> _>ĂďýUŠƒ§BÜżÉbL>÷ŹÎát|ýoHľľNxm*‰jÇ×˙†ásSš›€łjmĄýŤDuőʊˆˆˆˆL˘şÂ°~…ĺŮíţňé Ícďęœaçţ€łm)~ëó!Ö/ˇ,¨°´uߚ ëŕž=´ţůרü™')ÚЀ ]9Őp™ ƒ÷ŃőÔˇoéDŐCŚ­•Ž7^%qě荮N^ńŞŞŞţŔ÷łĂŒ1#‹żO姈ˆˆˆČ‡ÍŠ:KküÝsşú.ż\˙ źu0 •6$’ĐŢ3{ÉŞ-Ž˘~A˜Žsm\˜ĽIŁćRŚť‹Á=ď“j9!/Z^Œçpé4~_/ƒGŃýĚÓt?ó=Ňł<űďÍ3€äŮ3$›ĎŢčjä•p8ŒŠŻŻwÉ܌[JVEDDDD˛"!đŚ<ĂŻgłÔěÝ5çŚf˘Q" jˆÔ.ÄĆbCC¤ZϓjoËŤY%˙Äb1 ™Ět“Îé$śˇ—Lf{ ϞšŃU‘›”&X‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;JVEDDDDD$ď(Y‘źŁdUDDDDDDňŽ’UÉ;Ą]š…™0eŐ X˝ź’Ôńýěďr7şF×U¨|)ytĈ¤ýä~üć1Î Ď °|ežÖKDDDDňޔ’UoA_ýÜZćyk-ÖŹ5ăsäĹďóTŁcőÇ?Ǘ×G1ăŢďńO˙đ§ƒ9¨ýlđćąísň`y7Ż<ýťşo҃é›l=BKďŕß?ą†Ę¨Ĺŕs¸çűť27şZ×Oh>ę^VŸ{ƒżţAÁŇťřęgîŕKŢţb3ÓÉWó5–ůZ/š9Li°ßžŸü——yfW+ýpƒ4ž˝ƒżű‡§yş1řůţě_ßŕ'Ç7ÔƎžÄŸ}óýüMTSXĹĘڢŠX]™lß,nśőȜů€ż˙ö.Ž ćwR=W"KVłĽbˆŁ‡Űt<0†‚’" Śšńň5–ůZ/š9LńšUÇpG4s!‚~ŽPuC=3@÷9ŽœO‘ßľ˝ź›o=†ť›9Ţq=ÎdDXź~kĘň%…7ĚŤ™G!—ŰPéŢvŽž8Ĺď˛ďrëq=c9ůZ/ščšŐ —]Ď>ËŽ]kuSއ#¸YľWUĎ㏮ĄíߎŃxůLđ:2D06Di‘|2]'yáů“W|ו×ăúÄrúňľ^""""’ď4pŽD)řDăòłĹ+]Â'>ą:ďF×d,c ŕQ\<ľ!Űůş"""""sĺş÷ʚÂJśÜšŰWΧş$ŠÍ$člif×ŰűŘӞž*¤nébęW,bíŇ0Ÿy™˝Eˇń‰ëYYĐ~lĎžÖD§?2'ŤKÁ<6l\ÎęĹľŹXTBç›˙Ć7÷^Z>T̚­ l[[CMY/3Lgëyö˝€]ÍCř—[ÉP kˇn➵5ԖE š4]8vŕ oědčJ=Mă×ýŮW8TşžŢ˝’•UQHôsśń/ż}ŠöÔ×#ˇLÝëŮş˛šyĎ tœçƒw÷ńîšÄČpîÇ2ZĘň•Ůz×׼Řţ]ô­ÝÂĂ€Ú€ IDATęXPdIÇ{i:zˆWw53ů;!ć×oâcw-gYE°—Ś#ůÉťÍôŒ ´Íg˝ˇąeĹ|ćG°™az.´qhďAŢ>ŃO6,anž›Ÿžw) †Bś~îËlŔçđŸâťÇ2Ó(ďĘŚZFŃŇ <žu)Ëb€•ů<˙ŰGŔ ŕż˙ý;œœĐ¨Śž3‰ĺLˇwöcf¸˜bîů™Ÿćą…d†éء“g›ř…űćS˜;Ůâ2Ă´íŮÎ?ěh'Şĺ§~áAî,c—IĐžwˇ˝ýƟ#""""7-ŻŞŞę|?{¸gŒy\ü}ĚĎpś,˘ŇÄ9ž÷4m™‰}B^ŐRî_]†heץÎ1łššŘBžř⣋ęk¨ůůßřćîžě‰” Ή}gH.^Í NńíožĚNĆo‚kłEDDDd&ÂáđL‡Bá0áG$űđ.7¨1ĚĘűîćöy'vžĹö3 ű>ńö“üxw;~A Ű6ĎÇ‚îSźđýóbSGˆëJŘ÷Üv^ţ ™ö´.&ÔS/s2Ž˙<;^}“—OŚ'ôš˘El]#8s„×Nô2˜Î0ÔÝĘáćAŻ„UKK' ž‰ÖąiE!&HĐÖÚÇ`Ƒîçčۇ9é‡XĐPĎŞČĺ#;vÝ=jĘřáS;Ř~Ź•3ÍgŘńŁ=6-_ÍmĽćŞëĄ\Œ yםě<Ÿ řœí 0ĄrÖ,+Ĺ^c,ýöFžůÁěčŔ˛°ź‹—^ŘËáö8ýýÝÚţ6;ÚŠWnćţĹăKą”ŰVž~ú]Ţ9ŃÎŮłMźúボń-ĺëVł:zqškśÝICšăĚÎ×yvw3g/ôĐŇÜÄkĎo睞0‹ďž›{* áÂéSě=ÜLkÂ:OŸbě=tŠŚ~7Íň.gzedú:8rü,gú˛ŠëЅ?ËáSÝÄ'ÍźŚ˛3‰ĺľmď™î`ŠXw_~`m;^ĺŰďśĐ;Şc8Ůq”íG‡đXźlŁ?3Zɒ*KĎń“œL(Mů°›Y˛ęŐđSżô3üţoý,ż˙[?Ëúí'G˙ńąĹ“-ŽÖąeM “šŔьĨ¤ĘoďŚĎʖÔ2¤FiâiŔ1tâôéfď;‡xű­ˇxőTzeNĆ'1 GœsQćăQX…Á>ŘŃÁoEŠYľ–<°žUĺËůȖFŽmďœxŕŠĺąOßËÖŇG^~ěĎaöjxbĺbjŽóé7œdČA4ćJťsK E%…XŔͨ‡Ń%†r‰FˆNňz(!lŔ _ůö@łXŢl×ézšćí=íý#ŕ\ă.t9~üÁ*~ĺžyÜűŕ*ö?}ŒîIââ†Ďąçd‚uëçąą~-uőáˆ†‹ˆˆˆÜ2Ž[g_ĐÝCG((˘ě łáŢč2/˛ŐůĘ/=zi&Ř I[ă>žűĘ)âÎPZZ4iđB —ąžÔ\8Îë‡ú'™@ćú ş{¸ăSQ|ůlu.c™fq]ŸÖ–ŽĹĹďî˘- &VJUářW •UĽx8zÚť™půč•7Űuş^Žu{Ďt˙ŸÖݰ§Ď]´‘Ź)¸L†Śƒ§éq†ůëśňđĘBzOj°ˆˆˆČ­äş%Ťn¸…ĂgÓŕUqŰĘ؄Tݍˆ’ËÝ'ă:–9†-bţźą]ĄÖłXýýńI‡#ÚH˜Ňéą÷ĚôÂDŻĽ.3ä†[8t6…óćą~uل[‘„ËĘŠÍ},˝ĘŐÜľ< ‰óěnœáý1“-ě;žo>֏mźĄůl\]ŠÉtł˙hϨaĆ>ŔĂ_˙•7eLÉÖcfe{Ď`˙ ŐĘ;ϧ€uŰ6ąü2ÉrŚőű;LY5KŠâ=>Ů`Ëü†ůÍŻ<Ág×Oi¨ťˆˆˆˆÜźŞŞŞ?đýě! 1fäqń÷‘çC1Ž^AĂň Š ¤účč"1rôhˆW˛vý*n[P€!CoG7]ńĄł+`ŮÚE,_VG•͐ąĘŞŞY×°…O=ş†Â–SœČ҇ŠŤŮÔ°‚ĽĽ.ŮOóů>ŇăSœé•9™đčĎIôp˛š—!Lq wn¨ĄŚĐŃٛ„ ˜ˇp?\Okĺ•WŽĐ2Éě0A:ʲ ™łôŸ8ĂšD+óČwąĽ<Œ5ŽDgMĂš¸L*šĎچ•Ů: _Ş Ş–p禅̏@ŞŻSíC¤‚ËŻdčěôYRż%Kę¨ eH›e•ŐŹmاYMak'úS×KQťnkË A˘öž$iÂT,\Íă5°*gϏw°Ł=Ă)Żăö†eÔĹŔěäTK<מ,EľËškýĘC0œ‹WÚtˇRžr ő+ë¨Č$ĘxUÖrçŁwsď8˙î~x|hTRăSPťš ˘¸AÚâUKWPëç|_ŠŽi—7a‹OťNáâlŢź’%%R4ˇôNҜǝŇzř3ˆĺľí;SŰ? óąľa)ľ…†`¨›Ó- ůęî!łh%ŤŤŤX\–ŚťŤŸž„?î$F’>Ż–;–Aď ~ňV+n+kbl|ŕ.6WǨňzx˙čdˇĂ‘›M8ĆÔ×םd2›u].YőŞ7ň˟_ςÁZ‹5k ŕsôĽđTŁĎŠG?ĂĎ5Ä&ôÜńcüó×ߣ)w¤Š\ĘśťęYż¸‚ŠX—¤őLďź{˜Ă]Ůd˝ÚŰůÍ/ŢFĺ¨n* ńţžá…łž§Rćdźş­üÖĎŹcŢčĎIçŮoźĆŢáBŻ[ĂÖ5u,YPFYԒIÄik>Íťďćp÷ĺfž1”­hŕ÷­dYšah`˜áÁnŽěi$ąńc|bš‡R§ßá˙ýÁ‰1ˇoárëž:Ďłßx“+áw>VÇčŽ(˙Â~ţáľ0_řÂeÖc(يĹÜ{÷Z6,žGEĚ#ŽÓÖ|†]ťs¨óRŒfËŹ([>ű9>˝ĚŇ×qTQ–ĚpœśsÍ|đŢa\Há€đĘűůŸZ6ć:O7|’oýí;ôÝńS|őžyc.¨NŸy—?˙ÁqúŘŘ|nżó6śŹŹf~q›IŇsĄƒ{đö‰ţą=ڀ-]ÂcmaSM1QRtˇœáí{ů =[—é–7™Š–1i› úŮůçxšíĘŃ˝Üzě/žkĆąœńöśWß?ÂŤîç?üôřzâ[ű>„Ş7ń+On˘Öpôîy™?˝}̉S´ŠŸűĘݔď}‰żÚ>ŮýU-ľw~”ŸťŤ„ś/óŻ{'ż˙ąˆˆˆˆÜ\bąŘԒիýÉş˜ŹÂá>ĹwÍpf‘[ľ‰_űŇ2N>őŕL d„ ¸\ů08đ,ŮgwéóË.› <“-7pńrďgđ]vů ÷3㲿¸\šfÔşšͨźÝ0yźó‡q.Ŕ†b_4† 5€ń"㤇°‘’)”:şn“ŐórĎq•÷]/ֆ°ĆŕŔXKČA€ľq ŮmŽľËţô}L(„Á`ƒ Î cýÖZ ĆóŔ÷Áď˛ŰŢy!| Î9Ŕśa|Œ5Ř ŔZ( ”Ř4e‘шGšI¨çaŒa8°„Œ#€ďăl˜ˆ…pČĂŽˆçŕ°/űž‹ĺA€çeË ü‡łLö=– đGĘ\ö ĂKŕĆs. ‚Qĺd×qüúďƒ1¸  Ô?7•M """"W0ĽdŐz!2Î8k a(Ââp.Ŕ'Lp&DŘĽHÂց F\k˛Č!“M•.ć#łé“É=k˛Ä°2~ö€1f2ř&Œď aR„œ!%b26„ .%ŞŮÜ×âYđĹđ3كo—M^˝Ü'_ŹKö9‹?ÉÁ8Ć0ń(Ýá'ş ĹŞČ ÷bC…kń“qźh GěÄ Rqźhţp6R„ąapç2/š+?Ŕů)ŒőF’+cźěA°ŸÂ„ ˛u0đp™Ƌŕ2š×Œ… 3öŔ߆łkdŔŕE.e346Ł 3“,=괄ą` ŔᙋŻů8gŔd“Ł‹ĎŰěR›=}ŕăđB!B& 0!Ž4XČćYăűŮvf `ńƒń<?ĎĂs— 䟰1DŁ ä [bB”F"x. J#a<ăr ]˜´ďő|Áł` 0ž#řDŔfëoŔ ăšă§˛Ű#“ÄsŽŔF0Xź°G2pDý45$}Ďy cR)ÂÖá–´s`=Œs¸ çƒő| MÜ“lłKŰgT"7ęMŮvdË1/&dˇIřšDÔdż‚ĎË& Ł“Ac˛m×Î>&—x‚ÁóBřžçyšÄ1űĹ`LŽ&Ćň<çFއIgŇ٤2đą^—KdłÉŁőź‘rľX™Lf¤\k ?çeO–d“~‹ďgȝω‰sk-ÎŒľ¸Ŕ[G°Ö#“I†ěŚ eOŞ\ëÎ%""""Ŕ“UŸQ˙xĹŮ-cqŽ€>KŘf0„°ë‡ “!”ëQu6„šx48˛ÄĹŐě˙C¤€0žI‘!JÔd{ƲIQˆ ™Ŕ`<‡uC€5ž çzmsÄš„ǘl”Íőšxš¸Řż8‡5&÷Yn¤nc9ţP/^áźQľ'{@_8çźHq6Št^AY.›3Řh).đń *Ŕx…Š86\ˆ 28?[6 Č$16”-ßů٤Ó3ŮtßOcź‚lŻl˛ăEłĎŮp6‘ €Ëödť‹˝DÖ#Hô`Ł%@™°vÓeÜĽ.ČŕYC`˛=|žądp&LŕRř„GÚа`‚ç,Ă.CÂ"~@ÚBČ ˆ†Á>&!ß1ŒÁĺF `˝\9.×ă`­wĽ­–MXsm<űŒ#pŽƒçeOÝp1i ‚‘MߑݎG)äzÓéTv{Z;r‚äb<ë‘ Œąd2i"‘h.9uŁĘ°#ËZkÉäN&Ćbp#Ih8Â÷BĄđČ~zą×4űů—Ú^d“ÖP.‰wÎĺ’ëPöd’ˍČpA6ąܨD5Ű[ ž—MźgČdŇšóDßĎ&Ůل;Č˝/űZśwúű”ˆˆˆˆŒ5Ľd5B*Íö(d…KÉäzI38Éő\dŘBžÍöŒbą.“škCczpŮ֐grĂĂš(6—*†<˙Ÿ˝w]r$9Žu?wLTőCnIç}ĎóžŰŢâeş€ w??Ü#ęJ="EJŰŇÍÚş.@"$ĘbĹş=< \Š2đŚô\6RnŁ`Ł–wŔPIf*‚Ś÷ăŐ1#źŚ|¤…mód\~ĺ¤hß3ýŁ€azIymÇď@Ç;qü{űéw2ÝCÜ˙€}ůçžÍöö;ć×˙…Ž[ƒŮŁXś}‚f–ăńd˙˝ýXĚh‚n?‚Œ[÷ŰďˆűĐí bˇOüŚî%šDö ús8ţkćdŋb*ä•Ú‚8Ľ¤ŚIŠIJQ€˝Yz( úf†‰°™a4€’é90ćyŢŚŕ.|‘ЃĄQ őń×÷’| z VœM•ŰţÎť›ŢřížńfÉo4˛cŢ7aȃ!ŕŁ$Ć!ZRôađáɆó@™Š$ÁĂABŘŘřˆbyçź‘¤(ÁÇýŠM…TâńŕĂ ń ŘQő‰H˝Ćo1™ ]Ý˙źHj˙Ň, ś™2ݑlź‡X›#ŁLýĚF˝)ŸŽ˜Lc™¸ű > 0>éŃqĘzך3ZŸQw'=N–xmnŹ÷{ÁĹÚ)îO™°™2ňSŠürÖăÖ †.农; t.€áˆšqpcčdFgOi&xÉ7 Ŕúň°eąJOyŸżTűý(pH‚X‘PY Áú°÷˙(6öVő7‰}ů§iˇßŔüó˙]LŤ*y|EĆ(9?vŇď%녖 9„ß˙ŠX.xjq3ŸŒě7Ď@Nśíeł`~=˙%§FkŔQ`Ľ€Í;÷ň™Š‘ˆAäd¨ŕ!lš(F˛ÉdŒ{NgćDbö{żsŰ6x‚é`k?čŘ`2ŒŔĄ[ŰPŸĹŔ6ëfŔ›ÁmżńťˇwMžlHžp`ź›bŰƝX?NfbĺzfłAôűńĐ7”É!Ę=) ĚłŔĎG*’“đ_#8BPMݘ1šŁl’<Ž)°Űŕ‡aĹ„Ł˜ n9Ÿü”ÔŘÚYM ~2Ůż$ÁţěíTUfђl]Lu3œRŚL˛ÁŻ4°ĚŒÚ4˛ń”î’¸—X—|˜oĺÂzť~^×â+–|¸r‚׼\ŕ‹ŻţÔ5ĹĂŘ6ćqœŕbţˏú˛íyi=‹Ł~‘ýĆ T͌9ý”O—ôŮ?˝Ú 7“—Żî}˝ćškŽšćškŽšć×ĎwŐ;;śíÎŹŘ$Š-šUE—¤öđeS)Š6:˘˜­Čö­ÎňgjÜ ťŕő;i éX:)űy.Ž€ľ@h1Ÿ'€+Zě^&„—/ňu ™(°ŤňX‹a^}ßNţŔĆ­ă…Ů‚,™AqŽŒĎۧ%C)6ŽäÄsĺÄ6P9ż?°V—\8ěýŸi­/K˛šÎOĆű/žů/Íëń˙˝ŃePm0żFD˘č;Œüf_Řâ EŮ-˜şWř Ž$ƒ/[ŕ ›LĐ/l˘ÜÔąLDĎŒ–Ÿ–ź86eFd/éďţ›ĺëQžä\F61I šl&ě L?îĘűmă Œäf†É@ü@Ě0MŽ,isHŠaßŢťńxüĎ Ž‡lD8w<Śp÷,@~‡„ĂŁveTˆx0ľź´_ŮP D’ťŒöÜ*‡—›ÚuĂˆnl˘-žĆM­eŠŻSĚc1‘YčÓßYŞ…Ră=¤˜l´$ó‰ Ï˛í”„¸%îf R ´-Ip69*$fľđ™Ż×Ďó˙9TődZë^7h‰yBř|l˙ě:hžZ Řö[ƒÓúIFôaőüzůo{ť¤ĆcŒ‡ZžŰ|‚ŢőůĐg8”š"ÜżëŁuÍ5×\sÍ5×\sÍż1ßV7&;6č0"‘b-MMçȒďZ¸ fA˜b•ĐbÁâNęŽĹf¤OCăૼ#›%.[I]ucşb9Ëd*jŠŚă2NbqÉ=§4ëŃČó5îd1k;éďž,ĺşí§WA°ˇ?ÝŚćy~/Ş ÄńÁx˙=1ďÄăĎĺSýú?KJü ůÇ˙žüK˘Eß~W ěۏ§?,§Ü~ű÷?—üxź˝œé÷kůš|žÂgO!ŚRŔľžŽTXŁXKÓR _ę5Ue0Ůl ń™?mSăÍ6o@yˆUĘ˙şkłiZrŰ‚krĚ D*Őq”ăă_IŮęńIŽđňێ2Áně ˇaX<؇ńŰ}ăśďÜr˘1QÝę 2¸iĹ"IŽŕ^ °(ÜT`ěĺdÝŢůÓÇäđŕĎá<>pž>>řC8‡÷F " 솪iŘc"6J2,u…>¸!¨耀!“;’‚Ű ?œ\×tžř‚ĂŸď‘ŽĐ˘ĎŐĞ k%÷čóŢŚŃŸ+IWБOĚś .™íŤGśfy=—|vą•Ż‰ž§ˇł}Ą١Šyžđ IDAT_‡—OŸ‘|‘˙P=ŻWY.xúsRŕřôĄŞTř“Ďç}°Žc>YŢ'€ŮNV7ó L_wą˝6ő—?S×\sÍ5×\sÍ5×|˙|XĹnléÄ20Š’Ž™ÚSeäDŚîŒ“~ĎŐď‹äWo?ňŠ˙Ęů^s]>™${Žů@scČAä“ß2(™ˇéÁÍvD7, ÂvFíA„Ą`–ˆw…LÂ{Îâ›b•|+âdXĚždÝvĆźCÜA&j{ů{E(5t2d 2[2 żÝÝ7ŢTŮŁ|¨ő܍ÉLC¤€sڰŠ!ĺˆ$żŢűN„đç řxpdrgđÇăÁ‡;ÇĂ9dTíKŽËŽkƒÄI6q"Ł|ËxkcÇظ3šĄ™19”–ˇˇŸ9ż}ťž˛ö\ $ęÓ#ü˘Á}MŽ:U‰J&J›şü ŻÁHźx;唯z˜×š˜Wć׏>ŸŞźT m<•ż}~ÉgŻébuid<ľâ äž 4ÇËďý¨ëw'-ĚSrźף6VžŻWɁÝĺLB^ËW,Z˝ćškŽšćškŽů›ĚwUií&ĹG>¸ĄdĽŞJ-Ć3˘ŔLVŸj4ĐÔ|`*¤î¨$ƒ dCĂ!ƒĐ72“)6ŒŔÓĐîp•Hlż‘ǁ¸ˇ¸CˆÖb}őŽ.eŹjŠG€ĄÉ!ƒđܧגgŰč¨Í23s~‡ů{ű=éwž!LUSC:şuďjţő˙Cß~$c–ż5źźŻ™Oyđ/žŐß'ÉE Ž˙7mů)“ÄşaŽłËƒÔ7-ăŔ‰¨ĆbÜ0 Fű]ŕ-&śmľqŕýŚŞ<|:ŚJŞpÎ^—ÇvCӉů`ĘÎ. ö5*q8&›ďęěŰƎłçdC”ԍÍ*ě&đáĆ“)Vk /9íáźÂC7Ž Ś(?Ľňđƒ/éđ‡*"ƒŮ]Ÿ˝)ҒőcÓŔMKň}<Ř$Ý!œ„TćobĎĎCśç~Öľú”é:îóüşęhô)“ÍlpyŢł@ałŮďEˆÖkżXţfN×ő'"'ŘlťëÉŹ>Gžý§Íęć:Wľę7m/Ѝ’îŸužzá–ůż*-ďůH˟ŰÉĆŃ,j1ŤvžF'x­ˆĽóÓd6NŻ+" ŰŘXcœŒk=^oŒ58Žç8šćškŽšćškŽšćŻŸďcVi†Bʋ6¤YËt’-­üԍÜŘň d Šlw *ĺŐšŽfŐŰTřK˛iŮaJŞUűbŠ…B3Ů9p*P(ÉODaFş!8*QáJ'čĘNý…:Ţt?á`PRT˙ľąž-ÍŐíË3ŹĆŢÖŻÚfzşMŚŁă˝ýXţW5âăzÓĄLúRÝżőŹĄeżýZ™č/ ę˜žŐćC|vă] ;˘o$Á‘Ę(ĐşŔM:o ћ ƒ$;Ívhu°j乙°ŤĐÔRže1#,yD0ÜůŞđČŁnżżß7Â'Őˇůžďl:°ř¨°%Ÿ¸ÔďLŮĄœäžFŚâ9Kň;)Ůń1Ů4yD’âČöƸílǃ™Ő zä`Čä>ÁlŤ~aîhęÉšN&L&3ÉśGoŐF‹Zy]#•H˜YŔmRňk•’ËĆ `[,ߍÜwýœp˘CŚRíźćŸžÖJ°6’pœ§ľŽ-Ÿ<œß>.Ťş#„ęHÍ{œ.2ącéŸHBHݐĚłVl¤žTç3Đdłú˝{Á¨č)fÝÜŹM# “ŞŻkČĺÇt`Źŕ ^\˙j  %~ű=鏖Büë˙‹Ţ~$ÄŢ˙šdąď˙ŁSřý_ŃńVoƒ(ş)żâ‹Ü÷?kÖŰ0¤xsoĆ@śF𠨚€ćŃĄ>‰É$ô›Ę ¤$áÎ!Š0N‰uęŽÄŹĘĎ秊Šp;‹[ ŹH&ˇĄ}íGży›L[ąě6ř-ÎĚwöĚbĂü6ďäžaş‘20śtďĚHć€Çqgł Ç=xduiŠ F%ٍڎ°ËFŕlöÎ‰ĆŰ ˛ŽÉ‰¤đŚł} Z2ߘ¨•çQdƒ˜ĚH‚ ÔČ2+›wËň\W D!Bč8ý–*í3}šFĆŘęüżń•.wޝ›4֛4Ö …34(˘¤´Í–Şm|Ę:jÖtI‹}­yyzQŁŠ^Ÿ^˝¨YŮ̈fJ×q~vą&/Ďőمúó [Îç|ę%ú|2r}đO ¸ě Uƒ” jQ!ك˜2Š‘şV‰léň ‘â×ߜ1śŸŸ×5×\sÍ5×\sÍ5żzž Ź>äVŠź)Ɛět_ĹLpoHbŁźŤrBFąr ä,1ą L’ĘPđ91S† G”ńTçŁÂ“¨ddIŽŤB¤ÎiÓŔSŃ|ÖҤZ䵐֪Љ¨ (lŕŢĘ^¤Ě30ęř•ŕđL÷2&qü„ގ–ng⯽˙3qüT ك‘n˜ţ¸Tý K~řŸçJ~ÎJ!~ ?{Ĺ­´WżŹĎSć+ÚBßÓ[˙|-2ą—ڝ’—¤š@ëů íyçE\żz•—üÚż_˛rÍ5×\sÍ5×\sÍ_œďîY-çjő”Š čŽEyůÔś>YžŐ™”ŔĆƑV˝Ş \ĘçÇĆuKE¤yn[1]‡"Ŕ‘Ę͒™Šâa¤ˆ@3ŤĽƒkœJ &)ďš*s1ź´.şF¤eŽžů+ĺżB|üáL÷5tűŃą–÷ĎŰ=ţT?ˇ _ŕ9?é`¨Z!éçŸp(Aů"ĎŔ*pHr2ĹxcâlX~pĎÁ źŞĺ-%ÜŢąô3ůy=˝Jd"˝q`Fp÷d¨ %ď”ŰĄŇÎBe'NŠ&jŒ,ŠďÖĚŠw@ŘTN8r2$ńŚđđdv@˜Ł< 4HĄŞrFůdw‚ĂvÇ?žňŐ*öž&ĚTŽG˝0ö Qăă1ŰŠlśĄéä19˛Şc„$›A͖°Qő7‡TŞvąŽĆVĆPDtęrĽY/&$Ű6ÎÔ㨍‚uŒ16$ýô˝B6ŘÄXžÍŸc”,úé[=݊óţuü§|1ŞËÓ ŐK&ŚÂ\Ťů” ŻtⳏUä”çžÎŠçď–_4ÉłŠé”§DŁĂ•źoÓĎA@Ľ*|2žAKŻU;Œ­’Śű1Ľo÷ŻĹâŞüüœŻšćškŽšćškŽůőó]`ubľ`őęGşjŒU3Ď <ٔňpŚáˇź“Vý¤Éň{aˇ YJja{DVĺčS‹l1Ľp8%7V"ƒ”bNŹ“q#č`Ÿî˘ôg­G;mĎďČϰň—€jĆň°}űReĽűćsń.ÍÖ~;˘†č¨ššˇ9?Qý•Ďy…çúž“\Éň×ď^ReĽ€Ë’ głÉžĹd?ävJW#Üіó†Ŕ\ŁîŐE)Â[w9ŽÍۆ>ŻMŠYŒL4“7k/­ n)Â#’›­ÝI„7SŔP‰óžĂ KHUĺă˜<|Ö% <4uăîÁg"Čc˛™cGÜšÂěФéË lpřď¨'‡S˙§3ŃęÎ䘎bVˆÔ&M{ł+LŤ$Ž.šŁŻŃĹŢEDűK[~;'6ŹHű, ę>[zے_łłfHýRšQňíŹí¨°Qő5˘'[ą€ÝJú­NŘĹz.đJřt*÷â'__ŹNć—äÝόę_÷~2ڃ˜Ž”SńťŘ ˙$9^>Zȓ}ý; ˇŽúţ­˜>XړúĘňŽç+"ĎĎŐVŻšćškŽšćškţ&ó]`5œłX’1Îđ%ńh&AwˆJ•(éăP?8ě ÉJŽ4¤ĺށľO0—ćˆÎnĹJ ě⽸—3-ÖLJŚšŹ”v-4ČB•€3˜˝2͖6ÇZ4÷ýž Ť@ĚZ´j‰O‹ćďbaWĐRVĘďúéJúý;/lÇ$"§ŸT2§‡Ż"Ťä|şëyTżi'şjýţ!oĺéŒčžT*HK Üd Ą†ĺQŚoíL-œŁƒz¨`äęčŹt`ŐÉ;TbŹnË÷|rĂLšeŐź¤(ŚŇ$Fŕ<ÂĹ{ՏÄ}–Ć˜’÷~ĚČÄŠŠ™¤ú]-¸TÍMä@8pvđăúƒŻšáş“>ů8ֵ∍ňKg~Ŕ’RG şĚÖ cÔFÎ<LF8ŘÖ4ő:=Á˘ŁŔc=K9嬕ĐűôŠŠ€fđĺe¨¤fĄŔJç|٘y­¨Š˙—źxžÉššŇp×uŁňrż’úž˛˛ĎžŐ'+ůʢžIŔYś€Şœy‘Ÿő0˝á´@h_ÝŻiżçkĽÚR뎜iPZ—qśßZ"œOć´eĚąR§útĺ Y:_ŕ3`ęškŽšćškŽšćšżĹ|XÝśĆĺ1“ęŕĹ҅偈-ߍԳK5E ZKy4•ZŕE‚Sá1*‚cށ(ÚAMÍä$Jœ`„ bҤ”L0x*GƒSOét`N€şHœ6U槀ĽDĆű‹ŹWˆűŃí‡FqŻ<ĺż5ßŢć“ô -B‹ź¤˛ëśHŞł (ťŞF˛ű=“­BŽDŮó d śá1A“-KĂ bşUŠ´Hł^—1xăˇa ›I2l ~ôx۔A`&l؆¨`é }Ăvš!Yi˝›nx>œŹţM<šĎ iŒÍ@‚/Í\ş*çx8ü4aĆQ•38ąÝČ9Ir> ˛ŰčĐ1BĘ<XYdŞЧ@*ňˇ˜jU6#ëýѨâ5EpŇ ôyíF÷ҊbbX_ťĺAÍ@ľŢ{iĐZŸ[Ŕˇ;![Ć•NŤBć5ŃW}żÎŢÚXŕ”DEOˇŔŰÓĘ/ş•ŇýídŹÄŢúŁS@TNPš<¸Ňěřy{ÚŤšq&?ĽĂOůó+‹ú DĎ.ÖfâS:ů¸ŮćľY°zZ×9 •O)Ě×\sÍ5×\sÍ5×üÇçťŔŞ ĹVuŚřě†GŘĐrRĹz¸ˆô‰Œ1ďUAs2’Ť`ÄiNĺcąsCAú1HoIń"ůJüšš+’í‘%łh›g° œósĹ 0Č\Ěč’Üg×ô˜ÚYołżŽ;;ŻůbćőłˇSŇOPş>K+8iIqŤ>ŚźĄrJÖ_Łgęď „B@x2˝ržďr†2=˙šôÖTžĘ…űĹnIöŤźX–œyíěđwK\sÍ5×\sÍ5×üo;ßVŠŇvÄnĹŹRŇĎ` J XŚ1H0ŠëÖ߃V/% y€tđŒ $&ĂňRŠ°Ň‹Ő#‹Y…dfčM“Œ˛Ą NP>QńŻƐĽ*Ě –IÎ`%é˙˙ÍpĽ^ëxçdYýŽ1Şßí?ü„f÷˙#á~l€Ďń LźŒz°ŤňČîľ’ g”o9ĺǒy“;*ƒÍĂ!•´8Ɩą "Ň~îs˛Ó]•1Ń­‚ˇPH&›Ö{óf†‰˘ĂČü`#_ĘŁ%˛Tżk:“ň‰ŢĽ’§wťÁźƒŐăüřţq€&†pHąœÇĎ`왴|čËłú)ˆH(ůrYěd­˝Ô}QÓG.韴_N‘ô’ŇĆ,Ö''‚ˇœŽŕgŐJň R7$'ވ ú‘JöUĎbŸčďÉ,&U´˜W”“ Š^€OĎ-T°ŇĎDŔóŢuÝş˝jóŢéżÔ“ďŰýŸčöĺźżî_ř,TüűRéĘĹé™Ć*-ý-Ćx%nŚÉ›Ń>ĺŸZʍ ľ’ěîś0„łŤŁ: +™ŽI Z¸×)ß&Èáž0(oeˆ’cë@˘äđ`ی­_űC˛źfŸ_)˙ŕ#üŕ4\&o$o-YWł]’aÂŰPś! kŔŃ×k%Ęţ°měLvSRŒÝ:͡Ă}*üş…ŚRÇ_>ČőÎG Ő…ĺˇ śś[G:ŠiE ô$RLŞĎpŤ>z%8Ë9ƨ=œî3]€äŹ“É ÄŠÁ΄ąßŠ™„ňaĆ3ŃÖĆ~ʀ!Ď:™jľ<§ë˘}śŇĚŠĘSg‚î/ým9™ŇV; |’ßž ž/ŔVÖŚœ}˝ëX'ˆ7{šO~~ŹOPŻÇ–_Č<Á限­úRóŹ|ʖË×˙ë/}ŻšćškŽšćškŽůŽŮśíűťë-ďDÜX+ʅa2czeHëĆ-'G&›)&ÉmÜ0‰0˜–<Ů$$Žľ‘1s´ż˛B†nQݤblrŰŘÜůŕ§LnĂŘĺqŹ)Ę×Ř/IěG*Ú˛älŽ­¤^M!mcp4¨›g o ĺÉLŰÎ@¤‰°U‡çőżjjŞRŚ7‘Z6 rţŒ,v5#şŇŠXdŃţ ‹a*řăŁ:E3:U8Z ź‚–*E˜şôr˝ĺ 2 řY3ĆËsÚż|^Ÿj„űÓö ¤7ËůIň'ýd ý(ýéQműô¤öy´4¸dĂqăËű ŸŮWöˆ=ÖZ‚mJĚůłű_sÍ5×\sÍ5×\óëçťÁ*Ňň̜ĚÜŘ;(Ǵٗ^\& ů(PÔ>şĐ ÍUŤJI˛Áb1ŤĹÔ.HőŞ%›T‚)74ĚŹËĹb¨Ɍ^PşŁcGbň5  !ĄX>xäţ }É ­úcłbZ&;ł@ْú’loH8ńřööű˘ĹHâţ't˙ÍßöůŒUĎC/śUËó˜ŸRŠŔÖ,‘5đ­~PíŔH$lÖ+#Čî u۰řŔě™|̀œ Bš™â¤XůąŰ:i$ŚÂ6ŕ?+vĘÇ{pĐžÝ $ÚOZ2yaz ›âs–ěś˙-î§÷_ľÁZ˝čÚJU…8í8îőöÚFöľ’~Áy\÷YLz{EW`ÚŞŸ‰öxڒ/wŤ>1ŁňăF7CZFVÖ†Ď 63AzsŞýŁňéöO€\wŒçĆY‡Msœ][ĂρďËČ7ŻeË7 Ú›}ŠÖďdü×đ¨_sÍ5×\sÍ5×üwŸďOF! ű7ÇŹ@¤fF…Ť˘{Ý9ă”ß&ÉmŔôdČAäKŠŞÖ2ŕbŁ”bzXž=žr?byӚ’U,'‡Œ ŃĄźgéÇŮąx°ŮKp2(fUg‹˝ý ĚčÉŮËĎt˙dŽTV ŔƒÔk›ýľHr““ÂŹ!Uk˘ĺ ľôbűĚ: ŤnŸ‹Mg˛u¨ŽRęá­ÂްSŢjÚl*t­ ĺíŘÓKň-pLçěś8Ř$¨K5řÉÝë1­Ľˇ.Â.‚čক¸ťiTUT­ƒ dô†‡ŢäZČƶ꒨×mˆT0X–Ő°tn6˜QŻŐĐ“0eܒŻG]÷ă R°–éJL†8™ÂŰp\n gsčVň\ <ş›63˜˝)äîčŊž´h/čŞRYRŕúýӑt’ďqGmgúÄś˜“Ąő8înWÚŻjýll[UOEﵑ°ŔéÍłAtyšíóçgM–ÂbykĎësÔf)_ď*K!pbË%§ÎSö{ŢaŃ˝ÉÉČţ óË@uÝúâΗĎýĎÁ­Hoő†ÂzĚkŽšćškŽšćškţúůnf5ăÎ7ž˘ż':¨Ö*/AߞŞ>Q2g×kTŔÉf‚Ǩui{ ­r,ËÝWŕře1ęňŽR˝ŹůrIՑú†úéŰE$ÁÖA<-gíg0ׂ4łjJ˛Ň€×3ů‹#ZÁ)A‡ňŃLűȍRPM>܈€Ě;#|!â@ĚМl ;ygˇ7ÂďĹ&ŠŠü@˛b‡żŠ×ńPlhĚbę%Ů '¸#“Á0Jľ ;Šăғ˜s˘/^JiŤôúşßŤ—ŽÓÇäeoEř PM„˜*ÚLúJꝧě×˝”˘S¤WĘoږé[mÖ, zh8ÁݡŞÂ7ěeËŇ_Óg-ÎzNÉY׺jkʁ¨?ŮŰՁş6T2ł<Ŕj_mĎÎ)•?ˇâžtĘęv}nü×řKpÍ5×\sÍ5×\óßž ŹŞ(cl͍6Xtë°žĄ'ń@tkśî…T#%;$F*V7ćźcŞĚ(F6ucşWB, —Ď‘p\ #ˆÔ~̒řšřH— ˛ŔŘP8˘$ف÷SÖ^{fI_{‘YX)˙ç7żý/TM¤<¨6Șľ(o™Ľ’H´×Şy†Smš]#Šg’ďľ;— IDATľqPo@3a˛1HśŒŚŰŸĎ[N6ŻËLaÚ{`L"Ëď*”ôuH :P 齑 Z XÁ0ŹŻ€ŻŠ¨ˆ•u_vQbţÄx“€99ĆBŕěx:ć%ƒBą˘ě€‘Y˝Ţ‰Âśa˛3ă@X&¤˘DKJAŇśąŠ5˜€ ŚOŢžlüńxđ›Lžf”Ő@p"…$ žJĺ&‡CĘ@Ž´ečÍŞ@„ź$đúŮy ß°çľšB„˛eźqb´Ě ÜĘLŹň™OFľn+'//l3ëŢn%űž‚PƒđIڜĄJßÎň”ÖAňg?OžT§v#—Ť\ž÷]Ď3’×ÔŢĹ €Ź ‘3_i7ý…óĘNČÎöĘŻŽ×ó˙Ńë¨ű˝„2­×}\€őškŽšćškŽšćo1ßVϤÝD  h8„ßJ§ˇw$‹Uyt­Mu:)[ËQŒŁúL‚G(ÖŤźU‰Su8É086óň§.ek§¤×Aş—Đ pz/ÎatrŠĹם̒zžËűf„ţ;Í3´ĽČV ž^c…mŻđ$P+šŻÔí-ł€+(Kşƒś^4ĺɈ•třÉ ¸h–*Ł…X3SĘŚeiZ5-y/ćIwrŹDfA˘źŻ› –&¨'h%oŚŐ zĚęń”´ŁBŒî>ąt63>Ry“ä˜wT7ĐA¤ž$…\ʝŒÓÇ ZrőzśôFL@*SŠ]E„ßXI›%˜ěŐçŤVýÂşa˘lěÜ[ĆüĄ‚dm°Ž]ŕS,k />ę´Ńǫ̈ ŃRôľ9ĆśŢyžbüĎĐHť†f ű—-Yx}]KůŠ´zR×ĎFƒÚč œ•ôťBlŇ°Z,ŻÔ‰ôĺň :[IżľI°Ť’„ËëúɋÚÇŽNŹNn/lĎŽŹĹ´öů<)Řîmĺ<֒KŸ/Ž>ĎiĂóóő¸Ů߯Q-ǒˇüXňgŰY×\sÍ5×\sÍ5×üćťŔjf˘&H*D´„/ŮôsC­“$[QUFT]FĚ̸ZiźíŞ]yóŞĎĺt­U ź>Y֖9ś¤`žšTS°h_e1ľĘ.‰Ë^|’Â’š†TÂđ‘ôﲍ˙˜‘•Ţš÷žůěd^Lň­üE&ý ƒ Ĺč–ůYG•á´îšîˇÔ#p˛Š˘Öz!ĺ—YŰkŽšćškŽšćškţcóݞU‰(OLÉ ,Qut˘Ĺ\diąąĂFΠ灸Ě;!{…Éçâ´ŔŐ@ăŽG›h–ĎěY•ąš,O˘¨Ľ‚œVłčuă ŃAľú<뤊n9°eŐĽ¤ĘÉÜ˙€…çęě|ý~ɓgˆčYCC3Zd’Ý…ššşB Tšdy~EŞëę>˝Ř~2QużaÁäVÁYL•ŕŠXű+]”Á$lg‹Ÿ@÷’‡3Řd" v‰Ú˜hŸăfJ!–qJŻÝ 0O>T¸ĹdrCóÁ=ŞÖeRŹřvaHôœş!2ŘUřđŁ@Q‚0‰˜„Tşî›ŐľâR’óGjąšéLOLŁę$‰W™Ě ŹH?ÁXő ť&"́ä×Úŕ‘uďJ äA°‘˘2dV¸UÚ ?V¸‹M­Ř/]ŸŮ?ďÔ_VuKN-ďfDžâJ 6Í–äwžT°,`ť’Ÿä—Ú—łbŚŤräő‡ť/Żő{=Á¸č‹/ő ?ĘĞŹsƒÓbiíd=ĺÓF/ v]潹"örĚx܈t.Ůo}:“˝ŽYĽ˛OĆw…ŽRă~ŒkŽšćškŽšćškţęů>f•ZŁ ‰ęAŹŔ"4 ِŃKů^´­J´€ĘŘ6|ědT°KŽË7 HuOşt߼ím°kć.RvČöëE0rÖâžgF6Ł ܔ¸OO“œ&ĺĽÉ‹I­ ókŽšćškŽšćškţśó]`uÉo'R˛]O´ëhb ”$¤dÂÚ3{8í5;˘RGŔMާ5I˘˘" l"Ěö?ëŮÉĽţ¨˜Y ­n{]Řčä׉Ђžĺ> Júˇĺ{X:ɗ~tÁuәqĆG@×°ÂŻ—/†ŠˆŞéxYĸČĎţžľX^Ratɝ[6YěsË—˙ŻYĘ 1eP™“cě%ĽN/Š6ĺדĚęM=ďâ^—Ĺşż()ŠëŔŇIŸ¤’ؓ$šö†ćqJJ‹‰Ú°8Pmo$‚éÖ>ْÂ)VJ¸ƒP™G# ř,˜()îΉQ`+%ŮňÁ=ŕŚBü)…ˇÓ+š]3“Ü[:|÷I8ŘHÜşĆĆĽ׌Ŕ=PŰxNđŕmlĹŻĘ(°…űʃC&>€H~ňäřé¸q÷äŽçŔłźł"ĘĂýŹo芖%ńőÓZ)ť%ˇžs2F%ô–…ty.W]Ěŕę-Ń]“ Hçœgšďú´ŻoëřÖ¸,_6$>{@_Żwŕ)O•ÜŽŹĘáó x׌RÂŕŐôYţŐ'Vë@Ťő\Öyý[őQËŤzJuů|nńŹʘ˝Ô×ţ:o]Áe^ˇGŸ€ő|÷łú `ůškŽšćškŽšćš_=ß)N’ňú,ˆ‰Ů Ó—Şšg`Ń yȍ=“šŰňŕ@1IœÝŽ51bě<Ž 2ŤŹŇ&jč-ĚN$.&V|ĺ=t´@SŸÉF0EŮŮ9 dK‚Ěäx̖"đ]˛Űh˙ęZo*•,üňĘ<ƒfF/b_:ľ=ŽJĽĆv8Đ3wŚAĎŇ-ëçţV# ť"•č›˘Ě ڀITëľH@ĺYâł^oŐb°Ź<ššŽt*óůL´Şh2—ľůP §˘0r6Łš!9ŠşĄŕÁŃx”׹ƒoTŞi‰tśöŃŔŐŘdž’m‰äŔ”áNÇ;¸FT‰“ ŽŞ§ /6Ú†=+zÖ{2LŘD™* ĄŇŒç ŚĎb5ĎKW¸'x8÷¨đ-™łˆ“vęŘ+…:lC€ÇńS˝§˘LWžzđႳáóÁĂ+´éŠ Ę'ŠŁ60ÜŃm/×^Lt4ł™ŹÚ()đă BR5Jž ™uojË]˝ńbX—çŐ}ž,îš×~ŢWŔź<łůÂźžu- Í6ă ř Ž}ˇ^LźšUXOJ°ü­gŕRżŸ´Üx}VNŠŻ­źčçăžŕ˝b”O`zV7‰ž7ÉĄ‹˝•%3rM7ˇÄ>š~ýœžáLôFÍ_sÍ5×\sÍ5×\ó×Îw3Ť§\UK† ŔttŰ>0ÝKbçQA,ÍjJÜËŁÚ,˘‰KNˆ˛I0őV ŹV0Î-Üł}Žtz­óň𖠶×-2`Iɕ˝ź—¨â͘Š*A'ŻćlĹÖxdE ­…íËsŸ™  ZŢÝR5k•tHKc15ëq–Ż´´” |ᬒ)9o‚Ôó.Ÿ('Ř4°Á–cč)•(YdL˙ěůŢëčócTˇçK{Čb`Al+OʁĎÎ`ä,Jbń•Н‘Śźń.wRöö(VČVޜ<ČTT„™Š2ŞżS ftȍ bc”—ň0ĹLˆŁŞ†Ź+j”Én‚Ř@%Ř4Ŕ†‘ۆ䁊ąiĽřU#ĺoox83áČzÎ÷î mę÷ž} QEq"#î<vWöa ‚)ƌ`2ř˜g"mĂ6&ν$Ë V=Ś6ˆ–úć|^@(č×z1˙ jß÷LĂmvĄƒšâ“r*Ä?{K`­.ŐŃě˙řYGęçOýË߂îń]ŢĎWŮońĺO†Q{ŁĄÂ:L Źę°Î°ŞS5Л=dŐOľżvI…×$K2O Z/ĐŠL8+rôłOuz9˙&5î륎ýÄś~:~Ëî?ɀ §ĺq}ŕ×\sÍ5×\sÍ5×üÇçűeŔҙ—Ľýě™WřQn¸”¸ 6‰f/‹ÍR[ęKuŸşX-l3ŘĹq“ƒ!Ć ‹Ŕ$‰tRëEšŁx&ťUjěJÜAŰĚ´(SnäœdË@Cź|žéˆíq#ÔI„#6$6@ D†sĎbšă Zn;Âju-ˇÄ73Hˆh1—óńdňú˝[ŢĎčtݕ껾ŽĎ%ŸäźŤ– Ł@ąťwj}+\)?Ý÷ Žőç?kx˛őčOF÷Tçú˘~,B´y|ľar<`Ű1œ“Š‚DyŐú›p/ŢţššňŘô3ßl3ĐĎäޗża‹ mßj%†Ëɨ~ës=eĹ/J‡§L^tĘĎű˜˝ô _sÍ5×\sÍ5×\ó×Î÷Ő1-$WIĂ‘H×Ď )yŞGňôqUÓ煥ľßQDŠ]ž˜–/6Sq3†˙„#¸)xâÍňEĽ|ŻĎcű0łŤh˛ČJWĂ4Z!čď.ͤn{&ěft…I`şźƒ|Ę/XlPfôcÖý=ňd]WřK Ń,™ntđTRžĘbĆVŐN6îä]€ŽVń$)ˆ&ÉLi†*˜Toއ#YŰČ3čJD0•@tÔkŠU5)ˆV€•H=ţ6˛üŠ´5 G{Ą?ÄQŠpŚzň%ůœÔƆĘ;†ä¤‚E´ę†W×ëDPK~ƒYâgˆ†ń–ĺŐi‘ě:МŒaD œ!;Imw>"¸GĺĂwĹf†X]Ű>™~0ąz]Žö`Ť'îÉŰĎŰŞŠ<&˘[˝y #٘é “–JˇlU#âŹxą^Ů`*ÚϔŰö–<•ło5"J ß.ş÷TTń9OŠîSń"qmĽĂŻ™WOę9Ý %Ôą_{Jë|é>])úĄ%Kˇ>G‹ŮŒyIř]7żó°RŘ6˜ ’Š÷ĘţđôíŚ<+j¨}‚Ó×gתŹú';Ďs1¨QŞxÍÂË}eőg}˛o~Í5×\sÍ5×\sÍ_9ߗNfů> iĽ]GIú"šĹ9kň”ęm$ĄuŻiškQk*ř †U€ŕUƒYÓL4ƒvqž†`s1–PňBŠÝDňdWKšě¸j1;QbEŠí '_şU:82O?>Ÿ,WëIř)ÓÔl6IJމ;)œě1Íö,p}†ß4 ÷~m2cĄ;$’˜ŐU[Ȳ<łf đŽV ViȀôSĘkDIśí˙gďݲIŽ4ÍODÔ îI˛ş›UÓ}ęu:ű›MĚzzHf8`*"ó ˘x^XÎ.>šœ“îpŔ`0óŁżţˇ˜Ž+9Z",íďÍb‚‰`ŁjpŞż5;ÔšŔŰľAP>]Ě8żĎE˝;‹ˆŻżTuQ%ôî$wlě¤+#a×ňűŢćśáţ`d†C ڞłŰFĹ+ošˆ8ű0$Ś“ĂĄŢߑɝŕ>ƒ{î<"9ćýŕoâ¨8.†‡ŕ˛"f1:Ş6A‡ąI“ Ç ›“d+f-ƒĂ1f”ň e"ÍîŞjm‚4Đw˛<ŤĂNŔS›Iǝ,éi”Ő‰Z`đ8%'Ψ˙ĘH0ŻI Lœp#ĚĐLBË/9´Bs"+œéłĎë3ŤŁGV’§2(öONF¤„ąž†JÉ[ĎÔÎ^ŧO&í mš­ë¨g ČŔâ(€˜I†´L6{1_lp4[•]eâó¨ œyÔ9P+ůłŽ*“ćŞÔbůd]ú}Oůo.ȌČhiôňx6ŤŞĆ\Á8R=ĄŹçe’GÎÚ$°b…´>%•] Z)ßěh&;şŽĹrâY}§Cî )%eAüՍĺaU-˙éZ¸oC4„Ú”đm NąR*lRU$Ž0ç26öţ,Lj1ƒŃAH[Ë]ӌ-J\|ĎG›\ßyWĽ<Š>1Ů_Xǒ›Ôů ę\žüěĘôę3uŮ9źŽé@˘Úe3œT­N`„)™NbÜ=ĂȀëč ÷YSUě8ˆŐ›š.uýÎŃ­ŞÂ›|.OľŞ!Ö×ďy-%śßĘWĘÚúéďĺ ?ji­;Ö,ŤŠže(&ŐŹdžÔ´ýŽú5 *]9Óěď)é5#}yV×Χ—śđp’Qěđ‘ľQłRżď˛ąuŻg]ť÷„˝%Ěn-„/0šŮ˘6łYđzě&ľąÂçYaiKŠ\÷ŢPŒŹDěPeăGďZgů~†;•J Bͤ;d;đ‰Ő%=9űa×\ŕkŽšćškŽšćšÚ| ŹZFůíވÝ(T"Č ÜŹ˜œĹüP‹ţA,Ę?ůʪšř­žSyžŽj1ƒ”ŻTšĺŞ4≪p¤Ő"Ţς{™ĺU5 <…Đ -ҌS\lçň˘ľÜW\Şu8Вńe3RTĽ%ÂŇ>ĂÍśf7í)ÖZÜ+ó Ľ%­˘D۔ÍĆĘ<%3ö‰źz3O)čŇ.Ÿ* J¤ôĚ<ÄŇěś)^}ŤíăUŞšÇÔ# pO¤ŔŽun$ âAÚwŚ|ĂôF ÜdÔ1łměR2ďAË{UÉHśJÎAä(cJ9aƒŘ6,kăcoˆžbdbQŸ˝Kbé<2đLŽ™ 1MvqŚmźIÚ¨gIЕŮ,ĺą-îSxH1ŐuşŒ”’›oęŕŇŕ,ÉóŒHB1l'ÄpŠ>Ra ¤îH:!Rç\™,“Á 'Rő@Y U,Đ–ř44ńţl=!Žhő㊎Sâ{vžvşo]2É•źÂ’J6<:|é?žßOé.üĘ÷™™Ĺœögž˜K鍛Úô麛–ŇÖ÷ľť~ë ]”G*CĘż{Čh˙ký˙‘U—ýĽď‰M•ť ö,™ł—„ƒMŠŐśœžß>#'›”ĽA2J= ‰3ؗBŘ¤Ş“–|xbBöd˜3ťúŠ?×ӝۿÓ~łƒöškŽšćškŽšćšxžĆŹ"xä^Áľ)h*ŠZěɌdK‡1šélš)¤7Ůł‚ôœ‚ŤG§|)ĺ_5atz,jlYÂébžŤfĄqĂÓëçÓȑ„ď$NŠc–HlƒÍďxVšđd/jľŤgąę“ś1íjœč˝ƒěÎYϖŁk§,ŰNś/ÖlpŹđŻYRňˆBž2Ń´ mŸńŘöî=x>–Ť.ÉŻťŸľ5+đ¨ŘĚ‘gŇq<cűTWŻ7âçYáEůň¨şnô”¸ŻëłÂŸä)ˇeИŰg›œ•3ô=^Œż§°ˇţ‘őř-fRua˛/•Fű§§*Ý1‹€UÁ$đśÚ ˜“IąéNčĆŕAJIÜQaęŽe 1™ş}:Ň5NuľQqűU×ď‚%3ţÝ3|Í5×\sÍ5×\sÍ?2_˘ź%o)‚0!DďŢ"U9Z-,_d‹šł;AŠtÝ%ŠSkŒ˜ĎžQjQŤŚˆ N>ŸM Ó@ľ’g• cú.k‰gq[QLÖÉčť"•Ú›˝řŽNń]ÇrŐž˘Őé¨R-&ŒM “ŞŔ!â gŤđ)SAGuJJŽEő Ƒö°>ĎA,đś*tząocÔîBwÁ:ŠS]Ÿ1ç)‡ 1"’ŠGË5]O@F˨-Bw6îɍżU5M}¸ľ@á‘R^?oœďjbü•ŕG4 IŤŔ)5Fű]#˘ť@)ŕĘŞľ:ˇˆ`ݟ+î|Ëäť+jlÜúŠ^ŃĄŁ?ř‡<Ž|äŕ˜ÁÁDĹ˝ĄYŸťŠb›!’x´?1’đ`FőŘ)DĚňYŤ0çńÜäh‰vdÖűOŠÇ#ŘŽëŠAĺł*ćővŤëąźĂ͜{cE86vVŐL٤ýdGW˛/ĐaIuí˜-vžoî—dÚV™Tť… XŽCË3t(VľĎ Í%Á?Ľřëý”×;˝=/Ŕx˝Ž÷×fßű“@¸ËVŒ:Ę!v– In8ťÁP­‘˜ľa& öťŰ—žoDJFü6Œ-ŽÚĚĐÁőG ĹgĆŘ6†Âť:7KçÝ?¸ĺÁťÖŢűĽr8ďŐ_ŇÔ˘•–ýW]sÍ5×\sÍ5×\óŰóĹęšŃň}z4űoˆN26B!˜Ń!=V ŹÔźJz+tœ ŤJyÓÖ?< Î´X@ŠÁŠ8„ă6ЎRіďšĹv˛ČR­€ŚL†&ĹîQ’Ě)USłÚ)Ź™Öĺ}=ť3@ ÍůROóôžzoŐgÚŻ\ŞUď,ĺX=˜ Xú,Đú.ľ}şőnęý4“ź&ϐňԅ—¤8ł€~§˛ÖŠ( ľľŹ––'Ĺňš‚“˜(3Ë}:T@śŞ…%u†ň MÚ.…fN|Rąé“LAěƤXŮc(pђˆFëŹs­bĺÓ]]ľ€dƒ˙ţ|$œÔňpęŒ’c;ÂQĚżŔC6<<˜ˆÜиó˜†đ@ő˝˜p1l9AbbLYňs_çTíü|6ľ’čfŠČŘ8źŔ裣Ż_÷@˛dÁżŽƒÉósVľ3ŐwÎą­™Ó˝/ÁĎy˛ŐąęlŰvúNëŇ(‰úçĎż‚ă×c9ďëóű XŽ ¨NЍ–ŽŸrtÄ>ĺŻőEŤűüěU]×ß "Š¨Ďłý K~}Ęg×qHOÉRB”DÚŘ芥m4Ąé-ĹŽÇ9֖¸™1#°ăƒiŰʔśłuŘUeMíő;D´úŸ#Ů81ÂnTV~űCďé(Žľa•™lŁäß]¨ƒ‰´|˙škŽšćškŽšćš˙ě|‰YÍÜAŢŠM­ÎLţ#@X%´ŚW­Šg׹tMKöż˝ű6‡‚hÉ$‹Ó,Š#¤€IËsMŹŘˇľhÎĹĺť 6+ 8$+ą6'CŠgw)Ÿv•ý~UJţŠ’'(7•V×B_2Ůs˘‘  ĚXű×ńŹ UĹZÖ+4¸ĐÖJ+8ŚŘé’Oü”2KJ…Ř€´77Ńfí\ŞśFTOŠ2˘ĄŒř`–•$s"VI¨’‰‡r/ ŤĎw&ӓyÔE¤6”ĽÄ”˜X´Ä׌La“ •‚JY^žÚä<űb˝‘`'řWSămź1tGeťšOŔ:¸‡sř2˝úz?¸ßÄźăk_FË;+2ę<ˆŕŠě ˝źŽíÍ´č Ą´­NwÏˇôźwW†>ŽtšôbĎ^Ň_TǸw}NxËuýô–>f%g1ž,ď/ŚŘÖů›ß{1ס IDATWć5WŮďů…žVOŠůę+Ţƒi0ş€´Ô}$֌'/ĚíJÎ]Ő./>ŘŞ´ŠKwHÝk›äŮo+˝i0SYŰ6)/×? ŻýřĎÄbbŞě*t­•mHLŃ?ŸëNÚNČÖű6‚÷ܙ˛ăzcßÇŮ użo}œuĚuŸf{i×1KšpÍ5×\sÍ5×\sÍzž°$JEQ+ÖN‡"Ńţ´0R/fJő‰‹a xąz™ 6uŽźU5G=ł˘vŚęfËÓ7yzÔŁ˝ÜË=›:řáÎMź6‰Úş#óe4œ=Ş‚Im cc›wQśNO/ćö‘Ć`vŘU)+f‹.LfŇá\†gv%őY‹GŤ)˘%ŇÚçä_sÍ5×\sÍ5×üsćK`3ŇÁ¸3ălz஠Žč@S+şd–ôU¤ëZ$—gD8|¸°ć < „•„°Ä¸'Ş"ŤĂň(`ѕً;ÓŢËׇ3UaÎł2ĂĆŔg"UoëňŸ5č“foŁżˇş,ťŠ%2°¤:O­HQ) c{s5f-Ö{ѝíˇLŰ?8ŁaxŠĹQŐ)LRťŰł+C†ŽŢĚ$ŇŠôZ*Uľ/ˇĹ&ۆEodVľÉŘ͖ Ó|3“Zkc!yʗSť$&ŁÎťxÜľž aˆVuúÁPă Ń4Œ˝˜şůƒ[ÉEë$×u&ž$ś+ÝuCŚSgVď) řěp$a(-/03Ý+X´Â’¤Óz[îŤÝ“QŢŐbˇ_aÍR Ź ŁhOóLžĐŽ_‰óYěîJÉ}ÎbCë_Kv}úTŐЖżżÓBžë>ĺü™tĎkś7m^%ÁOoösœ’ű{DĽU{3Ą[8ĄĘĹTŮ:U[Wż)Tď­ZŠ>Ô:xŠ+›˛dć"Ę#‚ŽŁÍčÂAu¨lŁŞŠÜh÷ňOoľőcé„XIë3ž]˛Q›‘Ň&îżz×\sÍ5×\sÍ5×üăcţóŸ˙Ż×°–őßú7ŔfˇRŕĆNILk!H †ZSDt’SJJ¨ b¤ÜÉTDˆěTԊƒŒçz{-dUÁ')Úi¤ĹŽ&m”Ź4•O oŮĐ(?kd+&Ł$™@l%ůUC[ŇŤ´Ty-Ę_ْ/ň_Q ÓYńOÖ]!ГćC×ă4pĎ,đnöô›J:F×ăô9ׁIjçó/€P‹á’Đ–yqź 6 `‹4SGw­–„Qm°qoF8ɔ–Cb˜ŕ@•ĚZÍŻĐӆŒlßç}3)ľr(CĺdÓJF™ĺsÍÄU˜Rçwfą˝ŹŤ fG´[˛XşĹ>U¤ĚUĚi2&Ęh2Z c‡üQ]§îrkůp‰Ž]ö řąň‰Š3bHúšIÍôŐű.ŚPEΞÔĹxzCŤDç ؤ/é%­•Óú @׾§K"+n—4ŕsđŻ=¨ż7Ÿ€ćş“–Ü Až˘KĆnŁoƒŤŐ ó”đveÓę$]ď÷ôÁ ýš˝\ż<.Z­ r^ٍVRߛ޽§§nŘśÚ$z˝’-_GKĘî†÷ůŚ—Ĺ@ÔJ&Áşá™ ŐzΖ}S[LŻĆä@Înçúô|o˘Âtgt§­¨rüĎ˙ç˟Ď5×\sÍ5×\sÍ5żžm۞ȏ†€˝@%˙‚čƒđbë" eĘư3vL˘ţ?8ň-'ž*ER ÜĆ`Œ;îˇęEĺˌ,Ćđ Z$JşYÇö’Ě™€j…L{ƒů¨ÚÂœŠ˘ŕ"x–ä4[Ć'¨´ŞXF§ŒłŞ¤WĎfÉ3‹Ë>°LÁ{áj1q`yKU_éˇdW˙t˘éKĺĹ:~‰˛<ťÖ)T°l!˛lŒ<ŔSOIoĽ…kŸÉ¨•¤;ÉřËĆ ~ü ŞŃň˜*L1†“L H2ôŽČťT‡&€jůM}VŔÍĆݑ,Y%~ V˛MŸb:CoɜAŽbá&UY$ţ…ŮçTÇ`wGu0˛…Ď@žöG Ő­9 Rœ›Žó?Ňš¨HŽŹÔÎNú΁bľ?Ť^Śö R‹ëîP Őb,_Ş2̢Vࣙ¨0ĄHŚ Áœ¤ä˛ÜS0ś[ůWm´4šXŢ\ŕ”îÍg-+Źcn&6˛ĺ¸Ů€ľ˙”şŚ{e#+1)[Ôs}]ȒšęŔrVćąšÁąîn­ă*ŽŻY¸ĹʝŻ+U]›Q đ´ÁΗbkZLR@ľQ‰f%ŕŠm;Ş[uáXfĹD‚ăx°íô™ŽËîQÉêɜł*Éž†š™K 4…óˇHn™üLńh&Í6+]Ě{΃ Ş ’ÂĐÁÇńhům2˜ÜّxÓÚlޜƆĎăLVŽ,WUكł’ށx‘߆ű†´B”`Q>ĎƄ FŃ• ź0ábk?÷ŹŽÇčÓšADţ:é÷Ő7ŮPlŠ~TmŻv)js€%áŽĎU–”7+[ źŘá8ŸKôůüżŞĎäá×_,FĹK)2´dÝ}ŽE6ŽđVUÓS|ČÖ ‚AúÁG$7@ ͔g”gݾҌéMŚgÇŻ¨âéˇ:ćČdSáHcHƒĺ¤mœŤÇœěŰvĘGüëwzÍ5×\sÍ5×\sÍ˙Ć|ąş&HňÝ ŤƢRE”îž”<š‘˘h— Ááo˜:–?žˇDUpQöp|ŐŽˆ`é/ŹeűT;”ĆƒJhUCŁŁ4P]rY#0ƒ#{!Ÿ6„ŔŐ˝š)ˆąîUŇŇOlt=NKyuœľ6ŮŇ^ÍNŠťŃŹďMja-T-OŽq>†˜'˜HźÂcęya˃Ů!CĺQ-9b‰ËëYi¤PŐSŃsNllĎNçkŽšćškŽšćškţSó%°ęă˛1RHy+ŽM…,W 2ĎEťĘÄłdĄ3o ˜ Č0[r "ÉC ™ŻrŘN­ĽüŚ’Ţ9ހ% ŠE¨Çɞ̨šœ@ đhą&•6Š`^GšuÔĹ洏ú‚t ˛č.yTĐN4#%ĹĘT:i1 bňT'Łĺó|´Cϲ:F đUpXIreOѐ0F×ĎÔăŹÇŃ̛c˜v’r:*U×! "f%ë9 śă:0˘˜]‘ňRlśŠ—ç“ ÇLĐ` pë-eVý‹UŞŠş1Ă٨z)9'ƒ˜É‘†J0Ó9üŔí3âHłüžww'¨ ¨ŰÔË÷œ ž’p7€âlfŘă`3¸ ˆŢĐpOLQČI`ܧaLšĄÇI*Ó˝ƒŹĘëR^akćŹÂz’”NÓeŒŃň]#Óyĉ§gUN°Jłƒd~Jđýĺ,ĆtU ý˝„ߢ´vADŠůGtíߙŘöJ§w=’”?÷dN—ď–ßm{W#*\ě7ë‹LXZPݡxyË#Č1>=^ÖĆBŤ/Rˇ G‡”‡]T_Ҙ‹1ÝF]§›Öż­ĺß[żŒżć­¸ćškŽšćškŽšć?šŻUר>eé$Ö˜wţVϝańÎŕQ͟ žąŚżĄö*hůÔz}˝V›WÚV2ž~ľŕuą˙ä%eÎ'Ť“ĹÖ5˜şź†éŽHÜĂđL&ÂN0u#›Ů ş7ń•=-énŠ,iîbpŁĽ´‘UĄÝ+ÔÂ;TŮă¨Ĺśíh˝P/Žô4ůŔíÖçÜ‹zŞž*&A„m”lÚZĆy!КЧ 7™Ě$ĹFň  g1v&őúJ°ŰÁ‘;›wśĄ€‘Śě$Úrԕœ+DďDÝ’ Œ8řŔ؛ŐJ‘YŹłž1xŕůƒČ˝XňpžĄxnˆŕQ?-3alqśą{ 2›9{k ľq÷ƒűˆÚ„ˆAđŔőG$÷”uQ ’Ŕuu'›Y]l}]­žÚ%s÷ž>#*ŹädM‹xF[ ÓÝ[mr,o+Yžß¸´$žKň[—`v˙ęďߌŤ FNYď3qwÓ3 hůc…¨rĘzĺécĺš?s"] |+Ooë/–č÷ô›žÚőľźŮňôşëcÓ`ʨ÷$úůg[MAŃ,ŞţhvâoˆRŢđţ6´úqWZď 3ËV'<0fdyˇiՆŔ6FÝ˙Z˝Şš‹YžÝv¤ŚxŹErÄĺY˝ćškŽšćškŽůgĚטŐ^¤IvŠnLßąĄ˝vW"vŒƒ‰v]‰ ¤/oŕDý ĺ{-˜xuxľ0RÉúžTŕíÍö5.)jĽÖ.iŽ(ٝ™ĹTvnzÉ;× ńű0ލŻŻ´Ö ź%ľ!RLŚd§’śľ™ąl–§Ě†ž ‡GýšŔ¤”„1іőŽęÉNMŘbb˘¸ÜHŔ2Č06麝îŁ,îGźS™?ş×S ‹b’ěT݌[‡-9;ŞíńĽ¤źƒ¨Ţ\f‡()ŰČ ř™{ÜŢ ´Ű ÍŮŠĐKÖZ,ľE’şńn Đ.7öx0ő`6 ČŠ@î98"đބ¸Ň5HNąšéÜ3+QYC9>ę3ĹjƒĄ„ÉdŽyçpAĆŕÔ9Đ˝ý¨äĺp"¤@gËçJŻÍ'Ó˝ŽU_!D˝y˛úNÝ'cl'؜s2š!ĚĚSÖű öÜ'fă“u´'ó—_;éSZJ+Ď@¤vĎŻż>z…%!/ĎŐϓçÍvţ@ŠĽŸěë'đřň˝×ă^ŹíŻf1Ş}­dŇj†<=؛DVIŽ•v,}M“ľŠŐakkď,:iHm’ŐSťž OďĺňŞ.ŕö{Ěé+öŠNÔjSiyş[:ŃňěówBíÚrJŃm´'}ŻdaIU@Ĺb­éÄŢŠ˘ý¸ž0¨ %[×C'|“˝‰–IÔÉ#=*qťq˛’źÍŸ9ʋü˙ćY¸ćškŽšćškŽšć™/§×B/@%ÔoŒ< |&¸ 4”Œ˝HÖbݍbfWŔĄŤLąË3@¤ŘLM?S?Ig2°*9!|<}ĽüsJˆ[=Šş3Ňń-+Œ RŢZÍNcŒZŕŰSö'h8ŘvúřfrĐŹDÚ"};ʧÁ ˛{CÄSШРlŸŤÉ,ĎŠW×çžfÄd`jě<řˆÁ. ~¤eÇČŞÜňAĘ^ě,˃cbőţƒ’>Şœě’I ,‹‘3‚‘VLkLr[1H$˘°iĄÍŹłŽś:ćžN|ě<2ąááx&î0srσôŞyäND÷#ÄR…Ë’OĐÚM°aU_“ 8-ś9ŰŢČź#ś“1KŠ,“{nźéÁ9 P›Œ\jykľişD?HŤ-m_1ç5Ü›ŃIŃáxj3ä˟ú™5Uç÷€ö8>˙˝|ŻŻŹęŻ’}_ç…Q<ťKeI}(=pŢ'áóÉRŠ jÁşĺ^“-?˙|~㷙Óß:XyŞČ #Ř­úuuőŤž÷˛ľbÓŞ•ŞÝ€—¤ŕ`6jchą™PŹ÷ž•rýX rKśéTĎ@MIoŰj a€I{ëľU‰zžŃÝÁ7źńŕŰmçá“wůŕ§ďßůˇŸ6ţĺś1nvŐkŽšćškŽšćšÂ|‘Y­Ĺf­•żĄRa>äjŃl(ŠT"0–—'ĽÂq:ŹfŇá/”çĎĹZŔ13đœ$†ÇdtŘŇ#ľŞMxŚŔŮáBÄDm;ÜÎ!Ć&Š"LąDśąwňíýč´\Ÿ¸”Ÿ•fLú3źB•ş `!Ť%˛\žĎę<Ľ;4Ł™&GY^Öĺc­Ŕ–#'“N5– "'[T‰Ś7ŇďÊÁëZ Miq° hąK*Z:ŹRűĘŚĺăŇ HoҤ…}ŹÁĆČIP,&HłŤÁ(“é0Ă9âqçC7f$áQAGbä Éô>w)•(ŹŚLŮk#aFd3^9­76‚đĸ—mŰH?΍‰PO^ÇěYŒŠ,ˇ¸öóKTZtHÉÖË_L‡~Č-9wňHÁ´ĂĎÚżŰŮmőő¨´ípgß7>î„’şçœźáÜŢßř~ŰóI¸1yçĎť˛{ç*Üdç}4ÇÔšż}~ŽšćškŽšćškŽů‡ćkKT_jÉ4• <\.Ć h÷—†W•DÉŔ´ '˜>ČŘÁ’tCĐfÎjqşYÉc'Nűč@N !ČԒŤ0ó­˝­Ř’ŐíKĆGÚĐ< ˇ’ĂćË@ÚW¸S‹ń9Jm5+o˘ĚÉbPG:iËéśäǎŁg;×ěM1…ăôĐUXP-˜gpJ$3—ˆňjF*"ƒM*y6QLlcËr^bˇŽú¨P—™†iöńôű÷d AMo°–+şZ5 ”ĺ†5 ' ȓ )Œń^UARňfĽźÂ˘ő_Uy8!Î>ŒmźŁî˜ěüHŔvŢÓůpŻJ"Kćń´B„î¸U Rąn”Yř†DĽ “ĚŹ×ŕ‰X#aťíüœƒY@+G=ŸTđђůZ=Ń"UM“ĹŠ+œ’PUé>ŰňAÎég2ŹęSŢ‘˜qúH_j&ý™ďďÍňgçŻăg ŞíIíd_äÄĄşBƒÖu{ţůŞľQóŮż*+ěŤÇyʄ_$¸hmýZ•"~zYĽeŮcuSŸŁľŰ2™:ŞÓX¤+­@źşŸSł__…ŢT¨M˜#ŤNćŹ^ŠD4ĎÓ`fÇlqŠ v?řÓ6ůo?Mç~|Ŕ<ř/ď˙ňýĆOž˝'"Ř4ůĂćÄńŔŢ÷ˇ/}Ź×\sÍ5×\sÍ5×üýůZu NvXRqQĺ3zP<Č8{PSşw´Vt’ÓĘSďˆxĽÜę¨ÔßLR+@ĽŘcdŕžDjŰC!%˙pP9ŠýDžlŽOnˇoxR‚;Âá“[x÷y&ÁáyĎň”ÖsfąŞí!}J€ HGx'ţŽÝň9ŸŇŮŁfÖ×çü,˙­j›ß—řŽ‘fŸ˝§Ůu3/>TŠ÷"-YžĚuż)áó|üÚdYŇäß}íîT}en+QŘ^žëwüddOŘFЏ6#ÇŚ´ĹFő ‹˘âĺÇć™Đ­ńŹGŞtčçq˜a{1ą´ŘĄÁfôů›‘lVý¨&BH+(ŞD Ů­<ô#~đ}ŔoÁżüt㏻ň˙ýíŔÄůóŸvŢwăOoƒ=ď|ŕű&üawކńČdŰvűčkŽšćškŽšćškž4_óŹ6s3EťŻ´eą5ËX‹Ĺ kL2;âÄÜ 2öád(7,­Ĺc˝N/vFVˆd””33Ń<ŮĘӚź ˘tTş/őse—+j恳•ď­GŠĘ”Ěhçb"ƒ ďPžZ*ÇJ˛†šŃ豖B7łş‚cÄžÁěłtčŽáęŇgnlĹ@é (ÎĂ0if;’ťšł‹kź˜á80Uěd›DßYŹoőžľ€h6yUĺ1ƒI2â U0ĐÇ<ŠŠí8)ąAČčÄÔÉĚÁ$­dĘŢlluW"†ĺKe§Ř4Â`˜!ŰX5~LűĆ-~jčéü¸;“7Š5WÝŘnF)~ĽüČŁ@ĆC7Â'ď "ÜtŰŮuĂüŕŻ.ĺ]öbD‹IÜ˝ƒ‘ęlœk:d IDATˇý˜™ŐŁşŘÇh39“{†šó J_;RWęďßcVWW°œiÁŸĂ‘äźEäDzĐőľŸčÇ˝¤ýŽÇęËńœ?%Ç_aóÜT:ӊPľ%żÎňqëâVaĘ@%ą˜u=ćä ŇšÍr#ÄF)ŒŹMĽŁ˙ä…×çR×ń1ƒĜ'řNí0ë^U‰dßŕ=đ§7ç_żmźż˝óśćžçƒˇ7eßßÔŮüßߔďCŘ â¸“Űřöý;śďçŃ\sÍ5×\sÍ5×\óŸ›/Őę6T72° ŃH|˘b‡šT'(ˆü őgĆ łŇ~Ń%ÚZžNDȅsÓŽŁpçŹEH4?˜X;ZÚş˜XĹ0&w$븄ZĖl˛A]÷‚4Řm Ž–$RÝŽž3ş_TĽ$Étzqű[W߼Č8™:ŕ‰FůîR ärŇÍ–ü7IA…,ŃoĎS‰vܓ üđGFI¨Ľ;KuŤäçłř]Ÿ?C ?Ë;3žŁz°ÍŸ}GŘyƒy<ř2ç)ÓŐŽĽNYŻ7¨ŐŠëď™ń”ÖžřUfkW×éł~ć—Ďő:'›Ń~Ó Ż*6ľ˜ç\^K^Ű ˘°:HýL‘Ú`iĆ7^ĺźżHň]Ç˝^SĆV óďM{H×ńÉJËîkLN&śę›VŘjXÎň #Œœ•§]~SŒV8Œ˜LÜrrdIÎľŤœ+ő°ÉłGö|W ¤ătö6Čéí§7nB{ËĽ7қ ŒżňŻďĘ˙ř—ŸřóÍ8>w ŠcźĹÁˇíĆť97QśĄŒ|pȍÍ'Œwćb>ţţ9źćškŽšćškŽšćK󵀥LR Q#rbrŤ ”Ř @!Ř8ˆŘťWF‘ !~RpŒÓuiNaĽ“ö¤ ęA˜5ŕl×YÎpŹ×bWĹp*Djń|D…$&§ż6€đIŠ0#ŘäɚպxœňIÓ˝Š 9Iś^ ‹528:JŠÄ_Óî|l™ă"Y ůӓY wą˘Ç) §bu>ÉNHn&+9S}GłÂ™Re)řđ'~w¤äś*Î#‹-âXƒŸĂÓÄŁ*r†*“wţŔţzLtƒ ăxx=f40ˆä>v†(é“ !sŽš VŒ$‘|`lY0F@ä'ŕ!ѢPÁ\y`2HDž“RžEďzŸéI…;‰!ďx™ÁĆD, 1<‹Q+ś´ŘQďęĹ˝Ž•<Ÿ!Đ]i“ îäŐóŮÇ,ëűĎšOlj'ń>CŽúšhöż.Š<%żUۢçËŹôÜu˘žaKĎk÷š Â篛>_°<ä||‰M]Ďźî–D82ôôlGd§ó*ćBĄĚ#…]‚m9ˆbU͔Ŕ‡ $“o8NłS؟gknPušZÝT׏7+e96UŢLy—˙uwţ}ţý7ţđnČăŕ=&ɟŢoĚŰŕFňíí†#ź[/wÜŢq ţú—˜ýúš¸ćškŽšćškŽšćožVSŇ"VAôg,żU:0މBź!’DžĄzŕaˆÂ üŁď“ #ů$H| fiIđ’ždD•bŃőY‹Qť‘‘ĺwkA˛QaL;|cÓŁƒ{ƒ`L<ˇ DŠ lcרçŽîíT+ŕ`;łz8h–gđĚÔ­:KĎ~Č(Érn-iŹ::×%[^|ĘI_OŮąPĆߌĎǛîg”Hu†.śöÓq­T^ŃOahćt…-eďrôљéY˝TxŘ{cŠAhˎ٤#Š~\ľęî%qě%&GFL´Â?ÄŘ2şţŠűUE+Qz,°â]ů¤ýëdNGĺyľďݛ&oLžÉĆżďđěţ¨NzňmܘiźíĆĎžń—w~ţë_U~ÄäŰśccđíMŘ98|0Dřř˜üżŞ`ňŻď5×\sÍ5×\sÍ5˙Ń|ŹjŇD,`Ąz (‘ˇ üэɐ{ů㭘Ax2Š/ŠĄ3Kęú VĐŹ¤Ů쇯$lœ,˘%ů˝Ë@)VŐśřôX:`ĹěvőÉdƒ˜'C”˘üâŚZ'ůN‹ƒĂ6f ę^$Y ”´GUý@ˇœŽiśżÎqŮŘqŹĺ­y‚ĄĚ–žŔĂńƒÉ^ő*>y,Ť*#œŁězÄtœ’Eď™Ě {%Âvb:Frd…*É,Ád`X:G”77Kx‹ögĄíßM$ľęOŇ6,gˏßIŕoaô$ÂC@†&b72œĄ;"ş"!}1ćĺ[\çBlźAz1ÓžűtěÜł˜s†¨óö`ú†G 2ř[€äŕAbj>Ţɸ=ŸCˇŘy7áM&ý‘|ßáŰŽÜuă/Gđ—ĂńqC~\`őškŽšćškŽšćŸ1_ XBŤ‡˛™ ąƒĚňœ†łśUŚó*¨”S´ FSh'€âeąůĚcyŠ“ń† 31!s’H8›L"GTˆ|Gó´|8´îLzaüLíe<š­I?TK…ć—ZülĹŢd ™%ŸmoăVţÔîfÍ(kĺFiŤ˝k8šYJP ł%ŐⓇlĺ_ʈc"Şí Ĺť†ŕQÝŠ„9ËŕÎŔ2şˇ>5gڜ‹řy ńAę­Î‚¤° #2@‚É( 6SŢŘäAxV?Ž˜clXb2Pîc>Űđ G<đxĘ;ľƒ­†wöą3r`jÄę4ő 5™ŽZ˝şÂÂý8;GL\ľ7+”á1łńx0öăh—˛Łc+ď˘đ ň˛ŚJiomžŇÜúţ `*Ť™ý&đ{ýštŻę°' ŤŠŽŞŞôÝ<ĚÚj‰îň˘öĆĚ:žlT˙ŕ”żNşˇ|XšAÎ_éߚsĄe믯‹›ŔŒÄfűÂg3ŕD4ĐÚ̈Ś Ţň€9k3E#H‚lýFDÖÔür~Žó6óůV+ {Š JQP9×ő=Q团lŘüÁOň3ÜwţűżóţŃřÓOošlyđ‡Ý@žłç2ţĆăq@oşńŻßÓnÜgůŘß90愿>ĘlĘ_uă|Ě˙Ÿ˝wi’ěH˛ô>U5ťî‘ęŃÝ3r7älů˙wáš[ ܑ322Ý]]@fd¸_3UĺBízD˘Íęĺ=%Rţ„Ücçĺ|ă/žĆ'Nœ8qâĉ'žßEV•üFŠ+ÇRźXŠçÚY]JJéyĽ(N´54Vs+`Ťě$á˝1Şhmz—­KÔXyW§ĄR9¸C•1 "ĽŚÎ %1R„jľE}Šć×cŢCŞé؀L§IeäT ç ¨‚ĘÖ¨9É̲/jG|ÔĹľTĆM¤žăŁ€†ĽČjY"•ŐšzěXĘa™|ĎĂćò)TŽ,)R -K1uɺߑJˇz ę§K›!Őm“2ÔKЇÚ!÷•!fšKi,ő\7.íNzŽPuČƐF‚#‰É%hV3$f†šŇ˛Ę."Xvš)]…ÍÓFŹC€™Ašń–فČĆƒ°ťň6'ťš˝‰pÔlŠĄ5rňƒäĹc&ŠčPMĘ…J‡* ÇFn,ĺÚXýS{ď_Â1!S{ž‹˜Žq[É ç­ŢťÚ&–u¨ácíČł3ŔR6ŃĽKúnŰý5 łeí•Ő-Űţé—{)’T÷‘"ɔÞ­ď§ŻďöXÖßľćZ3Tj̄ sŮŐKÝěÜsľ8gĐEÉŐ Üłžă.ŠÄ¤ký.Ą&…XYę™ŐüKůśVVřéJŇEŘş"sçyŤŹ ´Řůô”üîúÂßýđÄřqăúŕŞ;gŒÁ¸ŸŽFČĆUo˜M´?1oÎ'™¨M´7Â_ozÁű†ü<ĺ.Ć=“˙>ŒývNל8qâĉ'Nü{ŕűvVm ~X9rĽÝĘ>ú VEŒš‚;ŤH°pŚ×,MfýŇx¨Mđ(XĄáuaîš SÖ̀–—5Ełň’žÔ—1wéôœÄR>Ë.Řmią[8ƟDę{žuPc’ˆO¤mDśœ–w<‹Ra“ú^é‘1ˆń Çşpş€ŠŇă+Öą=aącqÇZ§3PlŚl żŮÖç̝ç­ń|ŮŘĚÖŞ˛s›Ő6üütĽ_áů Ýë†4Ř,Šľŕäëř}ţéóŕ~c†ňňăOŒŰÄ÷ÉýÜŇůEZÚE2T?mŔ'Nœ8qâĉ˙řžĚŞuÂßV–N‘ć¤&靦ş,š˛˘ĐČRQ×ŢaěóaűbQߣ>vŠŁuÎjő=JgJ”,Ĺ$ÇżÓc‹”†eMąd‚KC֕˝h{”4iÖĹś'˜–ÝśŠžö&…E‰Ž 皌azNBĘî¨YĺLóhľRČTŹ,ŃŤH§ž’AZ%7U,UĎŐ$J…:”8Y{ä˘ĺ‡eW~ľŸY8~ľĘúÚř¤Č0€j4LJł-‚\UŐź ˆ]Ö㪤ŢcçI;ŚÂÖĘú¨Ů™$Ň>‘c'.㍻=semeBƒÔNK§Ë…ŁÍ`Ś2"š#˛ácŻí×í™-‰Ę؎űäQůŔlxÖüÔÉ!łĄË~ţŒĆšd)ŐTW™Ňą=şJ€DŞ)źO١űëďńZcÔĄ€5,rٰYyĐddĂ´~vËÉ´íŃVŹfÄą˙jöP\ůäŘe塒¤6]3×Öďú~vę5?n“3^…MÝ—őš)‰FM/ĺq“IjŁÇ ľŐÉĐ ƒÝ6L„îą^dYę`#D´VŞ‹ňŹÁ˝“ŠĚLŢf‚M6ƒfÂÖŚ×~t:÷]ŘÝůeW¤mÜďÎ}&.I—dXGnŻwö€ś5ÚŮŻtâĉ'Nœ8ńď‚ďŰY Gäň( Că"ÔnjJ•÷Đ;ásŐ7‚ "…Ç^jdƒŐüZŇLŒśěŸ‰"•= P "…ށ{ŮCĺG’•Ľ[fW54ć"‡Q–Ý †{ŠŽ˛lĚúNôj$ÄX%Övk•!! Ę,UBT‹ŞŕbHV‘Úh9J%]ŮGÁE٨"šNĂtŕäjp=ڐKUő ˘–FZĚEđ—MÔ¤f{č+w›1ńEžŽçfŚ YjčĚ*[mHJ5îJИź4ë4‡Ţ;OÖjz$ŠTD †ß*ł›‰öf)ÇGŢŃ62ƒ]ŒŰC, Zěőš§–â;D‹:Wž| œN`ŒH|:Aĺ¤wšâŤÍĄˆý˛źŞĘâüĽ†zÔg콚÷°×AÁ{5˙˘jz×?)&’Cţˇ ŤjMďŔR@ŁlŔŤřI-_ŞŤhľíĘjĘNŘľŃ}/U})ОœG‹đűw2V~Ő éŃ0üń1}óx?ÜO~”?"Ö7 ś|ç˛E °ƒek>îgYv5ƒDňxîRŞ~&¤“Ň™@ŘF™íŠŚgÍA÷Ĺé­ŃşŇşŽŒű¨ÍŢçN—¤Iĺaˇ&$ 0mŘV–ď/3ůmOćtöíÂÜď|žJŞ ĂšjŔ&4MFTiÓ[ …ŽFc ™Ě=ń•Œ+#@­Ű| Đ'Zî­?ńƒvţđúĎ<ÉŔŘiŸž˙ěGOœ8qâĉ'NüŰđ}™Uî EGƒŕĽţŘ'hCYŠ•2˜W˝Šw°29ŽËy2„e=ŽŇs rŠÝĎ FšĚÚn<ňŠÓLęúą#߆–ŠĽIŽb[ ź]|Tđ ĂA ąćd–Ú EJ쨓ʁ¤”-ąĽşÖˇ‰>"FŕkŤ2!VVF­ű÷TL|)U‹e 83„fúŽ0mR*őŚŤ)˝ň˘Ő´*k\ě 2Y ÁÇďHm$ŁÚ’WIMWa.BŽÚ!Í ‹s!iÝřA•Í‚m{â˘Bä^ęśö2Ť’ZëťNˇVśl‚ŔńhŒœĚ!ě~Ă|‚uŒd Žj¨‘ٌ!îÂW‚ľŇqťŕ˘ŒŸŽYľÎĘ"hwaY˝%Ł^KŸ•Ý\ůĎビY ŔîŽűüŤśŢ_7ü>ʍ8\°Ťä(imŃw29‹;âë÷śÝ˜łl˝ëŽĽŐWWČaŃ-â÷k<ˆëRB,ŞüšŰŚu01źöë@Ɩőź\$ĺXĽKšTUAŢۈ#ޘ(Ë:ßľZ˜+ ˝˛Ř­ƒ”äŽYvŢălĘöLđbÁUŰváršŇä˜ď ‚ĺŃ •šËéş ßbÂýŽm6ë€ÄҙŽ|2ĺ˘Â?߃ˇzW^^>ńc6IÂwHCŰFÄ`ű>`|fӎXçI×ÎŁŠ#vÁuău$Ż_^ůe(Ó6b#šăŚ|úቷîűí/~žNœ8qâĉ'N|?ž‹Źz^kjÄîŐVŞD’´N¤ÔÍqÁ/Z–ŕ,ďĄR:ś.x—š—ĽĆJ ȑłŹœŠJ˛{) >”A¨ ăśZ…‹ď)­ ˜RF=uĺ^× ‰4$fĆČŐSĄš—ÎVőkáuEjI’.ĽĐF&šůh†ĺžĚ˛&7‰šŻ9ŹŔjĽV-Ľ8yWs¤x$íŁ…sĺř"kŞĽîď÷đ:.V-ÉRꨭé!++œţŘ­9Ÿ†Ć^s#s5É63”SĺʎY‘ÔKßx6ăĽ%Ň]œ_ËઌˆčĄźţľY—ş˙lůŚ`Wäȓ ˛Tü|XÂsŔš­Šâ§Œ÷ƒÍŔDpmK˝ü äseX­śţ9ŘńY gjèśĺR>§Xqáˆ:L˜óŁőx>ŠŸtŐ]7ZÖî˛/G…c„*Šß•/{ńƤČđDŮłáĂŮOđ‰'Nœ8qâÄż žoşFIÂűCąX흁Ľ rHH&Ó7LkĂęB5űdV[lhC<ż™Č1Ką)•ŠŚf˛ —¤śZMŠŞę*&šłlŒ˘0=+łŽJ]<“A“š´‰LşRާIćdR9[[ű¨}•ÇtŒTLŁśN×#-Ňcç&Ť‘XVŤo#ńEĽĹ‘*‹RY›§•(ĺ}cő˜(I"kâ¤ĘsĽvmÓéE„“Ľ^ĺáN]Vć ÉDLh)AJ`›L:B—śĆU—ÖynĆEvZWȝô"¨s‘ľéEşœš/ „[ ťßÜćDŁřOÓ7žşňҍëľÓšbî<›Ó›"}cżM|ßqżěL`ĚΎ3öšß˜Ň i‹fŮşŁĘžĘň˝ĘyZ_ę2Œh‰ŮűVęÇýŃďÂqťă¤dáý>Ţ'dŽŰŘuĚiŽ9ŁđYĹJŞĚ[ŸCmmYĂż%Ňé5őú.ž+’<2ßË3ŽIm›×k5­ŐaQĆCÁOB­,ÝVś}YS@éΜس-ĹT­­rľ)Ť8 Ŗň)ިfېÇŹŠľxŢ͔mKtll+íŽ$ƒ‹LŹ]yRGŹłÉÄ Ž*lŔľ]h— 1e:źÝîü<ď`Ćl9o$É-ŕË>Ů2ůáy#ZǚóÇ?|eÜ_ůťß<Ńú}KśfĐ:ş5$‚čĆÔĆý ˙ĺő3÷~áËmň… éÁ=Í74/<];SŻĚűűż!?|âĉ'Nœ8qâ/âű2Ť8D"Ň )ĺhđהŐč+H&"wRŻŘ,c Ů }{ĚĘȲşćăö<Š’Žœ_Śt,'#QhZ…8š6M?śCW~јĽô&lšx$hGrb#rV)Ôá%TœĐš ńuÁČ{ƒîjžj]ěëĘŰŚ*Š2fŠś$řR„B¤ Ÿ´2ł)QŻÉšR—W*=JŞH Q:/TÖĹq˛$ŁěÍ1Ť-ˇiŇÜImˆ;[[öQQšŞą\%*g,†JpQĺ‡.4˝ňŇ76…ŤÂUŃą3łv\g83‚Č`ĐŤüHŒH/˘:nźîŽI×ŕ§­Ź”—Ë…ŸŽFˇjX’\mƒ˜ÉxýÂë4nžeÉĚÉÂÉ&q IDATk*áekžĽŇ4h֙ësSeIKLyLÖŕs•öލ^ ‹Cź7×_żw;őOlŔţeÖjć]Đ*gʨa—zÓĺń>֏É{aŇşÓęçVĄŇ_B“dŽbłDU%×,Rý݄m5ŁUNUŽ_a¤Đ´JŤđYśj­Š'jÇÔZŇÍPűظ“aˇ+xT™–@˘eOĎŹÝÜpšÔáJ_Väăŕŕbwš­wZźąiŁ&YŃg~´RäĹ'’ÉO˝ąm•ž^Z9ݛňůžÜżNZo OöűΘ“Űm2ůÁď~ú7áťA$ű-yş6zSŽ/Ď´ůŸ“Ô„ěš1nĘW7ŢDůăˇĆĎccxœ´íBˇIi`Ďäźóć5*uâĉ'Nœ8qâoÇ÷‘Ő´ĘƒŚ âdI+Uą ’š¤°0ěŠĚ€l[š¸‰Ó­ QBĺ‰3b–ş:ŃKk•c ĘlŚ´RĹ2˜)dNLĺ1 SJ,••Ŕ×íMŞX¤O˨ű‹*JŤÉY–ÓLGé5"ďS0˘TÁ‘I•-ۜ,N˘ľF+QĘpiŚĽ {Ö%ť-ŐŻěĆşň|U&ĺG¸]ݟcÄŁ Y|Đľ ,h˛C ôŕE”Jv‘}Íuž¤lżJŁmž$švĽ ôE‡4Ô+#÷Ák13ˆš#$aşr›;ˇ9iŔóŚ|ş>ówO?=]y2đý3_ç†Đľ‘é wЧňśˆé]„ŰÜŮ}cˆŕ~̧đ˜qŞAŮÝŤt˖Xk*X$]Ę>~¸mżGFő_› 9r¤ńƒ˛ŤţU˘)łňŚZÓ0Çb͑]mTŞÄ\9Öc’vúşŔŻ\_RVŢŁśŠ†ƒłš!hĽ^J‘Ŕ‰-aŤÔŰ)UγĎR‚Ëg‹ŠŕúŒĺ}‘ĚĘZşt5ÁŠ€6=ĘeވF#ÖŹ,Ő.Ąg"Eč+o •ç•€nÁŒ•…e•2ÁăóT” ĺhÇSéV{ŻGLnuÓ%Q zŤücWá.˜$×vYÖÎ"‰0ĽÔźŒ"‚_ooě”ezX'öÉ׹“ű ÷˛’ŽĽ@˙xšpąĆK3Ž ^$x–É%nźQžĆ.0Ł2žá U‚ło1Ů}#-Ô%…z›é˛t×ćlˆ LRŔl‘ÂŹvۚ¤yŸĘ9Hßwá°,Ľ˙].•oˆjÝ\I•‡çřĄžä5ëkt”É*“UfôřŞ=ň­žŚ”Ţ_‡r4PŸ§őÔMf\´ †(]‰\ę}’­1Śfb=VÓ"}’Ő{­ řNWĽĺrG#işń´ŚrҔˆ1“9;‚`íBĚÁe9š֘l•é^yŐ#áÄveF•=}Η.Mšd+§AŔŰĎw~˙luÂ:°˜ÂU‚×=řǟżđęÎĺúD´ÎfĘËs}s 2jÖn_0›XŰ0”ÔƸŤ˛ă´p4ŕ-6؝ϣńO_&üeđúŮůøđuÂJ栉0gš4Ţ>˙íň(bű:żľiŸ8qâĉ'Nœř˙‡ď"ŤU6tĆPJU/kž¤”ŞőPŻvÂ;Ş7"/¤QDŐ ;TŁe‡Źžŕ#˙Újľ_aßk›r•­ˆß@ŒÔN—ťQÍşb5Ż‘9™^śáH]†DŠŇ˜ăţŮô˝Œ§áâLÖhŚ`ě BD˘ 0+âűžkY$ęČGĆŁliˆL$Cp‘*ŸRe÷ՈüéJ, sŹ\Źi2łÔe[ł­Î…M)Ľhő $&IcmĤԖ|+Ť‘víŽî WUŇkbeD2˘š‚w ‚9—äžßŘgŇ=h—'~łYĺo×>Ľi5ýVIU22s2őJ2˜&Ě1îÂ=•Ýág‡;ĆWoÜgsçŽÔűˇÔR3Ăž¨.2đřów”ľWqš$şŹ¨ß›KŐoSYmÂďŠi~ř˙w+ů{ŰŇRz×ôĚăT&?ţŽ÷˝Üo×1Á”ëdćqw‰˙9˘-R‡2+űJřűýdT T ÄpϲĆS™QTëA„žĺŠh1m59ŁbÁ\°ż!— ýr!›ążÝřş;.Źátk e˙•ÜK•ŘÖcŻ‚Ż*łVöü{jwÍd3á>ˇýÎŔč&ĸsť9?\/üîӅÝÁÂą€ťlzťrŮá÷ʧޤEŃrŰw^C‰íz%nuŤpJpzKş&/ݸí“çíÂ×1x}KF{˘o“x•-ŚqmF'PeŸľ›ŹZßÁ@HëßőY;qâĉ'Nœ8ń×ń}mŔÔüa-ˆŠ¨(ąŘŤ,תŹV­5RTď̸.ëﲌfÔ4ÇÚőtß@&d2˝T™˛BNfŘĽě” ˆr‹Ä9(b&9Ńe)öLKq<ŚfĘšFލ”łIQíĹM+Ű$˜Š„ô"ź’ŒX9R/‚›łJ’tmaj&›Ź1Q[*Ř šV޲fuOHŸuQ›ňŕ0e7'#l5(×&ɚĹQTŔ2Öă™ř"‰&‰ä$S ŠÜdŢ QÍÂw’'ľEXjÂćžÔ>™ÁžƒŒ†ë$šŃęŒábÉóÓ'~4ăŮ ˇRz3!d˝Ţ{L˘°@ç>S÷ŹÜîđäópžĆÎ>á ĺ>=ËŞZS<ÎôRÍŞ VWfŮ̑ߒUłö°é†Ꭺ˘úgČŢG1Hác–Ć׆éA`ĺř&Ôn0ë5DęódÔJŃą}ú^xÄŻęŁ)˜w•öPfĺ ­ţAW WëˆOԔ=ŔLŻýŮČ Ç,Ťş!Ĺ6•ořńm]Öřúm˛łuăĽAKx҉ę…×)|]$ÍuŤâ­œřaŁO'×&qřNČś"Ôő>(ŕ‘Ü1Ž2đPšŐwyJçIh§í7Ź˝đƝO­ó*Wňţ•@x˛@ÍŘ)‹řׯƒF0 6™L 6„&ÂkˇÝšßƒ­o `ŽÁ=OA ž6ří&\›ň÷Ÿ:"{CmOOÉëëŕ-ƒŤ]řýԕ?ć•{(w/@nOĜýłvâĉ'Nœ8qâťđ}ĘŞ$ľ…Z*H áxťTŰ­TƒŽ´Y6á Â&š$.twhM÷‰˜!˛#(áa‹”}í ‘ŒwUkÎ`YeLs‘7|°KŻß“IŁ69Ű*â‘4­ź'UEÂtŠ9™I{W˛0|šwRŸ0qîšÔßHVŠŹF§t•AÚVw‰YÉH÷ŠąŹL Ő¤űŽĎV1Ґ2܌ş˜."Î"7Çśh/›çƒˆ JY˘k6q7¤9Ž”Í‘ ͸&ěXTŢ×ĂŤŠID'%đtT.l˝7,“ŤÂ“Bkđb‚D‚u"×3‚ˇ}0÷ ýJZmNn ť<łĎAşó6÷RŃü‰”äΠ— U[AŸ5岔°Ă6{ÖČĂî[Ď?ŽĎɲéֆj{LӏĚhţŠäĘ"ů Š”÷Q9 “”Ę<˛ÎPěhq~'ťjËÎ+ÇĎČ736"‡m8żů9>ňꏖäő¸Ž“!1#<ÉđŐp]Šžf0ľUń’Šlé†Xă(íŞçc\rTËr$ŚľŮť™rŮ~ŕŞIW-{ź8s:ŻoŐŘýËjÇN봃ܧb­őÚN^Vr]śţ™‰db͸Çv4.1¤%îsb °'äňÄÇüö•—VĎý•äj;"§^÷ő4?nß?76u6Snžüp¸^™ťóy:žŕĄ¸j5 Œ=ŮQ&×͝ąOB:?]o4ŢbđÔ?ń´)żowž.?đ’OüÓ/7ţx‰äţQ?qâĉ'Nœ8ń7áűŚkŇ×Ĺq]p" M€Aä†č¨FŕĐnOˆou5+Ő2k;SűÄiXVŁŹÚNF+ëjéMOL|­á$˘ÉX&ӑľé¨9VqL0—¤5˛,‘f0ŐHZęQY{ÁĽ×ŹĘj6ö5­ąIâšÔLŞččΙş2ťĐŽ<- ŮčLTj6ŚKƒ”ĘÄjcŇČÜń,ą‡ƒś*TĘĘŇ6^̀šáń({¨\•żôj–Ę‹j8`  ÷КšwQ R*Ą80\&"ŽÍÉÍĘÚŹ lWę>EužľĆ1‘yCúmu0p÷¤i)ž´ž¸$Ó;Ż>Ů÷W+fĽşßyŁăәs+mR”ťÔë”éˆY5g8Ézţł§GQňmA’ŽB¤G)ŃCe=ÔôĽˆćŻŚ_~Ő¸ű Q]‚h)žďŐʞ.Aă|>,ÄQÍťů°žWY1'˘úáą-őh~X€Ťá8%šVÉDľfŒr˝WtŤÍ]_ycľÚ÷ő„ځť˛-›o?ˆwΚ’Ú.ÚřĄMš)—Öx˛`żEú…áÎáͅ=$˜R™ÔMɉXŻßËcTŚX4‹tçzZł*YĽIâŇŘ礉"­á´ś~~¨vśŚhN6w” Śź¨cb<ĹΏ—Îß_‹ŕÚë;QĎĂšŔë@Ui|ęľÇŰîŻüЅ>÷Hf$ăíĆE’ßýţ™ĘţËW´ÁK~lΏęô1H›ě-é/~ž 9ƒý,X:qâĉ'NœřwÁwڀ[eâŽ.Ü4tÍĆ 3iLéŘ\’ŽŽ“4ď•Ý[ ÄQZe×f§fíş‰Ň˜ Ę -ë ŤI…¤r˛ V @"t|Š˛bR¤{"h”eőś˛ƒmٙsNŒ\E)ˆ2<ČŹ)”Č ő­Ôȕť i¨WŃĐĹdMvȲôÖîhőäff_JŔĘé: mŁçţ˜IŠÂ&ÓR‡Űa#–˛p ĚčRó(ş^ĎRpUŤČ)ă(pZ$ۃ‚gâćh&ť'ۚpm¤x‘üT|وg6ľÚ=AzmáNSœý‘C~SĹť ! i¤ćĐ*ÄJjËÖÁłJ‚T`¤t 'ć^äT{”%éĂZűžő,âú§DóŰ^ĘëC1ýö64Kę`¤ŠąH´Ë"„Ďń‡_qdS3Öý݉&ľeA^Ăďj-"áW œČÇůÖe=ŽR}A—ô:ä‘oť{Đ:€Š×ZĽIX­ÉIىŕ$—ŘQSŽVYV, ]Ńx#=ůĆmOśÖ`ĆŹé"ŸIČĽŠŽ˘T˙ôŰ.(Nj'cl=2ž ­Y"‚y(Í"Œ¨,+fŒľ‡,jxf)ÇŞE† ć~çYß?7~zyâEœ˜ƒ—­ńwŸ”ŤžżrQůŰPîŮٸąMg§&Ą?mʧ ~jA˙ńʋ9[K~ĽüŽç ˝”¸XYĐľOéŐÝť?f'—ÚGkHTŽĎÄČ9™VČŒeĎmQe1u_kĎTŰRĚźěÇë1˜TśŇ})‰>‰9ŮEéšď9[ŔCčŒ)\Zľ˝š%áY‘e€5HEč•őĽ!>3:ouŕ€ŃR :ĐB‰tzżY÷wUŘ}ÇSńpvßIľ**˘Äg\Tٴѐ9Ď"kšÔÚ"šď-ž‡búŻ•%}$Łß×ĚE?XuWŮÔĂmť Ŕę}ăÖGF5Ł6EYÓ]ŸĚ ¤m’ ”ý–•ľ˛óáqäAúä}‹4×^lňn-[m‹)ŐĚ­á¤*—tn4Ž‡ĘžŕKĄşLzëX66™4IZż˘*LÝđąłGçžÎmßŮłco5AMěúÂ>~eMś B*ŤcÔwR:JTÔąťŹĚą0XíĎĽŞÖZmÄfŇL1–ÁU„s~w1ţÇO˙ńxj{píÎÓ%šnb÷ ŠĆźÝŞLiŽÝxz2žŇ÷;WílMřqƒŸŽŻ#iűÎë„_rŁaüËĎw~ţüĆ~ťąű…9˙ÄĆżÜîˆm<çWԮĞřţĆw˙'őĉ'Nœ8qâÄżŠďş˛zŘ,r'äJF/;l_Ůә é2ڤf,TœČIˆ–j膦Ľ˜eí—4’PA5ńlĜ5Ť‚Á\WňqfŠ-Ö/âłĘuR g°Ú{3˅ŠV7b5 “Á];ćƒTĹÓë‘/këA*Ş$Ç>ŤUŇD2R˜R™Î´š†1Ż\_-¸6ŻĆăEě4VńĎGW­lľ7-r5C¸Ę@rŤ­ŐělL"•˛´ş/âw„ĘŐ {Yp5ąáô&lĽIƒ"ÂE'0+ŐmŠŠ„wßÉŹ„oJŠźˆ!ě^Ľ=Búdäšö  ˆ~¸0C™!ŒÜä‰!|<ě˘3Ţs§fFŚ×ŢfĆCa‹pTßUÖjüľďž˘yWH˙Üíż%žď„ř˜–˘üNR×ßÖ]Ub ěúá ŸôcËuĺREő›"§ŁLITזjŠŁ{žď’BŮčĂ:á“NŐRQKąDÜyąĘ~[Œ*Ľ’*÷ę ĹZ)čő8R Sˆš“šźîUÔu—'ÜďDŰV ŃĆËV9쑝fŽ{Ž",AŇiYšăˆCŽjĐ5€*šŠă=X݇Y˝÷c~ŰÜTiŔ7.M¸śĆOzçˇOţ‡-ů‡gĺŽÎł9ۓaćlMčÝa{BΝ_<á~Ç^~`Ҙűäí>ůúËr<ł?m¨5ň|ů:řç{ăë˜ü!đÇם1żč37˘}âmBx˛…3Ůč ×­Ą–Ut%'a=qâĉ'Nœř÷Ŕ÷]U酔DbÚ =GmŞJÂŹ&^ˇEˇŚ—2„5z‚Í`jҤjX8ĺ†Ěe-ŽrÉj‚ :’ŽJ”JťŹ¸GCŽ h ćʀBĺůVó ™ńP(“Ęř!îXz …°^mśÚÖÜÇ;q8Óěݞěţ ŤŹççďŐ<Ý×HaH”8%ĐÔ(ę e]ÖŮTŁĺʍTzVĆÔzËjX–ëĘĘNšf5ŹŞ 2ńŹ ďAžL€ÜiRjÝFG{5ÚnjľË*Ë8˝Ęąs6ąKÍî)Lí˜&+Ľ 2PMғˆIXŁ ´V‡‘łö\ulĚeeľtB:˘•Š *wyXzÍŞą6łŹŕş^'}X~Âú×đkőőŁ•÷qÚQˇüpűúăĂĆ{X9ĹéžŢď|ĎŞŽFéÇ}ŻZąFŒËeăůĎ˙Ŕ˙őţײ,Jyě¨~$Đ~XˆŇ´KňP#bNşSl˝ĎIjă˘Jř Ź]‘ňXŤÖč¤W>5Ă'{Ŕ›tŽ-Ţđ1xŁ‘™DÖMڅIăY&ŰvAük5÷rçŤféÍ÷%ćv}Á÷ÉAš1ďĄYЧGĄTDmť^˜´YŸĂgqśÖšĘ`Ăš(<ü^˙áŇů‡§äďÚg>ő'>鍭)˘Áf;á+Z0&C7śŽdťĐ}22˜×Ćeź|ÂEšŕç7ç— žćĆĎŽÜtăËŘůň/_Ů1bűű>ńvĺvß+_o˝¨bđüé‰[4\śľUTvâĉ'Nœ8qâoĹw‘ŐĚĹ@; 4QňфŞďÚÔR+SZŁć“ěE­|•X8´EJ<ŮZԅwJeM›BbľË8§.ćd.;§‹ôa-ƒč;)ĐRšŠ .âA,ő´CFŠŽá+QşúQÝëń‹ŕmC˛(Š#v[Ĺ9ďOůWŠÝG‹ęz, Ěú $vŽ}Ř"Ý" ccbZĄÍł­w$އ ë˜ÎRÄDx‘˝˛PRœf G˘cD=ú#w“.ŠP™Đc2v?ŢĎd3e#˜tî 6´=ŃD°lR9]•šAŮD˜š!‘ Uîٸća?ą*é"˝ŠŁ˛š’íAţ“9'Ö>g‘ŚĽĐ$Ÿöá°ŕăë|Lž<ţůxoŽ ęaÇŞ(i5ę˛rËe .›y.KjýěRZSŤBĽz\G9’^SFéŤŘyíńXżůŽQÎ&blZYmHšÄúŹ€ć(ŻA.{íĘgŰĘC›i‘ ľ{ę;Ac—ÎŒ ĂQŻ<Á™×RšmcĆÄ×&jWélyçŽ؅ű ^Lęŕb“Ŕ— a—^3<ˆVôťŐsÝÝšÄńš—Ţčó+×ŔäŇOÝŘ $^šŞŇqžĹůéů—˙ř˘ü oüîĹx‘ŻôŢQ T;ĆčdwČYlJŇŹ1ŮŘb"üfsŽżiü16âžó‡űĘ‹rxƒ´FÜöŕëÝđ~­ç8žň´]¸\7܃M=[帾UŠXżţégôĉ'Nœ8qâÄżß9]Ó?XWK˝!)ň `™LľRĎĐʸ™bZ¤`HŮxu–ľó¸öݜ˘R_ÍRhZVŽrZC 戲ŐĘŃÖ+Ľ,…—ĺ—XÄů¸řh•ŸŸEFĘ'ť2–ŞEÂ9şŠĆ~Ó S×á+Cűn‹Î5ĄĂ‡ů”o^7UŚűăE^}°őŘÂé˜ Š&ŕI—Ň×L˘JqÔëuéAAŐ+KŰ:-î Ř›Tóbô;­mlfÚA§6?!˛ÔLPiLŸkÖqِńŠÚĆĽmˆ{TžŐq.é˜FUáYěBKĺ°;sŰ#x“ŒIuӖhíW DŽĚ粓ůg é_ľü ŔkVfýŔ‡ŸÉÇűUĹVú~ qźßźoö°×Íí ‡ŤšwąŐĽú:]œLáţO˙Ÿ?Ono_šZ#TH™U$VMČß>O“"ń ”fkň Ęr[S0ΐśvuŤ:ĽoTĽ˛Đ9ŃŢQŸoö¨×`FŔÚD#*$:w°ÎU‹ÔÎł:-&Ú.ČţĘÖ.@˛őÎpˆě\/eqNwŢRpíĽ x~›bFx2¸Ęß\…'ëK ZLĄ;\™üř´ńҍOOƧ͚杺˛iŇúV%nŞ„ ćWŒADŮň§OŚ^ét^Ě4ž{ă~ßůIşăíĘóÖćœĚŢŘĽžŤ{Wn´áéšlrçžĘgżđvŒý­íZĚ'Nœ8qâĉ'ţf|ßt •׏\^‘T3á\S-€ć"5ˇá“Š5{;Íî„<­ű,UľÔśFˆ> n„*ZŇ 2Fe)ľŹšEÝ1úşŢŻ9“já-Ţ[)ĽöYíş°8Ť€ĺ,eę˜6áŰň€Đ„âa˙<ČŠ"ú![¸‘™áîDÔFĺAĚ6ɇőŘAmZöÖ. ˘ oĄŻűoě\EިćI‘ဒ鼌fí‘6klRŻA×FćĘ k[­Â)ĺŔŒYJloŒ¨ţĺAŔöBá˘BśÚnÝ Uz#élj˜ ›ŐěŹŇlłńf‰fBtš]Q­ÖŘČe‚ŽRÉŰ1¤J3ž—ůsxQU^đĽÚ˛Čk¨xdNKýŒGŽuÝŃăöG‰ŇC‰=ćp>l¸9ӏ˙ž5Šă‘ÓlĽŸƒ! #pÝŘґ­”<őQäś]Řór$DfŐ,™Őě Ę-Ľff|ŹĎ ›%œ ŹĘކmN4IÚĺ FNƸsŃg&I^ŸŔƒ9”űšô!ŞYť™đIď˜ÁÓ&tÝe\öÉăŤ2s)ˇ G-ŇĄĽÝSHi•˙„Gžľ ŐHœ$} ˛ţÍď“oţúŔzˆůČąÖóęFŰEФfELë–Ç.jłäIŃ"L5h4˘xBÚV|ć O• &pŁ[ĂL1SZ÷ŹFVá˜77é‹ČÖđĹŤ€É}˛Ď‰[C˛!D•íd`”]2ŽYA­—]4÷ D6b:Ӄ{ÂŔ/kŰ4E‹4…ăGP”o•éď!Şjí‘űŹň+[§°˛ŚáďÓ2Ç%ׁÄRCs=ů¨˛Ž÷JdÉ˙•v˝łfK|—÷ߊëbŻ.üż˙ĺŸq÷*MjWČ ćŽm˝Č˛Ŕ•ÚÎ̚Z’XG,őűLŒT}4TGÖ7ĄĂI0q<ĘZy× gD0măzŘ㵕˘k˝D¨śkb >QK~xşpmYeiéëp˘ŢˇD؞?ńIŤ‘úłĂXŞľŽĎâ|űĚČFş˘Š¤)] ń;[N6ńIoÁ%6š)ČŞ#ž IDATqż9ٞ:Ň/<ĺÎóSç7öĆőxEŚ.dKܡ ‘Ž$ź˝˝Őź”^*s˝ťâŠWŒ‰Ś×{Ö.źĺ†ń:„Ÿ]˜cĐpŹcŰÜŮŚđŰ獗é<{pąĆWă~Óůˇˇ_. o^íěWĂş'Nœ8qâĉ'ţf|7Y=˛Ą,ő´Čc•‰”ľąi˘–Ť¤¨ą;„ÓĽŠ_HFŽ‹ÚĽr‰€‡ą•"*Ą "pÍ„ÝÍš,u1¨+˙9Sh!Z͡á¸(‘‡jUŽD5üÎŞŹ-˛¸žŸÂăţÁ–TT‰•{m˛ž÷Ą˙ eŐt̳˛˝&•7,wT1Ă0:•OÜdbڤvTmĺZMáŇjöfm¤ "ˆLô˜Ĺ G}'ú&Bë $‰LvbB ˘]Ľ@ľoZäÍE¸OÇA`މŁxcŠpUcFb3yiFeÎdĝ$făĘmL<•{(ĆdˆŤŐů Їřßľö°ŕfƃȲiżˇ%É{ŽÖ{şńoäŃđűŘEý˙Ř{ťĺH’$KďSU3÷UŐłłÜĽđý‹WĘ.…3Ű]]™ „ť™ŞňB-YÍN-ť/ýÜtVˆ_$Žżuđc+p}M~÷î?IîC-ÍÜÚFšp+ÇŞ˝ăž2žhM)­š%€“Î&őźD„–ľYŠ€ů¨ÝR땣ś†ĚłŹěžhœx{Ĺb2ĆŔDÁćçÚXĽÚéîSEł&fZ3nÝřšO@đ:S@ĚءÚŔ}•ŕ—ÝřҕSů>ĐnDď4…‘Âż ĺ¸ ý[ƒ6żĄŇAœ—&źnŮéó-•1 S÷Ł>Ů$Ůş°‰Tq’ÓůęřÁ7œ™/ü”ďˆ Ún|;םÖ6Ś&Îፑ‰1ٛąm;šuăO_”ó0n‡ń~ZçĽíě{b~b’üs;péȗ3•6îüӛ"ę49ůÓëĆ÷y‡Xßŕ,r?ĹđqüO]Ď.\¸pá… ţmüąĚꢌNÍk”¨T¤#TŃLQÍ˝ĂՀz_6Ô9…É˛Vf2âńAŠŹŤ+×S‰LTł2qËşĘR– %"´VۧžŞwý,/ň Ťäh­ŁŽçTzdłöƒ"WJ™Q¤8ŤLIiU­Ń‡Ş Đ%‹‹A`=w˛Ôš "KůU36íĽ6Ju—mWŔvfŒ•ět6Š)˜Mˇj^Os’>h頝F@{!­&{DŒXYÚNŻú¤Ě>WžoľßŚŔG˛ˆf0ň¤ËŽî/„OR'áďHLŚ;_śWf 6mˆ 3ÎÚLőÉČF ‘Ü#ɘ •o˛^ĹPąŽ äwšŇ˙ŕT[ÄńAPĺ™~ŢĆz Ÿj+uM@eTŐ9Ô$Sžśŕúś|ţűÇ&aŃ*“ET˙]üđóD íłExkŠ'ĎýŕˆĘ[GÖ~o&ŐüL‘S'&0´ąÇ­ŹgÄş>…šB­9(? Ű?ŤŐY´Šľ´7TłŁ]ą`AdĺŽ;“}W„ ‹0$ƒ#‚ƒ]Œ/ęźIđbЍ1“I—ŔeĂîöĘŚßđןˆ9Ř⠙Đ{pl]yŮ~ż#ŇčŚÜZ92úĘ.żjŇ3‘óƒ÷tvŇnĄĚčXž#˘żÖĚՀż{ĺke0ĽcÝç¸f›(~Żş:˝5ţŮ:žđţýŕ~œ8;ˇ~~5něZˇů5ŕăôeAöw$7~éĆ_$Č˝Ą~GMůĆK´íWÁ҅ .\¸páÂ?˙SĘŞ’•5äńÁüӜ˘Ď˘" ˜T›Ťj}WĎä˜@Lrĺ2]ŞHˆpNMfŠ–>i2Ţ0"Ş”çaÎX„ĽĎĘbŽÇ”˛HhNR…ă%Fݟ66xÚ~-&⃌Zó*Z–×&ŕÚHŸUŽăľ‰Y%7Áfk‡5ŰvX™82Ń şń,„j˛ĘŸÎÎśÓóžć<’°´^Żđ<'bĘoY!ł Ż˘Ř*{ŃGžŐ6ŤüđjgĎgNq ŸD$‘'ďôĽ ś~Ť÷ŒG•:5ťábkłU‘¨öçnoŒtœQM˛˘Ë* ZĺÉÉ)pˆňýţÁ`g$|ř,{8U¸ő×˙ń™_Í'!,eřąúŠl>ˏ(5ăAr?(~gţÁ°á|Z€÷˝Ôßuő˙ôŠÎ>#+ß:0‹˜Öˇ2ŸFńĎ,ľDŠ‚RŻÎiČRE ]vďĐ^íŮidÔ5Ť ńÁAc—: QIşBŠŃň żź˛l9ęZŽ$ľÜ.>OnźżžŇđE€á›vHĐžšp&œěÉ{(ďX3n󍲯­­ż IŽńlčýy^$Ů7cĽKňĽ{݉Ś$H&#ö*ún ÷Ÿ8R0‡c óœüvŔ=’äŕeSnˇÚ4~ŃÁnJrNPěüʋýĚk3n6ůes~zťó§ŸŢř_^”?ő:äů7Ú}ҡĆ/ű΋9݄ž)çźńß>N†;­}ĄyBoH^6ŕ .\¸pá…ţXÁ’ŹŢ˘ ೈá" DŽŽFhG3ˆé¤• X´f@šĚjƒ÷Ăšť`ˇűœlbŐĘɗśí ńÁ9O¤ßč$ÇHěţˇŢxݍůţÎË[ăľM$&săžÇý÷!ôޙ8>NşÂˆÉ—[çýĺ•˙!ƒžđ˘Áwy+ˇĂ… .\¸pá…żˆŹz.˛ÄR‚D+ď&ąl§Ž) يЍ$¤#Q9A2P‰E&]S3c)_š˘şÔÓŹ,Ş1k.5‰ ÚČ,@¨Ň€`&‹Ŕ&*NHeEŠźŽĚjH‘H?é8Łă<Ć6\=&ž”IJO:5âÚjÇŞ´F$°u;:Éś^'bbÖ× ^…?*­JrÔČeîy0ÄVy49苀¨6"ŮnŤľ6™dľŕ>;ä@S8#–m;˜ýĆţř ě‘ýM§kg„Ă ëő\Ăiiu˝t­ýÎ&Ő"çÎŚQ Ô Îž'ĂËŽ.Ľw3Ľ­űŠ™ Đ,ěö‚3Čt$…&Fˇ:4AaˇdoÂO”­ý´y ´t<…přmďÓIF8-/ű¤KçfĆ-OŒÁŢŹŹ˙Ş<ŠŇŢŹ¨´*źšąőj&Ágŕ3y/ËôË6xłdꎪp ź– ‰+ĚÖřxżóËîěoŻźmÉŚJœƒ”[Ż}čo§ Ç$4xľä˟Œśoř4>î'żžƒďÇÁ!Táëh|LGL‘Öů~$ržŠąYňöşsHç8“›&.\¸pá… ţ~üá隞ORú­CŽj'}lvś(#¤Z8זd}Đ/ľ´”"­ŹžnKűŠMF2*ßš>˙›$ˆY¤8´l}ŰäL#l‘2(5V™‹ ÉQ :‰‹qFŮsS“đÄ8Ą•íľe=–Ň>…ôąŚ^Ş8üÄ´—&‚ÍłĎE>*W¸‰WĂ1Ľ#֋˜e™BÓFć,eUĘţ™Úšőä„œ7v3ś\[­mŤšŸ¤uŚOšhGQÂ×^-Ę)(ŽPĆ"ETĄÁ& ÔîĚ&ßrp`ˆOrˆk;.;Öç4"”7,’c ”„ÓDŃ.ŒťĐÚ7>Ś1c•BiCłšuçR¸%'Ůߪ­wmq>6:óIpy’SÖ×mžŹŻ=mÁ‘OeUČ ?ąZÝ6ňC‘Ň"ŹŰjCnÔáKS mÝOxM&IYჾ–ó˜ËɄÖËö EB)EϚ”mײěĐŚĘxyŸHň6á_ß'wOžťppŇľń=ę-Ui‘řĽŹ^¸pá… .üCđÇۀWëĚ"˜šňŸ˛Ô#Ľf_2A}%ĄŤ=wr—šżČˆ"ˆ ž†řY$Âśj¨ÍÄÓ`5Ö˝ƒÄdd ×Ě´U TŮ׈RšćÚnÝzÖМˆtˆÉČ*]rŹîw•6%AJĺĘ´,Ăk;v€*ś }”Ä”§rX“Y ˜JeĂim#ÓĄŐĽ~QD>'˛ląSÚsšƒŸ5—‘ŚšlKAĚőJ¸ŹŹŁOÎtĚvöH<Ő`ƒś!s’ĚEHŹ^ďđjvá'f;ĄZDŠ ľ­¸\$Ţ^JÁózĎ\_ńH&37šNnť/DLbV[jö4KMďń+ÖžŕÚç.•ú´*Ma=îVdčYpT [fT&uŠÂbFN_×Oâ*Ş]eYŞËFźn.™lŤŘŤŻy˜”š\zď\[•)ĹQÜçşYę¸a†ĆĵʓD’\ĹŽœ˛3Ô*›•Óí&´5e4ŤŰľěMëPŤZ­ˇLO$—¤ç ͘~’´íĹŮşÓö9šÂŢ^٘źhݙ(á’ÂÖľ~ŤňäđYDQ7ŢÍș8ä\{´QčÔďd“ĘžYíÚMËłdˇF¨pşÓĚ÷łÜ÷;nmŚŞUş&^ˇd[ ôţRóJ€ ÍŔÎÁЊY‚5nr'ŰĆ/[CÎqbăäżÜ”÷áÜ<ŮçäËKňş5ĆÁ†äĆů1¸ř•ťG83wĆÚcŔ]7FN>Žŕžo(-‚_E>ŢżóN¨1§˘ *9`Dٰ/\¸pá… .üýřcĘęRˇ4KYu zMиue“š´ÝÖŽ/ěśÓŹ^óá+Lŕi´Źr0M¨*7Żň “ş(kf3ĺç×^Šë˙ý~çˇ1˜YjsÓĘżî&ôľđÓ×{†ž~ˇG*§WnY­ł‰qĂůž ’h&yŢą^_ŐŮ{Ă"xÝŰ͒Í6$“/㏠Ýź/ˇŽH§3řĎ?˝ňŇáĺVΌßrăă/ΌŔű ß2ůŤgž´ťóUĺΝĆčśúڔ÷Tîóŕ>…/ˇŽBÇ9tmLާĐ>B?› /\¸pá… .üÝřc™ŐôĽśä“'Ľ´v f”2gڈuŽ1ÉtʍĘ"‚•Őô(v3­ŚÚ\JRVâuűŐĆťŇyˆ3ę{Ëö#Wnq•Gqş—ľvŠižIc2ĺ‡}O?9ÖާIY)SŹw /ö¤t˘ŚF2ŠĐ¨a9ńŹ˘˘TĂp†×ΐ^“6’YÖIńŞpŚBdQM'4Čé¸ĆdôÍOL iÂôRŇTË2|ˆBœľŰ^ëƒsŻšĎ[e)ŽˆĘFęAŇ@7ŔŠüĹ$qŽS8ĺ [ç& ^ęńš&_–č\÷ç'çÜKEŒÉ™U*tŰK­Ë Ž &Ľžçëd­WÍS¤‚Ęܚ1×Eľ4×!C,Ëmވ$f:+Ë)ú,`ĘścqВ§ >9Í"“M){ńŘX„’"ŽžŠr˝Ž œY„ÖˆXE<šl›ö|lšţljˆ"'ňúH!Ó9 ć`’Őžk"“;4­fR‰Ňpť"ś’ÉČ`Ś"¸n¨”ýŻß‰IŠqfքŒ4”YÇ”×ó˜5ĹC8čČ TwöcrčF“d‹M>ĆD̈l4}GQL*'ëґ8ů6¨Yš¤nd >(Ry؄”“Č™03œ¤O,ś˛wgYP}™ľ%ë~pNÁł3=HU´˝Đc`ň ÷ SG˜˜ƒťńáŠĹwĆ0BmĺžK5OwŚîô<ë -ˇ€vŸ„6Ž90ŒR´öœĐ62źĘy˛TUOĄŮVĘ8ĽÖîZ‡#ŞP şű’őËޚÖČ9 ݰ<ŤLőjžŽu8#*K-ˇ>VKp‘s%‹dŻŁœĆ¨Ür.RFYX×5.ÖpŸěunAc"ÉRU)ľ3ˇľ/ ތô˘@Ós)Ňp›“ ;ťéA„áY-˝EnŐNô„#´śƒ39}ÇłŚ^Ň6RŕmeHň;śoüŹÂƒ-'¨ň_V‚99Ď_÷ż•%6ł‘Ň8ŚŁ[ă'­çvNç‹ 3¤32¸ě˝ń˞X&sŔOýäËžńśm|iÁŰŢI^#0‹r``Ś´öJ"(:?P‡)wöďƒh7~;ď÷~ӟůżÝůoýơź1Zm'Ů8—ËCŃ*̚*ĆŰţ3"É×!čyçh;Au/ß1ÖšĘ*Ş\ü… .\¸pá…ż¸`iy}Q­˛#Ő2őĘ3›ZDěŃa#šů$–şĘttݞXC}$sY#ĄľN÷Yۘ‹l83X­ŹŸíQ…c’D 3?żh’ĎÇ%’¸űĘËV÷ޘ>ëω•€˛’fé$n–Hf>ę’ l[ۛ†ÄI< t=ůšş‹S¤6#ŐŞp*źČť‘BCKĹŐVE7id$;ƒ áTCĽ2ś’ł˝ĐTI ™“œNĐą,f]qáN3Y×`]‡›ÜI˝­ĆaP5Ljţ¨Šŕ^ó<}ý”RÖgAć‰ô}ŠĆĺ°Ľ<ÇŞ4› îÉŚŕ1ń{Y¨›ÝimÇUń1IŰÁďőEMŕ”3şŃ‰šb`GęV­ŰŚ`]“N°“x8ßޝM’×˝UűńϷƔÄgĐśFď3ŕŰTž~ ÎQâˇnLmô<ŘújCnŠœ“&—lěęloVęownâ(1śf´fôDԆ°ľDšń>śú;'í§âű ď˜$íöÜßżüďć| elŻĚĄ ťqƒƒşóƒ–h´ÖůîľŐěÜŰŰęŘćĂ5˛Ţý\ü~Üë˝pá… .\¸đ˙ˆŹîVš/HLJU„,ťŤ‘ HŹ<ßjë ŞuuVşFfhx)z l˧žĐçQŻMnU%‚‡2ąĘR ¸&É=†Żaa¤Ń58BٚnCvLžł52‚XšŃ”$˘TA“KM™mu]kˇߔŽĹIj'Ú ńÁ™Ľ$ǜDßę]m}ÍĹÚ˘•gّŽ×ž˘“ű÷:PuaHbćĺ`âśŃ(âÚ3PňÂŚ‚-…˝”Öľ‘šÉĎyşíj355[vᲣ‹u,*khC#ČÖɜ„l‹ 'ç*”be{#­w$KÎy–ĽV”1'JëŐ^<ѕÁU"ďlöZůŰL:Jzá63œŢ Bń L•Ü6°Ć︐˛!(÷ŘšeŠöݎU´Ćŕ¤ń1’?ß'˙:’ÁÎɗÓůI&Ö^Ȁ=ƒPa×ä—Myۂî˝unÝ”]rý~Ý1ëŒ(›¸›aMŔƒIç8Çŕ/s篅_O¸ĎNÄŕËmr˙r‡˙ţŐůę'g{ažÉáŮH+kűöJĚAś.ŠÎŁTlŃe…×§˘ş ¨)1ă3WŐâ|á… .\¸páďÇ"Ťf=œš–iәńsiDR›ŤË6™Ë?(gJFbÖŔ,ľr“$ľIDĐŠ’"TišT)¨ŻĂ*ę)ˆ(kş{¨R‘Y6a¤\ԎgkˆŕуXkŕľŃ fe…œQÓ8äÄRšëƒé#[YäÜ-2ۤěÍRí˝ZˇŤ(IT÷"ćEÖĎY›¨"˛ŁÓ™KÝŠbľJe)›°˘­ÔÜ ¤bՎD“`%MŮ̙ůZ6ܨVן Ě&5o#9qśR›ľ^}O Ľ‚{ ´Ę|zM“¤—-;ąĽÖŒĆčF8V„Ďź˝Ô!@$]ĽHBœ„v2jşDľJkR”ťîźdpŚV+/˛ôÁ°ç{O֖jřGšr¨^mĂ~’şŃ’K IDAT4™žŠžŹŃüN1؍—D$͒*R jmU‘Htíĺ Ľđ+E€\’M‘‡ý801T(ĺTa“ä°"Ѝ3Ďłр1˜šœvĂ´| Sz-‰­ŹmCçAJ)“ĄĆŚVTé¨Ů2h U2ʙĐZ5FĎpŒÉ‰pW­/ƒŢoäźlBŚ1Ć-…f;›&bĆpĺăĂůmn|ÍÉ_§p$l͈L<_€œ÷pśiäÖxŽ×'–ĆëÖKINEÄéÍŘnFďŐ;ŽéhƒÓOHeƒ?˙ö˙ăű ˙rWÄvčFŰżđ+pžÎ׊üę? ó“ŰËöL˛ítIÎk‹çĄ›[g"+Sýů7V˜@z–m=+go˝Źĺ.\¸pá… ţ~ü!˛Úă{m@ćÁIáœQ%AÖmeQ•Œ\ş‹Ŕąţ]Ź‘Rť“RyBđÎé4Y…HÚјl­ƒWclĂľ­ůĂ'Ç5lóT$3ł>h.‹'ֈ9IŸčƜúœe”ÇÖ%ŕľĆđ˛;fŹŇ#ĄÚa}"1˜śK5͌šČ! YšYęîCQeĺ W˘Ë&ŞEŠyö­ÇŸes´Î -[jÔ| >ËÂYaHV q‘´¨Ćßi;’“™ŠJíˇ‰…@*3ƒpŚUƎÄId‘QÇ{!ÂŮT ­×V–:Lz=7)o錤QöiľĆś˛Á)u`ĐpîŃ0‰šŠń˛ŽN­Vׇ%JőVÖ>Ź”u7VŤó Q>˘”ëąÚ‚%Š|ĘşÉu ‘,›q࢘Ô÷×Eâ@ڎiʃ•$­C(u RôÔĽłÉÁȝžƒ!­ ‘TËrşnCľ&yš&äfRĘn†ÓĽ—NÝ7$…5eÔIîŮA‚9'ÓöRńŃň ‡Îhˇ:Ä!ČvCňDtÖĄŽŒ{]c”Q #‌PŠđr˜)ŚF׉IŁG5üęxWzŰڜ] k A““1ÜĎä×áüy~˝'_Ďr$źvçőf w~!Cȑœ÷Á‹ wvś#ŮýŕíÖyĘë¨ßMżÜ6ZfÍNš˘Rs9b­u"ƒdçĺ­Ń˝ŃHîa ‡}8ĘH!|˛5áU„÷Ügz HŠ­ćüTQż§?5˙^ÁŻhniŤÎč¸ňŞ.\¸pá… ˙0üáA@Y…H›–"”f0˜łT=`Ů?—Ý2ź2¤j+Ů "ůůő…ÁšɕĚ[ŽjĽZ‘„'Ň:⎙2éLŻźbk}Y|ëű3ŠŁľĽč:ŚFša&DZM›´ŽJ4í˝—˛ş”C'žs4nđH3Äúó~ČÄKŢ,â÷Řú̺ݲ5˝ˇĘÎ.eWUŸjŻęgIOfelkK´śNiYšaŠmEZ‹8;Eć4fmĹRä“q2ĽĎaşˆlf2ׇëĎ"Ą˛ ćšóK}Uâo#‘RT•ˆ*r1\´,ť>Qľj‹nőŘŚ—rœˆé§\•E(ÔhY‰č¤!řʔ!ÖőśZ›+!+´ŒĽŕWZľ­ë'ŁTĎÇuál+ăÜŠűB-NŽ™5głěč"`Ґš| ™lÜe§Ć’LTčZE@˘Bç,w€4ÄThŒşndl˜O\•ĆPŠ’ą„j%ď7rN´-›ůżľ:”KORQ•É7#ĆEX/\¸pá… ţřcKQŞY´ŽŚłY2(I¤ÓĂIyLj(OqA}l„.›pľË–ZfVIJ>4+EP]ś Gr‘ĽŒ‘D$Ý m˝JhÖ\KÝŻĐZG2˜‹(fć"śŁ”MĽÔ"SĂç@[‘jőŐFŠŕs€1”Öˆ•Ť]EĆ?¨Ľö$§őP„ś>̚Uˇţż˛"?ňšŐ¨ź^ńe ~>Ąu_Ľ-§+Wťrą,ŤlÖózdf%ňAžrŽĚďú0îžTÍu8°^żç}?˙-ˆY}ĎʤŠČ*TATS<őÚe o霾2œä˛áą-ĹąŠŚ ŇkŰweĄóQB…,Ňş„FmkO7×CľR—ýźžn•üdžŐŘjR#" y0|ŤÉ•,•ż…Ł.Íc‘šAŠ–şŹâŽČëŚu݋›BˆŁi ŠN jVjÖgŇI=Nľ OgĚšŠŠwgٜŰj ĆOĽiá˜Ôűťqb$fÁ.Šę"ŘP3L˘ˆÖŢąŤâ39ÄČź#Ň8Ăi(Ą‚éFŁŹň9w”—89ňÎm˙ÂéőűŹÇ‘Řöœ˘ş‡r6`BŰ/=ř˘‰nEt+Ď]×`Sĺ+Âý„AçŁ ?ˤMřşrîˇC™ßœˇćÜŰ+˝mlăNúÎ> Růő}”áۜüë!ü÷#ů6)Ćmß㣎‡‘|×Î̚ˆĘUę6#iŰ őÁš~˙-˘Zörj6)1Eť5`[‡JYƒÚţ‡Ď/\¸pá… .üŕ}ŞşÓëž Şr3˛ćSÚV*ćßúĺ¤ ‘Žř´Ó=č—ú‰[_%L…%ĽöQ'BŹš‘š6ÉZöŔŹă>Kɛ]ĘUĽ”¨łÔV(rCÔžĺc$‚ÚąœŁˆ‚QdÔa˝T^_*ekřœËś›E†×“‰§˛­ j}ŕ-Ĺ1žSőˇ2˜‰Ş}Z€ÄZ–[Ę$"Ť¸ĺQHúóąüřzŤő"“OUšYâ4v †öÚcĘŽbú$‹Ÿ7S5"ؤ졪ş˛’V˝QRďψ’U0ł˜{6)‰Eâ]lu@×űrYů-EUWŮT9łH%"u”ß=ĎXיš^EO¸mčRćU„fV ŹurŽçŽëłľU_° B.{ű5Š€ŽžgeiSĐֈœˆ.ŻlşŽˇeHżGŤC— ZLŹmL}l׎ďđAŒ"ßęëŽd媅ąŹňÁÎDBč¤y" 6Kžˆ ݃mkk“•ĽˇÇI .ÂÁ˝+1g'H:N gôúËRZYîÔ‡۸sύHp{!úN|dĂŠJđ’Ξ5śÖ*_zŢËRż)ˇ0~=žÉčĘ Âţú…_ä;Œ‰ŠĐd'$™Íř-OüŤó/_›oűiœžő‹}Ďŕ#ŕ˙Ęďsň[žU<Áá{Űč'Cö˛żűdJŤç鱔z+źężAUëet_ĺIŤL)=Đ^šŕđX‡5üđWî… .\¸páÂ߃?FV]‘,Ť`¨šQRté:eMq“˛ěUűďgnľ>Ě!@­š‚CÖż“ÉžČfj5‹‰ é%JĺŒ¨ÖXŠä™Ş›-áĽŠĘ"aúڑ*˛Ňú(ytUÂăˊLŠť`öPCkťőAFe‘Ÿˆxň‡-xŞŹ˙.ŇşćJĘółýX–Ľ7ž*řRj#—ýŐŠ ˛vgs=/ĄŹĂIYmýüéľ9ľ2ŽgTžŠěĺ"~˛ÔÜüáyœÎ3\Ä'+{IQ|XąŁëăśĘŚYěł1aˆé*Şçř¸OT—šłĄĐ-k—VZű=Q­Z/ňCuŻüěH˜Ľ Ş Ś¨źí´tR$×JÉ#˜Ő4ŰÔŤ8„M‚\YUŃl(ŚśÚ…uM šĚ"ćÚpNĆŹ×ckÜ܋@bÜوŻngĺL%q˝a&´<˂ŻRNŐľŻ›Ü$y흝ĺób)ź4c“Ę73ÂG*Ýu@˘ňĺYöę"jAÎ;Ł]ˇN6ÝŞÄ*ƒ ř:'s–ƒâť×|“Ę$6j/UC‰9PjŽjËR›Ł)›żćˇQçOöÁ/[C÷ÚqŽ„ÓÝ Ď~ť{K\ĆÖëBďűxl1ƒNxŸ Vü`ăë81™„žV›5JPn‚Čj”<ŽKÖWu˝ŻˇÂúűeŤ0ĚŤHID ŠËY`JŒŤ`é… .\¸pá?DV†Śŕœ4şDŮéVń 8ŽŽS]YC)B›ţЍŚ0Š|jŞ=UUaĚšěźe‡­EĂăŃҙĎfYQ-ľÍ'šÔĘôYˇ­RŠhfMŽd5 ‡éy`Öj-&łlžŤ”I¤Z]s‰°­žöŁx‘Tŕů!WÄʞip§÷mY…ëöcĺ#~ëUq˙´ oŰöl†z|ö$“ňla Š2‘zŽO2,öÜłýQÝy”!+§ZŹëßáţ;ŰďCéŹBĽG9Y&íú˛r ?¨¤˙/1ieII˜˛U–óaYţĄKTkNH-&Ą?JśŇŸöćçaLV6–ýűQşU#› * áLŰ1ŸˆsÍĹ´ŐĜŸŠY“€YűŞ*ĽL1Řڎĉ¨2ĽsËŐWf6ÚzHu ’ľ“+ŐěCP™5Ű32꿛&6ŤÔËt•?Yç -˘íłŠ›śĆ&ĆfŸÄ‰ŚÜÔШîź=ň˛˜ŐÜRŚđÚVś$ť€DđU¤eŰĆ÷ŃeĂŞéؕ)ŻE.}ŕ>š§së;ŠCŰwţ:Ť…ÚiŒ><‰1yŰÄx5çˆäN íAËäM{籠°7˜ƒ_^ol ~jAoűoßř6…ŰmgŞŃÜů'¸@ۍM'qěö…~k 2•ŸÍř˜w˛ýTĽ#PîËĂa֙c@ŰÖŠ`V ľĎşţ‚ľ‰+‚ëzůń°Š^mÜő˛śGľ|_¸pá… .\řűń‡ĂU‡o äĘ ŚS%9”šąȃđei @jŇJmŃ&+— O2â"÷ťÉžäçÇh*V%;‘Ľŕĺj>%“´V›‰?Řh3ą­Ě¨O•P0SˇšŠĎË´­TLëKí”gŁof0'ôţ°$ó´őśÖ–…W×ëORkŚ˜Ů“”Ö׊ôúRKšuŸ,Ť°-[Ż=›?ŰO;ěŁÁô÷/ÝÓg\÷ů Úë}}<ŽÇëîew]Š^‰ \¨>3zUzUeLľ'*+`YŻJů^ ć"´ˆ#zš9°áu¨&JԘtYš5ÓÄăĽ\˘u-!Y˝pá… .\řGŕ‘Őľiş#„&Tƒ&ő!pF,{¨ LF,ňIŠ=žnçǏqĽ>Űox •*YVĂúĄGŢ´ŐŚőA¸öVKľ4ëeÎ"sŽÔĘxŢ>|”$ĺR%ĺĄf†WáĎóű‹`Őż?sŸ-ÄüWľĽŚ~-=Úh?­Äů$Ęeu^ŮO–Ú×z}OŤÇĐTËśű7DUžEOňźÝżÝڐ )<É˝üp;?âQ ôPZ§Ö>&xÖóŇVęŤ 5%*ö;ľöůËçDˆŞb‹P˛ţ?‡•MZLBŒ‰"ë{ÉÄę„(â˘4/b čjś]šž6M‹H4ILy*ŇŐv\Ş÷&ÉôdçtŤ S¤&lr&37z~ R*xPVl);š1O¤ő§úM&“AْmßąlmŁ™Âř†˜]ě[§ĺšPgŹĂšŠt€vL66KŻß y¨ŮŰFĚ D˜qçpá=:3“afcĆ(۰*–°mŠV“bŠk'Ůđ<¸gc[ĺW‡wĎßi÷j5…Ó:9OT’f`QD°-ƒ&eéo’ĚÝčé ĐꣀtYs›'S`A3a#Ńźž(ş}áLăĎßNţü}"(ŰË #îdŹr55‚Ďƒ¨ĂŒÇHŤ´-Ž )Ő^ ˜a´Ěš"Šőűőƒj*ËŹŞˆýđ—íß/žpá…˙‡˝÷mnIŇ<îRRV÷ěěî}˙owś7łÝ]U™)î~/<@)kćÎrśú%ÜŹ-UjŠ$Ŕ O<˙ŽšćškŽů/ĚĎ1Ť˘¸62&&‰#Á0ÎîÔdfҨj•ň=†”×RÉOBҚ?Ţӝ^ĆĎď°)şĹd–´ş6EžĐŠę?Ž˝Ŕœ*| <žLgĽóśĘ‰' Kbݘ˛Ŕhňń˜’~ÔáDœĎeRÚpt‚Ç’ĘĆó œ1ť*Ľä$äd‡?€žčJ ]`ôĄ?œ§ŸzW˙“RČĎ^Ôz^Y?ůąŔ”獕7öôÁf$˘FŹ€ŤóyO?ëóń똔lšôÚt8ĺĚT/ŞfIvs9Ÿ+ŕ§A=Ťë4ŐĘW,†P2M2×ąË ű‚–\NG“FkĘ>lĽ:w‚Ý7Ü oG$9'ßÓ*™ň˘î“ÔşŞS…{:M;ˇŚčŒçupďÁv[ŚłŽ÷ľ'Č$"Ů^oe,á1&2'ŻęL śŘyiĘk{ăPáˇ}đQćŻsCżüęťS_Ŕƒąü§JýÖĚU]ƒ‚'ˇMWxRůw#…fBŽ”f1- ú‡KËz)J*ůşTšWuÍ5×\sÍ5×\sÍ?c~ ŹN‹YžťĹ(VŚI1z ĚŹÜAůďR”ŽZ””źWIü”‘ž ŕ§)Źu2–ţd+˙ř`Öbž>¤´‹ŐcŇZ{bśütóxzN˙Zü|ŽĎ݁č§Đ 9/$s€•î{Ęy?ډq܂ęᎊ’ˏXŻőpëqňäßăg źd‰gpT"+ˇ ˙pîâ”Ďc8=Ş‹ýýĘĹbA‹}T”ôş'b1źođĂóş<ÇçńĹ\×ę¸ýĚŽŸ W°ęŠĘÇ\ŕ¸iőŹBáŁŔ­jUöÄXÇ H@Ŕ’{u`ć@Ú­˘Ÿc”çÖlmřҕű;"IŘĆ ń ‡J1{ĽŮŞ0éÜd'ŇH‚!b4 ĺ;˜’2ąöqi9wZ L“ŔP’Œ‰Ł¤TpŃc&Ż&ź7ƒ99LWľĐ ˉŤpłÁožtÜő•‘Śá)ÜÖ:tOLbĆM`̤Kő$›–/sÓŞ9"“É#•'g.H§™˘{$c:‘ěŘMékľžHmşÜÍxdbRő3“7˝ŃOŠó'˛lŒAŠ!91Őg¨ĐÉpžsţńŁx[÷“Q<˙.ĂyJc? ŇŰ0ŐZĽxžŐ7Ÿĺźî§ß4ţşU5óIzťţśęfÚłJEÖß|~|ćŞůąň=N3ZxkL>¤ćÓW˝ •bŠ­ş}ŢLŸžŕyU9˘„ôFwu§F|ô@˛Âˆ2ăD$ń. ~&Ÿ’e9öbI×Á”\ŢźÓťú!ćůyěUIZƒ 4ëš?ÁÜú\ŽĹŔ6˘žE*g>Ј’ZZ/yvŒgŠó-H'uS'bmš¤`^2á ƒŽđœçd1śÎf_\şŇh:HÝĐɁišM@,CŰ@őż3ő•›L2k3Ă,K–úbtŸĚŮPë wĆt,'­ GÖűBc1ô؉nˆW~1҈ůĽ>‹9šéĤšTštZ$ݜM…{ŰŘ" MŢZcłäžÉœI3ݐ& şéňb+ť'{*=J=đHa3ÁÄç Cƒˇ›­ş(á—Íčfźh­-›°uĄŮF"4Iś&źĺ¤[}ôů ťÝřEw¸ ŠÉĚ ź{đÎŻó m !ymÎf­wD•ďÇŕ˙ţ]řŰăŕžńŤßřݭ֋3&C•h7lą§އ`RžZ97wb–‡řd‹çŁźîžŢÓ$%p č őÝh3r–':"łz逯šćškŽšćškţós`đ9ŃÖđ„&đDȕ¸ťz KČYÁĚ3DŠÂU D&sű ?ŸÁ ťÓZă#uWž2ázŹ-&uy›=ĺ=í’ňCĘnyIeĽőę2ŢŇňIf[ŕęŻ?NĚşfËSYŹřk4‘ŔWÜĎÉ_e$Ę ëâ(7ńb¤Ă 0IëF9Rđp:H$’ÎĄ„H={&r/ÖTdň2‘U'‡';T3‹A•ł7ő”ç3U8˝äÁĎżYA;ëŸkŚŢÍŞ„‘Ş0a1Á›ŔD–<łŇťWKJyTSŒ-ąFľ­&"ƒĐb’[îh֌DńČĺœ-?벚>q••Öj"'v/€,^ÇJ,éľň dCs’U‰D"]Óak™‚Ƀ~!sB:b˝6&ú45<ƒqŰ1<œÝ‰pLĂLi9x„"űƒ‡*˘wđ튠rĐ[ŁŁ4vŢÓŮhs‚›ÜĂymżŔü†ëĆK7ö6 &˜*Ę­ ’•xým_˝ž~Ď eR[ĂF˛­C‚ŒänʗŰĆ˝4`řډ: ú Tj)lŚ´&üUżav+Ş%/ˇ.ʈŌ |iun݃& ÖËţő1ů÷Ż“˙ü{4~Křž†SRlĂo÷’äRý˛ ¤6tĽ#÷L|Š ĄJoŹ–˘ĐűJtNžÜ‚Žuu>\ům?ľŤöÉ×Ɲ!ąUŻšćškŽšćškţ)óS`53ĄuŞ1RŒœ†WŞŽ|ŠZ2?1&%㜠ÖÚ3Č(3V5 OV XŮCś˜żX7–'ЊUÂz•XňӓYýœś‘Ďçů˝ýżşŘŢ3řüݙ ôšśĽj+Źä€|x3[kĚ9‘ÖŔ'Ú:iř†T÷+éL)˙ŹČ†Ź”[O'Qn˛Ŕv@뙤Y˝úş™ßĹUiTPP_žË,™őŕ fr˛Ç°Ěą™Oę¨ćzŹTŔTIk?Ŕú3 ę”+gŹór’ŹňüůŒŒjŤzć–;nw+3¸6n3/$:VÖz1m˜‚úQ YiˇI“„~ŽP4Ţiz+F6+ÖOŠs–ô5Öú‰FâAr+ɰÔ&†Ś“Іć(fU]rŤô&Ś­Äźˆ:6ľ`3c÷¤ĹŽśF_Űôâ ĚźqëJ¸2†“R5GďR}°&ŠsC˝ÖŒŽ ƒŚÂaS§é Ąƒxoj_f~ĐÚ‰ÓçӏşŢń‡<؞ ëé5…“…Ő§4š€Zݤş˝wćœOmf€U?ě |RZUٍaY>J ™˜8‚1Y‰ËIĐĂ9Ähă+w )¨ŢH’>Ąć’ÖĘťŽ¤č†ĹÁ”žęg–HűSčSř\Ň_Aí IÂŁ˜Ź9ž,ńNĎp§ĎŇhŕ&ë3ŽäcBfăŚĹ”Ž‹¤ocO@ő”ňڊ 1hůą†ęľ•Ň ›UhS)Â7$§ä)ĺ— ¨Vżě)'_’őLRnKŞn$I&žuUśśڤŐűaŹh1ŠÁ“Ú ˜şaKRJ9ÝV§{ľbťžâÍ­ 0Ďó@OEłüŹ#•[V*uFu{VšQ*ü’Ë÷V׌ ł5B•tgBmĽłďÉđ¤÷FČĆ1rĽü:ďßrăáĄó•ƒ_Ś3"řËë/&č,üˆ:“‡–„ÚD ^¤ŽçŚŽiéŻďmđڄűM¸5ĺŰŃG}bÖioŻwşĂ{Š&ƒŒ`Űî¸vţŸß~uaź~!$†ăń šŸ.ŕ•LŹĎŽS÷%oXŞ)B— qůčEČňD/Ţü¨­ŮÓÇQ`˘~.€řŹ”Y7ć%ţ§,řÇNSaÎń aúk/?/}đmŐzţî” Ÿ˜-“ĺkŐgZń)>AňôQiĂb •Ç-Ź#d éœ8tx1NĺŤK†4t–<ąđdŤkíé?mţÎĄ[ŠŞMítU$Ę Ëňą ËăŰ,főĂĎĘJ=-˙].Ůś|芟ŢVáÇbĄűŐşĄRa5gżn¤sH+0šŹZ@ÚF‹QRJ pzT¸S٘8 '%0­TjB!@› éNEN­ 8ČlņG~źŸ ”Č Ícm˛lT&pŤÎ6$wfŢ٤dŮ乙!k[&ę„`á.Šg‡VIłĽ ݰMšÉZSšł[ɁE•”†E邾ɓՊ:i´Ö_@i$R›vć/Č6Ëă,­Ł4]çł%4ƒfúLŠ~Ÿ;ߎä}ďŤ.čŘţJDr“ßý;Ǟb3^â`ß^0wŘZ……1¸w]MŰ&lMŒn¤•btÝźTˆV&śŽ/k—öcÔi›ľár |ßw~ݕďűWţ>ŒżżwžĎ†5ĽÍ`ˆ•ô7s]=kmD kă"×Čĺż6[ĄfR^pŃúޘQŇęÜ-%ĆtPŤ@%"Ş˛G¤üÔIŮ!ţ°ąsÍ5×\sÍ5×\sÍ˙Ůü4X$溙.&§™á‹Y@­Wş'`Yá?"IӎŹ4a…6Ÿ~đ“ĘŽóS@ ŒĘS | M˧zĘsátJžň\ű2dfëuŞ˙´:Le=Ő}>Aóů÷°‚ŁT™sbÍÖű V•‹Ha3i}ŤŞ˜´ĎŔĽçmě’fĘëDŻ0)÷bl[Ťᓍü8AĐ5Y (Łŕh…Đ(Ţp\îuŸ,‚…—„Çéř’f„öŒţXi“ČŞ b…\…;rúîNěą°<ȋ}*Ye}.ƒŞ,Ú"°\ĺ3ŢČäDĺ„řuco2Q)PyÄNĎŕ[Ŕc:ƒÎ{4ž?&/ݘěŃŢňĆŤf…\IĎű‘|÷äďSůˇĂřGź0Ľ"ˇœĆď w$Ę˙l™d3ĆđĘ­îT‘şvV’ľ ĺzÖH­5?Ł~í֋ąOŠúŁ”ę\•îáó)ýUűzťćškŽšćškŽšćĎÍOU2 dŞ-]Ý̟,ŰS2Ť LČŚ‰Oh[Ő šhĽlęGdQĚąş,×Mă’—¤ś}řeů𵞀˛@褾ňfÖÍ#Y{>VՀx>§űÓZ S~l:YZwGĽ$Ľç뛍ö![.9đ™.|‚ă˘ă)O>ÇÎzŐşŠţôÜ읾ɸBĽý–Ďr.I1q!ŤoV擓‘nRžR:Y’hXlš”ěô¤ƒžŔżľO=­Kj\)O¨-ŁŇ{ľ˜ONózvOaęFĆ(éŹ$1Kş[ęJA4S2:ŚŹ$V)Ÿ+‹5V]}˝QžM¨WY’Qő•]k'ć:í4Ľg0çVáM˘¸tîé•Ţ‹ÚčéĚ´R*“c“ŻR>V‘ú  ‘QňÝ Fâ;äk˛˜ű@4Vď­VŔVbŠGp0 ńňÄZ1Č˝56íÜčpÄcUľJą:eVH› ČbGG#Ź@|x˘ęźhb}#ÔxLŒ‡ÂœÎ7Iöéć;Ům|§wăËŚu C| Şź 0Ťŕgë÷[uŸjŇoUÔ6žż?x?‚.AšńíHĆîüŽĆŒ$ڝżŠń}Ÿ<öM„×™üë‹UXVÂążóp˜íÎc3ž:|{_›gjĚTfž<Ż—J¨.ßuťuâX$͘łÖ•­S‹ąÖeÉ'°VŠŕś5byPÓł:—˝VďłrKóßöÄvÍ5×\sÍ5×\s͟ŸŸŤaYA8šd´)ň‰\R;ti †„ăÚč1 mh+žŠ Џ(ćcĽ S˛Ř„NŕŤS1V¨D庌őşń\iľ’´Ő-Şşę*ʛW9=šźÓ_zÎóç Eœ˙ ýÄöě*ÍĹřŞÚ'YńŮCúᛍXţÍĎŇYY˛gx‚Ü?DýŕÉýř-Ä)YĚПyťK˛X%6dŽFTB0Š„Ł˘¨ÜڇLń<öUá!* ÔŻĎbuęÖ9”Á XÖăBŒhQ5,IŃôH1Ž*ŕŸťsއSÄ (ˆ+§†Gůb § ŒöŠ{×Ö1Dłí ́ Őkš ŇŃtš&G DɈMÁĽÂ˜š Œ¤ëŽćƒÔí™NÜd1üňZĚgvT*‰EcäJÂNgLekNćęśÄ=Im•Ţ,Žg"ťWBtkÄdÁ]6RnX|'}gSĹÚĆŃnŮ8˘Ŕ5˝qfç&ÎȎˆĐľ:|C”#km<<8–ŽĚɋ&ď8Üśň;ęPý>ƒ‡6Ţă†X&˘Á]ľ;/6¸ Hvîv­A[Sî//Șą^'CĘşąnľFăV!GnJ×NWC,Ŕďđ<7ʋ(÷Ţy;Dđmn1â;‰°ˇ×ú|” (śq*›5Ԕo’ô9yŁÖ đ˜Éť8#̄.ĆýÖió5áE’/7CśFş°gŇVbˇG é¸‘Éžcź|ýJëĆűôڀ°`ŒÉáZßóŕáň|Ýßé‘D7öcpĚä7‡‘ mŁe­ł3l,ÇiĐŐq˝#ÓI˛§Ő:ĚU‹tƑÚ’uí’ĺ§Ëęę]žVYţᜎ´ňŁë˝@ąŤÝˆhÓ§2!VT;7ஹćškŽšćškŽůSós`U ôD.yŻTQo zEOĐ*Čb> LHNDox–ż‘\L‡Úi¨TUJ&buécV€Q$–ƒCĺ nÉ k=÷1FIŰVěíę*­ÉUšóQ•+W>Ř•ňDś35WŘ1[ĚoyMA?šĎ)Ŕ?ˆ˙ ë­ŽÇÓŰË `Rk?­÷•O3xŽ×^ýĽŇĺŁOUVuGˇú|ś,öV˛*† IőzýfĚ,ć7Dé1p-p9łB’*8Ki1K–{UĄ´yœÎ]6 ŽŹs§˘Đ$‘OI´„ň쨼ËÄ2ˆÓęÂtľĹ°ÖѸÚ‰ňöŽ4<ŔŁŇ#ÁdpŒŹçŕ ňÎô`†™0ăĺ&%[ŚÖ[y}“ŽQŠŻěÂLĄ‰“r§ň27D’Ţw#¸ŃÄq-{F‚žƒtE%Sf$‰ľ^‘Z­7D‹7Ä&1ŚÉkƒÖ“żÚ _§pSçƒG36I<`—VLĄ% §ŽukBęFÎw|${$ż™Ą™VĄJYÝśÓ ˘dČo­˜Ő—/oźĺţěř}‘ŕ;°UîÁŘ'ď÷„)/"Ä÷//Żźž/>řţ}bŰ/ľÖŚv~sĺ„â2ř:•7mHSŽ|ő˙ţ&ü:‚#Ť×yDđŇkÓâUw0Ł÷÷cňž;;Żxo€M‘,Ďp˜+ŠŇ°ę ĺô™ćbü…řPMhY˜I˜=“Ó>Łi}˙‘ťzţú“Wő YşćškŽšćškŽůçĚĎ,Ľ?A“mQ -ϐ!)śóQ ĄĺW„žjDŠAÔX~ŐÖ!hë•fb†/&ŹIÉ@QĹç@ű­|‘ČŒ’Q}—ŇoUײügimq}Ť_rÉ]OŮîłrf%ôę3žH–˜uI˙¤˜ŸŁŞ^˛nLĎŕ$YŠČP‰ŤgčR%Ďç*6SZ+°ďó f󔸮p#ľö$‚´ľ'ĂYAOAPŠ¤éŽŻfHŻŮ‰’ęJÎ#ŤŸ…QŐ%Žr[ńź\7ęšň‰z+T°­ę@dőf1˝°˜Ďvr˝Bm@ŘV@9œLÇľcšdĐ9ń„ŚIŞAzędŇVßęéçőľnŞ3ődÎ?62;"Uí3˘€9Yő@˜Tȓ@Ó^2m¨ ւ9ÉŁäĺä+҄Î@˛#šÄ˝"Łź"ząa¨źAîĹĆ-/m¤`x6ÔÍ꽾$ź‚ÇD|ĽL9-“ŠBŁĂ6‰lLţ˘Î¸˝roÎĐž=ß\Đ&xÒďQÉĐ6oó¨×̆űŽJ’ž|őähJˇ7ŇLćTiźh˘ýF2G܋ĄTăE•-“ď‡WĐWĆS.ŰĆîÂűHžřdĐřB㡝żXĂç 7)ßëë„ŃŽY^ŢTćt´'‡n˜ÂË]řĹÁúćA„ŹëbňmÔwŽŠň?Ţ6š)żÎż;~”~ްľ“D•%ó=Ż)kJjyNsIîKĘnĎŔk2ˆ vö¤ŽĘ)=ÁŹüh-ř<ţĺÄ5×\sÍ5×\sÍ5n~ŽşĐV鞚ËCŠň)œ'iş•8;ÓV­ÉŹ ”Uݢ>‰ś•ä׍B†9V nV-HFÝtŞ•?Źm4f8ÍN`ś‚˜V*č&ĹĐN”X59ÁA%f~„Eđ“,VĹ>ÉRϛNIGc’Rlăf Ë3š¤J*†Ÿ•:+Že1,ş¤Ň…#ëwĺýTVłn~Ő᳀űňęŽč—'ŤKSęXK]L’­0"˛ŔœŠ-A¨°}:[Ýb1@şäÔËoR"ŇąKÉ@–ÄsA{ǎÇ:ĺ#Cšú;m1ş*˛$ŮAÎGÁ~m%]öžŤ´ĺ!-gTmľŇ2Ş^ÄŁdž˘•|Łľőŕäśş}Qä€J&ϚĎ [ů8uŐŠ MœĘF–Uľ:ď>‘ŔU+•:֒ˆ†DśźšöSÄPé•F+ÁÔJjnRLy§ŐúĚFß6žŇî•Ěœyž!lÚh[ë$I›h”ôôm˘5ö÷Â˙ěő~ßzgśÇL~pÎ>ƒɰ +zN:%çobç Łšjmě¤đeö4dą•_ĚŃŚŒ¨ŕÇ~°ç›w~“Á—ě ƒÇă`Şń‹žŔMx¨ńżţą3Ç`Jcx`"¤)oRrÜ­uř>žóţ>řח;žÝđlüĽß ßřL2ď{đŰ.ěc#RÉeb^űhäęçŐŢđéOđ™žhoäř`üĄÖŚäJN<&ŇkĽŸŹë˙ר!p‚š,ŤŔ5×\sÍ5×\sÍ5v~ ʊ–_QeÇE.¤ęäĚŤEcZ .łŽ­ĽĚ$ű­Ŕăœhż=CJ*Áˇ„Ľ]ƒ=˃§Ť÷Ô§ŻNIŠńłá 5tî¸mőřtŇčřJÍę팁kő=šY1p DZ8] ‹6ĽKf\LbQ“‹‰ÍJ Š”W˘$Ľ*UŰqŃ÷Ź@§SJ{˛2>OF÷ôżjç v žl­Š˘9HéQŔBőÉ IŁŘoĄ@’¤c2™ŮŠ!^}*NäŞó(ˇ'˘ŰÚ0ƚϺQąHŕbŃĽtÜuƒn%+Žň˘ŘŽt™ĺ‘Ľ‘1éZŹüt0ŸLB]ĚÝT]€°|ŞYşÍ'ђ[ĂCÎí"yöřvSēΠÁr€đRÁLMsIÚkł%`ĐÄŮŘ$ˆĹÂ7qƨšYĚu“AČ •č45ZiFŮĘĺJCélÖQşŒĽBŤ‰ćżđş)>Tť4šÖ{łXA2šŻMœ<˙ú˛ŃĚęźëŔ˜Ő;ź(żöÇ ž˝ žŇˆ1Čvƒů ł@옎H˛é Ą÷ĹLÂ_ZIe‘¤KĂLhŻ_‡0źáGrD2dçrDăm "ţMëZ6rÚoôŢPürk´—;ɖ› ű˜źźtž9jĚ9ßżńwUäv㠏oźOá[nü:ßôg8ÚÚĐHjă&X^ó˛TŘYţT2‰Č§$^LđšÖu_›FOPűÇZ[UZ§¤ügžMŻšćškŽšćškŽůŮů9ĎjÄ@´•Wp1Ą˛*iDŒAWđl%VÇ!0)ÉŽę [‚ňŔĆbPŸwîĺEž(łş\ÍJš¨FZŁ…W nLĽ˘„J†ŰHf‚HŠ.Á¤|˘b†… h9Imt­ÔÜNąŠéŽ´N[ Oź˜%×UA¤A MKÎŘDČbłŔӖÎcד­Et1 +…÷Lř=eŢ%ű}B)‘Y5%™¸Ţ(>[‘œlZ€ž+Wj ˛şVŁęnş> äúb‰c'´Ó˜¤îűâq ÄŘlT¨RVwkˇĺ÷[Lš“yZŽ×G¨€mŢ:Ää8B˛$Üj(ŽÜłzffRľEëœÂáYU9Ź ŞżľÖՒqFĐL+j*e}ć@ż’ޤłjňžĄL"…– %-q   B<š!Qě˝a˜•Ä%´b :4űzŽĆRrŮDPIí´Ź:Ł<ƒś${HՍ˜ôđɞɔ!ÇĚJNCƒěIčzoËŻfF“d˜Ú=x2Č%ÎJU2ąk>Wď ƒ:ľ”'˛ăÜ8ýŤ“ŽĺS?íŤŰәÓŘZUM6Hh˝gú ŘčR ¸‡˛iâ9Ád%&7ĂRPŤă}ĐŘz[ŻQ đUœđb”Ď"Ŕ| o öŔÇ\5<Ö |e"Ôţ‚Đ,éz~Â%´>Ď)J—ľŽ¤V€Ź]‘Ú|ÇĽÎ?@H[!—NF˛{!lu3F&fwŚő™`ˆQ&Zrç̒NJjhɰšTŇ2f4)™x4ČĄËó¸[ť=ýĚă8˜TOʍńBăž5Ÿ OśŚD‡Ţ„‚/j4Ę˙bÂvƒuĐFť×uäSůo)Ä0tŢcpdŁçä;Â>ľ‚ěF#@oĺë<…ăţ~Cu0Ă9F )lá&l÷F>šÉ—÷ń;ăۃíţĆ}3|ÂÝ=”Î?çďű1§ńNSnľYroAíN8ť(ƒ´";iź“Žě^ľ4mmPđI÷-¤Ę W*e‚Šŕ áUeeÔŚ ޤQ>nűOŘÓ?Č~U–˙5 ä~Nű>Ź¨ĎëőškŽšćškŽšćš?7?V›ž<ŞŞJ†˘%‘ŐV"Ę(v¤D•žFĐ*Ń׍ŁŞ%Ĺ. šcÇ31+špO_+ńdqSôşTŠÂąŕ* ílń`Ȇ…Wí‰(ś‚Sž<ďIľ=ßGdůg§iĆ1–ĺwmqpȆ‘L1śédÎ "!'„,ĐJ1äj>…śäÇ>+ŐřCö\7Ŕ%SŹĐe1‰îKś*ËçZ>ÍçőĆdF§É@L+$HĺFo‰hbTՌÇ$ŁŔ”X…F™T ÉÝ')ŠĘś<˝YLÇ‚ ­äˇfş:v…ŠâÓUaz2˝<ÁžŐm{xŚŘŕá%Þ+ý•’ŒŠ"9ČŘ%fpł>ś-}IšKZ˘OÉszŕŤb'EjCdî8Ę~$ÂąšJ…ĐÎ-Ç \ę+̧C Đ ‹hCÂrÉĆĽ˜gí•P,•`=,q‚Äčj‹XUÄŕŤ™Q›3ńpŽ‘NJr‹ AÚ^ŐO´źnƛÜČ>qI4 šŃ590F šą€rÝŇyC;`ĘŰśńx Z %Wn|JÜrmHŒňskI`7ý ňŘ t“bPŽ÷ä˙mN´+ŞđB ťÓpޏ$#ů=ďë\% çŘwôö…GnÉçN†ĄÇ’‡lvĂ,cŠ4Dyˇ­Žš0yîá¨Ö†TF€•Z-Éű™RŢ7#†“ݰÓďÁôÄśFŒYחţ°ž_*d$š0íóŤD•ÖsĚępMVÎĺY˝ćškŽšćškŽůgĚĎ,Í}ÉĺŠĹé+ĆsyÄTGV퉡éXďŸÂF˛X%*¤g,0'TÇŚ´­îńßňа^’b*œ¨ľĹ@ţá= ŕz[I¸ŠVů -˝Ě”jĚ „\éŚ'v­ăKýˇeąŁJâvž~%ň–u&H&žJGĂš|Šëý“ĐĽ¤,fř ¤:}P@ů™"ŤŁTJâ+VŹm[ŒçŠdfr[ ş Lz… ሠ!¤d’Lë„;]+ęSuÂ%ĹĽ5Z9L!urł>7ƒŽi"žhŔ#¤nôŤy§Ź#•mL&J[ VŽĺ ŒYáXžäĐNŐČÔgW,şf,âňŻ0Ľäł<Íą$ÝŁJl S6$&ŮîŒýë[U0ĺdǞ›.ÖzÉÚ[Bz…ÍŞó1zů9Ľ:ccÍHŔĺ…8bV`9lŕ4ö(půröńАęĎľp¨ –€UŐSFňˇxç ą‹˛™TĎ)÷9‰w§YcÎD™šź‡3ĆÁaC•°öz§KV¸Ů8híĽ6–”žˇępĂŤ>Džl_h7ĺő^kpć ýŕämmRź4 vƒožĚÖčRŠĐ÷ź?*ŻŤówzŚ˙~ľĹ’žßzv Żď<Š˙žÇŹŽŐó[nyXŻšćškŽšćškŽůóóÓK–“I!2ŇhJÝŕ/ ě󞒕ěÁ)Ď>RwŻ0˜ŹI_a=‚ŔňUxOC|Ôߊ!9řÍg°Đůz-'SZ%ŒśDŠNąžş$€*JdĐDđ,OŤ,Ągő.%F´đk†ŠąĹ\ĎZ€|fC2™)Ťś$Ÿő8ˆŇbVq;œ•6$=˜ä¸ąÍłövŚnŒFĎY @'ń9ŮL™ů‚Ä:ŽL)_ďęS5–§XJˆzî IDATŚ;ĸk1ĄžąŤ†ÍQ€@e{ŚŁ†M†Łí({*ę'{Z2Ůc&*ËăéUŽ“RŒŞŠŕK˘}›ľ>ęóZ!I¨ŃHşž[k[¤o0Žbbs"÷;žłęU†[ě7PąžłmĆôiě•ăôMk#Ąu'ŘP­5Ö7!Ľc)4`ŕĹVK’ą•Ÿv]JF˛§aŃK <×ç=wFż—[žŠÚ}ą×“= 4fG…M ëÂďşqÁ-nÉÖ:á%!~‚k1şéÉáÎű<ˆ„ď™ MwĚ´ü˛ń V>7&B…z™-aŽfrťÁ_nÉ/ÎąN),lmœüҒ{?3ŒH!,ËoÜ2ů뽂×ţű‹qďÇzżąYrx…O`ćD7̝#ƒ‡:Í^xŁáLv„c­ÉĽ!ÇŐËťť;Ą†Ř”ƒÍ`ňĎ_0˙^ŹŁz˝f:ž7dl”I‹¤łŃFĐĽčOĽ7寡VŔYŕ[kD |­gS厳ĽóööB“ŕ_^mIîđMƒcťń=:˙×fü͓߾í|KaěW™<˘ąSRŢTĹ#+ m…|`”łšF=YĎĚŐçľľ$Âu--Ă'_é7ŒtŠ7ôź–ĎÇ.ŔJVĺNfb­­”ď\@őBŞ×\sÍ5×\sÍ5˙Źů9°(*Ʉ qĄ<Łi7@VBnucę'ß×É8ˆČň­‚YŐŁŹ<˙?łĆpG´:FUWŽ”O­ZA:„^5/’A.đ¤@™)´Ĺ2–,¸Â{”,oŞvlL´@îŠ~ŚôŠ.śx…Á„Ô zĄł‰HҐWyŚöú\Źě™OůóÉŸŻCJĽےŇ>ëlę1g•Ł~>ĂaŠK#ˆh™˜TYŻŚ"ěůńyÔ}z—21 ^ő'RŹÔ¤6#ćJŁő(ŰáɚŸ5çłöœ„4BiĘM"iłŇ„ߤzuq_ÇeĹČGÂŞąQ™”q´@|ňĘZaI]*=x“ Hn‰ťóEiąă4*îyŁÉA6g ‡ű­/ŔáhvŚe†šéˆ/pü ZEyöL%.ŸŽ$ź(äÖx¤2˝Ö§âHŽ’Č‹ FĽf;l ü4)†]"!!Â`Tˇé <ﴀđJŻv‘ňžfĐĽŽ—ˇŰ ńëFŢkă٤Đ(ؤ[ă1“ć4c›ťv6Ţą[#dĂýÁhwRƒf\15ZŔ$qëĚt~ƒoçWi UT`SĺMŒűŤđŻ÷RWNσăvgÉ#ŒŽťđ֌l9v°GTí Ĺň×\{InmąBmâlí闗,oń“9ý HŸÝÍUiŁŹônX‹ů l‚ô ]Ęő§7ö”‡ŸžîĘŞNĎ6â>ř×kŽšćškŽšćškţĚü\uÍb>7źXĹŲY΁Yŕ`Ó{ !<űBUŠ)Œˆ’˙.v>ş.Ťgľâ‰TϞҺçL„ô‰X#ćäłËL˘jh„dJƒtRŒjĄX ŠȆ’pć r’uC›QLđ9gMĹLĄ[Ť×‹žMĽ‚p¤Â_ÚĺáË`h;‘ÝwëďFœÉż^RÂÖÖë}zí¨tţŹ­˙ýŠę”ĚJVF”™•”›áô%…ŢSl1‘Viśx jƒJnşóž 4ĔMGyË˝˜ä­Bi\l™ƒ1e†Źđ+hšt-šś6ˆ¨Ô\Ľ*XŹ˜Ž¨ÚlýŮ{—-G’Mó ˘JšťGu×éMż˙ĂÍ,jŞ23ÂĚHĐ ˆŇ<˛kzź&sŠ8'Ň-íJ*Uxä—˙㎠`ĽAĎŞł97˙ą„ÚRAŽôԚ˛G2ŠžÖ,+Bh Ŕ›tŁ<ž­äŔލ”bî%‰‰ŕtÝą|2[l¤t4'.ÓI ŃBéžĎbœĹČľ&Hč6Q1f@g"÷Žä“İ&+H d–¤[F¨`lşŞy‚]#˛ĄÖř<aCŃŚü؅7‚}ťńŁ!ŚŃTđ­•r!„Ă„÷)ĚÇDç_![ˇuČÓŮeňžĽ1Łárç#áöHžÚůśҔw8>ůýŻ#Ő˝1Z/övx86Ĺ0ţö ~ť-ĺEßyÁ<&ŒÉ_ƒŢoź˝}c<Ěc˛ˇ!°k^ŇőA/ŐBÄŞfZ’pŒüS*ožLYŕQLëDdIzk­+š‚™N?nyT3ë­ŢťXVË[ďKš Ö×Î37•×ú<莚ćškŽšćškŽůÇç×ŔęˆËÜjCaÖJnčŁŔ— r|V˛+JhůÄBÖćđŕ–ĎLł†ťż* NŢNÓh9ˆT,÷’ĐŸ4k‹Ż,Ś$–ĚŻ/P`#ŤÇsPľ2Ąś@ Ÿő'‹ˆůfő4ĘŞ(ŠŘb|‹Ą[A.RáRfĆű bIŔg pß4‰3(fmśeĽ—Vďj€ÔÇ&ňň]žźŘbĽşKÉ DzxŐuäŞăaäOŮŘÖ÷<Ŋš˛ˁcÜ4*t)+øăŘ։Usn˝KĽĺۢ}ĽńňzÍLËzÚKŚ”$ł‰âŘv/FÜ'šmČ|Đäţc>ŮVoeę‚ÁHk0ł*ILkBO#´ą pĽ/&´<ЛuÓ>yx‚ĎŐ­šh:oş#v#âXE˛<ĎĘ!Hˆ,G4@ȁd‡,/łš`큆 ÚëŠl[ CĘAˇĆĄŻű|&ëި`/‘DˇŽ˘ČQ&ŠBkJ“đzżÝ:ťÂ˝/ßf tLÄvĽr"ô˝j ŢşqŒ'#Œ]@Źqk:đ)ÜóË7žľÁÇÜyřÁ_Q6/Éuzp¸—y,™v&!`[2}˛!Ě}ç#2…ßvᏠ:'Ď#ŮZăĂyŒ‰zb÷ΜÎíí 6çÝ'ů„c%khľ…CďhŽ5ˇŃ\^Ň<ďëăZĆFŕVIâRzö:ôĘ:i‹]UrĽ^/_}kÄ)˝ç$h+ĺZľŃOÄú÷âŽ˙{`Ó5×\sÍ5×\sÍ5˙őů5°ęĎŞ€ŃĆŢ`Ň DQV?u éˆÚb@Ť§SȒóQ•™,Śľ¤Â/6•Uw“Uý"RU6.&Ž§ĐŹsVה€rI_×fVt%ŤŚ/š_Őü“ÜĎÖˇŽ`¤ľA]CDńŐŮÖN•m1bQ ->WŽ š?1+Ĺŕˆ*ść,•,ŚKRmý‹I=ĺĄé$ĐÎ^GÎÔĺDe‘›ŤŰsfŽç›ÉJŇ­´Ö‰bˇľwžRžá‰Ňý¨”áHD‚L­žĐĹ^‰ňú˝ő:ƒ{,߯RŇJG_—őj8PĐJČÝëq1r X1ÓŮ­‘L˜żÓgf4-1Ű^ţ[ŮJúíaô'ÉtĄo>†9uôÓX@ŸtŕđłŸwuąŠĐi¨ ݜ9ľ¸`iD89†H/.;ÁŹŮpR>í˜z]K ÝASé˘L’] é˜UEOqCƃîŕRÁJM•­-ŕ§cy¨1C6ÁÎ]Ľş‰Ň6Ćńą{6Ôŕý(`)ÖÇAşÓˇFk7śÔZ[^@"°Ýn|ÁżĘdś;?!xv†$ĎŔFĘVď=Q>#Ř5qpˇşž1ƒOťLZďŸnű1'1aĘJ{Űé˝ńţxp„ň!?˛1ŹáĄf/š<Ѳ, pž,8…•ü›¤|Ir_rě”t2ŘusWő•eĽu{~­ýúu_aÁýŤőě@Öż;H:˙fzüoŸżćškŽšćškŽšćż>żÖłŞRLTœâ‹ĺ(ĐÔU‹•“ú7˛’8§;ŚŹŘ)ßa€Š‘3Đ šő â/ڤ‹Ł~JÓ%Ĺ]2žŚ‚Ç@łúQ’‚Ę’é9ň”qŹMiCĂqmĺc]ŠbŻ‘—Ć(˙Š,)°ˆ0ŁzKO–Ĺ“ ĘÄ­Aœ 5_}Şg§lD”oQVŞ1TR/Ző!H{Yá0ÔP[čş<°Ť’&+Hg_Ď˙•śŔş­Ă–ěşž6™4śœ/Œţ%XL†/śœäó'ĄľŻoę˘4’!CÉh?CšYň aóęœ˘¸TĐÓ cZ‰Ë˜1Ć$›"1QŚ'éÂÍT:*‰Y ˆ7*‰xď ţ,ůł@´;* ‹{ĎF\;X…E7Ś&t`Ǹí‚ä’§`}]ľ,–Šę)í;An4|oĹbnům wĽľ’"ßŕҙ9y­ĽĽ0săť}Â޼ѤT›ż{"şń7Wc÷ŰjIß&0ŢyăoƒO†už´WÓ‹"ýIú °RŠňĽž܈bIľž×Ľ-S +Ü*8ťPO/ęęK^3y†Ś!?}_ރŹ/&őL(>ç<čz)/ŽšćškŽšćškŽů‡çטŐbdhĂ$Ş_tĚKb§/YjP‰œ"ЗwľœŚËo–"°ˆËjÇď`[IGľc8Ídcú,oęœĺM[É+3¨ít1ŸŞśX”ŞK)đVlÇ+Ôve% Ť˙ő”%ëňŻžäšËCú ˛*{ňhtŇľ1]ŇŘ\Ţ9Vjq’´Œ×cŤÍ÷ڌg%݊őb&}–dYéÎÖʗzФ“ÔĽŮN0Ű^rlˇŽů mmŘł‚…vi˝€"ĹҰ <“@!'‰)Œ¨ď1…VÁ3’Ř8p! ¤|Q üVŠ]Żç÷ôŞáč O¤ÝP?I¤íˆtRë A\ččvÇ4ŮÜŃ­ńx„G҄9Ÿ„5Ź÷ĺŮMZÄ퍌Ol]1ą’ěęIW§IĽCđˆş–tƒ#ʓÚ,ŮŹ<ł™J2iމ"6ľ*•Äi­j™Z'Ć„ŔĐZ1ťĚJŠF”ŚK‘ Uá#‚{ą‰ÇbˇŰƒűd:̓ÝŘcučŽAl7ŚŁŽnL„1}ť•œYŸĹěˇkQýĆ2h}ŁKňđFHň-‡"yçŰ.H0ÇŔZ ŮxrŰr˝'ß[§á“ńx°˝}ăvťsŒÉűăŕŕßĆx ü]I >gă=o Q ɋ-}]“UUł–m…­ď9Ů˙zËě)eS–Jœ– ˛mK‰‘ä+ě­<­žŞ­T Ě*a¸éşW ]{Ŋýyd%¤gŇ:1_z[˝ćškŽšćškŽšć˙<żV]#ËÁ'ĹL䒗Ű+¸$#H­ęŽEŠ„NľłSӑ(–Łç$Ąş=YX0ŽJ“] Œôăź"ŒĆDU˜bˆśň“VöMů8Đ̍Ł6Ŕj8R̈Ş‘Sfřƒˆ*1çŸBTÎ/žrÝĽJ|ýOą9‚ő­ŽE.@ŞśB`V_ä’őj˛ŘѪހ)[=OmUůń*'k+_×éô¸JŃuś•Źé%§ÍŞŚŮ$ÉU¸cޤlhU;s Ź›š<ݚNSĂ$ń"œ÷gůV“†„ÓMֈŹë•VF#OşO_ŢËĹÎŤTĎŤŒ‰ŘÎÄÂůPىBx1ĺ!ôńD›aV˙ݤ{‹ŕ¤Up$aŕf¨śâńl[žçÉݲ¤Żsu§F­[†OÂW_nďYIť¤B‹Îđ ¨RHŠÇißHŠ{M‘ŞŤ‰ŽäŕŁ^PŚo•śş|“œç“˜Dy˜U0@MŘ"šď™Â&ޤVĹСĆoÚČ­3ľîgÂs:SŒÇ˜u`$ÁPǧ`yĐvC"hÍřĚ g‡¤˝)ü>ƒMźŞ0îş!­şU3 ÇvÁ´11ŰÉ{Ç nÚ*XœiÜÚ7ôŰŕFňťŇxť-ťŕŁĄЎF˜iës|%úžĘţ `E|Uóź:PkĄĆɈş-˝ÖĚŮłZ8D.9}ÚČYgŞU%&„f?%†˙ÝXk?tUŮšvÍ5×\sÍ5×\sÍ?6ż´Ťc˘j †ImÉĹX,P–j+=ľäŁŻŽÎ Â‡´N7%C0Š^ՍQɨîĹ*šâYěH˜ó Uˇ*6§ž Ž 7ĘdHŁI@ĘęRMŚ6"ôöZŽעK)š‹ĺ,ĐQ#ľáËĂČ)™5t1”gĽĚz‚/Đy˛Ťšüg+ühZř™9‘ RŸ(B3%} >™Z,MÓÓó*•@ş^čŤŕ¤ęąm’pú;űV2ËXňă™YŒ—uÔÇŞDą•—4r2I1vźüŻąŘčŞĺđX6ÁXIÄQž˝ęXu&% ź.’śť“h;gIV[20:+Zń'}ť“cÚÉł$Čä°~al,?ŘLqUÚń`ôĆ-ƒ­5žĽŁ˝äß]”›Ŕôä÷9şV˙čŚF΁™ro•Vý@U p,)ˇšřˇI÷í“çĚľžŠg2ˆ&Ń4™ŁäĹ"ĺŃś&ě ťŠÁnBŰo|ꓛ š—?řżż5̄žŽđd8p8o˙íżă›óţq`&•čÁmbć<04ƒ;Iú@ˇ?ş’ ŚYuœ6Ăś;›Lžąą+üĺ=`)Á&ĹßÚäŃ:MóĺŞĎAf˛ď;Ý÷LůĄ‰nĆ3ƒ÷cđxţ z[Ţ[Gű^?+4™“‡ „rÉЍOŰŤHm­Ábş^ĚŞJ–T˙Oü×r…”zÝČyŢżĹXKÖë-K9 }Cć“ě;q ´ˇřü{p*"XﯪW’šކƒÔ:ԙǓַ:ŘťćškŽšćškŽšćž_Ť"Ż.ÉsÓ‹I#çÚŹ1Ŕv^’Y LŰ!ŞĺtŚ!VIŞ"ˆÄ:,ö22_rş\ţľeP@OÚFD”G}šČrýlĄ°IjA’ćÓś’ö%4‘ň#.pzzn3łů;'PĺOAţԁZ•§ď5I‚ô¨Ę—4Ęó6ËHK"LŠ-ý9ájsţz,R’Đ\ tÄI{ĘËŤšY@ŇTës1×>˝ÂŞDĽ6úz^ŁĺŸ•Äü•Č’Űů,ŚvŠ”bŇI*‰YBqľbeš÷Źc2ëĚ)Ši*ěéĺ%śVLŞíՙ*ɑR,Żmř,&Ř3ŮúĆđd„2˛1cŇšn|ÎŔüŕ_ď1ŘÝi8ŞÉÂ4AÓp fL$˝čj$]˛ŽĎœĐŹdĘRwݘŽ*đ ђ†îć|´¤ËƒdâŇ8źŇ`oý!x¤Í’ ›a3PSş*Hr×ňhËń7ŢĚř~ťłËäĆAoƒ{oHÖăý|$՝˙Ű ŹĂ ­ÓŹCSă›?¨ĘsŢb˘ÜwC™źË*uä3 tg&ť :ƒl›&Ű֑9šYąö˝ďx|DžQL[çťśÝůNxśę•5ÜöJÁǜÜú'ˇžńm{ăí^ëâ˙ţăI’xÔáρŐ5ÓŐrŹZÝÇYĄdŔŤVć%ť˙™I•ě&F,UAŠ+ w/őÇbfYë&IhxőăŽlňKę[ƊsÍżŒůëń|ZëŰęMžŘ:Ē Ź^sÍ5×\sÍ5×üSćÍU‰Ć$KéËŻ)P’ZwĚtŃbó˘Ŕ¤ŁXD!Ź4ßÄi„**^ÁK™˜(´VQI˛<Ť%ń%ń˛şSˆ%‹UIf*˛Ř@ ŻZŠŇď2˛äąŽ;ćGh)٨ˆ1—|/žúumhüŞĎP+Š IVo(Yň[+Š „şRŽ‹ŤdŕČę‰\^çÁGNţKĹE0sš5złčâ¤íDżaRu6żÁÝJ~üˇOÁ|&żF–sÚŚHß0Űý˝7îů ˛˜çnđ‘;c%˝Ž7ĺˇ[ýý›?LřŮ@'ĎnŖÁ÷śýÎ÷}ÇL™ x÷ŕłmźűV‡\f¤“:"GA"‘ˆýÉ|z(IÚĚ$´#–d€j^ŕVDW´T‚łČ˘bƒD+źÉŞŁĘĺeWTľüŞKďžkW ÚOˆ™|`˙ţg•6×\sÍ5×\sÍ5×ü×痓@^ľ4؟kO˘źeӗÜ.fůˇ˜(zŤ$ڜ¤uœň¤JVu QĚљܫ9ˆ€i+ĄVtą¨ň2bSÚ Lé$S„`jŻŻIVbŻJyES”šź …/r1ĹJŽ% Č\!F_ějœ~śL,ƒ™:+PȐôŞů—ÔwśF\tĽÓ&çv6))t[ĺFĽ˘ĘŸ™š<• Ô U*#A˙Š[RlG󁈕7c1ş†Ő)!ĆNlĚŇÂJĆÝwvV'ŹHĽÚúdkľIďâ¨>Ş’‡Ćy3ˆ;ĘęßÝb€Z1ĺ"l9ń֑9HM Ÿ ŮĄĹ'ĎPT’=-´˝°‰ub%Îć˜xßpuŇ'"ÍŤ‡ŐE kŐĺjŠÎQŇoĘÇč/pe2—ÚZĽHKűęє,)zSĽo ŮI†6Ś4žĂńŠ„›nŚ„  Own9ŘÚFˀ€ˇf|äF¸ňń|ß â¨$˝•LŰ`nŕoí;4ĺsL,“4al7Ć ţýýQJ…žń|N̔Âs"<žf|W!Ěř̤“„ÖódN·;ݟl ű ńI´­Ř|ÝP>¤łÁLg˘ Uú~ÇRxúY礈˝ń˝+›Á´ä#‚÷üۇóŽ;iĺ]@XD^÷ŻRÉۑgőjľT…@iZAnAŤ*ć’wިîi‘ŹŢÜČ×=] RĐvŞ9äőžÖ4+űľÖKąQ>Ö|˝Oœ݈ ­RŽu1]Ő5×\sÍ5×\sÍ5˙œůE°*+šś˜ś“Œ3€HËÓjńçŐ˝H Ši”×5:ĐHk´LíŘ<*ĄS*-Ř,žˆöbi´tfŹžC”Ś•üŠK¸Ÿ'!ĄĆ”FÁVŹŞUďčD•WJofIxĎ YÉŤçÇhó%VIFěÔ\)˛xů;cął"<)9sŹě[˛Ó3žé'‹,ž$žŘśŠ#źŔ0ľÓ˘‚qŞGľĘ.›,/­BDr٧—”šS:¨D•[I&Í(9°-˝ÓĹGą§oąó|<9$IŢđçîÎśmLkLUţ1žˆ%Ď.ěVAf‡Ú˂ý8>ySĽ7ĺ]7ćcpź}'sT’łô"Ÿ¨’`y´­128¨äîîݔ÷Ď'ŸGńß×u÷VŻ›@Z1œ™˜ž§O §ľ"K._Sˆ6TŠMĘŤîbHdިXżŃő×{×éąţĎB“2ŠÚ™đWWę @׊g=͋Y]ď 1ýË×zŐkŽšćškŽšćšÚübuM’ЧmÁ!;íF´ŔH!eC2V5L€GT÷¨6 ŽňŤŠ`ź;Ⳙ̕*šŕĎUY˛zĽz š y‚ź3Ą÷§¨Ĺdh/4’ŚÉ‘ĘŽÁ‘'3˘?WYěj[Œńޤ?UWx.)`fIzW(‘s&—ĎM tNä—ě÷umWŕ’‘äÉNŽÉ ń‘%÷ 6ŠíűĚ@ś™OL’H0qp§Kă™JËęń+ĎęasŐp,ď˘ÉŔ1Ż~S݀dˆÁtć’8Ďz d‚'̜YŒ0‹áÎů,Ÿ°ušĎT$ŢŞˇtąÉž’Z•鎜Žőbh{řŞŻíůDŹäߌFd €Ël¸‡tZNÜ'áƒ#6>GĽoV@uSx´Ź'QŘĄMZOŸX9ë@!çŔÓi­ř‰§ň̒šŚˆrö.lgŞńx&ă uĽe‡V€ě­oYV‘Oڰ5nĂIݐ\Ź´ o-yŇČřÁŽÂ3#i î۝˝'ßÍřŸ›bM™Š|Ě›ƒiAź3ř€­žG“dťÝřŰó€éŘŰŰśUŠw Â_üdň<Úz­+ ‹éô^’ÚʏÜ2KÁ°š vôÖőˇŕ+ôçp•ü Ôţż^ôľšb´˜Kj\L‘Ś29Y$°tć ɘĐv$'ňŕ%Ól6šŃřň˙a ¨ĘČĹ.&.F6TŔSIQŽ˜Ż §)Z,Žé‰žXEJ~Š<>ŰđQÝŚŤ×Ö#Ůx–WVę:'é™“iBWĄ!dŰP™hNžI–ü˜DľZU”ĚYŔC[ysâitŃv<2h ]™ä |CdÖ5m‚I'#‰ĺcà ʆ´b˙3‰Ţɘ<r&m<‰śąEđc–ł˜Ćd†Ń§Rá=˘YŇâ%%n(Ú6“çxptĺ[Ű5ú}Ł­´bËb g(űJuśŚXTÚď@yë0ćă“xSźÁî“;Aßo˜7)YŽŠ ĎÁóýI´Ćó¨uqťí|7ĽĄDëo6aI܍Ř6Ł#[ýpă8ˇz~NńR3ÔaVÚZ§V÷§´Sv\~ě3tˇÖppF1Kć 7[žńľMbůRůŞÖ(˙ľŽűŻĂ1­ÔçóÉgSŽžć“I=ç×:ŽC (/ęŹ÷Š\ěy2Ő{Ţů;^Álç“Ę˙óúżćškŽšćškŽšć×ć—ŔjW)_Ś]+ŹF’jŹîJ‚Žř@$ Оch1łÖˆlkƒW›űf‚SŇAÁAŰvŚT?kęĆX8P¤Ŕ°‹˝R;ăŹqYžT`éí%׍Š ]IĂUWó’ ¸ţi–X}łúÚŕfxýŒ”\RU_*”lđě/­˜ä3 ĽXŞÔ’8˘ŠĽăZŒT‹šaýŒ.żk1F7ŇçJh6:ó+ŐŁü›ČňőĹŞÍQBę@Vŕ’¨0uŐmdҐ¤UbŻĆŔ=žj]–[)ůłÄ@űNŒUăcZ%ĺM5 TęľÄç’uVPŽA¨"űíxđTxŤ°iT7`š˜*ň3=™áX>đŐĂ+Ú¸iV˘lVRí‹=E֒ä4$l05Q óYaEłŃ´Ŕî Ĺâ@Lo ‰şŁă@÷’›~ŽOÔ~ ńDš ÖżŃôfŇo߈ńI¤ÓçŕXŹ-ŰśęōŔ39ĆÄzcÇę^hőz}.)÷ńt’ŕl[˛é"|řçÁÝ7öíÎ÷ †đÁwŚÁť ąď¤ĆtúmG#ŮēĐÉq$ÇG’Ňčm7ŢvááBjĐăÁÁRÁ[ÇNů˙şçĎ>ľ€bSpj-VpoŠTVEM‘ë㺟ŠR…ÄhVĚkŞŐ}ńŞťbUŃČFWGkEbëŚW5 ÖęđĘZĽý.Éž™•Gýä„#ńU—ăQżçTUäz(˙ęZóČz(%@kWđ5×\sÍ5×\sÍ?c~9 XT1‰ąŠZI˛"Z=1‹'ŢöbME zƒ‘ “J]5‰hSb% ŻÝ*žJň\ °˘• Œ(śŔœŽäŢôJ|5…)ő}›–Żîěm$}Ős“YŰ R‘•BÂŤoő'śdI~;kCÙRŒ“œŽ/„*Ź(ŮőłÔ†z%žJ,đ†0Î`5Ň˝@Ź){é_ n&Ç ’˜dR`W˜ăKęĘö¸4”`bD64YŇë“)>}¸ĹJIʀЀFzú>/Qc7ŤVtë´HďH f&Ú̘͟%Ĺ6ŠÄVSŠű 'HVżŞŒ&tŰpŠĄ×˜Đ˘˜U/–wĎ@2é‡îUQ$JoËӜV’aŮ ƒG,Ŕhv˘•¤8ĹĐ´%I.vë“]ŞV\™I‹ƒ°7Rł*Šl#G1šż3íĘě^éĆy”7´ƒć݌ćÉĚdĺůźĄ|7aú`椡ŰŞ9Bŕ˜ĹNkŘt†×ë$ßľ;<’ĚJî˝}>ř—­XęÖ Ň6Ţ:řôç“ív#Âiéh3CۇżóôşÇŽLžOăÝ6%í7ü9Šémú'I|ŽűýeĎaNGMVú4+ŕëgŁ ş‚”ä×V`’dŹĂ,Y@wUÎP˝2 ¤ľ%ż_ ˇţY6ÖŔDÉVŒj, Zއ\‡]KEá^L쏁¨Ąj•}2ş/ű×Á՟ŢE0[ ‰+`éškŽšćškŽšćŸ2żV3šm %Ű,nŽş ­wŚBÇ|"í AąůQŚtf+€Xyż”ę=A֙°I&Nmpˆ“a,!1d1RˆK‚7e˘,€†É‹őœÚëw“ĺS]’Ý3čĺď™Ô?UÖ÷ˆ2ą%=6zŒ+ ­“sTZ˛)ęŁ|§'łťŇŠ2â+dikń’I§ZɟW¤Šžm)ć: OŸUdšGý, ƒ´ ĆůňFPÜ\Łg2Őčř ‚)ţą‚šVOlfů[ÇŁRrĽŘДbՌž%ƒ4-žÖŰƖË{¨;ŰëćŠŢ[ !ÝšwÁíV×*łę œĂ6lD0gĐ)ĐăD9ŐčŚXŻ4ă™ĹVV'jc—$0öČĺy„Iˆa sÝgÉÎHÇęTl[)ĎfD´ęç#ć o;űńŕ]“ďüÁ4Epšn¨B—ęÁ}Ű[ďĚéČwĹÝů­OÚx˛cüáBg’ÖŘdBÝÉ'ďĂi~§ˇŕޕÖZąă‘ŒfüţpF$ŰŢG $™Ę6­{1茁n7ţ‡ľW“d§ucëĘßÜx˙ýÁßřHĂÓř=ŹŘx3XőL֔ěń/Y,PŠťÉ*ŞŰÜŐđň,˃žŞKţ~‚Ęrľ”ál[6€ęíU(ŕ×ëđKӋmŐęňĽő×ú‹Ó{rÝłžňJľ/@*ľţ­WŠpŰśőďNřüIöżÖZnO­.@^ŠÄ”:x¸ćškŽšćškŽšćž_ŤĄÄ@mă(ňŻ— ž6ůĄ/ÖSHfŤÎUmŒ3…UËç)dILeu˘Rősuáčb ]kOűgöRŞ?1^aH_lÇWýĚĆ'+R›LţNĺ˙CąˇII‰-ć Ÿżă Iš)¤ňé*Ě9Ů$ xDS‘‰™2ó„ÜR›çzT!/ň v1X^ňZ§XD9ŸsŰ ˆŸX'u/ŐńňwÖe34'śÂŠz R;ÄĤ|ĹK’ŮľęTl…h˜­ˆ• ‚‚¨„Ü {oŒzF1hÖQ¨”/&"0›–´—IŰžXtr˘ZaW!F*č’ÄŽ,_$m§ž "™Š•í ŠÂžAh]ŤďęH–Oľ‹1r˘)45\…†2$˜ě1Q÷Ş A<`XŐÇČŕš58„É °Žü&ëp¸ËDäAËő:w‡4$(ÁŰŰ7šAÓ;f‰é†q­B´HB{Oö&Hěü%–۝ݙ^J…XKö˝5ŢGđ#éfě&l݄{SLŒĎX]ĂĂŚ<Ăx˙xňLĄßďOçýéüÇgňűü΃†[#[ůŽůůĐŚz‘Ö˘ŠNĺ„ĺ%= ’d†9šľÎS&AŹď‘ĽŹ(é¤!ë€ćLwOÔUĂg% çňŠjŽĽ›š­ĺ\oi+,ŹKŠRěĺ?ˇĹĘŠ.¨+•ŞŽ9ßCTí%~]űóAVD˘*¨ď?ľfŽšćškŽšćškŽůÇç—ŔŞQ ^IxkŁRőą’<‰ÉԒďyĚbfú­¤ ”$łky8!Ű"P­pŕŘ2…é’T ¨ź$†™§glßî~?’Ň~1¨É+5řç ¤Żt_hQŻ'0›‹ŃTŻtáĐćGŐáź6é5$Í0łĹ˘Öś˝XeëXÂ惥F'*0Ć´:NńJŢĽ¤żX_śŤžĆ‰dh9€Ű|Ž. b eÉ{/ŻžŞřYşTy`ZŒjj8ÎbWď=—§öşDI˝×˝ŮYGô$s§s°ľ ÓIA„Š(Ý•˘MoNć͆ŠŤŚĹtG0f<ÖulH§e˘Tzłúä%Ő*:&hđIŻ{fŒb€s°ˇF43z$.QQŚ%żAˆâÚ2ęÎÖ[ßđ苕ušź‘ωhđś˙†ű Ü1S~˜rťmÜ{ŐîŒYSQšŔoÜT°|0ŁŃ{›ĚŘ f Žâ9˜Ď$ŁMÁŘw#Ňń0ď:˜ĐĹ"é˙rëč<ؚňcŤűŻŸYIšGă/ów\ďüĺÓyĎ7b~đü,Ďćßp„ŮmBԂđĺŠEäR+@ŞÖňyx‹ů&3OV=R­ĘbčVŃnŐ! KŠNő0+RŔWź–ĽvÜk•ţĚZóšçËüş|ĐP]Ďdňú˙NĽ ë:•˛Öđ9_g_"TuR DŰ"RË˙Zňć?OłŞď! ¤&ĐŹÖLŽĎ3¸ćškŽšćškŽšćŸ_öŹÎ,VLNs…uU|P‹Á´´OŚçJ.`çR,Ź’,†FíŐÓú $‚?{ĂŘÔÖkü“gŹęcä•äKéőą6{ąŻŻäޟýfYŒQRaĄú‰`—ŕ™‚kF#a×zy>´—¤XIŚPlŤjEDŘń8ëY›ńĆi„€Ĺ ĹhvJ“!ǀ<pőňäzÉ›8ÉA§űQLŐHŇ(OŤmˆÜp˛54„¤…Wő °ŤóˆäM?‹EÍƙŔŞ+@ŚäЁČD<^L9Ň0sBo8ŁjT­ąoĆôS­NT śL"?Aœ=–ŹŰˆ PEoGyRi“-7RfIV,Ÿ(¨Ň˛Ň“ŸŠ„Á\LzDľšŠ+ďl:Ť÷Ř̸oëÓܙÓÍh>1Ń:”ŁźŤ î˛1Ňůє‡UÝĐÚ? 0‹rkʍÄcĂŇŽtœĂ9Ă:Ÿ˛ăA~>ąž„”Żň1bŕ*dŔçŹ@"í%ő>źŽ›ĘăůI0 Q†×ݧmr3Řcҧđý­ăm§!źŸšŘhüďÍůëą3úŚÔĄĆ[2 ­c.vżÖ +DI¨ŔŤ@Ŕ+)7EQb凭е%űUY‡BKŮ`ä+LIMKÔ-‹][aLAĘśčsŻ5vʸ—T2JΧ<=T*Ź)¨´mŹ×ăĐőž#KE‘s…€i”ů,VTm}­žˇfʘ6Š.bjíeŽĂ(žúT#ňő°ďf_ŻšćškŽšćškŽů˙7ż&ŚdˇĹTŁŞ˛*+˛>ƒ6élxĘdyWL ź@ŠËkšdČWWŞœá$ňÓF—pýľ_s#˝$Á˘ ţž˛$}_Ň`ŤMeĆňŚ–?VŠMîÉśŔ÷ž“!g˛.Lml N+ՍÚHZúb6cHu ŘÜšŽfҚ0=—żśœšŞ˛ŽP`dÂŚ^žLŒ0[Ŕń¨d¨ "‘bŚM'ŐfYŒ˛á`JËO4›)‘A“Iŕ„ÜPb •şĘ'){¨ŃÄéŕ vĐč„Ôö˝eŐ{tĄŘ/&.ĐúLGý@ÄŃÇ„SĽ<ˆiDxÉ~uа1 Mr&Ggŕq0*ÉىœL*€ŠĽ0Ľ‘š*zdŁ'¨'#a~ôŽl›°ď†XĂ,xŽDĽŃxNş;ˇ´4F<ءhÉçźăbşĂ<8žÎs~ňÖj}¨Ů*ĐęxüqüëŰF$řPDĄy‡ě’HWv­j˘Ö řH­z˜g ÇLn›ănwÁśÝčZR?dr7¸weߪbhÎ'Ÿsăß>.văß•z,ŚKşŽ•ŇwőKÓ.‹9<éÇ4ĂŇŤU–äu ą$î˛ČÓóǖ“3 ¨XÇň§bZ ‚Ô†‘dŤĐ¨ĚŔ4JŚ^7ói)ťDž9Ď4IF(ś}ůW3Ďż˝„ÉVÁa_k^ę#KaŐŮ\ِud (Ż‚ăb^YŒm”ŹżVá39؏‹Y˝ćškŽšćškŽůgĚŻ§gmŇč b–t7•Ć(鍏NEQċY˛ę\`1ž6Ă/IďާL÷Ťˇ4Ľjłů“Éô°RRŐĚ(kR›lž˜ŕb`íőýP›Ő~ĘnO)“X89—,” k+f Y~8¨ínŽM;śŞ{ÔŘ R•`Ş•^T~Ŕ%ŮmLşÂFĎYu&˘LiĹÖ.v5˛ar0ŘŘr šŐí‰WĐ‰ä¨ zK4• 1Ťţ…AË\é§Ć&IN9ľÁő,$K^+„ C˜v§ľAg'<ŮđĹ´–ä‚Ü mN,s=ĎDéÄ d‚ąí‹sśL¤Ý¨–QÇvÝęža2RpRĽ„ÔŢa:u¨`<™˛ƒA„R1ÁGŔŘn•ulnáÉČŕýÓi6i–tÝ đFŽTĹŁŔUCiĎASĺsőôţž<śŢސ|şÓGî÷…”ŢÝŮZç˙zL˜ÝaL~[Ňę#“ďžďôyđ>ƒ‡ auo9¨%™Ë3ę‘3s"*Ť{fĎ9"äđýŸ‰ĘţMwUe73^˜#2kf—ěÝŢ@oŞ;"ăquUSŃdŮÔEJٕ“h×ɰU ž´g…šĽ”ŐwDŇşETĎ´¨ůŞBŘrU×\¸pá… .ü#đÇČŞZ…$ÍŮĆШ3ŸeŸ ŹĹŔ­!,8ŐjYý§-ŽWŕ|ĚC–ĘʇÝď$ŞŸfNU˙j8"xUQD–’’gŐTVĚL>Ié܈Ç|]DÖăG䍌Ś38m5—Š ŸóŹŔ+m4&!—ŮŮsÔ{•Ed‰eŠĽw˛UËÜđGٌ‹”rí§8cˇRŐâIč‘őď˜@“ŽŚłˆsH§I2dZ!ĂѤ.5‡—=îŐ{+ŽhTZk 2:b”Ĺ7~ ‡Ń;ô–hM@#8,šĽ ë辑şĐŘ4Č‘‹•ÝہŞ;Ňä(5e¤Ě:C÷M…pCE°ć‰wŒƒÁ=á“Đ1uŒáBO@…Ö•pĽue÷†ƒĄA˛G§ŠńúšŽ†‰‘žáâ^Ľ•0"4[ŘÝ9&ńy§Żű~TÚ˛+KWTnĤ*űᬒ ‰dý]–ÉMoFŽ XŠ^ăł_÷÷Ţ2„ŚB‹`;ď?„÷ĺÎą%‡4r}ăÇžńĎ?6އđ͆Ź<Ľ#đ¤Ő‰‹Ý0yräŰ<ŹŠśĄŒ:´)Ŵ掚f)÷ó`G>qśó’ľyŔTëić|W?j$ŠgpZÎŻ ŤŁxšîKÝ,+˙ź=‰őRI3kN9+oĆ,**űşČ¨°ŹĂ5ëĘ뉺Ě[ œŐGő˙9 ¸ĎĂŽ`ćMeÎ9ď,;çÁĂs†-iu_¸pá… .\řťń‡ČjŮNkSvĐčfj,Y‰žěgvm fU\b*dƒbZŐ%ăTgs·fŮ^EO„Ň9Ť&Â*ŸűL?zBsnbe~ŻŇ:…œ[çzŹř žŸ 3-Ľqd҄"•‘(5Ų6Žť´Şd‘˛9ݏ‘Ĺ )kŤŁ4-Ľ7EXΌՒ"ľ‘•¤{؝˛×ş$áĽę6…dC4‰xN¨:Y§IËRYŤŞŚzD+ąxT=Ž˘őÁ!“ůœRš“n vlT(M´Éڔ\˛”ͨ “…Űx"X[X´vŤ:‰ŇšbÓiYŐ>aFćQDYŠÔEhF&‹xqTŞń3<Č*ÜRŮŚÂjÜ9‹6݊Ü>šŔrÎF$ža‚ř‰ĄŇzŹ<!‡cH.ÄŘiČbČH¤ K&h§÷"ŐÓľw6’ű_QV5ÖťtT•=ĂT°ů9‘ôQ*8c›äŤUGëŮÚÁřEví¨5~Yď#ů}+ĽŇÇAęĘĂáńíÇpś<ţňäßőNîÂƂ‹ň†Z’z† Í%šbiÓ­Ŕěä-ęXÜkÖÍ4o„—B{Ž6•˜Ę§TŃYscg7oîÔěgź:ëÁ¨óUc%†ľy?^Y~Œ™\aLgŽőNŒÄÄÉęVŚŰŁ*g>’|f1Óžł KThó€-Rgr"3í7ĄÜ3•ťłćs˜÷0ý<á… .\¸p῍?DVű2ŤM!Ć!ŠJrč@hfx” PU8ÄhR‰şgjŚűŮm:•)崂]fŔĘŹĘx%ú9Ť$ć7>Ԙź5_$ô$ŹU? ¤Š°ţLTsÚmU*ą´,ĹyŒ4ĽáՃ:7Ú=Pł}Ť‘Đ%ŠˆOéÜň ™€W ’d$‹„÷&řÜčˇđWÂjDUáX&)ĽÚh:wi ‚Œ ‘ŽĽ‚Ŕ‹'*iڀećçÖÜď šĐ„<Ő˛sČAEřÁ&†ĹŕđŒI˘T˝,ĎŇŹšĐm)•S3ĹHöžc°„ńeUš6z+劤*)Žx…óˆ+^S]`óše•n4 (!ěZŐH"JŹˆĂ=)5XˇÁ9Mă÷„goĽŢ‰Ěş›@28¤”l/•ĚŒ5yU Äki(űő6Ą/Ć5Ú­ϝMkĆXÚÎ/ÚŘƎĚD`T7 eą…´…Çžq[żô"~BňçqđűÓ9Úb]ʥВ O„_—ĆŸou´oÇh}qĹ IDATK'÷ƒ˝):N‹ÁăvGł.—ľŐ5…0Őę"¤ƒ/49ˆH{+â%ĽŞœÝşem>żć ę N…´ľÖ]R~lkŻ02 (2-Ĺ?ľ˝\ŠE =›ăAŠź2S„­Íżi/–J–ٰăhS2ërVé ÓĚ纪Văb€żćj‹œGM%5oůQKÙJÎ g*ŇnŚŻ°ĽŒ3ę… .\¸páÂߋ?fa°˘š¸T7č&F§6ź[JŐO¨–u0sVŰLŐA´ÂG2^a+bU=Ą3Té´ér~˙sˇg@‹Nă4&=ĂZ˙̕ŠÎţ5Ş˙Sjƒę´ †•JŹ"hÔÜéŚtöNz–Ľ42X¤jGÚŹ¸¸‰c§…ˆĐmG°,ëd¨Íp%&aŤŮYwDn¨lŕ^„PB„[$+äŢjŽSŢq]‘ą1˛ć*{ › Źh6‘OŇwAňŔ˘‘cc¸—"$šëTm+Ĺu¤W’kŤT۰F Ů*=řžŽö¤•öyř°kçÇî4ŮYZG*";t!ö9˙Ř6¤Ż iŹX§ĽcÝđđH<‹€nڌă@FCÍ!‚NĐl@(‡vş)j}ĹÓůްǃ–†şŕűN?rŞÖ°FcHĐíΟoUŐÔÜřËóRůdፆ­Šő ƒÉ‡_š`V}žË"ä\’[Ŕ˘JĎZ+ŕfŠ;­wBC…˙ą– ďť"Kg 嗄ß=ôHvéŹéU=UYCŠg'r™ë‘9˙Č$¨§’z'•9W’śŞfB0böö‰Ą9•ܨšĺę˝9@&§ŃŒše0ô6ťRkJxůš-2¨Ó-§Yô#Ięš1ÇHŻäçŘęLëőޘáîdJÍ}‹źœ2jíkkľ–Ď{Č@Bőĺ™c“Ä_¸pá… .\řűńÇҀľšŇęůtm•fhœJÇ$Ŕ™ęŤÖ&a•OsŁ:ÓsvT^Á?ݨYA>RjEm’Ë(sƒz&űž]Ťźţ.őÜćć2Ă"­m΢ői"lŞliüdŁ#Š˜bŹRÖÁŔĐ ”EcŞ@Œ˘łöb̙Բ@ZSZ 2•ĐŽůÁxUś ,ż3Žšyľ Đeă6UŽÄńˆ˛ÇłB–tŸObŠd¨PBăY}OGÍÚE éańRŁZľšĘTŘ\‘(őČÁ˛ěÝĐÖŃD3n_z_Ú]é"5ËŹĆąd]'žâ Ňß٢W…Llč†HŤŰô.e 12ă0šŢéâ ŤAs~´q;­ßhâ<Ɠ!ÔŹk_A„=OvW<œq$Cރž4î šIŹ‚?ęÚhĚN—@Ö& MăŔěĆŞÎbŽJ#űűbü8’>ÉŐ˝˛vŢŇytGAú½‰ó€[BŚąƒÝaˆń¤ăß ĂéˇÎştţçMąćäQ6iç ڊtëpřk J xÖŃ#„#‹DWżé\›3,),ŤUT^ß?1ŠŕLӝ.É<,˜UUjőX⣺Q“fe­•N—OW˛Ň„×ß5iŐ_ú~˛e›Ëź”új‹:ŐMA4ç}`vĎp§&ЅŹDtłyŻŃœu`Śö"Ÿ?1ĎyFvÔäoŃşý'ßšpá… .\¸đ_Ĺ"Ť§z™'œ$1Č L™ó‚ř˜żp*ű§Ľ7cVŔčůß6tn‚çĂL[Ýé-äŐËzZŠe& żČ¨|ęg}ý;Ú¤Źś emô˛*Y_ßS*čhRe2ŚĽ9¤‚™ĄYäŐ8­ÓÖ+R=Ťéô,ëc˘Żşžšĺ 4"˛#ł‚6ĽOë­ĹFĚŞ ŸďćňÍŁć9\ -+,ɞútśT#1ŁŞk’,U8š×ĚŹXŠÇŠwîMŘ+ô—đ$q| öľŁ!¤Ôœa`´í†ŇŰ’AS…aÜێɁˆ`˛°d%‹śŔ(ŰgÄŁěť5ôȗ&4 zl„Źˆ*_Ĺůž+ٌÇôńş ÖÁĘřŹü˛(É 3řÚ;’™ <ÁV˛uŠ <<ǝG ŽC°mĂVăf O¤%DÍ/ś›UĽ ΗĹčV¤)FÝQ¤ú+UťŇ[Ŕ˝iŽČY!$˜l€ńuG@TőŃť'߆óĂáÁ0#öÁwƸq{W~}~„ň˗_ěŰk+qďî<÷oilQőIť+΂j2źćGďá<ŇhĚĂ)ôäg):{QâŠKĘfŐËě_•ĎäíT\çALŞ!Ͱ$ŠŠăaôVäŘć:kZç)YfƒZci'YœAG9•TiÓŠ!ŻŮV•@Ĺćc•Ąťń¤/wÖ.lG#ƆŤŇ¤R}ĺěeśYKÓű+ĺXęAëÜĚd ¸DÔěç7çźďd^dő… .\¸pá?fÎŹ¨Ős9TËž¨j5f5;ÉŠźLUŇ} #s7zně"?ŐÔäüőó{3%óg’ʇU¸žöˇVßĎP‘SďeäkšĄîލ=g5Ç|‰ł=–Nźęj”şšÚ˜O>7°Ť$.ŠĽcR¨’ÓҚQśčH”gmśË°J‹d?œ0áŚĆŞŹ IĄAʘ?/ ?”pŠyĘ8°v‡ÔŹ)Œ–8ČN[„cš[¨ŮVo H¤5őQ/$îőŢéˆwžG1\kd7Ú¨wľł2¤Tl“`?ŐdGƎЛpĂú‚‡s¤ ăAjVpRƒć;Ů_zSuţrťł§pą5ZLœôQ=ł™´T6 ŁŞdT&Q”@eCí(‚ˆá˝ą/‡ŹÄ(ţsÓ9ťIĐzcAUt1Ph4Z``"xsăĂô`epoŢň ÍˆÔłÂDyČʛŔż<|ŚHďy0ŇŘ16:|;’÷ąđĚ7á]ŕűřÎożĂŰţ•ŕŞ:RůąuÂ꺊Ňp1ŇGŃLVkŠŤ<^f„sÍžŹľěž1ׂd›MĂł—ľiőő)ťZ‘ďĐŔP$öRoIF4Z<’ŚľžO-RĽ„2ŠT U•3ď(S%ÄČéRxݟj!Nű<˜Ôű U•őţ<…{jYŒĽ,ϕt>áρoóŹěŁîćoqÚ ş†V/\¸pá… ţřCdő´ÚƜŻ<7l1Ï"œJ`ńWúŽź:-NE´fH1ů´ń+źěż"˝Şs,5>óľyü ťS–⟞ţůEJrĚ d›Iž6Ÿ×ĐFĹŻTrŽĎ(–âElŤžćÓV5§2Œł2p*ÜĽK€ FɈJĚ.ڜĘюŚÔ|ŚÔlßópz$žĘS…Śűj“ ,$äž]8î˜6ő"†$™Ź-šaőţŰŻÄîlŤ˛‡ăc ’ ów°/†LeTE ”› #ӎj)Wˇ 4’žƒŽ‚,{WDƒô˜U<ƒƒÁM…Ă:wqnł^Ćn>q,]ڏ\ŘChţdY7¸GĽ˙ÚÂW{â>ŘzŻ€*SŞę˛Ă¨ÄŕĄgC‰Ő5šÄ;Ť2ßﲳh ÉŕvˇęÇľŠXäTËVsˆŞEЇ!Žl8RŻfĘ/K°ŞżÖ. ‰°oŽÇFˇ›­Ź˘üßß6n&ôľýĆؔ=Ş~Gځ"uZ€E[ů>„ߟŕ‘ö őIQŢYč„#ĘV;+GQ)’xŠƒ# •ŹnÓy U&‰šEĚ*aZŤÚE‹œÂë_"*ą9! 2ŤęxbΤK‚XŁ™BěU{őÉb+­RÄuŽ7ęš:ż/ ÍŞjŞ|űóZVHŸsők5|Ž)Xcp’ěisÎŞĂA•ŒşgŠAÔüßUkŠxÝzŹýżž]¸pá… .\řcřCdUM_&…œ]ŠÔ|×´ŘćiՕĽfN’*ˆRN眪ňӜj%÷ bŐ8ú˛Ô‰|<ŕ'B*SůýŠŸěx}Öq*¨źŒĹ‰HrhGgçŁd…UiO˝˛Ą3ĺןŹ}á(ŚR"I3%Ľ#šă°ĚŽÚ§ÁĎNĺąďH:{ĎĘĄaA§ŞŘr0ڊŽ™čÎ4ľŽI†E:_$i-‰PĚę=ږƒewžŰÂ}góďɍł>Ä%ˆÍÉÖi“"tŞÓófAeíĆ]“Ţ…/ LzŇ+\ŚMuˆ–t+Ťi‹ŞÂ:âĂÖą“­q—ƒ7eƒîŤ ›×%zÓAÄÁPęurŒ ęé™ě}ŘéMĐĺFŽÁӓĽfŤV˛˛šUĺ‰Â]’6gx›5t ,wœĆr3ޡŔŮ90ČÄĆ@[ÇâŕŢĘďvGDŘSŮ"“‘EČť–yŰ˝łťąE’š|ߟ|›Šđ­ßH’í€çţ`đ< †łĎŽb“ ґ¨GůÝż’MQ‚CW’RĂEĽ,ç“ÄéyĄ‹œ ÝŤ•*üi9ÎŐ%ŸŔ>92悙ŤfZe—68\ią3dÁŹRrĽÉŘR*ţËČěY=çh€Jž­F”?ĽVëkŽ[•›ęď ¸T0–°™h B*U9gˆRX#ŐŚr[RŻÇUaăç§-řŻo)ŢŚDÄtl|ş%ĺźWţ|łźpá… .\¸đßÄL֚5œd˛‚LŞŤŸŐ*¤ŻÍě§MhŠŞ>-ÁB„ŁÖł—:›‘Óî[ťĹĎő5çă}<i;Žo||˝žUYuUëů“ 6ůP•NĽ\ §ÇńRVUŃBóŠąDm˜%v°•ĂB—Rk$ˆT’Ý ‘÷"9¤*R Œ'¨ €œýŁ3„Ş6˝BłƒČR˝\;Mʞ|›őÓr˜Đ„;EÄ5/ŘóWL+´‚ciÜĆWž‡ĎJA=[¸q€­XkU›˘F7XÍXIVƒ›Á›M„ťLŐ=„6mˇŞV=Ź Í[W̊Hë ÎůĽ é´Ü¨ˇŔ‹ÜIV°+)ÉmUş&ŚŰDěřňĆşî.7žřƒčëâ¸Ŕ]œCŞrít´6hó`#T[‘ d˙Aś•Ö;˝Ă=‚Ă ĎdȍŒŁlĂ ˝fxh…eí;ßhlӆť¨ń؄̃#…Ăiw6´cŹażm~„ńďç÷hŒě¸H)šV-Śc?ˆ\*Ô¨7Úb쮌„ډâÚ+Ýz^ŰfŐ_Ť*USăł4—6­ˇźlî1 Ťőy˝ČXŠ‘iíCe §iŕşNr¸Î~ŃD{ŻĎUÖ ű¤ ć\ËfĘ`&ˆg­ĐyČä4Ť{…{ĚšńöZŻ˛ţGv<c Ůđô9Cېic]PÓJ6Ž K,Ž×›ĺňĐ9˙ţš2>?q™oP¤ŮÝéKÇGĽYLjšƒ˝Ň€/\¸pá… ţ!řc6`÷šQ“ŕ&ń;ż~ŚűžćU9çJcöŠfFĽüžÂÎßŐWpJý^)ޟC”N墏ÂZ–L1LŞřCfˆŃŠüś¨NVĎjvl'cľVÉ˝é5#3T=FýŠÎ9I&¤öů\ć_…ѨTK(ÁJĘΈÄčHRvD`ɢG=îšQžáĐŞG] ĺý (uRQTcn´+Ą×%ą¨ú–~Nß項3Ţԑě<$X„”=•V„HŇ0slžď‹&‹ŽôpÖ.|íĘ*Î}ŞŹ6k:š$N˛˜Ń4XTX­ćWKš6§[˝—‹%Ť4„ĘÁś¤ŹĐ}ŕ hĆb ­ń%7†*­—"ˇ‡!ůdHŻĎM„;ˇ. …ŻłFÍaŞoŠ•ŠM˛3íç™X qťá.H>ĄEĂq[‘ž.lž<\„ÇN4ÉĎ _Ĺył îB`—Î&Ęű[[ů!GÓ Gş}áń öĂćÜdĽR‹+OűRÖís̈́Đg_mŐ͎ޟnőůÖĄIĚŰ SŞ6ÔşVÄĘ֟5kýrÚGĚ[A ’ ´‘9fTo’Ś•ŕ›'ďKn鸜×üwd•Ń:1Uß$svčJŤneV]ÍžWýPfǘj­9ô5ç*•4\•ŞFˆÍdîęQn ¨ŕî˜5ôŒK›!XÓňó}ëœc7›c e‘N„Ö[‘éfEz›ž~ć… .\¸páÂߏ?–lö"mŞB G¤ćŃdJ1E6s"Ó2—SËąŸçÓŚŻTÚżUZ$Ľh ĚNÍYÉA)żÁÉ>‰j“Dsyś†OĽ6‹QóŠůaV)˘ýš*'3p’R•-ënîOPĽi'â˝T1Œ†íxj…(e"M‹$”X Ş[”Ĺ^= cxurÇíɍ/5›(řˇĆ˝YUvDrSŞŸTâÁ˝%ޔ´íŐĂę9؞塞t,)XÜMš5cçmQ:Âj îô<ƊmV?ىF…FĺbźIb]ĆĹ ?GŮŐh|1!Ľsφ4e•$ľlÉÍ*mؤóëÚąŕÇŁÔ4…C’qŒJžUh}{đŘłŞ'q'ŤcÔĐę°BŒL'ěVŠœŇČŕHĺđÎ#„‡ › ďšłíĘżé řÚ;ž-ÜŐůeí˜&O:ť ˙|$߇łťĂcÇŰÁ÷ýŕă‡WçéňĆęÁ:­§Á†˘V‡.*SÍOĽéŔÓ8/ÖW ^ĽľĹg˝ŠIŇNËíě={c´HĄĚC”Ô(ťźľ:dúŹf&Ä\7|üÍb“gÄ4ŠZ–v>j§4G)˘”}Wć}㟸ײL˛zţ^ÎJ,›ŽƒČœsă5'힘&NŐSY[*œë˜ ČxőcHćď•+` ÇĚ>:`őźsńÉňóřÁ… .\¸pá…˙>ţŘĚjńڞOž ˝gmĚČňŠśA¤6Ę/‹oćK)ůô3đĄV|îJĺœ{i¸´Šp$LŰnĽśŚśRF|Úi’łćun ăTYO;-€Ž ‹QЍ–ă5; u€˛ /'OPCă ľAnU˂ż:K—üF؝ôĆNDq°š[Itîţ%ĘJÝ$𦨗ć3<É °Şő‰( 0ž!‚zg,Λcll÷ńäĐ/źi‘˛-#đpžšA_Ë>Y¨ř zŢďÁ—YE#ŤŔm5H_ÄY4‘˜Âל”–`4M–ş]“>Ön^gŻą™°tx›„Ľá˛ÎĎI^ľB‚ĐŒ  Đ&Dne%mÉŘßyZ…űÜű ˝Ýůţí;öHĐ:GꜶe*ŹÖéŒI6§C 2^3ŚL%¸‚ܐ X“š=—šV‚@ËAĄ !ŻĐ¤SáUű¸‰ ­áQĸ]>ŕ .\¸pá…ţY8•fҜM$t~Łţůô{b§mîç.ÔĎ?“ńńX9Ť2”Šzžlż)žNő—ž„Ô\ęet5V öœJP–ÖE_ižé—†jŮćĚí$νţV›vcM'Ĺ ‹ ´•DpmH:ˆńD¸ą“;Ł˙Šú’D‘ÉFŇÂIORt@jn¸~$9’ÁvĺŔ4˛žs٢“ľ9;‡ŇŽʔ٧ޤ;đf5›Ů$IQ†Ź]ŃyŕY¤őքťUwf“¤™pSÇ5¸KŮe—Ś,+†Š˛4aíBë5_ŰDX4hí([ś)­•łY˝ż˝Ő×ŇmU%"zăÍ"ËNIő¸f$áĽúEě˜8Ç>HťaYóŔ_›˛mÁl|ůĺĎ żĄ#ńąąíőşoKYIˆąč:c¤ćŒuÜş˛ÇB¸1P@Ű­fqď ›'K3üPÜkrUř˘ĘŢVt˝sř“Ż|üĆ÷§ňž?žÉ{ă‘Ę—žIČM šłé Ë'ÎB†€|ĄÉFĘB˘HNy/‡€*Aš2浕g‚őźś)Zy*čÖ¨ çihƒTŠ˘VsŸâGÍŞú@͝˙=gIG$‰,wĂg” úŃ{|ÖSŠTšŻ„ĚŢh‰ic0“…ŰŠűXC´,şNÝé,MĘIáÉŇŔŁ’ąC*9ŮÓąÖŚŞ[!bˆ–řůŠYŤƒŠvVC%¤Ö‡—JÚ Žý ľöÓÍËŹfĐĆî5,ežpá… .\¸đ÷ăîŞä“‡pö›BYu™*č‡Ç°9ĂFt ął~Śľ—M.#ČŹÖSŠ%‹\j:âeÍ3FV(Κť´s˘ľ6ë5q ‘ÁšÇ ‘LV§4\j˜äĎMî´fxJUĎx‘9ŚúR¤×kV.§j‹`Tŕ҂sH›ďSĐ|y"d2Š~Uř@Ԍeś;ęĎéěD¨=çkŠř @ŽńR͇UHĆĄÉćÂ/Œŕ Ź{SÖĹ¸É DhŇi"h/Űh‹¤eT MÖźiSc4ƒÁ]vşfRőEÄx“@níŐłzoAS¸-Á­U礙ҴBoԔąԔžÚ]kłßlp¸ŕĄÜ×ŮI›ÎĆ؝8ö ¤mŰ˝”­de<Űh„~˙~°řő/|;˙ňĂyL"°ŽĘ˝%ŰHŹ/,­z6=ĘRŰĽęV›CwžťWƒ ŽĹ†őľ>÷Śôž>ŘĆ ŇŮ3ÉĽáŢ8–č,ˇ_ůş,XŹ? š€Œ”y@!oˆ&ÎN“'Ą+ľ<•Ł”ž€fNÎ'9ÍAڝ}¤ŠŐZúRR¨ëOgĽ”tRŹÂĽ2HiĽîˇŽĺfó€¨Ö‘$HŻp'“Dz+™‰iăż&ŞfSűüd‰Í´őRlӑVA`X)˜#]bćIĎn˝^´’FŁ,ó}I‰ÖĄNxesčˆÎ°Žéü°éŃ҇#Ďđˇ¤Ë`„V0”HëŒcĐWR:m:N´fŻ{Ÿ™2FĆővĐ]¸pá… .\ř{ńÇČŞęK%ů´ő|…+Ő˙圗;SYä'UJY!⼰֟ÜgrZSŒ!‚Ĺx…śŹé)ôłŢQN%d>ţœwsŃYGS{ĺĚ,ëđ–äˇ^M˘ZvDŁŹˇÍŠtjÖs͒ţ^$ľĘAƤÂ>şUaHdYV;űËYos)Ş1ʆ¨Ł!ŰwTK•Ú|CzbÔ„ŽÂȄá>*u)í,!HTHň/š@JŇs'Ÿƒˇĺv°Ř‹Oďü"Ő#&|mĹ˛ě— ‡Î&†ő šó‚éÜďJ:ČHŹ 7Inm°6Xťpż5Źi5ő:+؏ä9ŔoÜߡ[žÎ9†ż>°šÖłŽ%9č UăCťƒctŒÇá|‡ÇŽƒh7ś<ÄŠ,Öxđăˆ-ä#i‹˘űA;}˝#Ä$!JƲŢ9lۆR3W-2&đf]îŁÁ΍ßż˙ţżí Vľ+]iŇéćŚČ~gՃ§ÜłŁ–D Ű&˜8’űKÁ첁,H|ČŁçźč\RR@žŠŠ˘eËmbľX4?ÄF)š&D­AËA̸2•"Š#jU›ŕi´iýýŹ6ŠT8’ťż,łçězkő\…ŔĎyOŤ°2˛‚“b^ )†S–97.9k´ku€öĽ—ÎÚ‘z˝ÓfœXٟTŠěżî9Úi™Ni;ÖŚJ;ÇČ9cš1ŽJžwBŹÍž[?çî/\¸pá… .ü]řc3Ť“<ä™6š U|ÖԜřlűýkźz˙*ˆäœMí’8ÂJ€}l+7ŞĘäL%nYŐ4.F›ľ!ĽşœŠżC¨ či˙SĽS • ěQ6U § hPäô|­V3˛ŠËŤf…,Ž’„Kýj¤$vžt4žx6ˆ ŇqŻí7~Pj‘Öf=łBmbGöމѧrŐ÷šYiŞ!eŻV…%˝fEupŒŰ´‡ÚT„-kwžš˛„VPĆ`çáÉvž.7$úB¤’âŹCVŽŮĽ™ŠÔfD“ĽÂ U§•5g+’äOál3°i†ť‘§=yŘŮĹ*Z]ąő2äăuÍŮzŃ ëkŤë•é0VĄýap.\¸pá… ţëř/ WÍt!Šźĺ´ăý§?ýŸU`n¨?”˜ľ÷wăá IDATK 1śŹžMÂä+Tĺ´ű źćçú ™YŚóßÄŇ éőŘgmUCsڌf8‹V Œ‰Ňć#Q Äg"*sC,ĘŸ3މÄFbě(śż“#•Œ'ƒšÎ+eĆsLűqÎ×0`Ä´T7D:™IēMôľaßéě´~ĚýřĘj‚‘^I‹¤‰#iłjو_8ť@×Nďu!ێçĘĐ ‹ĐPžG͢f áU1˘ ŮËpBÜđ`÷Śň}KüXllaôĽłŞ–žńë›Đ5Řä^!=ÁŸwă]ţˇ˙ÁL`­0œÄ]؇°=ƒÍ•ÍoÄ6řáç6x>ŘĆŃĺ=;Iś_8BŘ÷Áđ#5éóĐ#2x&ŇNG€°ĽŒ B<`×;ů|OAmgÍE‹u$˘†Şq˜2vg߃G&#“ şĐEYX‰^‡ Á#p\ž8&$iE‚244E8_•1ł ÇĽĎpŸşŽO‘s.9+^ö뜇+˘‰¤Đô`P΂+KuV͏ˆC[Ę1ד™1+Zţ“îăĚüÉúŰZĂK›Ä–;Ó-@%i˝Œ ÓY›Cz)NĘźĎčŹŇ™GVľ>Ęma­UĽÖ/ČӎÜępÇ4É,ľśŠŮ×Vk-ŁŹđ á3đLëúŠ>Y™sńŚ1Ľçő™ZľB™äpÔôgWɅ .\¸pá…ţ8YU™M~Rţ;5ÎFHQCý5†u2˛T!5<Áf CŞę$ŠĐ”fRÁGÔî÷{‹( agŕ˘8ŠH–ęšç<Ü´ńŠĘd`’xdÎ~ÇI`՟ }nš‰'Îhwlü@ƨjüAČ´NĎʙÁrŸÖA'IbčB˛cxŚcě“lŒŞ(IGT1:֜L%˝!z ŚÜL0šŃb°{2pƒ†c"H_ŃTF&‘ÁʐÄsçá‹Y˝ć¨JŐÁHŮ5Müź}éôfČîü€"=VTęx>xϕc$űo;rż#˝!ďďČż>ŃuŠ×ž÷täߒ˙ů—'˙Gü/ţ÷‚˛ż°"ƒáÉą9ŰĄüŘŕńřą2€‡7Bűž<ěXkä˛bŠěŞ„ďHZ%ÄJ˛§°Z yóĘ óŠ”ĎPœCľlŻ­ăźƒáÖßy0ƒç<îŔIeźďřœűÜDiś’=Ńhüś ÷śóOëĘ×1xFđo‡ňŢžI )¤u:I0XiłŸTbg^鯿Ń4ŤŮYͨ¤h—şžćÜh †2•XE¨ő%XŐÝDÇPşs6Z"NT[UÍ_jÓ3Př§u/3ˆČϚ™ůÇUľB̤zb#Ęt,˜ĄěÍ~2X¨$b}~­Ry[Íŕ“@›MŤeóMQđ˜śč OvžśčLÁ´ąŐ™ˇ Š5™öë†ä†hQšIÍÖ3“R1Ť°§Ďţ狧^¸pá… .üăń˙KlefŮŹ ¨ Rj…Ť*˜*QY{R„–ő{M…{ŮX§=ďČŞ€Ş;q ôt"˝ŇLĂÚéóyÖ?`ö56 HŁĺ;Ą+’ƒĐޤÓd ) OĹöo“hE„mC†aMˆĄ¤ˆ'ŠĄŠT–ŽłŠáţ@EÝ1Ö˛"Ÿu$ڑŹTÝČDYĐŚ„(‹H[PýJ—˛//@tX$š3“—{ŤZ-Ťr/&2˘ú7-A;ߣÁó7BďSŐzň&+jÂMOUšu|/’¤;ÂnÂ}ÎӍCż„đH#żí´ ˛ČÓHGŐ°~gÝßţ<˙Ďü~ü‰Jănƒˇ{cé MYĚXŹń{,l›đ>Ş73[çĄÂ{>I}ŁÍŮMÎś;Đ+HJ­Wjě88\čmAűZsĄšăöĽV(;ƒô@ŰʛPéËjhÔaˆę-ˆŹÜVĺaoü幗ęg€ł@ÂjŐ-űoϢ5OW\;Čš׍ŕ[ĺ sž2[Ń8аęJÎŞĄ˛ĺ×3gzUŠœŐĄR)´™BçAf ŁŞe Ę_`Fˇ€<ť†ËZÜ4ˆ,ňwr1Uý‰™ăŔŹÔß3PMUkýeĐ|ťc­•ńxŽ?ű !ú(Ő)UUŹćÚu:3šŐďšŃ›1FŮ&Á”Ě:ŕPńiQ>J˝§şSŤ§9×VçSMŠšŹ|ôœŠ—š]A92iӑń3Q=!ňş ]¸pá… .\řŕď'Ť"3é×˙ćë§d2‰ÓÎ+ô B­bS"gâmNőš â:S„#ĽG 7݉¨šÔJř­šőƒ"¸9bvt&ŕ¤@č9ЍMňf™4MśˆzÚ>-4)j™™EzcŞ9Ţɜa8ŢĐœ@Ǝ„UW¤€ŘŽĹ:MʂéNË• $Ű o˜4RĘzŮy+"Ą†Ë†˛‚6Dž,™ŢKę)°Ť&MJ‘Ű0kŔB˝”–UßRY>Šĺ^6S˝ĄˆVÇŞč$Ľ1ɒňşŽĎƒz*8č2ż†!UvśÉttC%gwŞœş1ő¨ö"'ą{­ëOýČ2YšęŮoŞHR•ę†”ÁNľi1Ż ő ŚŸ6k“(2JVXŰ˒\iŕ9gWăLůý+őSŚfŻŠ .\¸pá… 'ţŰdUôLÉŹ@”šăă”(Dt’Ă"2ghR›ŕžƒžţ?­ŁQ‰ 26BdŸˆŞN%TĎTâHˆ1՞ęCen\gbMŮ)’Y%„V˛0Ő˚YÝŹ&Ć˜ĎďY˝§ŁHš4˘ć {Í­95łśűÜĐďs~PŃ4Ź ’/¨¤ßČ9gÇ4ŹTX:ˇćˆ+)o4łęˇŁÍŢS˛HƒęŠ0Ś5qĹĺ& Qݨ˝w,wÖ~CĆ(ëŚĺŽŠ°Db덁Óú—IŽ ¤ł. r' ˝Ł#¸ľ9ó¨Ő’fđśB×ŔDyóSCŹóŰţ˛%żƒÇă‰ÝWL!W!#ů1v°Jr_koôç$>žăfětţuKvÜśäÁžÂawxxđŰálÇÁXn4‡÷q°>ý†yL ÄÎ@ŤšžÜ°Ľf˘ç;‘Ś¨l¤w~řĆÍ~…¤vĄ{ ş)Öy8š?€d=‚?™‚ š|ĺ_ź#Ś<ÇĆď Ž]9v…lŮŘěF¨Ł) YŚőWHŠÔäčę󤣨TmfÖçP\ŽĄEÎ4Ş6§KYˑ,K9ŠĽ“Ą„VÓĄ[uÖŞ)+ăĽVŃkć$5GÝ "D–RgĽ ńŐgšu#É qŇ ‘‰˝lłRiż)JJ%#ÓĆűŠěŽOzNËJ]7/9vçROĎĂą|‘Ĺ”i)–†ÎŠ‘Şň9O$ŞŻXćĚů ˘R܅֭fŸŠ+`˝ŽŰ|TJđ‰ĎÓ˘2‰/\¸pá… .ü}řCdľrCFV1čÜlΈœ$6hyTżŁZ‘ÍŹÚ‘c>’§Đš2źć)5ŽŞ— ç ąFYů–ŠĆŽR“” %RjîŮß:Ij% W]˙{oˇäH’ci~TÍHČĚÚ™÷şé閪Žü‰p'ÍT씞5++˝ąSui¸ÉŞHO’FR zÎůŽĆŔŁHłĘ,ő&@ŇąŐk(ťJ=&@ĹËEęłndó‰Ňpl™„Őóń‘ŕ“ćuóí=ëV{ďŞލĘ9TŞIŔŽh ™oŤkł—™NřŹ|%ÉŚBj- şłkrř çAłC÷˛(7+Ű$Ép?5îŞ [™ľhČ;I3Ť^ÎĚźxn”ˆ)˝7’Śđ—žürS6nMÉhœďCůőyňďď| %ěFĂh÷FŞpź×˘ßPd*?˝ń—7ĄíBóŕK~zëÜ6¸waúΞĄ|ÎRĎśOOžŐ;˙Ý*űLúÖđ„ ˆÝč]‰uxá"ô ÍEŃ˝1yrôŰ_s ţNäóœőű[cÓ¨|óśÓ4řů^ĐĽ@p”Ý{ćłóŕW1üY˝ÁŃĄ˝ěĽUŰyCrÖEöiľlŞŇ>mđĽň J†â­l°‚‘Št ŠžT *ÔdAcÝŹÍEáeuKΑąÖĕ}Ź.^ÓĘž˘Vvt˜¨4Lf‹8A÷r%X"Qäbł,"6ţ™ŽlKŽ,Ú´.óç×H”YD{ŤŸSC|˘í…}˘ţ|ĺĎ­•- Cx}%ťá•9­­"‹*¸c­—=9ËŃA:ÖűçwŢ?.ŞŻşhľ×˛ëg¸lŔ×\sÍ5×\sÍ5˙˘ůĄeŐLiœŤHăŐUčŞňIč-‹á˛Ó!ÄŞđ„.6ęĘʁ%î΂˛âڊÁ›°˝~÷˘śtń‰hűźŻyŮkA5ŠDr˘ŤźF$hMɨ%dÝ´†v$›'ƒę\m¤ľ´jCs 2‘ çÄF2SéóYŕ˜ľ€FłZ rÁkR¤ňuR “†đ¤şIËâٸXßÉČ|˘ÜqŇ|0tcŤ†6IśvăAÚš0§3=ÁŤ—3Ćąr} &˜c f„ł/+ć}ŁŻœfJrtŢşaŢ4ٚ"ăäŽÉĆĆŽ•Íí ă?˙xçß~űżŸÁi_pNž>‚˜Ľ:Mb‘ä~ănőğJ÷ÉíŢé{çËüΛޠ}eŠđ}Ôpşđ=E+÷ůÄE7öe_ŢzreXŻĹüžM¤7ޏ'ŒÎœ0Óřoú•)'G†+QÇűFwIޢӶɖ§1çŕ1ł´aö~ňoÇń)Rř#œsżÎ`j)zÇś“ƒi2˘-Ą°č´Ź…2´Wˇí˘řZ$ŠBDŠ h%1%_Dۉ™ŞŤ’Ę$ľ-e˛Đę]-ľpý>ąĎOZ*eƒ/25ĺDČ'ɎP9TQ[ŠçHâŮQs`[ ăęÇQ-ľ2Ó*Ľń…˙ľśžv¤2Ľë˙q:ÖÂ'€ŢL"S[ Ö×Dĺ ?ßäőR6ܗ"[ gŞaâ ź4K"'Í•OS@˛>§"ʜ÷ë;°ě˝ŸçsŻý4sÔăÉ˙[œőškŽšćškŽšćš˙ƒůńžUQZ&sĽá2k9”Ź:-.‘U3ŁÔ"Xjë"j†(f,Kđş _Ź-ƒIĄ_ŚUľĆÔFËIZCłhťţZZU‘ŸY9őlcËł:09iˆĚľ\MUyA™3ƒ]œ ŃĺIćIS+5vi=c ›:9‚.%źőřÍhzC—ÚÔY7♉šĄfX:gŔ ÇrNŢ2iڈ˜ěőŠŇ󤡺×⟠ŸšĐ Ä v3LŒJxžďĚl8‰ä@:0¤ŃQ]śé̃cœ¸Ý8çwúؘóĆĎťňśľZ Ź HЎŮďFoÍ kŠĆD{ç8Ÿ|œÁˇ_çŻüűďżóOçťld€Ú™<ÜŮs˘Vośí<8mçý9đéDyźš|ˇg~%žĘáʡ™źŕŁĚśTDގĹ7ş)GmHťŤƒł%}S ×î˙ŢďŒR˙lr2Eyă({ŠŔ×îô˝Ó¤ŁÍyӎZŐŃüq(ďóäŻďOţŕ|ŢP9ˆlź›SxÎÉ´[Ů@[ФžŠXZDTj]mŠT^NÇŁĄuö˘ ş*™2™ŹJ%)Žx*ž…Ę4L)ęmŰ˜ąˆşŹÎї3aáteU#¤*dbK…^°Ś¨Ů˛úBĘśÄŃXËóZŔuÇÄŤ#8Ӓ“^‡O}=֜$ľ š%>Ş?YueaW&ÖQšxe_‰ĽzŽÔˇŐăV¤AŽ…Ňd-Ýe­F”ţńńG‘”ëďľ˜ŠĄFýÜ˙cÜ˙´ýţoŠ*u¨&ë:j+ëđ5×\sÍ5×\sÍ5˙üüXfU(ľ&˝2)î tŇX*†ćŒ"á–:SvĚ€%çD´–ĎuŞĆžeő,§l|ÓţYËŞ" >ăÄŸ5dĨ×ůŹ,N„–WőŠŸѷ‚űlS…MéÉ磻Lśńä~˙‰ăŚ>H›)›Đ?3ŸľÔgQŚľ”ţL/[-Κ–Ţ›Ů:_ôż‘çƒă8řugűJ€şU Ž=ą–ŕ—Ó üůšpązR…Ş6R- ˇŰĘHg)ىVOpđǓ•MMŇzý|)ТűD´¨ž)/•°V‘ÄdeźÓ1­E¸rœBe͕"dŤ5ˆś Ϥk’˖Ť$'ÁV6ű Tw ֒XsřšČŢ‘’LÖÇŻúey˜äłşŚŰňÔF)żŚš:„u˝ŽBĽĘŮQ¨ŚWwkłÉœÖJŸO-¤E/…ť­,í?VóÔËłvÜZ‚᳣Y^ŮůuXëĺüŻ*ŚŻšćškŽšćškŽůńů1euĺڌäНĘhŞ@+cěRă“ĚŮr.+ď/EÝh‹.Ɔ#3ęćyËQůąŹŹ’Č‚Ľ”˛čŸˇÁr€ 3ꞭąŇľZzKЧ[eň˛ą5Ă}eŃ8XRBڐ îŔ´ §‚Ľ˙(ӓ›­şšfLQ™IZÉ)Ž#­łk˘śY9˝@Ľ˛t{?Ť!YăÖ+›Q‹qÜđő˜6úŤŻr&ż“|L˜! ‡‘Â9Ŕdl´WÎE˝”ę!†ât=ˆŰš&Á ďL1ţđŽŇč›1ôIŚ“Ň˜q˘ü´ÝŘ÷ƒs$O˙ƒtĂ|űŠĚ:XxĂË–ŹśdEú“műĘÖá­lĄ{ŇDŮw#n?ńŘ'Ď3ďuíšbɗíKŠ˝4ňćlitQ>â&Â[|%ÚI&lY‹ÝŢh"źŠ˘RJ˘vĽeeNďá8‚Čdl )ý`?•o!œűü,°ĐŁ5ČAę Ů.A„0]8ÚFj-3Fڗ.Ÿœ4Dľ¸.ćOÁ}ę벞F–´LR6şĚęÍ:qHŤ &Hő˙.’­jCrpf§sևF„™ş2Óľ ›:ŠUQS|ŕ x"ËŽ<ÈZ݆úvˆúÜÇz|*‚§Ł˛×ˆ֟7„ôˆuB úUĘnCV„@Ňëp+*UZ b}Ö2ËA`ZšÖĐŞĺŠ{Y¤+§[äđ…"Ť23T—ÎúŔŻLęú'ԟSp.k‚ΗŽZ)ź/koRKkřúŇĽH/ř•ľeAžćškŽšćškŽšćŸž[VYéPŠńLŻŮîĽ^Sj˘Ir<ť]•]v6¤*?ĹOL7Ź+á­ö><ŒÝ mƒývc“Ę…LAłĄęX, ňôĘr—׀@ňD۟4aQ]Ö٨÷ţ‚)EJíÉI†ý ĚQLQ޸’˜uRb-ńRŸaü ¤ ŠFF~ާ‘ľ +Šlν 3ڃEú†{ĐdÖ+-ľÄÂbÄôĘľS‡d˝Ý*w^†{hEt^ XXâœuFĐĐŹ{wŘśúgëňżÁ–ÂëçT/ÂŇ5×\sÍ5×\sÍżb~hYí~bEŰM‘wuŠJFáZŚôE$éQęšdÖ"‘ŽD Ë~(‹H[ٰΖőß-AeŠJ/ʰ”šj†SjI—X•$`ţdŘ:?8Ú bŇäd†2›‘!E*!CQ ˜běţ™rCćŕěwc.şčś˛ťĄk)˛ •RrC*ˇÚŹ>OŤX™%ťDâ$ˆ32šˇĆЎQő7Ľ§3Âq‡œƒé‹ŕލ#œáс$ă‰(xŚđ— •¨ŢkBŸ‹dœK!÷˜ˆvD’óy’rŇňA†pź´tÝ0?Čí†d˘˝‘ވ2f>1ÎYҒn7´śDPĹHvMz̄=› ˇÍ8­aj˜îˆg$w’ÁŽYe–­Ő–r#A˘ŹŔC8šŃΓÖXă–'ÚîěRMą˝Uš˘Ýl‹öě)<ÝyŇ9ö†í;1'ӝ˝í3ůc żŠń×÷;ŕ‰đˆ_Lš×’ćO´Uќ˘“Œ˛?őރJŚĽşpGŘ"ň‚19ŁŃĽ A-źI­>Ôô¤5CŇČŹ*ĽŔP+7Cćşö"ŸyŘ9—Ú' maËT\ Š÷§'ŚI““fĘđŽ0QÔtY[ëJň˘ ¤í¸Ÿ(­SŤŒŠÄ u'ebţŽôŰŞO ”¤É“™÷:ĚHŹ÷EőÝžžCĽNŐ¤Ž”ôřd ŠB“$f‚)îRľ24ÉúŐY6zÖűU6NB„ް)źÓą×‚jšž§ľ†Ů¤Ń9-9…ĎĺůYj˙đÍ)˛ÎÔţŒť^sÍ5×\sÍ5×\ó/˜ZVŌžěs=˝ňˆT MD Zę )l8h)2šŽE2ZFÝ<+˜čëî}A5} ’b5Y ?Q­U“V7ҙ4œ4ś8ABИ„[¸l„ZSČw‚KđxŇRÉůdhuޏľ`9N 1ëąi d3“W¤ ć ,iŇ "äNÎIŠ0Źŕ<áłlŽ˘ô˜ŒÖčáŒő„Óهómët`ΓáĐ$ Ž(˛˛‰iÄóäáă˛ϓ^qŕń`3ʖ<ę9 ŠZ_}—pSXä)šÓ&âoľH“hœ@Ő™ö˛¨ŽďčZ ÁŁ”t$'QŰ`:ž†Ž‰gb˝ą§łuŁ7Ă"řI?Ůůňv'ôĆádŁçYżí¸ŹćÖfÁŚÉž ˝)îAœOŚ´Â9Ëî+‚đ˝ěÇ) QP&+@Ŕ3Ë ýÝ7ććźĎdˆ˛M3ţ:’ďOxkoœ ˙ů~rĆ;×Î1ƒCď˜)3—Ě'Ňď+shEď[ÝŁZYFęßK LeĂÍ"Ľ (ĺ˜ mCó,…›š”űšˆŰm)Őłš˘ősX‘‰*7›ŐË[jfőw[x'éh´î̐ŐE[2‚/Ťěʙ§ ş–d^ˆ[Ÿ˜­& Úј„ŢĘKím1ŢIűB[ŁÔ[™šW­žjgX•Š÷ IDAT0KF—WëĚ2ާY‚tVisŁkâ1АŽŰ†)lóŕ ŞŁ5ś !đ¨ü&·Ŕ.őf=Ď:$aňŐśzŹC'OGţ×_•"ĐL˜ţ_ţŘ5×\sÍ5×\sÍ5˙?ćǖUr)ˆŕŞe˛\yT{ݰŠ 9—=Qč9IŰKá\FYÍ3IŽ\h&š2œĽŔ΂ä0‹"źěƒEÂąś!R@˘'fáϲ&úXöĘ @Ňçş)4×꩔œ4+Ó&ś![/XŹţ†&YUá41ԝ™ŸÎéńšpgŽĽÔ(ĚÁDi*Č<>IŁĹí4ގkbÖk™Z*­„sfeq’O OŞÓęFü_áNËĘ †OZ&žIH'$ 65-xT.ś_ú°i]#W#Ôi mEŽ-I°PĹM’ś+ͤ!Lؚr7Řď;š7Ţ4xăÄn;jÂ!Â#”_ČHn–łĐBč žś`ëp3¸u›p3d-hĽ"×âǂď¸Ă.q–]“@zYB÷–˜Ckơżđëüű7ăÝß8­łŤóqž C”Ăęé†(ƒ{-Öv#5‘Ő˝™!w"xíb"eƒo2IM,‚ŠJςĽŠhŐťŹ˙.ŇV&˛>.;Ć$¤“Y‡#Ęš˛ĄEž–Wƕ‚šłEŮՆq"Öńšžxüů °AĄˇÖűż>‡ĘÝh2yęšgÚ˝>_$"^^‚°;ßi:‘˜XŰJńV%˛Ó4p1fƟJ*e˙MłĘŠ.úˇÎÁM&űf Šu˝Ăš÷$˘ŠTBrßvv14żsŚ2,˜gŰp—äF#ňHcoÁŽĐ˘UĎ.°Ťƒ "Š!ěâ|'™i^ ˜,Q›Ö ştÍ5×\sÍ5×\sÍ???XŞě[í^VĐp”@T×Ršj4ľ”’•ƒ#AlÝřa6óĽBikq„ED­ú—ÂŻTÄŚB†ăîˆeCKQRaĺPÁsç¸ţŞ“HDSwZ8!;¤“ 6Łę€‘ÚÁOŚ[ D„‡:&iĘîx–j|žU•Ł>1ŢÝh˘Ő7UMóR/‘†Jr~6uş8!˝:4c€;>áŒŕŒÂ˙ŒLD:b !muŮĘZT˛T؜ˆ´ĘĆÝ6šäĘŇE-YhŁ”› áƒÝz]'wˆ`Ű7Z:]FY–Mh}㞊ĘnJkĆŢŞ#ó֕ˇŞĘס_~žńs;‘ź“˘ź ţöő>é[cóg-Í蒼ŮÁ.ŽIă-OŒFe^ł ˇ Ăt 9™Ů9鄖Jö–IĆŕůLŚ4lߐv#eGfr a„ň˜Ę_Eř[ ţŽ7>rgHőĂĘVůI˜¨EQ¤YśŐÔŮk­‡Šş–=ĄYśœ‚cEV.yd勳 –E㉨ŢU´UŤF¤bŸ×ŤrŢ-–Ÿ”˛ĚSc!č:™š×ÁGV&T2—UŘ?é?^Đ2‘EJޜąűŸšÍČUń’Á֕)?Ń:¨Ÿźńŕđ‚=éü¨îVë°`Ej• –VďĽÖ÷ú.°ŽŠTöÔ*wŰKzŽĂ0U<*Ď+R*Ťd VľQŤÁ ľŞÁ2í˜Fƒř@¤ôčŸ[ckwáť?ůp癷ZÚQ&ĆfŽ{˝ˇďâ˜(aCIç`ĐgŤß™Agç' qířr,č?J˜|éŐżzÍ5×\sÍ5×\sÍ?7?–Y•\ݎśčœU}Ť_4ćʰ-]ńó Ű­)ůóf3Š:š¤T˙cLŽśŒ˛üŠŕҋD,IˆŃpÄ:BçMƒc.[ĄĤ›brÇZsď(ýĎÇ-FTňÁŒ@ř9苑š4zg&‰K.ŔK˝j™“™0˘ňî“ČdÎ@$đŐ=Ťx&çK•Œc-‚ćÁłÝĐDNÚ,›ić4Ĺ$˛ĽZĽO*uWP# _ŔefŇŐ=űŇÄîV]Ż)ĆnEF7ąJ‰f‘[ßZéä G{˝î='űĘPöű{/Ĺŕޕ˝)Ihü”Ćíö79a>đď'ďˇÎ×$ŽI˛ˇäáÉOâ¸*_Zc×AçdӀśĄ­ÓcĐZ§ľuČŃ6nÍŮ,iRśTÓÉÖ6nyV2RgpDç&ĆŻcç‘Ć÷Łńm>ůx$}:Ď żG㡌}唍ŮlŮf™g-vÖI:"śTżŠ\j˛Hż ŇŃő9‰ľJÔ5ś˜EĘÖ`˛Wľ“”Ő–2'ŤwXA–•WŇKŮ´ž–ßRs}]‰s9ŚAx‚64)7LFő›fbŚD$f†ŠĄdњ‘ës×4ÝÇ1žX$Ą1ĄˇNĆ(ĺ×:‰—Âm âŹNĺLş€~Y)ő]"‹˛Ť˛ĚY50’A7ůěN"’ސ™Ě™Ëé Ü$˜t’&–Î[|íoŰźsÎ?˜Y‘„” óNJňц'_ŘšmÎ]7>f02y4pـdË@3¸kCtŇ\ ÜÔÁóOĆň\çîÉÖxíškŽšćškŽšćšz~LYÍ@ÄHŠ ŽĚ"ýv‘"}ŠŽ›Z-$梍´m'ĂAĽr‘R÷łŮč1+JhfŮ: ĒJ“ş‚”äá&#&Ć&AĉjŻúŞßR\•]‚A–QĘfYýŹAJG™ÝĚEŮ ÇӁęją‘%̔RTÜK‰BÁ'â^śÜřRjzYfĽ/’‰éFd-méƒĐΐ ΃žěťĂ6ŔÁ'aFxĐŹ×뜓XśČ%+’ĆĆdаĽƒí‹,+t(K˘d§÷Î&É`"'–‚ZŇĺľ(ĘŞĺÉśw6i‹ŕœuA`*Çŕ}Ŕąľőw9?›sîú<ůŔŇůĺ—޲ݥűŕ'”sď ƒŸ,Ťö#ÁíĆn+—ŮfŽ™Ň6ËeőĽŢIĺ2ĹimcŇńpŹ ďßnü6•żř-„<ůmLžóĆoŃ ˝qbLýJ˧łóŹk*29íŽfą…‡Üy‘žUúKóĎŕÁĚN„°Y$¤ZViϢ^{4ġFŽ.T§Łd1'ÚJĽYůV‰Ŕő†DTOihĂlýœlX°*šDkŮMŮŠŇ\ľSNÄkCŒĹý’ZpÓ0Yöj¤čż’ VŢä1KQV-P•¨–Óa}^äeEnKś—łěÜÖK{Vj9hhő/ď˛SŸŘĘ_âĚYśúHÁľsoQݧĄ´Xť?Ľó—źé7˜ ŕV4“#”lÎ-UťéÁĘápĘd Lz‘“\‚†Đťń5ÁIâ rÂGŔ9sQ‡‹ŹB-áöŻřjžćškŽšćškŽšć‡–UÓRˆjr­3Ľzhëˆ?Ťw1ăó§ÄDzK–0¤ #Çń§ň˘ƒJ3ŔcU~ԍrf RŞiDĐU™ąŃe°Ě“ľ(Ľ3i¨Ą‹' 3 łJđŪŁՃŠ×â'c~ âp:ĎHĽ˜ÂRsŁ–”)JL_]é¸=5câáEe PjQľŹ„*4%şDŐÉDőČJ‚ϢŹâ'śňoľĆZzVm–YŠŰľĚg–YƒŹŢKSETh<0„7+­ŐÔ¸ÍÚ­*y€{Ť]tU–%Sć(ŹŽ8˛łN5Ôęڅ*9ƒÝJę{´’ á1…đ({ĺw‡/7lLś~çvë՝‹`â¨6Îh4Š×šľS3‹@ťmŐkiÂŕÎǨ``ÚFžvű$ú~LĺŽÎ˙z ßć˙8&żÍƒĆCŮoD †|ĽçI°Ąá¤6šTÖW썝˛ó˘|^“"aןE”Íd˝ż“lŐ7šŹš˜(BłJ R‡e .Ęs䪊Y dZ/ëŽ(şľi;Ť˘(Â+ŸK‰ĘH\œF ‘ f”Ő\bxÖ˘ć1Áë5šÚ*ŤEVhHĺsŽĂ‚X5^ő;k™¨ś—˛JˇĘéڑŒŞqIĂö]‹(ťŤŇ{ăŢV5U{ň˜Éc)PZ¤*­)ŚpĆRÔUŘ5šk-!ďçü[*x˝wno7ś<Ů,đe÷5œ.E}ýĂc™Ĺ3ąfH2ŔC™­ŕĆ;žÎGl<Ď38ĽţÝĚ@rçßŮřŸ§đˇ1ůvn¸‡ý„Ĺƒâë6ş˙Q‡&şŃ2•)ٲ”kuÇSéźzj,ŠšâĚJ"Y}ŠL_Ő/Yę H Ÿd]/z.YÝšËę˜Â,§ÂĘh#‚Y-p’u}#ŤĎ7ŁÍÔ?{p_kF#%0­Ď Šl˜xAŽbeÍs‘…iHĹŁěśŃż`ţ$ľĚń}őŁf–Š_@6z<ŰϘ?‘śQ\jgČž:f—oYK-užHâIÖóÎŞŠr-\vÂ?h]W\Z–ĘžŔ.Â=ťü÷?Ýnü{ĺ]5…éÁeXç?ž<Ü9D1{eJ >5W?írĺcŹFh"•Š1i 6›dż#áÄfĚ_P4•zÖ֖ťäškŽšćškŽšćšz~hYÍô)’E=•ĘŠÚ°œŐ›šY —\‹”źŒ›ś%ĹŮýÄ \ °bŚl1ŃÖ D;žL˛J,eЈ7& ôśßŤRG­ŕ0áe'6UFË`FŇb-Pč'yÔ3ąy0ź”łđRMĂŤ UĆX‹nQxGŒO‹39ëń•n\Ż“ö‚ę08šŁ6Ш›qr-W„φž(ĺ8Ó1ąOe:rő˛Ž ˛ˇŐŤY6ÔŔĐpŚŠóDů…•űÍĘ J*›*-&ÚvęrÝŁ¸Żť”ĘgîlV˛]łČűĆ×-? ŹŇ:ŞĘL8<ń1ŘĆQő}ĂsŇeҗ2­@Kűý}~ž%Ý'{7Ft0kĘŚƒ- ÜuŘóœHkňĆt8Ož=v<áÔΑÉocăé'żž'™;Ůôî|ŸĘ÷ăäáĘ´ša-ńYÚ}Ű´:ac8ŽwЂ"ĽV^Ô<Č%ІÚË= …§B¤!RŐ׾+[uuŹÖľqěs‘,§@Ôň)ZJâę-Ev#ľŢC˘˝Žu ş2’‘/GAŤE”ZćeŠś&AŚŇ­”đD1ÍĽÎ+ž­:†Í ¤Dupk[ý¸Ł>řQP„c:ŤßW+ŃŇED™ö†únoôŐă˛˜L?ákEpÖNŽż9˛qú¤78Iš œ“a•žŢć mŤ˛đîţŕ.“˙koü˛+?÷Ź<Ź1œöĆüžüç‡óÔmŻżušâšËśť\Cv<‹ćŤR‹fÉ×ft@˜á™Ć´Á !ú'ůY3Đź"Ť×\sÍ5×\sÍ5˙ŞůĄeŐ_Š]&šŁş#P„Ćɞëć6ë~˛iiÖPE‚•ăëé[ĺěöÖŤŚĹFâî„)gŽ˜—ýWÂp5Lŕá8§;'ą,Ž!’Ž4q8WąÎiFş3ňĆ#M™<}gJCm+[:Š›ƒ+aJpĂŇI‰ĹD­@CŞž;’“şş!Đq<´z<ľ OaZĘ3ćK•ŻĄěŁXŰ €„Ž÷C"Úëő—­ŽNTQŠż's˘ÖxѲË:,™X+m× R×aH@ NCóů™.2đZZuƒ< VznŮŠă ­WOkÖëÝrÖJL´ e/2ĺ2 ěť'ŃżR)GóÄuÇüYYtÍő™~Őј€ eŹ-ĽrdĺÓ3KĄ-Wn|.ÁÄŁę“Ř؀7ëĚpŞçXŮŰžý ţĺýăWŢ$řŢw>Ó˝ń™W­îŰ?łű×\sÍ5×\sÍ5×üŸĎ-ŤwžłECŐŘÄ“&É˝mŮWwœ.I˘)óvUáŢdT@§Ľ´u2#ž3b:™Ę3”˜ł`;š|w!ćÁ”ƁÖb6Ş:Úą”XČyp´NF)x„ąůdDš(ŇlN Dԍ>1™>Ę ¸—g0ă¤g­¤€˛6.KĄ*ľ% Š´D;¨Ľ@çœtłZDyË`¸)>Gĺ`ĹV?É ł~7Żě!´HҒ etíl ¤ÁŚRŒ˜'%†˛xŤJžQľC _ÔëučBoUk#MŮ­ĄŞ•ßTeżu&Ő3úľO>'BëőŢřz3äö…ůxđx<™ë1“đűh G m:#”™ÎŮvލě íwç?ăďÜř=żqä-pů‚çw˝áj<#já°{Ůą›TrNœ°aŞ$Hőwz‚jb™śş4!ŹŕXbÂ*kçęűT0­Ă–)kmTN’މGlˆĽ×iUëc•5Z‹‘ÉÝP-ĺ5$Š]Şß ěFćę-MJMA˜#ĆIäËnÜĐב<č˝ă)u D˛ÔZi˝tJi°ÔFü‰Ú˝>S~@ťădťcócő*łjŽĽgÁʐŒŠ H֢ݼ”ßáÍN<ŒžÉn†Öş^-KHĂăÉnwö 2ž¨t<x$ŃvÜvţď o*7žZ˘ŃyOž`“gvClYľŇŞg­R´@j™K˝ŽkŢTJ%^ý´[#ˆ\öéĚ@´ŮŢ xŧ~~Í5×\sÍ5×\sÍ?3?´ŹŢ˘ú1oyđ&ľ Š5śQ݌†”J#đ6˛ —°D$ wś}هc€*i Ďd†'ÇdÎ`" 5ň<ÉÖ!ƒż=Ç,Żč\0bĽ~ëwFővĆŹ m’´HZLĚŘ3˜­áłěÄIbĂvž‘Ő]9 aúYŞŮëţ3)Ô śDBÁ3Ů´”ĎĘÕb$KQMVŐE íjĽđŞV×k:ŠĽöÔFଔŰRT7kxҖ­2 Ú¤ZyŔ.ŠŠ˘śŐ5A0Ÿ˜_Ź2’]` §§łm†Ze#MœśbăČ,KwR€¨gYWo]ůöß?NzUç)wdᗄQË_ţĚČĚ łŃDyćŤ/ŇE*¨ťlťŐąiŤ{–Ő•šeSŚHżô’c˜ŤŚ‡L˜ľÔ> wňIäU¸íőľ1hľ™DuBŚ:;ÁmŰ0śYY:xGŤŢŇ&ɖľŹűć€q́L*§ŞÁăq˘^K§›ŽLng^Łn.茸3…óó“XCtCUiď;ţvcř΅1'q|ç:'lœ÷óäĘżÍ3śzź˝MFfÁ˘äârĂQŽRŢVŇęZĹɔ7\gőŢúgpŇĘFťrfÁ AtŐÍHÖáE&¨-O@ŹjP÷ubş-]‘¸×{M輌RP"Ő¨>RóĘ~ EÜe}mŒuؒ˜]ŰňŽbL-R­RůP$Ik7.T“*U!c+7*֊°ë­~^­ĺNוş19ĆYŸÂЃԳłŰŽô,Ľ~Że-ýaeRW*§n$S­ čŤ7ĽLkĐpv[‡kÁ˙xÜqĆʈÖáű9’ETŽ;ťźóŽđ1˝~>o䨃ŞçďÁ§[[×cSZÔ!ÚHĂ[-°šçRKłĆČR•›Őőt{*¤Ź× ÜëI¨ŽańťţŹĄŠ¨í5ŻyÍk^óš×źć5÷üŽeuĎÁ1WeĎNó‚š8Fˆł›P"d︁vřΈ˘†)畜Ňř žŕ33K‘ě㜍Lœ6CŒ fô‘ŤÂbV=… ŽŹz¨Ĺҕj 3"˘ş,#˜™„Vć2‚‘Éžn8‹;šôt<•ą2§P‹Ăę°,ĽPĽ–íÂÓÔlVrrş˙ĚLšŁ*ĚŠ°rśš IĎŻ-ĺą Uš…Ş‘•%‹źŻüçů › ×T\•&pšĄ6a–Ímё7ĺݍ}CŒŰVJ}0Tq¤`3ŃË^ÚZŐäôÉýq‘âd–˛Š  ´•1‰ëÁÜvđź1읱môM‰hČPŽĚŽÜ˝Ąb\ą37eÄDýX*o*<¨Ú‘˛„'ƒĄ+ `‚äEŹ,ŞÄ$}CŁąóޗ@E8fbŮšŘđč€Ő󖟙ÓʤVˇî:“@ôŮĐŤËJKМ9J™U]Ô]h ^jˇ)‚A”ľT)BósÉńUÉ$ô˛'[ĂŹ3łÔНHđŐZďžY‹*E US4GŠďœüďţgZŠđSU)5qŽź¨Ź÷˜+ IčAŞ1ýVćqܝŠFŤT0‘J¨ąI˝Şs´ÁœZ9j%ąeŽ>ޓḽa*ÜĎߘRöć G¨×&Ňšq§'čš #6ć6‰đZ`ĎQyiŤĚóSţÜVŤQ™RYŕ2—Iď`&ŽQ˝şe_ž+Ÿí+X0ŹYŽň˛:'4_Ůđ'˜k–ŸJjDaŁäy"đš×źć5ŻyÍk^óšżk~ײú6/D•›&Nc"ŞĚĆÉđ“Í­:,#HŁ€F}Â8OF–ő6Fđ9)˜ Eímłę$EžŔŠZ_„>S"˜˘%wH–9–ƒÄŕŃ+oK)#‰ )Ó **f&.ÂN”ÂâĆŐ :F|ĄRž7öü[Ý$’ę"…n|.Ďľŕ˜&›ŔC…) ‰Y”25#¸"yˇş ÎŹŸ+—­đŮJľ´zuŃŞKŮ]9€)Z}¸#Ů~)Ů IDAT[˛ÇŔMŘU8Lqšˆޒ÷Śčœ0Ůf,+öa`ޏm„ŔçýAŸAŐ6Ž&8•ů‹g•ďLż1÷w:˜Ńůk˙ÎÇ=é4Ҝź҄ŠNŠAnh>`$˛+CŢšĘçMäƒJoôerQ z^Ő+ÝßhółÔŰ88ô˘g+ŐN x˛ÓäbZ-ŞO{śńěM-ŇŤi,ŸŔs5TZ=ęÓ⍭÷DŹjCWÇf„2˘dUŤš!)Ť,jH [Š) NĚNŘÌÉfe,őt)ŁâEúm;1ç˛5OÄ÷RfĽÔDĄ*†rŽ•„]ŐCśÁź–ŞYÄëZĐÖ˘÷ľhסԖz^Ţ@Żú}ÓFł˘ňşÁĚęTmŐMĄ‰ęŮŘéčůł&ëůÁ Vઌ`é5ŻyÍk^óš×źć?c~ײŞŰňٚLş2…Ů/$‚kÝ „]J‰=QēǘŒHz*““!eɕˆĽ)ůłŞĽ÷ňÍ*ô13AĘ<ˆ–ϢŒ•¤Š’ăb˜—R—eÓeeËȤgÝ$+pR˙őľg^QŞkSQ0#§ňŞ&Ľ¤ţ[Ń$ąÔ]YžQ!ј¤‡9*Őú$%°śza…Ęáf-ţBŇŚLcŒe[•"­ş)ďŚřî0ŠäKSëFůИ‰Ëşśl4š3y¤3ĐXSގ |'Ĺ­ÇH5Ž Ňœ.ă˘k#f˘Ž|˙śŁí­čłtĆ4†HănFˇƒS•Ď8ř§î­1F‘ĚÍÁç$U •[‘rÇ"íRöń°ď0˘ťHN đöEÄMF6\Ł˝áy1mŽşî)+{Ů †¤N{*ŽËâ-špYôće ´Ż…Ž:MŤ#U¤¨ÂHC˘—}ÔsœemUăŮ*Ϙ†Œ“Đ “Ę'?-óf‚pRÇ5mŽlU“3ODbs'›žL=Ůż@AE N0#㚨޸'áʌśK-rç—m} lyb9pjÁŰ´ăFŸF“‘ Š´> 4Ť.gˇÎ”Ę G(ť\œşŃäiz/ŤřGĚmsŹ÷ő;Ú¤€jbU9u_˝Q’AŠ^ő;aV€ŁyŐë/m‘ˇ•F0Íě4kĺ€6Ż×Yę€ËÔő,Ŕ*ć0Ĺ+wúLE‰Ëú+*ŤjYŞŠčĽ˘žć5ŻyÍk^óš×ü/›ßľŹn1Đl8“1$dr…‚8-&nŐOxfpQšŐńč|ŒR”1Ë.™4ĚY€—“˘‰î9™cUHěF¤Ň—…ť °sâńƒ ů Cň pb6 qáÁÁ/׃űfœrđcB׃ŒÎ0CrŮYŐśĄóŞě!wb¨ět"ŽŞc‰Q`ÎŹŽÓDwR˛ÔđœhbĽ@y2ًœ+Qľ)űƘɖ“ž^˛Ţëu^ť<ôl4™¤ľĽŔ ¨ŐrŚŽćdÎłrÄâU ăK} ĹĐěŕ;.ĽÂ…îë ÁękTëőĽŕPâUSS–ÝůĽžúę.ňn-gneUWŰę}yäčdi’'˘ŠÍ“Š ‰j-ŞSžžeíś–źĺ/źšąyĂ"Qŕm˙F¨ńi“{‡Ď™¸M˘Ręéď-Q1Ţ Ä ~6"01B6"“ž˝ŽĄƒ†në÷kí{SŹ.§TžX *uĚɸLŇĘú/L\W-Ju‹t ŰĺVQ\˘ěůjô ­>T!ţ."B7Ť?řď˙ţľ¨žć5ŻyÍk^óš×ü/ßľŹŽ„Ö/NSTĘţř˜e;t•R2DZůFNb<Î\9`,R(‰2Syˆˆ‚pŠ@”łG–˝tö‚.Ej¸…łQjPŁÔÇ]3Že-6Q4•C™ł L|;ŮTX‚* lZ‹a1—d=ďüş™Ţ(5m×üRZ xkpÍú.Çę[Ü´,žŽľ8Ćß(›n†KÖs–ÚťŹ„*Ľ:‹-Ĺ´H˝7ˆ$ÁP'ô¨9ט|váÉ}DÁƒw&ÂĄ°7ُ•%ôś:<OŘnÄćĐvű7îrĐŠ^Ę3’;`!4m¨ÚńgƄžľ¤_™œM:“™‚f 4ć¸s…a"œęHT’›&ÝhÚť!ăNl{Ő˘ˆź—˝m•ĄeÂßŔĹÄţý⧋ô=–ĺżĺ ´­ŒnŠŠnśěđ0c˘V*t h›c$™Q㯝ʒ m92Q“/ "¸¸ę)śŠÖçL"mżć5ŻyÍk^óš×źćďŸßľŹ>ćDT¸04’+ËQś7ÍY7nZůĐ\ %Ač1 ܋02+ËfJ˲ËI&cţ„ęČúłMŞŇډ”ouŹN’C•žľxzVnÔ2 ٰąşś§m׍CÁIž{)B_ÉŐEĘ˝I`IQqY¤^Żz›‰JV?Š•Ňc*ě"Lşs$çśa îeőLrý|—ĄôjŐ›fˆ§îtŕ‘;?ôÁŕ‡8CœŚ=Ľí;N;ţ+œ÷¸HŰhzllń(`’tDE˜úÎf“;‚Ş×ÂgJJY0/ÝCŁöŚŠĚŤě–iVśí(eŮüŮo;x÷ŕ]vŚ&stŢZĂ˝n࡟UĽJ L 1Ą…“l„:ŕ/\É=ŸÜ&†ŤĄ-VŚ7„!DP:Ą[-yŃŮkis/PӒăAŻ.ՑĽ0ĘŞI„ľP™L,Wf4'’eűT:˜2‡áMatÔŹŹé˜{UڰŞ[Ć|ăIľŐݚšzO#ö<~Y# ndXI9m#râqÇTIr)e gv´˝!ŃöŽÇĹ(ť~O:ß4řŁß%ůÇcňnHZű#"'ż]“ ĺG˙Á5&#'Mž2Ŕ}œ„9˜Ń}cʊ(saäQ‡0Z‡.ÄŹ`QâK1βCťŃä$)˛,j°’˜'”|Şm]ŻůľĘęýˇšĐ§"í9ˆÔĘыą\ ţźÎ™X@š`ŤV–"›%óR‘„\ŮeĄIpIŁ1ę÷-§ĄĽÄ›V–yfÉK!V ÍŢZĐŻyÍk^óš×źć5ŻůO˜ß—YEńLB’F"‘4OL ‘ZÚ|ÝŔ‘Z˝œ)¸ŐŸßŃ/˘kJ~Š[,›ŻPÔ^q,‚3•zLSĂ zT~ěČľ0Ś™R*éa‚‘4­?;ź’w/pRŁ–Ů&ÂąßĒIV;G&Ś‹Ju,žYŻŽ*XU˜#ř1&âʉ27ĹNßQŤďSvÓäĘDLk!ߏĽBmüšT~„ňăšĚfTśœ¸˘Â.ľÜ‰š’‘°›p7e–Ť‹Ü›tzÂg”fâ"+Q!TöS”›ÄR@ĘÜČ„C“&ÉÍjĄźšňn%Ň4ŕ_–ŕ%vůs-y˛sK*¸˜Ĺ˝Ë°k2 şÖ “d¸s~kD–ĺ÷!•ĘŤŢIQZVŽvËÁî÷ ńžÂÂ=7~ľä#ŒG<âW:;o|öÉ/ńŠđŻî×Ř91†$Éݓə7ś~áV˝›gПZý¨OܲYĺKíIĘĽňŒMýŠZŠ š™˜)Š­`B̂‰”e8žĂgîľT|!ąćĘX3ćÓ:NŇŢx*ňeé­nMůůŕ? ÍZŹ"뺙Qmolœ•9uwD !]•7Ő:ŠJŕůIȆ!˜ď„Â6︕–ťťńGkźĎ“?űŕ›ńfAö‹ŠÎšœŚ˝3}pa4’˛‘_(™Â9ËĆÝSQuLËgŕeWŚú|“˛óŁFfŃĽ%abŠÍ‹P˛újżőyQżäĽ*OsČˆëOuUS‰*jeÝÔß×őŻĎšHÁéL+hSÚV‡6TŹK0×Ď-Ëž{Ź>][YwŐĘ嫖 YĚИLŠŞŠúü¨ŸŤiŇCÖÉZ¤ĽËâĺ~Ík^óš×źć5ŻůO™ßľŹŢÖ ˜;ĚŠÜśRŽ 6Ԋ¸şKŕJĺűś†%\Ŕp#Ť{u-›Œ˛˙şŞ&ňYeČ5“Í @”(ňe늈şkÝüť$fÂź5a_BŮ^ÖĘŹ­ç!<)˝Ľ´m‹ŽęVĘJH-ČŤR– ¤*ÚłĆ\Ÿ{:óöN7ă7’_CWeĎΕ{Áôh˛çE’Ä|ăäď|făŠÎĐĆePКd˘SĐaě‘U€1„śuú< .P˜áˆě []+‚-ÉŚďDNđHVgGŤÁÜ1š°,ăčoöĆM…ƒĘoÚ¸*ŮD“礁×~ýƒ_ň;wŰ 1~ˋ00ĺâd"ƅ˛ó–ŸdÖk $Sˇz˝˛ňż&Nò—ŐTô‰=âg Qĺ -OÄߘcŮWjńƒ˜ ţ<ŚHRŤę„ř›*#ł‚lA)°!r/tvÄ|=â‚ď;œ)L5ş4ˆ‹ŽÂC…Ť—mőŰMx›ﳴęe96)ŰŢfĽŠ<58•d“‚9mËň[uĽÂłŃ­nĆu7LঊŠÂÝ'Ι¿áŸóŕ6N9šŘp5d(=Š šiœ&Čn\rá˘Á ł2}‰Ň˜ËÁÚő(;n@ćNjĂ6ĺ;"ƒMޟpšŠ—d˜ ů˝¨Éć ˘ę:°•‹+‹/Wr ˜7î}°š âܟ>WĘ>i8縸iă`ňä–ď:8¤”ęMŔu§18š’QŻWšó˜;qÝŕş&É;˙Ě?đčĆBŚ3ÓFe÷|jĚŃjńą˘–);ę“>AľěʲdoOâo 2‘ěe=ő†JŮÉAh+g<)HhuřÚĘŔZsPÁÖRŤkq-Ťś,ylŠ1G°™ĐgŞč|ŔRQŤ^ŚVŠ&%8ĂqÔiy2bŕî 5öÂ܂Ղ=1ä))Ş?ÄLŞcg;¸łĺá]ď–üůöď–X|Ň$ƒŠٲěÍöƏü8§52úĘô™FoDţ‘3ŕG\\1čžóYľ-V]ɨ:&‰Ľ[ţ„%{-˘ă,ĹŢŞˇßp’ĄŐ‘*¨5FV•gX¤ J9A´Şar\ˆoËŢűô?Ô"[Ÿ39'jV ,3R žäŃI3vSČřĘgŹi‹^‹r<ťŒĺgćT]ʁI2͐›O‹łČú~ĽÓސúţg?i_óš×źć5ŻyÍk^ó?=żkYýžIsAŹÁ"ń"†GeťŽ>ř΄ćäŮŮ~›ÜŢ6vsĆŰÁ/ż<ř—űĹůč ŢH#ů\Ö`=ďäŚüéŰĆ{6n18ŁT٧˘:]v`UśޕRٚ˛‹°kY‘Ľ¨Ző˜šq÷ĆÝâü5ýĆŻ Ň~~˝vşuFűƔœkÎôDĽSšZŕźĹĆ!Ÿ Pw.‚OŞżń1ŠŁ"¸9ÉĚÓYT×ĔŔ!j™ąˆŻ°­zuD6eĚň¤ĚxԍľĚüِ ƅçNŽŞVsV˙jŔńä˝ ßóÁť jUłçŔ˝ŃL•Ců1‚Ą[ĺcĹřĚ?~šď|†ň#n|¨c'¤r‚1–źçŐőj\`ĐŁě¸1kQˆŮd{ŞĹ”=;QĚŞEŹ\nŤŐŽľĆÖűĆŒQ kvR‚ ăŽjA”"­¨Ć̙4ƒ>Ăƒ“9ƒ —E88ŹłŢZ”—*¨"4(“Žo¨*6°}[Żľ“ăeÚ S§ŢČ~ÇVîą5Żî`߈(‘Ä“?]ő]˙E'”´űśÁ÷Cq/UÓTüőüŕʆˇĆŻ(?소ˇľ|‹]Ě ŽP>ÓHťŃgD**>P2mQmĽ–J+%žŐĘ(ă7ĄčWeŁ3Ôa^ˆ–ZY kzĺýšŻFžăóAŘVŮuoőšfeŚuYzż@Uł(ÇóIčU/2ľ”M¤ PM‚.Š’L̍gŚ`ŞaůłžÇ|}w‘uÍ!Ěkўą <]ÂOŤ÷s9ő—Ĺ÷5ŻyÍk^óš×źć˙ˇů]Ëę?2‰˝€J֒+Ľ0ş3Ť<éŻačŽH&żöäGŸh?ÉfܡţčüőŢŤÇ1?n2ŘÝé* ÁřěźÍÉ?ţooüW{#¸˛ú)ÇŒŞ˛R„ŚđćĘvŁiŐ⍲ĽŞe´š}Łm Hţőüß÷俉đËö—˙‰™w>Ă@“!!Ő*рŽI˘é¨ď´čŸně}Łn—é;M…?ʤk)„*›'ĹPVDOf7ŚlhSČR ÷vQľ-š–­7Ä+'tŰŤZEëŕ@Ҩ˜ç@9=q6bÖRÜŘěŔťٌ›$přŁ<Ř]y‹dó†de˙ÎzŸ˜S§~˛›ňƒ‹Ď|̃‡źóטüȲ*ƒt´Ęţš"RůVľÁœâ“Čk1o;ˆŁú`r,Յč†dUŹ vÜŞŠčŞłT2™ô4t˝çęšv.ŮŘ脔B—TŃ ÉˆZN# Ňă ˛Ó4HQÚşŢ]6äIUg˓ÎĆŚs­ČľěLlőşV>2ü’“Ô ŕ{˛ăۘó*˜—CŢhr­Ľ,!¤˘ŞĐň$;]ŞÁç#ŮCše§1QÝ3ůőšüľ ˙tN~Ëä4áCźşVÍŤ#X!"¸Ä˜mgô‚5Š;‘ƒš:W’Ęś>Ăť• ÎU™s•"źŞLxRÔ°HČ^×F§”ęœ\ ŐZN—ŞZCłÓT€jݘI ő{›‡śŃ抃*[vÂ*c+"Ő˚“9jN†ŹĽ´,ŕ™YŻ_>#ą”ě\ŃEďfњYšUuEć,w†Ô5ú&FŐ\MäoţŐKw}Ík^óš×źć5ŻůϘßg>ęö7Ć IDATŻ#ĚvSTŤwVF4ŤżtĚä›4öo7ţĎƒ˙ëăÎ?ýř żöÉČF—‰sčiŒ‘čq˘Üˇß¸Gb1ůĂůFŽAäÇ9™ç${ÁSŢŹłeŮţ~ëĽ2^Žl"Ř\ŐäČÄŽŮ6ž˝ßŘü9“.7Nžó8'—Ü*űŮ6ˆ^jPŒĽŢ8š'î űRŘv:˝ÁLg†°…Ŕ<ٚ’Ă++íŁ‚śÄt´-(R(4éœů†s•}˜Ę։Nš<łAzőSŠŃpë 35KÍâA’\\4_ĆW&Đ(ĽöFrź1ÇÉéÁ%“ŚĆŠž[ۘ˛1ňÎ}Ě>ů1Ÿó`raАŃ@Y›jٓ#qî$EUMѲńRcÍ ŕ&ŮP&šŁ2‘q‘bˆž™źáQ@Ł9sY2ëżs~óÂL!4OÇćß`­7"i›“QŔÔŃq1Óć4Yś\Q†T}Ě%;']oH,Ŕ“5lœ¤mŤúÄ0™L;P‚ĂÝŞËuťăDÍhܑœ8ŁŽ:*ĆĈČ €Ý”Ńŕ—šąg0݉?hâ<ƒßNá_†ń‰óá;‘“!b2˛’°şá‰2S–jŻő~ĚĘxg&&#u)يš!cĐŽ ˙R§N4´Ş[f€y]ŤČúZ•É@8čtő•1UŒ˛ď: œDb3–;WP7$Ë:Ž*mÁÎFÔ狪T5oh']ňĚť.Ľ•úńę}“Ś‹ŽúĽŒf.SJBőŞ&ŞĘŞüŮ]ő7“TOsĽé á4Š~VÍ"@?ÁlŻyÍk^óš×źć5Żůűçw-ŤŸęłŮ¤TË&EŢU°‚Ď9PKć ĐNž9Ÿ]¸Ďޘ’čüŔvaŰ˙ÄÇ˝}0Sá›î|×ŕŕ‘ćÂuQ I¤™œ˘˜ú†Č…2˛łÉƒ+ˇ‚LĹ(~i8˘˝lˆZ 1› Z‘cI\„†0qmdvĐmĺ<Ť:čˇyqäрtvÝ\€Ďä×89cbńdSî}ňë88Ľ3ŇIot FÜVîoϢ °ŹÜ“Re-ç)†qr…á:Ú"öŽ "Q2ÍŐKєkË0ę’5bN6/–)Ěń óotîl¨t‚%†e”:(şŔKą >es{R…]ǗU١ň­[U…âq'¤ C1ŕG˝V)ő|mg—]ޞČsÂ'Žx”2*ÁloU{bIĉ`4=Iœ]Ş{Xzşďˆd垯Éç8ř+žŰwúuGŐčžľŠ:.R¤äŮéćő~Ęd— ě¨%–Y˝źOËóělŚ uIć$ľ–ď@ËVŸIęNł^5TâuÍHÔ›“š D_´N2đ՝:‡‰Ź(’Alumƒn˛F Ś^š]Ę^/šbň¤ńš\bV7ŻXA‹–"+"ˆÉʡ.ľ¸Ââ -wČĎl+ě\Šě hUŘc-ĺUškq-Ĺk^óš×źć5ŻyÍkţţů]ËjíeVő4›W­L$›ůS¤njżgrxŁGđËLźÍżńżwř×ó2áąąľ|ňaƒ_đÉî Gwöo7ä88űŕăq§‡‘×IŸe/œ$#…Č‚+śŹŒ -asá}ŻËŁŢřk4ÎŰɍ˙ö0ţŔÜHĺ’D§éQ”\ƒs:bžgĺ ĹYٸ RË:f –ˆÝŽĚˆ\ '¸Âż2´Ă,;–Ŕ1„8ťžÎTŤÇÄÉ4ĚęßAe:'ŁlÇęHje c zPĆW#çŁ&RJŠ›ę<¤*‡RWě8ÂźNN\LćétS.URߘě¤ćjœ )ŔM`l2HÝɘ^UߢľŔŠ^ĚÜhŔ”ÉâIÄDĽhĚÂ,e{Uż¤’ý‹ +Ś\Ą4[=¨Z5)ĆfÂ5œf“ĐĽ¸ÉI§™ŕTÝ VšWd-Š)Jc ŞE5×g#Ë$tg“AČDY‹S1:c‘›Ÿ¤Ř$sĂrŃPK͓Ă&´ŕFăœ\Ü3‹0;WŻg3ČÁă‡Rňá;÷´Žq1úö†´ŢďÄŞŕq5ć˛+gӖ"ŸÁ0Ż,mNš !9f^* ěšL`,şśP™Î–.M!VĹ ’LęÚä`JPΆšţÜHJ–evcúó`@WVWÍHœ-/L’žŠç@ĽHŮŽ‹ŢŤFFőďZŽU!ŁD˝1pŤşž ­/$řZP÷ FůěKŠĽ f(0*‹/őu°–ka—Y ˛,üԓźŐYKęÓLţš×źć5ŻyÍk^óšżw~×˛Ş ť$› ‡ěČtA€DŞŠ&„4cP4Ţ7Ťć4řƒ+˙ŐŽŁŢqNtoœoÎżœđˆwF¤ń› ăä>f-§Ł#ŽDÖMŕĚUI4IT’˝)7…ŚE îłmüpçôҍ˙6”_ü5’ť'÷ćD6TœÝ1ŻjŽKŢ1šsq0í;ŸL.oHNT’!ˇZ<˝3ĹĐHÎq'uC¤#Vu=ŚÉLEł“˛Ő˛Ł —NdA–BŒM.$aƎűɜ;…Š*caŞŹ%ŘɨnĚńřęĄjĽLɎŇ+ i †Đ93šŘüËüŹţPÄn\şěĘŠŒ|Gô"ć…i#qŢx4’ŔmŇăX–ă"§JV7­ĺdƆҙśĄë}‘Ô&fl­ŃgĄ’F›t:ÎdjĂeü\`łŹ–aĚ¤Y˘ n5Ö˘îăN×_ľJäӖiLq<;hľtKU´lRýŚ378Ă0S˜•g5dv„M:Ăoxl+Ĺą ˆ^śäŢqO"•]N\&‡ đwZN"&“R‰ ŇęwHŚ fʤ;×čĽ6ÚNZAŒPç:ţLćD 105$`ęŞX‘j ŢbĐŁąťŮKĽ\œ‘f˘ž!ůÝČĐrED ˘Ľ~KѤ5.ŇZuş˘ Urvš)}^¨{™ւ§$ĂăË­ŞhT=Đ\E5BłdhŤE°Ä]Śnx”nY‹P,ňŹ´]ŸMĎVäz\´Ţ˙/{ďÓIrlwţĚĚÝ#*>éh1úţßM -ôžČî. #ÜÍlć‰jŽćÖ šŒť`ńtĄČČHœź~˙‰ITŽUó ňKěÝ܎˛ˇ˜u+ŠmOö˜l˝´đ2VëśBߝɞżŇ6oäWů7nܸqăƍżFVM°VŞÓ4C—ăݸP<„š’k âđ9‹€_NŽ‹đä[Âč‚Ćh˛p3ţ/MŇjB#)ťěÚë ž™Č¨R—)ĘŠ$9ů‰k0ó¤IđTĹMř”Ćoüǂ˙Ąe-YňoŔäĂżńn•ďLç­Żš^‘†ĺ,['že1TIŇ:üA"ŹMřş>ůđď<ôsˇ§–Í09^…¤dVĆ҆VÓhTł2^ľYâ-­]€`VĆú˜>71ě4‘=ƒ˛-™!Œ.\óBĹč⸠Rćţ°Ěř 9x NĘ@RżśA3 YŽé'"RÖĺp­Ç$‡6wCe˘ş7RuíVW'˛•í˜R˘äŠ*ƑŔłJ,מ‘Q$JÓWňĎFüÁ˛Łšbs+ŽiĽÄůĹŃŽş78xčä3:=•*Nj9išXzěٙdQ;¨‰íÜď+ŚX]‹iŚĽFC5JG(ośj3xŤĺ!‚ť W蜼 „\|oŠIăÁç ÎŤQs/ä&‡9Ţiq1Ű[jXĂŠYěĺŒčšLŤrł#ĎĘw u]Dč[I^Ú1‘mľ†&ťu[‚! ę~MCVbVÖ)[ŹË ŐŚËÚzĄănt źu|]Xë?[|u+ÍÔ—Š–jl•6šAÔ(.š`5cř…Jى!јĽĐgůtǎƒtG2x´`QĘyي¤lćęŽďŸ%Eë=Ůj÷XŹăYYXš¤ďÖiz&Žl­÷㮝^™UŻwÜöf~ڃą:ü¸qăƍ7nܸńOă—Čę§\šUU>ěJş3Şeeö 4ŸœÓáŞ9%éŞ<´ĚŹŽRjŇ\ŞXž°šňáGtţW\˘äHBßq3ŽH<“O3ÇâßxˇÎˇüƒÇZ ŽRÚ䍫5ţ=;˙îÂ_ĽöľƁúbŘE˘ŐäúúH*Đň"Ľ{ƒRˆět™ŕIŞądÂĂ>˜1ř&C2šx 9é\ľ#*^U˝ŐPş"šä`h3+cůŸÖł]Žú€OíiŞ6žŠhŽ\ôވÖd‰ńäĘ^VdwV…ś¤}+BÎ[IŐśł˘ąm\j"3ŚÎĺŢ™ƒĆ, ijţľSZ9Ć@äEVV5gÉ`b‚dٗ‡9.ɚ։UűĽ™^ţ3 uŞŒHö÷ŢťŁÁé0Ě9˝J¤$œw›@ĺ¨ĹĘđIcrÉąIq>dVž1­ÓóbŚVkp ]¨Ň(×Á!“Á!“ÓË ŸáĚTfɜD\z2ôÁĄKe­ŕ‡.–Ă­ÔâşH_Š´Š3ĽcdĂĂid˝$ą`S•F÷ĹçԆ‰Öoů„*Qř&âlLԊ’‚„M°Ż×Qô@ňBň$ÍĐ؛ˇŚD*Ł)‘Agá$íë~­ň1×2ĂžI0ÝĄß9Ţ.‹)˝HŚCë•[–<Óč/­Ň”ôŤ?DČnHL¤ÜǔÜAŞQ¸ŽF'ThLŒž_çIf'Ä!Fľ‰ťŃŐ=›‹ŇwTeT‘RWxüÉčťv`ţ•™í’Ź¸Ű€oܸqăƍ7ţř%˛ú?ĺ[)9$Ý Íä›V!ÉCHԝăüÄW ť…¤)ݒ!‚îÉ+$f°†ÍjňƕżÉ˙3żéw"?´4śČÁH3Ä Epś¤Édx§5ĺ/ Ă ¤óäżđť “˛ř­HşD$ŞY*jđ3ۖ˝,Ž—źŃó,ťhŽĎX^mި.+Ş)=Ą =ÎęAZ‰čB4›¤6š8Wž3ôw¤o<Ëʸ­– ĽČ^€L^ڎˆ•ú–¨!Pł58dĐDɏ¢…aęD eˆ.ĽYRŒnĘÓ ŸŽjŇ[nU(pXž@"–d–ýŇŹš›U&SM č¤V›/°gg ( RîĚŔTI1"˘2ĽŐ'‹ÄEęŁJZ Ôâ•%ĹŞ))Ť,Úh™„š‹¤s˜ł<ąf &ŠĘçzďXN–hŰ&ęc•B~eäÔ^YŸˆ)ŞZ9[œŤ|pźö6'‰Đ8Ëž xÔçCćV|'¤s4a؉˛€/œ%É'ĆĽm'<ŁdÜUöăÖ wçĄ^™ŘLJL,şŮiĚ Ú.+EWf„$3œÁbŃQŮs2ŇP)íQĽSĎÎ ÔŞÜI:-'š•[wĄYe‰Ľ˝rA„ YŠŤćúĘ îőĽŸŘűŻdQHCĘú<´ ˛Şü¨ěŐŞŠŚ3Ո„ąĺ̰z)ą™Đâ"ŹU –Á/bXĘhĹô$$ůpcX)]żÇƒ˙mżéÁoŚ\ůĆ´ÄWv "ąxÖ܇.ţđoGqň›ƒÉĄŹŤO¤ëś j5­Ó›3w.1 –|ßŐ7U4x’Z$vE+QňŐšEĆ.y‡ŒÚípňÎa?¸8О´xB*Žo5—"IËœcoV[íňAłÓRKŸŞÍF×oh~ňUw, ,š Šy-†%ž˝H_‘˘ő5Q­ĆŞIDКî‡> q’βjOšNr&2ŒIŰł3Yí¨RĘd:-^ rY`Ĺ`9A5M#Njƒ×ԎYÍŽĚ:´##Iô|î‚aEť Ń4h)ŁH ş‹tŠźš ŢŰ D–ľ˜”/6Zó2Ň5ˇŐľž#$Y;žú ĽÇC¸Ş„%օŠÖśěKݓ8ÂĄIWُ›Lٖє*Î:\×Y–\‘šÜĽ­ ą˛żf ü˜ŃüBL^ÍÎôP9T•Ę.ĺh{Zœś›pUžf9šB(ÉK‘Ě*ęjĆÁbćUł?űޑ¨j$c˘ZśŐĄƒÚW&őUb¤é՘L•aEÔ{ćB8díąÉ¸ÔA‚+]Ź,mäş°fd,†ÔŽ­{=Şj#“R3Á:pi$ś•Z6QŐ p!ťVŚÖkőł‘BŘkę)7 Î4†ě™Ł ÝEKŻŻ{ŞfHěC8ĺĐřĘÓ޸qăƍ7nÜřçđkd5j+ńĘäôŔÝÉ났ŢۃŤB˙CœA’Š ”źľ(ËŻƒXg&Ŕ^ÚYZ3ôIç˛Ń 7FŚđ°'ƒÎÂxă‹™äÔڀ bNL0˜´ćLĆţPš4],Š™ˇPŇÍj/ńÉ=?kŒüŁŚcLÁ˜\<č,– DcARöSL}§Ç“ćOlW \шHŇ­/ÚÎĽž $ƉŘ;…ľÎZšvf´1=ń°"ĄéXND!ě Ĺ…Źě4u’ÉŠŽŚÔ¤ đĘjĐâdI/ľVÖ/"´lÖL.Ĺř“łQ˛JjjÁŐQëČ.3ęâXŤLq0đH"ŞÄ(¤’jŠhCbÖą\$™”ÂźIN“ŔpĽśBW }Ô~ŹŽ'GӚ“q'ĚY*k#ËŻ°ä 3tžčń ¡âę,Ql+ÎH]3Xťaˇ3DńĚm1_˜" Y>Ú:€ŤŇ"߄>ô­.žÜń­Kç>0*+md˘2p :ΙľE|y5ó>ˆ/Ž„‡­­¨;˘učqEÍ…â,kFoŠśÁ\†ä@ĺÚśŕŽČÄDŃÝÝ$ë`LŤs3Bę°GŁl˝ÖvůŇźđVENőôł˛´Ţ׏T˙Ić´ń˛ĐWžUw~ufŁÝ}Ŕ7nܸqăƍ˙üYýwŽú/… ŃŹž!<łfAD‚–*‚iRÓÎbHbă á)0ĽhŒßä NŤY‘Ŕ…—Š%kŰ\=4=Iƒđj}MŸ4ë•u 0]¸7"ĎřÎ÷öá4|g%`˛í™ ‹Î#˙@YËA.P &o }A”¤srĆůS˙ –ž"œE(gbć„'Śťát—(›„˛Żj–í7.’MÚtoHŞoý§˛œŞÂ”ƒđ‹Ń„šŒ=.Ęäl˜ ‹ŤHĄ `a&\KňŹčjNŒ‹TeŽ„ö¨FVƒ3Wíi˛p9x4¸B‹ŔHŕtDzYŽƒRĎD‹¨fŠâä$–Đ[ľ+ĚŞhČ/F×ŕtĄY°ä@<§Ą~ÚP Šš \ľ™VŮCŮvSJŠF’fƒ74.˜ŸH; 'Š}+Ýěůčmç+sncóśa×ëľY\ƒIłÁ)†Grš`j;3›‹­Dš˘ Ťl‡[푬 –ď˙ţgО” Ü‹œ´VMŞ%oUł'ČśW"˛‰ěUŠ$BÓ"/ćŸ5ƒEPĚł’Ô€IŠ şwMIDet­rЌ¤5­Ň'u‚ĆƒgŮ?ó$íCœđ ›qyÍ}<ôb†Ö4 ŐՔ)‹ÖúÎ ]‚˃aÁÉAOߖK-KąÝцĹĹʒŐ軏KD`Ľ|=ÖŤMVđWÝäČş]¤ěkaU0”ąŐăČÚú\™¨5r>Éö†ĺσ(D,¤3ľ-ę‰[˙*oŞźvc-§5­v^jƒ6[GŽ ÜËX›4Á˝,˛än˛Ý ł]gpÄÄíé$3H­˛ŤŽľWëű€€Úś.d,œFx˘ZD9 L¨Ă€˛pżžížţ‘Ží •NOß-GAžŇ1h\„uD”.ő|#eŰźëřŕ ¤s-ă‚çd샂lĐŽ•¨•šŽ­Č)Ä.ÎъP„Sˇ]=EQŠ÷f¤Ň_ Ý(Ißrš‰ďB0ꐅ,{:•W‚E˙zÍ݇•ąŽ…â×5*•˝œŻtë7nܸqăƍżDVS’)L1œĽˆr  ľ9ńÎď:NâˆtŒ ĽeŠ"B_ŇíY+˜ý;݃•­˛ŤŇ‹Tx"LˆŹ¸h é;‹űĺ‘dÇIeO`đ“×ě­O¨6Ő\›ŹDîÚŻ źŞ|*!"1SVQj:čzÄhÍű˜Ő÷‰Łu#Öš-ŞUň¤,4q2”´˛WĂ”úĆ(UTuŤKÉVÔjŹĂŹĂWE°ä ĺb´"ç×ڄQ[=î.{šůÎ!“nUŽĹ~ýV*CŤIחÓň˘Š‚TŚŘŁĂk+Ő´hƒFҵ웺›~A˙4Ą˘DDŮ|#J‰4C˛ČŠŠěFčRPÉÚ.%ZŮ~_ ś_sD ůĘ:6MÇ1,œěe~˝ĚeIL ‡f5 #RśçV­ĐfR=žfű0BÚ€íÄÎR×ôŽŮéERE0ą"É*_YZ ËMč'¨ŇÚ&§ÖQżH›ŕĹ~nű@ĺŕ“HÁ0TđVŰľĆ&ŐAÄ'lâúŔY(ąË°TŰQ޲)ȂŁÍʒ‡VKuÔýŕa(“&oľ•›TNxżąš%ň•AV-ź„R‘Őę Č1ÝYâ@ö=2č<‰MTkšŚÇöŸ].f~zꍡ*ŽgŠ$ÂC~ŕ<ę°ëƍ7nܸqăĆ?_,X2B')‚óÎje‘UŠěŁAމ`¸ŇAŒ•ohsD'ĎüFăłqĺŹ934PDޘHó‰XCH.ô6‘œ¨>ʎ׮M×&†Ů [TA>°¸čop5F\DîüćŸ[RTŤŮ1ůéLŠ –(řÚtŤŤíďÉëŤ'i#zWćŒ*żů“*“‘ôĄÄëďvĂrnÂŤ[í-Áj!žž´ÄüÓ˙ŞL<لřŞ ˜Œ=ŮĄ˜D5âfĺPż`–Nč¨mÍŘjšŽú÷ŹœT„Ţ*WźBönŞ Ôff˛´Ó5X T‹‹Ó•ŚIWgzăóą”ÖZŠ$¤Ň)5ÎŹZe_ôľŤ|ŠĆ_ô_j&5_cE]_šÔqˆđĘlî˘0!ÜQ{]‡WˇJƒŒDŹ,ż™ÉaÂÚšGZÇÜAń}ÔĄ•—ľnČr v‹ĂËi &őó´*űąH4;"^JaέçVˇ˝ˆăžâAŒF=”„×} ľZ¸ľy[ďťjÎ̚B2%¤jzUŞMsíýŰ(ĽQl—*ŐÍ+(M‘OĂ⚡słn†śgˆZc­ "Űňm‰űd˜ŕ™¤$Ě>°<Ȕ*ą’7$?Iś­œ*v“¨­Xľ­rZel›^HłšŁĄśe{<ń´"ŞÚ˛š7Uj›÷ŕ“:”q|ż^,<Ƥ†ˇę˝YĹaÁö9ě#xvšLŽ?)˛7nܸqăƍ7ţ˙C˙ń—@çä¤óš?äí-RŻJ ŁĺIć!‚ç‰LŢHk\Ůšô{Ůő äĐ7Ś=śO2˛Şl‡­"•ÚXɰ—8S€V۔Ž<ړľçrý$‡_ŹP }/{%@^ĽHőžÉ™CÖ.Ľ|ńĹ-˝ţ‰'_ŃŇMTżÔQá§ľ7Ť7}Ű÷cćźĘLţ¸÷ʇQ-¸ÇśáœąíĂ{ó3’\Ź„ÜۏIŢX‚fy/kikŠZŮ_ٖKŘ6]y1č"~P˙Š11 :“đ"}‰1Źl—–ŐŇjJD"^_74čę5çňEžKíôPz^ľˇ™­ vÖ$E9Zâbźľ¤çD2ÍhZyÎÎBökŠUWúŢÝŹrŁf†ônHnŇ!žşŸyDQ­[Ő/˛ú: P{˝uĐ%v{qý}loˇI2ľŃ÷‹°ÓŸČčĽ¨Žš3ŻÔ„Oěžg)UYZoľoŰFý ŐŹ‚¨AŚ ŤŹÄ•ŰŢ$IѤë‰úłlÝR{ÁŞĺh2Ád•Í××׎jŞĐăɟż†o[­ÓĽŃEhâ˜>1ŐĆÁ˘‰#1Y¨_JˇĹľ IDATU4´— :Ąľš2P‰Rˆe˘ů¨ţ'1KĽůRł"žň{¤ƒýTP$6mťŮŘ/hßJŃÚöLíJ\ <ž8čË2ŒŹ ŹcM÷vęËBé›ř—4wnÎ6QŠHlo]Ś'G×Ęń dľ ![-ľĚ˛ŽĘ.˙ÉRĘlWœŽa_ßł>Ŕ/Z+őIľŠîÔ×nŞţ‰PĂ&Ä~a@ŹE/Y–Ă€<ËZ Œ­Îń•…ő=oT‘dˇO -;rOĘŇě"Žş>u)do˛vBŰśęĆ~mˎk’HîŚáXuȰ~CD9t—C DŹƒÝ׋ÚÔlL2FП‘!&yS˜vĐ"ś=Ý #…)Ćт9/r dNš&—uš×őtUzÖ͑dmÁbd@S×­xƒgŇöl×IpÔóŇęäľ˝m,˘¨”2ě1@gŮz-7Y/˜UA™ťaR0SéráRę!ť<+ŠŹčĺ›sˇ w;p˙ÁĘĘţ6ĘޟDŤ÷ďËşžt`óD-a7'›œd<ĐöIĆŘZÝšĐęLó˘ń ÚE.-8Պ”ËÚˇ–“ŇvŤŻ€DĺU=wŚt+§Ré^5‚#´\„ŐP“Uöß|’ůôl4&.†í Ű•*ĺU_[Ż{Ćçő5M&‘ăW~­Ţ¸qăƍ7nÜřř%˛ÚóžţzŸČŤ}5'9X9Jő#3qé4XVĄ‹ęŕ;ډÇËô ,~€=ňƒ}7ßV)‹HPćˋŚQę5ýŇÔŤ-”" áš•‹×rDJGň*ö?öłĐQ$U´ĘŁD@,€ł>°gÍŻ¨:Ä5%óYťĄ1ëçń—°Ą~–ęĽ5+cůäĘNçśe Rfľłâ[ĄŠR&‰ĹĘ@ľÚ]‰¤me6Vĺ.YQ&Ăň*Y‘Eľ"Ÿ;Ó*ň3KŤmg^#˙-ČúżoŠ]B% {äW^¨bŚLR,OJ|ŠXőłEl›)Vs0˛ŸV20Ş-jő*9ęśđzlŤryĘĄ˝UËŤÔ=ą˛Ę{üë2č&,˛ ]Ťv[N°dv4kÚĆTh[+•^P1Lë "d éŐ\-ŐHL:ƒ DH-ŐÖě੍‘Ť6G‡Ń2.,oš¸´Ąš°Źů—RŻă]îf5M„€CˇÝ°œuý4/t”uˇ˙ÎS6gÍŇ›Ž:|°DtîçľšşÔÔQmĚ^d*Ą rĎć Ôę°ŇRG,gĺ„˘|‚ÉĎ×:‹ä›%Âůe’ŐMřŇěÖí* DO2J}’YďŕjśŚë¨ öö$Ö ŠTŤđľ”ŃŕD8şˇ}E…&“ •¨ˇź/2]/‚^ŮX‘šňÉÔĘbœĆłěé[].5ú•e­ƒ Ą,ŐUŔä§Ććםçƍ7nܸqăĆż żV°”ÂĐ'dîSţ‘…ř !žž-tÂ%ŠeÍa8ď˜< yCu–şGgĚhˆ}c…VO„ ń‰óVM ş˜Wm™ŠÖžŻ —*ˇYť)¸“ĄxM*_^×M|ŤLGňłÚVłšcŎ"ľ_REXőÝuŔ\őß´wüšHkt.Ž%ô–5ă•ĎLm\<0švž3śÚÓQN"ŤŠ8Svśłšlë;tś@Éڊk“jf,)˘˝1)+ŹĘ&᝟Źě¤ŘO×q”ŮtҢGÄ~Ź/ Z¤śXľ‘6Đ|–H×nАd<żŹĎ˛Ő^¸"iV­ŔŠś79ƒFrIŁçőe­öU§ĺ'HĂŇ+Ď,Škh!(őug}ˇç´îł";Fľů 'ôoh^EfęT.U^%šˆ ȋÔ7JÄȲŹ: RłEB˛ŹśLEu+šNhç-lr›„,L•‹Ęފ #˝žÖ(Eņ–h­fyš „#Íśşůz­bh\›y6Ä*ťkî}Іjؔžüí¨śĄÚrÍŤ^e­"ĄzˆÚ,mö˛“WaUŚ3ExHpyـEACČ Lˈť"hÚéR¤ŽŒ"Śž6‰ĺë`Ľž~ŠŁ!×ţ Ké­Ű3é˛I:ĺŠőł‚2ˆPŽć$ŰB˝'T'‹ËE×YqľËI“"üY­âuQďo%0ЃľÎI•+9“žß?SŕZăV›¨ö/‹đ UśĽhŢK7nܸqăƍ˙ ü’0ő;Jó ÍFd§Ĺ.žłHž'*˝>ěĺaU†5.ZœŘúƒŒ@%xčď¤_ň{ý}~Ö,ťHFŒŢŮ*Z`mźˇRmňĽ˛‘ZŤ!•[“€œ?ó}Y-ÄeO­R›š81$Kí‰Umżš&é‹tßWŠZEg]“&“ʐ"})ˆ rîíGQđ{cRěu&“÷M"ZĺĽˆÂî_bl2ć*¸VA’R­żčë‹_­Âť(=YŮiůdÉ łŽĹŽ7B–:išHŸdŹ*ŽĘ"ŻuCěš˜€ĹY?c{€˝ˇĘvfqĂLIßÄI:ĂJńuéťÉ5]փPMÇ@Dlűi=˛ěśV“MGE‰(e.2JEÄđßş6[Ąe‡Vƒ8aďť Ą×0ˎ†ƒ„ĹéŽćÉ0Łá m¸>JY×jš=ÄéĘ.E ”‰Ë,ÄBˆđČŤŠH’ ŃĘ˝ŞÂ°"ŐE˛[=_Ę~mVÄM*‹nQ˙]_śäV÷e*–gŠćbt¨üľDUćőuJ‘_SKţő˜‰Z Z™RIŻsO„ŕ°Rż&¤vdۢĂľƒ:‡Ĺ&ŞđeeśŢë˙ż˛Ü*45śÄŤ„H¨Çľ&e‡Ö†Špĺ$óÄ˝•j ăÜę}ÔáC şKr–くk‰ĆD-°čĺČĐYšç¨|íŚkŠÖcô˞˙e÷ĺuÍýçőEPsˇW$`|‘Ý;łzăƍ7nܸńŻŔŻ,ÍO°Ĺl˙moSĘV @ňIˇ…ęQYÎ<+N˜ÂrĂâÂŁ­ˆOs–‘ďäz"˛NoŸ•ßó@¤ň`ř'Č Ĺđ$>ęCŚ=ŸAŹ$˘fVD÷Ž{ŻVXQR^’Ř„TT .boƒšÍĎjeŕž~0˛vW݃AfGBöŽŚ˛Ž,˘ęQó*üƒĄqĄáUŽƒ!ů,ő(+Ş˙´KŠZ"Ő k‘Dx‚yÎĽžÚˆ31u¤É.Ëú![I;Ëjé?HIŁy˛˛T\Ďý\ú÷鈌RF×:ĐhMŹ‹X:ŁUŒUß&wŮĚÄQŚt$#ݟŤ?[ňí´=mkĘM­ÔUIšxŠŽŔ!ťţ&ś§j눒Z¤–†J~ĺ›ŐęhŔ†\¨jJŰĘăC+cě˛XŞ,.řÄdŃY¸–‚{ŢĽŇTŞYă˘[Đ3pŁ ‰¤Ňˇ¨–˘Ż+“H\{öçTˆŔr<ΚĆÉ,Ux+“&E˜ČšmŇž•x!pd˙˙§Ĺť°u̜ťč¨Z}U.‰ Ф%3ˆŹB݉˘ŻŒpdčůQ‡&šłęŰ>[?ÍBb–;!wÎVb7yMד&ą3¸T–Y@rŃda›ŘĎj8ÖÜ"ţž(b“ř^YSIGc~Ý{Ď2F¸,šWśYÓ R880q:gEę]Zśß}—~Y_˜;Ł:˜Ő̎=ä"ňś߸qăƍ7nü+đK6`QÁ<~l _'u‘eşäsuş< ťlä:] Č2ÇI˘h.†]¤Çřߘä:ËƘŐîúňyJ‚™‘Ţ0™ľ‘š7\ƒ*]ŠŠ™YEŽĘj:˜ž;Ş1–¨9•źč",iäÚŞ™ě†Ń]NÓ XĎŐVm˝şęCySŔUň‚šKUhƒAŘqńŔńľ0-r\­ł@>_WHüŤ…ľ˛ŹĘ"rá|GóDt”’ˇľ‹-…ËsŇ5É쾣ŞLF>ą‘ŠřÉj-.œŽeVTş”=Ó´âm‹ź]™ëľÁH/{­lI^?‘WP$Ř]ŸäŢy­éE3ʲ™Ż)­ÂEC;ą‹ŸOŁŠ2ŁlÜ`b•5XáEś,ˇUvˇ÷ć$ĚČ\ˆvČd šhŇŤXI+k[ Á",˙¤Ű 3Ɗ>'C—žlňóžCŤ5ˇ+žągŤ,J0LËŞ:r–!^*LҕŢWíçš'Z.ČNËŔ­Ń)Ҹ:Äú ˘Ł˝ák•Ľ•¨ź(ČńńŁŽł4T:KV]ľMl/<ű6¨ĆVG%EĽňÖ3ęš ‹z-RiÍÉ]d¤ů")J×?ČvěY&ƒŘ$5ë`Iü í “łŽ ľőů†őj%ŽWž–dčË źˇ71×}ˆ x•nm‡„É…ť`Ű­ RŻŔz•–I˘&ĺŚý>ęűj* ÎZţ|`ďôž~9aý3Q’žwTu˙YŮہqí"ŚëW~­Ţ¸qăƍ7nÜřř%˛ZZƒĹĹŇ7ÔÓ —˛śL"ŒŚ×ś6:’k“Ú*ŁIw^˄!†čÚůU0™4s§ÂžœÖË˝[ł ‹Íl*ZEFUžoHî \–5R˜ĽdIŰĽPYű§Ň÷$E‚ÉŹü_&ô7$NÄŁŠí&^áš'fĆź&+ 3ĄkL3”Öç ş€IăĚ"Yʅh'hE.…Ú~$ >hz éő3çI ¨ 9Ę#źŞm)ëd:X\h72¤"“ĹdV{ň+‡×:s[|ŘĽSe‡—˝ß*u@ m@Ź23ŞnľN°źŔv9$ą˘Ôé,U°ĹůľeŠđeC­˘§Ÿ­°/Hne. k Ö ™(­ŽtLŞĹˇ2›†ŞŃdmłĽŁÄdIŁĺ'Ą41*ÜÉYv`!iÚJűË@}b{IĽňšaFX`^6]ő‰ÚEčĆYsJużőďľÍKÇ´čymĄ¨žź­M4ßE@{6Fş‰eŞU:2ë:Ľ'˘ngińmVňVq~ mĎĹ@t“&;[™Ľ’:ƒŽ•Ď4Qœš0™Źl4Í:œů"d˛­×eÉ=NK!剳ËÓŇżŞýW(ŤźŸX˝§MJUOŮLYĹešAjl;í×ČR9$äŘšĺř™•¤ç'ˆâÁś=WĂľr‚>pŻýĺ–ĐäÄc Ąˆć -đm5Żűfű×BÝêɟxé/ăK‰ÍŐÉkířƍ7nܸqăĆ?‡_"ŤšEdB;MN2;W´ć•Ÿ›ú’ÉĚNăů†ą÷ÝÖá6Y^vRąíy™ü˛żV­ŽZTž0ƒÄÉ´]$/G#d–r('ČŞÜčŠRÝś}23*+Ű–“™Š‡~MaĚ,e,F<ë­UîmŽ eđăoŸĚiźˆ˝148z㚱›R[Ś“šł™îT‰N˰FŚŃżZH! $Wĺ}˝Či~Y*wöĆćVŽ V{ÔL‡+]Ďj˘ÍŔMߓ"Ő Ş)Ě0Z:Ąr˛2aőy?B+ľK$a>i*eَÜĘsٖ3ő`b q҃ůŇ~s[”ĺĺG}mÝžZžöC 5¤˘ť|' Ÿ˜v2/†Ć"i•WÎ$rŃs‚ŽR™ĽŽ?R’Î$ľ×>'ívŢ6ZGŁţ>QL„Ý$ž6@Ě'ÝF‘OůŔSQí$‹–ŐŔiUJ¤Z?'B3&ěVéĚV! M˙Ř÷?än€.‹ôŠz­B‚&Fj`Š U†$VĹK፦ßp~§Ë;łż•u}AŘÄb7s"˜­×­MagT‘Q–2ťB0<cÖaBĘ~/jhßnXň{Ç8S°śČlĺPđXHŰdĺĎ˝rä!ĺ˘ËÁ’ľď•zęŤłŽľŽŤĄűwRśăÚČš0i\^YlѝVŽ‹nO˜T)Ő:/^ny´#ë¤É؇^'˛:i4$^sK Œýkń˙ŐKýŸ@öł(;21˙Ὸqăƍ7nܸńńkĘjÔFŁžś9™`o„xY9EP­ ˆĆU–sm…ÓżęoLœľęt˘ľMŞ2>ŰůVťŤí˝˛y˘ Ńf Ž{Ë1ŇśB Đ+żY đrfÁ˜ř&ź‚‘âŹX4 \=ӕ‡@zăJľÎšĹŠşęôëqßőůYĎ?ž•‘Ö_úľzăƍ7nܸqăŕהUWhI‹ĹڍşšÍxUÓň–žBË„ü[ńđ*cA´>ČórBîQ6ĐTÄ ÖĘriU˜“žež×îIVFř“0’ů¨žS”šmˆŠř“ŐʎŤŹmUuMR‹¨Ž+ ˙ś’?~p>ŐOžEçůŰ'ţăÉóíIďUAŹáóƒĎ€tŽoƒ÷ďo¨:ňř â˙ÁĎIČE‹Aš |9n¸;&ěđoo˙…ŮźTÓă{˙Ż4ž°’–ľ‘jbřJQ<žd6L:jBĆ sÖ&l|"t4~EPËú,.I†iâ7ěeŒřjü­ň%ĽI˛źČŸĺ,{r‚HĐÓ+ż˜Uv$RוʖY—ĺg٘÷ŤŚéhž“žP>öş$ä'a­ćyxň2ŘZnsž›ad’X|˘ä:+ŠŞXrŘś`ň‰Y‡„ŚÎʅj§“Ľđ#Ŕ"Dé2‹$ĘŞVçX_Ţô˛ ěRŤ&˛-đ†pĄ<ˆ\{ ÇŇŠD¸ÄÎĺ ÚdĄ(.Q6đ×űO‘72/”"jš”YűˇůŔň‰ú[ĽH†WĘVvƒmÖĄQ5&+ŁRőż4]@Űߛzîô*c˘ăę™LŠ×9ź1ě$8°xľč~Ö=GCŰIŇkâ†Iđ@d‘úłJpȲ żšŠ›ŐOŮiâGY‘mîlpűj–ŽđĘƇ!œŘ2rýé‹ou÷śš˛iŕ9ý ܐśĐŹTaÚ>{Čřż_$ľ!ě‚+ĎwÄ?~ĺ×ę7nܸqăƍ€_ŰYľ‹oŠłäą'M’f—|§ç'Kżaţ…)ox&C3ŤřfÍĚĘ#V;¨ďéG|[N'"ăk:&c—ŘT0x-„Ö4F:¨VvPsք…ŻRŔrŤ6ë“eUDÔMY$!IzđůŰŹ+]9LÎó¤mB|@{Ăç…epzóŻ,i„*x• š(éOüłsţÇçř&Âăńż.Îë†ŐvŠ]pćoüžŃŹJŁ$řĄża*œźż˝ńß˙{#š˛r‚(߼YăšÎÍŰźĄœëbebćh{#"hiňU4„°>HůŽDК-ŠŔćśsŠÔNŠÉĎř^#‘ FŐľ‚ě‰Q”ÚRHz f–'AÚľˇjƒ˜ŰÚ-¨ŞY9Đ ="ń[ĺtĽmĽŻ)ę1Ëhi:Éx [ÍŤ}ß-JJ Z™M‘j÷%ž?UxĄJŒ´lŐÁŠ´H°z<ĄňÎĐh{ÚŃ=óS‡ ʐYî(EŰm"y ňDźž›ŕ˜îě­?ˇ…}•ú–ŤČźÔ5O?íd.† —4†k+˛äYď•Ôz. ŞďŕĎzŒTP/Ëť¸˛sÜZç:ReG-?ëđŤĆḐţ@âs“;X4ŤĂ•‰d0ľď_őžÍX¨%ÂPc‰“ %űUŻ1Đ:¨ —ż"AY¨ÔĚOE¨×_ˆjXŕłR?("ľ!k$â‚EYÄ5ž•é}žä¨Dj¨“’¤N<:@Ѐ=”změuĺ.x’wŘ´ţ•-řVźŤőşlŕ*MŰ{ÉůdŢË57nܸqăƍ˙üš˛Šb˛ˆ%X§Źwґ4VjŤJSÂF•ŇčB$°ü$˙”KÉůőÁ]äŞüŤĚ˛]J)tNî&ŕR`dŰ=K!Œ˛üސ>ŞdIŕ“4݌+ŻŚĎuˆjéœi€ŔšD Ÿ?~đ×ßoů‘o'3â‹AăŇ?hŮ ÁeO÷ČBDIíÄtfNë„.Ö2ćü“ĚóÉtŞ17Áeј<3p"Šű…ʉŠń“Ńă˙fď̓ĺ:Ž3ĎßÉźˇŞŢĂĂž‘ pÁF‚ (.’ŔMÔBJ˘lšmŮZźśŰ˛ť;˘g<1ŁéńLôDĚ1Ń3OĚtLt[îpŤe˖ÔjIVK"ľpŃB " ’Řw€Řˇ‡ˇTŐ˝™y揓ő ônPű~!Pu_ÖÍźĹ<ů}çűđR0‘*ví푢€ ~ˆŮł;̚?ęČřäýÉqf̝ˬŮóqŽ0„ÖJQs¸u?˘R Ąk,'cx)HžČ hŔ[&ˆć8—s{önŠ.÷[܎ő€‚&5ysr¸X™ĄSŃÁĹÚŢW´­Hq7uŮu E?_˝4''ZYl ‚,ß3! %=’“­ă)€:GŘX´‰#%ë—vb,ź xě@CU1RxoĚ~Ś”EƒҊ˘IM Ź}cŽHĆš.Î× -źScĄóúŒA6WRGfłG­Ç ŸœĹ¸¨: ŠIÉ OU[ÓÎWÄÔŚ%‘ä.9;ěqqm\ç,ÖŠ ]Z>Ë;ŽŞŐ˘s‚š!™c.‘#ufs]|+?‚h5ľJAÔʔÚÇë0řŠD4w뺅=’뙟žĹ"c„ü3óĎUR–Ř‚÷ů–ŤÇyÉ2iH S+HeÎŕ€Ś~vT.­IŇĄpuV<Ş‚h¤ DK!x…AŒˇk{Ź ă0Ÿů˜CÚ }  :ÉŔ[5œ˙äń#ž)G.TU•ş[—ŇîÚ Aƒ 4hĐŕ51˝žUĹ6´R’'蝢Gň%.3ÂQË4UĖ4yú~ĽN $ŰŔffÔe6NĽm‘@JĆöÄĚŽ¨*űU“ćeÓDHQńžFi!ŠBőj“ćj29p ĚRÉ*oxkR­8_"Z3<2›VkŒgS÷k$Î ôOSĹaşą‹7,3QÉ5eÖM(Ĺ ś^LŮš¸%$MÔc8Úoˇâїˆ‡śD˘sTÝ>)&ŃMJ?ĆĚ0ö‘˘2śŮ9’œ<1Îčč8ŢՈ+ˆ*ôž Şú̞ӡÓnŁą"†@9Ôą(–RIIqšײîŃ$”’roŚ#ů\† ń- 0)G§j6$˛"ĉEřbÎ}éDD%5A=žđ¤ŘC}0IŤ—¨‰+Ž˘1´ÎˇÔ%I‰8˛ń”Âľ8źË.Ž(A°ŹË¤ ‘˘ő¤ú’”NZVŹHiâđ\šœÜâ’ÄŮüZ܋ϾPŠf×^+şĆlíŠVx…:G"9˘t}DkC*qŽ ŠEĄ|Î\UcóDžB*Tâې˘˝>!ŠÂ1œ ˇÂ’u˜TPW”Ňʽߨsďo‚艞ŔK$i~~ńŕ[Ö§š*{’1ęâČňüš¨3đRYŸŠ¸Ü:Ť(QŹ(u^HąF c†CH–•*nĘOëœo,ŠĆząEĚ9iB\ÍšłXź•Í‹f6ü,‘m™ČžÂ{˝˝R'Œ5ׂşŕĎýz„€Ÿ2/Œ  {vqšLa8ۍ=–CÎŰÁWŠľeäqEűľžJ4hĐ Aƒ \ŚUŹÖApŢăŜ} W˘ĎHKľB+’¤CĚٚ^e#šß*-Ô")¤M “ ŞĽżˆ‹h’Šş˜,JľˇxŰŘŚhMŞ".o\ىőbB %Ő)o"­[Q#–Çh.C¤X ­­Í‘uÖH"ąŻ)$4&Ć&‡čŸŁ[ UŸ*k#L’]‹íŢhިEp…É3%y\aFPIÎ$ďpŠk™jrՑYłčĚ(Š*O5äŠk…Ú˜­„yâg"ÚŁ(ZŒĚčŕ[%˝î$N„˘5 žMg¸„XQ´Z¤č?ŮMý´|@ęĚ*鋧Œ˝lx%hîTJcšč˘ž…ŚšD˛X ťwŢX:ĹMÝwQËą”AAŠý|-@Ä —d2]—jR23!ÔâFźöβkŮ­ĚÇ%ą#-‘B2Ű ¸AÓg˛źŐA)Q‹łŽĚlć*D3ĐҞdššY+{ĐGĽƒ÷v0˘9JG“ńŠ€:D"‰Ýz#œ IDATHmŘ(PęTRŠ9,Ť3FŃJ7 ŠDĽgůÂöwÎH9\ʉž ­‘ˆőn'íP¸.VÚFBŹŹG— AI2 ‹’žő{jú‚¨VđájT#Qö™uŽu/5QÚ¸,¤ö CIá'ŔľľÚ˝uBŠŢ;+ňq¨Š=G)á‹Â¤ç˘V냾:1Ëť ‚xGRĽŽÁ˜jČq>Ö0xǀ™TŚVf!-ągj`/xWĺ<ßüýP”D2#l6×gżŔfUSLjfsEL) ~đ“=ÍYźä>ěó+ŠF’IłSR’&RÝłC•˘ĺՂŤÇ§óľÚ Aƒ 4hĐŕç`š2ŕ„ha9„Zá’čP’¨S‹ŇORÇ5‰šśL’´C’6Nű¸…ďdؘ­AJ”O—DËúÄ%3B!oýpvő­ĐÔ)ŮH(łˇƒşžQ´đއ&‹ŃđŽ"EcҤÝFkŕęÜĎ'‰Ę$­,qôtfś)[Ă ….Qf"Ą ×ŤéNŒjŔŐXî瞏!AŒÄŘ!J߂0Šç=)ŁŽŽm…ŸS†Űs™ŃGd!ŢyęPß6™ŠJ Aň†łóĆÚŒštCĂäIڝśŠ×@ВBű„荍-ÚĆ\Ś~–gWfФVlyW[ÖŤ”]Áú4ƒEXßp6MJ=s|ďA] 'VÄĆäÍKÉ+);?ĚsЄ§g‹Kc.€jëcTĹyGHÉj:­čr=bEkBIÁSx˜%źJ§¸¤Ä\xx „ä,ËTÉ=ŸXâ€XĽKʇƒ¨“˘ČŻwśÖbH8ßE|ŃR@R‡ŁO+"UKbTŠ2ť(“PÔ \JÔ8Ú$jTkźjf:Ţ WiQ¸Ië˝öŽ'ńĺE𨐴49žÖ”Ţ˘Ý _D˙]P’oă\MájúqŸzYú;IJj?D‡ Hžž›I‹‰ź!ˇ c—9 qH¤{Ö(ŒAUěWÉĹLň¤ÔgPH¸Ř3FRtJv*ńRd>Ž“üpvĹÜkŤI¤&… ď­,<+ôĆŞ`Y–˘Zƒ´‡iwf1ťˆ8+ŢŠ ™a e‰w‘ţddbtŒ^ŻK/ Îľ ŒÓ­‡p2Ž2DkŞp‚nWŸč1wŢlFf”Œ÷'˜1ŇĄđ‘Ŕ0“ă“Ô“'IÁSeh¨ Ój32kˆ˘cJŽ( )+Ľ §Ž"ű›Äác…丕–C)8L>š§ZÔň:ë$””@TëD›¨dfQű¨+PM„ “ekĚ=ž îŹ‘‘ZAc?šĺĉ80ŤJz1FËů)2M Ćö&Ÿ™ţ,Ռ:0cjSÂŃ7ś {żQ5ƒçœ1뎬EőĆb‡)KhŇas˘ŐW˘}“—§I¤°\بŮîŚÝ/jŔ ^#uH”ž Ş9G‘lě.öHĺ źNJ ď“s.RřHLŢr} E§ś‚Ű™<ޛ&,‰•Â;+¤DqiÜ{­Íˆ,!šHvQÖÜŽR¸Žĺć&˛Űm"RZԔYŮŘÔQőTO:Şůéě™ěW'ľő톈—š€‡˜P b&QŢ9$ËlI}‹0ňŽXW–Ćúˆś@КD ei…Šff[íp ‚IÉR ¨W\čŰł>č!vÉćkƒŮ2^?c0—š:f§äV‹ěĎ%Çgi vh“jBl–4hĐ Aƒ ŢLŻXu-˘3ĄĄŁ ¤KL%I \ĽšbÖąEPŒ KéRÇŢGZ:JH-DÎŘuu`^" 1 ˘}Ä9ëgM Ë>lĺýoÄç×kŠÖ›&‘¨ŠHAĘŹŤ+˘k!Ú7öłžŔ•m’ ¨Xq,ŢĆ4Ÿ–!šRMG‘úŮř‚oĄjŰÓIë,Šěľ>šäÓ%3œń}:mO­ŢL‰Ňý4Œ¤ ‹|ńý,Ťv„ŘBú“t'Jbę01>A¨fŕœ#…ŁœƒĐŸ4y.‘ńÓŃ2<2y g0kö0ĄŞ§ňl]1DĄ5‘‚"YńĽ$„Š˘°œMIfJ$E›V8CÍĽO() ĆHiRZž&hI0é­*šę܃˜7ěŽ Ľ~fBÄç˝ő‹Ď‘Eůý ŞfeŐkÂťDRÁ{ĹĄDU+RĹޗ´°Fľ˘4%Ě܋|Páú^o}ŚIQ Gî‡őV^ŠäĂ +¸âŹßŇ9CX°9÷˜ôU0†Lžžz¨kă]˛ĺ“"ž$VhŃĘŻłŸŁůŸNÄ;­đ8ˆ/.°(…K¨´íđ NX!ëŹĐ%9$&ŠŇR‘ž‰›ŠŽ)¤ŚŠŢr?%U)|‰cŽ’ĀɾÁLř˘ĆÎ6,_ÔasiĚ:xg=°*&áÖüĚx"J‡"ŽÁTŻh–űŞŕĽ´<ÜbĐ1ŃAŽŞ‹S†Gƒ5$ągkE ź+Í$Ij¤ęcYɢRĆ1¤5Ì´RW[ŽŽŠĂĹAęŘĹ2S…¤YĚgëETťŃ,żěűDŐúĎEŠúćN]x¨ë܎ŕí°‚óI†\xÁ 4hĐ Aƒ—ŒiŤ…Öˆö ÉŁ¨T(Ľ‹Ĺt ¤Ž3 О˘ë %Šŕ]fćRVć O-r~"ůď"5N<šŁp…ą„*xéç m6ĚÉýn.eÚKÍ)Ö%ťŚ*ćkK腔eĎz aź(ŢŁ*¤şś¤ă˜ŹL++Ž9ßŔ#ęܠСĂIÝ<'PJľç$:Pzˆ3J‹5´Z8íÄű˙ăě>ف‹ ÔTýą_Ó*Œ‘ś/Ú.Ş@ËOâŐrVIƒř!;iŠžQs—‹áŠă}ö×W!;6˜KtŒćZěb"ő*p‰hŐž\B@R˛XŤöË 4hĐ Aƒ ^'ŚUʆdBMďŇžÚÜ/SEHĽO„hýiĽöuÄZđEŢ,gŚAc•b›ßh…1=Żîb$37 u6ĚŠRYAŁ}“ëƄĎ=dś#Î6Ł*HŞŃ˘ƒ}bŸÝL§Ü=Ĺ!ąoň=@ˆĆÖy+n$UŕÚ$_S¤ G”a=ëD!*Î$Œƒ|R:‡Şł˘Śc&5^JFTHŠI(JcuĹ+B ‘ I‘H¡=­lă%0c¸¤!ÎöH݁ɞCSÂ+>U$1ąŠđŠ"¸.VDWB ř˘ ĺ~EIŇ+}-hĹ ”6…WŰlKa< hM!–ľ{6‚$ßęd˝Ą xgÁŽšŁ)‰őgJ §5 ˆ()‹Z¸Ž´:3^ŇPgĚuŒJá3 šjT<ĽtQőéŕë “Âú6kcšĽ@R QВ^.°mý*‘ÂŜ͙˛ÖbmŒuÍŏ8$N"ž„ŞĘfQ-´ś^ĺBĚ {ŔŠ:ľ¸œ”*ĐDě I$mQşHôÄŇ'Šąv6cĄ%Y„Œ&‡Cńy-˘ÁŠű@J$Ô¨ˆąŽ̄Čť)aďZ IĎşVkh•"›ŽYĽH6ž";›$@CśŠJ=Ë>ŐˆĆ˜ŁŸ˛dŢN ź”Ôti1Ăž\e‚ď00ł#Ş*gäÚϓüý )')ť7—¤^ĹÉŁgX˛tꎒ$ZGhĐöŠs ĎW‹’˙—)ósţŘ4ćgŻŃU\L„¤xoëZc"ĄÄ˜:‘˛:ŞJB ŠAƒ 4hĐ ÁëÇôdŔ$< Ń>QŰ >N´¤]TÔĄMYD'ĐhŃ'R´ÍWë,ĂĂ6­uČ*š\Ŕ&ëŸDÝyűH#H^˛4Ô%Đ`\ŒV(BĄ1żGr§˘Ŕk0‡Ńz23O.›)HŞŹžu^”¨–c*D+žŐŘ?clLʚˇş.{*¤(Ě<Ç%zJ˘Ú3é¨ó”tQu8<$ËĹ9œtQÂegŘčŢ{ËëmÔÜK犒#…ƒäJ‹żJˆ¸"bŽžJŸ2(RĎX*i j„Ú¤‹e›XJj’ďX/ags-‚&:P0–tĐKœ ˘eLVŞÍ\×{bˆřҲ^Dœ˘A Ä iĘŚ=—z‡1ÔuđÚGSa!‰ ĘŔzsŗ‘"š[œCc c5˝Łe™ŒąS(’$u9pV=ŠöIâ)´gîŐ$T#‹Yɢi‚H][ß6Ô2{Őˇ/Ä`ą7ޛyS¤Ŕ§Š˜ČŽÓbM´¤oÄŠőXĹöŮ<_^3ۛJ"Ş1Ź!'‘đˆÖćvMxńhŞP,‹T’N™`šşOgëŻpDľC–˜Ä 3Iő´Ä …œS !eSЍůžřl$”’˘Ž‡GPíŰ˝.NŤü^œő‡‹ő‡ŔAˇÎy%F(K%Š29Ů%„.EŤ Ľ` káé÷#Ą[ŁąË)˙ŕ`LĢrěçcŽŔĽEéh.Đ‘X)ž-K.äHŹPľÖOëUľŰű.#řV;gÜć‚ †óRĚŇË0‰#fł%G’@ŤLĔ@L†ŤI ŇBÓ@bq\×Ć –ž‚$Äh™ ÄĚŻů›š‹g;XđÎ˙žә3|5aĚsŹńŢŰgŇÁjŠ x‰Äd?7Šš8Kžž™K™ć\´fĘ0wj‰çCą>ä˜Z´1ô%’^ť$mƒsôiÓŞ'@ĚUÖʨžĹŁÔ—}]>ŔQ[ťšĚůŘe—Ţœ?+.­CŒ9v0ĺ ęZ!%B -§D/ŮŮ Ř#yO‘űsC6–ôŢŚd}ˇâ­FDçű„dtíÄd”Ůs†ěĄHtĄ(Zh„–œƒZ”:ôŹ(t)z‚ ąP˘<ă“5<Šśƒ"D˜¨@&!&ŁŁ”­„^ ÄűDÎ9ŞZéwť@$…@Œ‚+Ą[ő˜ěöéu+ćΝÂĹs %ŠB=ĂŹŮłéőú¨SbŻâĘRĄ"tű]úÝcăfâC¤_'úľŁAƒ 4hĐ ÁëÇô˘kb…§¤vB;;§’ˆ˘RŁŽÄnH ŐĚ: 6óŮ–”Z ŸY‘Š$OňDpEË íăÔz]Őe†Ä%s~MďIŕĽErŠÁĚ_ԓ2ë’ąĄ-ďp‘4i}°ŠĘ—ešş¤„Â$Ě`ŽŚ5çŻÉľ˛EKkHĐ֔‹;ëű‹RRjMŢĚz9(ůŸŢE4XA)D“#ŞSš‚ł‚†„hÄľË̂ú|Żkë &‚O¤(´[5Ur “Ł0şěŘń)ËTĹÓrÉŽ-mË3uˆhRëWË@QDánŞ.°˘Ç{$tqˆąÔŽeďT|žhĄ”Ƥ3DrĆ^$g>ÂTńă0×fU瀂…K8çł!VŔűŇzWŐ"QĐho‰9BǨ1cęÍu¸ p¨ %‘*9J/&gEQhIĘë%KŔĽ‚šŇuŕć›MĄDs$ŒćšˇůuŠBËÄjЅmŇŮŘÇΌ}’â˝P:3ŽŠŠ˘”„ĆhýżYVšRńŽ@ű¸ÂăTѨX"Îŕ€&ËuŁâ oLž MÔ cÁ GĐŞďpšĺĎ^đŞćŒUy1šJvŔÓ@•› Ťl5Zف9š\üFGR(|›OÓë{Z“ŽX+I…ń~‚ĐçäÉŁěÜs‚ş†ąń1B]Qő;Lt{ôŞQD Uń%ÎAÄŁuE Ö/—$Yś§*)F4Aá;T3*JbŒř”ŒŮubý žäOc.pbĘZ÷˛áT@|Ž ĄBdˆ¤=ź3Iv¤…•I`}î¨ĘÔ%¨Ă§.ÉwLZ,%¤š˙jď!áSMH+˜U[{$_zb ĹN{ô¨ľP˜â+šżYS.ü„1jZx&­xv…Áˇ!ö­a›—‰@[jB,2ÓŞ8U’˜ťlŰ+QLú›°‰ĎJPëŮ 5ę=NĚ)Ö¸ł\¤ hŐĎŹýYöů˛gDĎ^Ż Ć.—bď̠̊\óÓMŃkbrt­]$bv’}Źœ˜ †čdŞxňÉ$ľ8H}cę-‹ĘŇ1:h •x/T1GŨâ$RU‘¨bPAˇW’Ş ýŘBűÂX5ĘXŻ"Œu8Sćôř“c]ĆűŠj˘×‹ô¤j‚:FĆĆ&Ÿ çu”Ę9˙3JXá0TB!ävÓŚžSňÜ=űÜN]Wd*ŚÉ‹ŠvSÜńsŕ F(œP§@÷ĚYŁ7cœk›?‘łńN.?žbýŘSŻĎŸ¤¤Aƒ 4hĐ ÁY˝zľöűś10çö}Mç× 4hĐ Aƒ 4hĐŕÂđđ0MsUƒ 4hĐ Aƒ 4¸âĐŤ 4hĐ Aƒ 4hĐŕŠĂ›SŹúÄ}şĎß|,2˙ T —7ţňűüW7žq×|+!íŤyô÷?Á?~÷<üĎů~ú7ů>śŠYoŕ\7Źç3üq~íƷ쓼.ü˘÷\řĽwńÇüI~ë–NŠň†˘ĂÚ˙˙ü××0˙?Ócťfí4hĐ Aƒ ~‘1͜UC93ńĄw&\žX: uĎqä¤ăĹŽŻźč8ófň-‚ĚL|x­2žËóýŁoôŐ‹ď¸ƒ;ZřŇs'Ď3‰yÍńœőĘů{™y5÷Ź]@w×f6 ?˙ ƒ÷˝M÷ěrÇŰŕíDÍ?ŢĆ}Ÿş…÷ŽÜĂßníńz—Ž[źŽň‰[XxAń›x劯ńož=CşŘ4hĐ Aƒ \€iŤnvâŸýjŕžścăvĎSŁBg&,_’xônxöeǙ_đ]˜›™řČť"‡ĆO•×˝q=Ňš†{×ÍáĚŚgŮÖ{­WĚťq ÷ŻťŽ•WÍbF ˝Ńcl~îy{ţ“oŕxŽt¸™KxçťVqr|;/ ?c.ތ{6ýń^:â+řł?{R|CŻŰ҉<ť˙f˝k%‹śżČ‘7ä;L9˝{ ϪΙ/eěŔë/†/ÍÚiĐ Aƒ ü"cÚĹęMˇGŢ1$üÝWJţňĐůnŔóćŤEK4x 3W­dM{Œm=ÎEy7é°ňÁ÷ńąŰ:Ůź•Çž?ÁéžcîňU<řŔűř­ĄoóŮž žŘ{˙žâďÍ=SbœßŕŇŃeËÖĂ<ňđźcÉ&žqŕ¸ĎĘčŢ­<ńÜřP 6k§Aƒ 4hđ‹‹éŤ˘,™ŤHĺŮxäÂż>yb:ÝPĘÚ{˙Ý]ĘÖ'Kţ÷Ÿ =Ÿř‡żSóhżŕżüźç•ó•Źâćzţ—Ďl8§âNâĂG>ş"1aĎnĎż{ÂóâÄŤ†=”řŕúČoH\=˝qÇĆ-žĎ=ă84¨ňÉߏřgßwŐ*žôü›čřW^ňÍńi|Ä×D‡•+áǡłăŘĹśŻÂ‚u÷ókˇŔOżňužľ÷,łçŔ!öwßǧß}k7~—ç'Ÿm!÷Ü{w^ż€yÎŘëqúř^ţÉs<šˇűs6ÉmŽť÷!>qמü_řéI*żG~çaîé?Ď˙űů—9~Ţ\Ěྏý2šť‡˙ٲýÜęŻ3Ÿ{žƒő+ć1ƒ.Gvoçń'6ą{âüČĐBî^wݰ€yCB5~šÝ[^ć;ĎěçÄÔ\ĚĺĄßü0.8ťžć}ŕcü‹Šš8Ě×ţü1~2~y÷ěíď%Λ s÷Żý ^;ГFv|űË|îĽ Ů9ÝťůŻĺ:vűŰěXt;ëW-dn+qćŕ.{ě§l˝ü“¤éގXy?ŸůČŐlůî]~+ˇ_;“NœäĐέ<öäVöuĎu9‡ľwŽćśëq՜Œ´ĄćťˇnćťĎîăřENŠŮKy×;×pëňůĚrTăg8¸g7?xf ťÇĎšv1ÂĘwÜĆ˝7]ÍŐłZH5ÁÁÝŰůŢÓ[Ř3qń§˘ťď ݤkX˝rß:pdZýŸă„öđ0-j&&ë×uMéÜȧţ𝠽ź‰3׏bĺpí?ř?éÜÂ/Ýľ˜ĄÉĂ|˙ďžä‡GňÂ|×ÎëűŢy \âz(ć,ăĄ÷ÜĆí×̤&ءé~Đ[çŢíůţżűOœ8;Ši=Ç 4hĐ Aƒ+~Á‚˙ăŕäý5sV]yçBčôź0ösrVr׉zŽŻmvtEšíţš~'lú^É˙ńźĐPat(ńđ*er§çĽs4›2'ńű÷%tsÁgw đs]­,^˘ŹŽż{Îóü(ܲ6ňČrxałăä`oU$>ůë5ż˝öl*ř›űI<°.ňžyާś Ý<†ŁGĎlń|˙Ü~r`Cɟ>íůÎ&Ďw7yśžşŻ‡")Żfýƒ×1ďĐVž˝őôWé,ăCY žÇ_?ݧMPş§”ĽwŽ`ĆÁ-l=­ #ÜýˏđĄ„/nâG/ígĎń ŒĹ\ß:Ćóű&ĎnݍŤ{ůńćôĽĂ ÷ż—OÜ9Ěžď}‡/<ʘGí21´ŒťVÍĽˇs;{{*n IDATΛ‹|đž%čć |kç psŻeýęůĚ]˛”%áĎ<ˇ‹]Ł-–Ż]Ĺ]˅]›065 xč×ßĎű—{ŽlÚĚ7ä8óšuÝn›7ÎËŰOçő8}ä0[śěb㑂Ž›Ĺń Ođ姡óüŚ]<żéűO÷¨ôŇďŮŰ=^Ř%Ě‘ąc‡Ůśu•ܸ|ăťśđâEúaݜkYżfsŻZČđĄ-|űéMźpŽ˝e w]]ńňćăśÖ/—0^79÷­šÇÂk˘;žăŤß{‰ç_I,ťăî[ŘžĺƒZQf^ÇŁź‘Ö‘ƒlŮą‡ˇćhšÍÍënâ 'Ů´íç*ĺ‹křÔÇ×sÇźŔžMŰxvÓ>öžNĚš~%‹Gˇ˛ůdž°›Ĺ]żôżşvŁ;ˇóă÷°ű”pőš›Yż˛d˙–CœžXŐaÁš•Ź˜1ÎŚ—Ž2q‘—L˙–]Ĺݡ,fń˛•Üw÷ZÖßľ–őˇ.ežŽ˛ďđäeąüRĚăÖ;—ą|FŸ—žÝÉé9×rŰÍ7pcqˆ§7ĄXv#ˇĎeĂśÓYľń&­KZż—đů.a=ČĐ5üŇÇŕîš=śţôe~˛ë íoăŢeÚe͞;Ř;đtŸă 4hĐ Á‰˛,§/~~Łgďu‘G>ZsËÇóŻŰz^>"LţŹŠ(ëîŤůoÖÁ —üË—äź ŰŢ-žwî[“řÂ17UČ]ł*˛R„˙°ÉżÁóü‹ŻxöDφɚů@ä×WyţˇMÖk:wMä—–'Kţç b×}Éł=UüÉÚŔ/_Ýâłí’G8Ž>%*`ü”đҁ7ŽgŐ͜ÍüĆN_tł:týőŹr‡řúĆSDŔ,á÷ŢÉ=×͢]Ÿaűóűˆ}ĎPŰ é,fŐ҂ńMĎňˇO:GVüÎÉk¸H‡ď{/żąŽÍŽÇç‹/žó^ĺč–Ýź{ˇŹ™Ďǎ皏şž%r†l:vž„Y„ÖŘ6ţíW^äHŘÉśÉ÷óXĂŤśňW›ŒÉ™šćVŢ˝ö?ůţý†3y.vóJz”OŽ˝w_˝—oL@ŕô‘#œ|ş†Ľ{ę{.ŇëwŠ÷ěíŻÝţK™ˇÄŘąŁŒ^Ż˝¸tüŐ8ř"_üÁ^ëÓ=öß^| żˇîZVŒl噱K_͗žÎ„¸ďžôƒ}Œœx‘/ˇćńĎYË}×oç‹;lőëÄ^žôŮmŒNžs…—w°ˇţżťn5ˇÎÝœƒTF¸óĄu\ďńŘ_?ÎÓÇĎV›ĎţäefśÓÔϞľö.>plűö7ůÂËy|;yn_Ÿ?üőŐźçć­ěš˜47sb4á–Îfž‡×叕jNîßɖ˝'81Qăg.ŕŚ[Wpű{ŢÇÂöˇů‹]Ž,]9šő%žzém]Âş‡ą{Ăs<łS9žh7\;—ůnźYk粿w~Ţ'›özÝ~;ˇÍěńâ×ăË;ú(đÜśÓ|ôˇdÝŤŽŚ˙7hĐ Aƒ ŽTL;°ĄwČó?}ąäK;„rqäŁ÷>óńŠý{5żuƒ^źęĺďŠůĚ;ŒQ}uĄ N;žwŽZ•X3HqĘ}ŤŽ{ž¸ˆ+ďîmŽ}ç0$‡ˇ9ś'¸i™Rć?[ł,ŃNŽ'śĘyLć ›'Pn[ŚoYČŹ uĽ×Ť.ňˇŽŤ–,Ŕ=̞ŕćrď/=Ŕ˝óNóô7ç/˙ÓĆŽ[ÍÍ#gYl*@gŃU\3ăüO‘Ňk%2ÄĘ÷źżc˜˝ß{uĄšß{z&掺žk§ćbˇŹž Ç÷đâŃWo쇡íĺŘÔ VNmŰÇ+ŠdٲyM\ťle:΋[Ϝ3ť6íç 3¸~ŮŹKœ‹KżgoďxóOťœy›6÷9‡AMœ<=NrĂĚšŕ>L—>ŢÄÁ=‡8W1?šď ݤ×-›6Ž)tĎ+Lœó=rŠ(ĂĚ='cIf^ĂÍW{&wlâŮ㯢ES—ą)ÉC‡UŤӚ<ŔOwôp…§Č˙×ăŮ=îXríBÚý¤‘^?o3ăâ/˜6Ňą—ůü—~Čăśńü–ÝlxöY>÷ů'x~ÔłäÎŰX;ărŻŹLNZqVwű„Ôg˘Ť€ŇíVĐiÓšělšé­7mýNw=Č Ž_67ů ÷ô§´wˆwżú€čÍ{Ž4hĐ Aƒo.)şŚ{Âń…o:ţĆ sç%Ö^§oĂŽI‡żÜů%72>Ţ? ˝.ăAX>s˜rŃP˛hőZ\ˇœë0\Č9 5…?ű;7k&sœrňřčĎf$Ýóg9dĆ >őOW\ô%qĚ şŢ[ěz¤ÝƒüxË(ˇżs!×/ö<żëň:XS´•ŤII¤Š1iç^Wvó´ÖΛś~§šd˜Ů#B{•œ;qćĚ$éÜ$YyŸă 4hĐ Á[†K*V§ pę„ăé“ÂOŽÂŸ~,r˙ęÄ_vç÷cá[ß(yvy͟Üřôž’˙sۅňÚŃ]ž ýšwޔř‹˝ŽĺŤWEÇW.ňڟ;4S‹]QĐnI:Ö…COY@UŮVź˜9ƒ=Í+gé?tě$‡&”9S8´áqţlűBV\ˇ˜kŻ^Ä +nâć[×đŽŸ~‡óý#öb…ÓlřĆÓl]ţŸźí]|hß7řŇś Q&víb{)knşšoí=ČâŐ˙đĂm—śţŹĎýfÍĹeÝłü֟qŮ7í\Ćź˝­¸Ôń śą NÎ˙ýěľ÷ň{¸šţž-|ď?áŘDEPđ×ÜÎoݡŕ‚)¸”)IǡňˇďćĚEŤVŒ_ô Ľ`¨í ö™xS&@™I§ăá2í–^óťđ-+žßŒő{iëá űjoĐ Aƒ źÉ¸źbőT§„Ă VtLS|î6,ö|q—pbÁW—Ö|ôĄŔ ‡K?sţ5´çřîaýŠČ;F`íJĽˇˇŕÇŻáŔťpÖůʍ ) J草IU89\Ľ,‚su‰nڞĐÁÉą‹°ŞúćěűҙQŽWpÓÜJŽŸżUŐH (l*Âd—ŽĚeÖ Ń<šrˆ™ŃřUgŽąiă16miÍăÁ_{„oYÉ OaóŤhÓtx;Oî:͙ý?âGKßÇú‡ŢÉŽĂßçšWíęľwvô¸yĹőŹ ,_9ƒjď lžč._˜=kŽ3çĚĹ f—J56iL‹öpŐs/˜‹f;elě"Ć,?k".űž˝Mă}.eŢŽLźŽ9s^ugŽ0Ç+˝ńŽ1Ł2ÄꛮŚ3şĎő9öO= œŤü˛ĚtfŒSIX°`6%c\LHo/çę„Ě÷ôçŔĽÜG7Âüَtz”oJʋcöě8­™˜¸'řń†ŽßKY:ÉéqĹ͙ÉlgUáŽYł†qçڈ]îsÜ Aƒ 4¸˘0mŕâk”e ˙|Áő‰>-ŻÍTŽżú–gW+ńŽ,˝ČO}q“ăX+ńđƒ‘wÍ~˛Éqć—pݪIJs4oW­LŹtđňžł2ă-ű}—x`ľž'ťýćÄ|„ű/,Vľ2×ߙĂođ ~8ÎŢ# żh!W]đŮkFĎTtćŒ0 ăťyqtďşWľ)FXsď­Ź:ˇ—Ηt^uĚ Ő8ÇÇŚ!jŽŽň˝omâPk)<źšŒ'°{Ó^F[Wsçƒk¸iFŸm›0yąkáXźj9 §n°0wĺr–şŔŢ}3ŚŔţ}ǨÝn]=뜹hqĂÍ×2‹ vďťČ\TôUn_d..㞽­ăÍx=óö†Ł`ů]÷ňąßÇĂŤF.>ćKŻăŞUËYäĎţ~ÁĘĺ\íjöî?‘ď™Ă{á‚ęž\Ŕݡ,¸ŕ IǰůpdxĹMÜ5˙UBW×adę;ŠÇömG¨†—qď­ł/<…+†˜3ăâ_w2<Ÿ%łaěŕQNźŽęĹ3{ţĚ zGýœëšďŚ™H÷Űżý—7eý^ÂzĐ vď% /áśëÎŞT¤˝˜ľ×u^ľ†/ď9nĐ Aƒ \Y˜6łşxeŕ3ÂÎ}ž-Džq…W%\Š ;žôŇĎî˙ě)řż¤üŻ÷ţ‹ť˙ýĎď_­yž<ůŘŞ„Ž{žż÷5.¤Đůo?ŞüÝ6!ÎI|řŽG ţfűYŮđŠ-žŻŢžřŘúš?ńüđ8Ě˝&ňK7)Ł; žzđÂK§QaË8|đöŔ§&=›Ç!а˙€đjo—KCmۏđČ{ŻfĹBǞ#çŢŠÄáƒÇIŤ—pýĐv6vńÝŻ=ĂđßÁ§˙Éݐ"§÷źÂ+ݑŠw¸™+ůÔ'VvíeÇá3ŒϜĽ7pύg6ďaĎĎa7ę#/ń•]ĹďßťŽ_šű(ńă“çő݆CťxéÔjî_ľßÁĆ˝ŻŃ-¨J5sŸřh‹gś’ć,ĺž;Áэ<ąýlďâؖüčö÷s˙ú÷ňɑ­l>šćFŢuÓ0;~Ŕ^xsÓčQö wÝ~Mngßx@ľĎą'—~ĎŢŢń^úź#sY:Ç6äná0ÂĐ܅\wM…qâNU݃rĚYşŒ[np=˝‰Çś]H_ú:KT3W󉏶řńśQtîľźsÝ|ґxjgŤN°s×IŢ{ďj~ĺQ噝§é—łYqˍ,fœČĐů—Ôq~ňXőąwđţßx„%/îf÷Š 7<‡ëW-'>óž¸=Ę覟đ؍óĄć]˝ƒœĄď‡˜;o>7Üx“?řĘEłF‡—-á™ŕšíÇ__ĆŞ´YőĐGx˙Ěăě|ĺ4'Ç+dx+W.aaŤËćożŔÖˇ@çýf­×ű˝sQ\ŇzPŽžđ×>Čş‡ßGúÉvvO”\sËn Á.ç9nĐ Aƒ \Y˜vąşűĽ‚/¤Č×&Ţť\™Ý‚î¤cçË_}ĆóÂ4 ÷l(řܲŠtOÍ'öˇřËs Ć$|‹đ+÷*§v8^úŸž*ŘzmäŁF樰{{Á˙ó„gçy—ăó_*9˝>ňÁՁ?\˝qaă3%Ÿ{Ćqüb;ľŕřü7 †ď<üPÍŻ ŃńŻţźä›Ż!Iž”ńíŰٲţ~ÖŽYŔ÷Ž=Ż8ěîŢÍÖîĺ]ˇĎeӏNQŸŘÉřÜnž1ŁC;öëÁĐŹ!\7Gt°qën˝ćzî]ŮĄS(˝3§ŘýĚ|çŮÓČԌŮđCžłěƒ|đžwóžýß乃çŒ(bă–“Źżwc;v˙ŒMh`çSOqŕÚ;X˙ŕ*fh—Ă۟ăŤOlćŕysqœď~éqĆ×ßĆÝŤoçĂë„jü4ťŸy’ÇŸŮ7ĽÜ=˙ŇGřî76Đž5w>t?÷‚ÄĂ|íĎă'ă—~ĎŢîń^Úź #+ďćwŢłč}Ç_ţˇOňňy;;aţíďĺfÓß=Î×wž›ÚŸaţ]đOďmńĂżţ]‘ŇĹ+ížýýFąň~>ó‘ŤŮô•/ňĺËtť};ŕÜĘ~j5'žů5ţvëĹóq\é–ÜűţŕÎIžţŻgĂĹ{4hĐ Aƒż`ž‚bćŠÄnIČqĎ÷źÝƒy38úÜsßĹĆ#Wj x…Ýłż€čpó;W3÷ĐK|g{S¨ţb@pŻţŻ–›Ĺ Ëf˘'rŕňčÝ 4hĐ ÁŠ×íüş0+qĎĺÚ‘Ď6|ëâŮŞ˙9@ŤC|ýĎ?˙Ůc×Sń˙˝˛š÷Üł†đńťhçM™ö÷óĺĎ~ŸoňFĚĎZĚ%łY¸â&îžSąý[ť.’­zá ¸g ~‘Ń㼯˙-/˝ÝĂh0}Č,Ö˙ƒűXvj/[œfB;,Ys3ëőŘô˝’żŻ4hĐ Aƒ˙ż˝űŽëş|˙=÷vN ‚Y€HQT°,Y˛,Éaw’íu­ŸwfjfśęŐÖŤyokßÖV˝Ýzޡo‚Çoj=ií‘eËöČV°˛DQ˘˜s‚ČątB§Ű÷ž?$‘H BSú}ŞPşoŸ>÷ŕ^ôůÝsîďˆE[ó`ŐU“ĺ7ąŠcŘřţšĹŻ­úńa0Ţy–_tžEwz(đ9q*ƒčDŒŘ*Źxá¨ŮʗŻÂJ„i˙ŕ=~}îNXÚamŰLąŠŹ}6nÚÄŁ[\8•Adt€_:Á{ís׍B!ĝ-ŻîYB!„B!<ĎÚŹ !„Bq'Q*7—òdŕćf”Ó‰ŁźGe5š'—MĜœ$=ĐGzh+ľ kş‰;šŤB!„B,Âś†\’ŒÓrÂ|4Ż_ë|÷އťžÍçGŮra‡e˜ą(‰+—‰}x€ŘŃC˜ńʁů1Łű¸Ö7‚Ă~{e2$/wF–§byF‚U!„B!áń{rë:œîłš6l"ř•ŻăÝśóZ€:r8Њƒř‹ƒřvÜEüĚIB?}Žd{ŰÔvm؊Š)űWßÁײ5'ÍýâXŚIüč˙öŻÉŽ-S óGţ,]#„B!Džó{`włĆîf ˙*Ź“§WlćKÝĹţO9öĘ?üˇřvľÎ¨ÎŚl6|ťZŠüĂ‹wç]ËV|o3wóV|wľ˘t”ş­/Ľëx[ZńílYëÝZ2˛*„B!îLš‹Ę†zšŤ )p*2“QúşŻpś'Fz…ŢrS­Fc•víçŁóuMúXĄ6smŘD١žƒŁ˘ňŚŰYŔěŇQQI١žĂŔŸ/?GX—šÍ4‡4}ŮŞ§l6ô€ŮĘË'2˛*„B!î@v*›ˇqoCzx€łm=ôĽ=ŹoŢĆžzďŠurw7ëxÝ Ż[ąťyůŽŐą2mŚy˝ŸýúźŞ5ëŤŔŚcWŠŮ!žŁ˘’ŕł_Góz—X‹•˛6ǙȑöB!„wĺŻd[ľ‹ĚP;űOvŃÖŐËńŁç¸Ó 6ÔRíXţ÷ôš`ďÖëÝç˝[5|ŽĺŸ•˛Rmćk݃wűΏY€])üş~í˧kȓemVç8Ťw9hň¸š8™ ;™›XěÔ4ZŚnŠ>$eš7ÜöăL‚U!„Bq‡Ń(đťQV„‰čĚ1ŚD4FŇňSŕwĄc,&Œ,)PܡCĂçV˜łG´LEK“˘Đw=X-ô)~űqÇ.ZhÚĚí5Ľˆ%,Ţ?•%^ôŽ€•i3GyŽşőÓŢ>,äˇ+‚¸4ŒeÍ(ďjč´ŰŘćus0e|*XpŐ­ÇQ^AŞťk ű¸ÜVŚÍޞŸŽńíŞ2vř<œŠMň_şú‰Yî xůƒš ţ˘wˇÇ#lúœmcYsÎ=Ŕ'Ź !„Bˆ;‹˛ăr*°2$3Š‚úm<Đ`gŕĚŽÇÓ¤Px],*ˆˆNZŘtřÖS6ŞJ<}ż§ďŸűx߈Ĺ_ýÝY¸2mŚšÝ׌›–E‰ÝFŠĂFw*ĹO†BŒdŒÜߊíŚÉdÖd ĄĹďáłÁBžăŇdMĺŚkn÷˛íőíY™6ťJŃl–ża—ßˉhœh6‹ŚĂąkéÁp MŠyˇý¸‡ŤkŹęëxöß<ČÖÔŔ uÓY¸ŽĆ$\“mďĐmGOó˙ńä­7B!„Ŕ$kšB#K˙ůSź×Ż‹cš‹ĐdÍĽЧ;,ţ׿L󯞲óľGlx;E'-~ôšÁ?ź’e<šoáWśÍŠ”iq4çŐĐăF–Z§Žqi2wÇgŰdňÚě7+˨pŘůĹđ8Öź‹ÚŹľ•o3€Sń§â 7Z‘l–_ŽŽĂÔďęŰ~Ü­]°š䍟źÂ…“†AF?‹]śýo›/sd„B‘÷Ź É”;.;XŠI†GsOiNN,RÉô’§fŒEŕ˙y>Å.“ď~ÉÎúŞ›whÚzLţâgoËbdoăWĘ ľ™™H`Ęá@Sp%™â{݃Ř<,äsÁB:“)~š@M SëŔžB?ľ.=É4Ł™ ÚÔs–a`&ˡߡcŽ3˜?čœ Ţjۏł5œœf|8ÄřÚU@!„BܑLÂŃV™‡BżŠëŁ[nż—ĘŇMŢv‘1ŕW˛D'á˙ţC;×ük,ań_ţg†NçÓ´ßŮVŚÍŇ}dŁ´`IîwˢŢiçŰUelóşŃ”˘ĘigoďÚk4ŔŚIÓäŐĐŁSS…˛Ń遞ŰŰŐeł:ÇŮňȡQéĺńI ΅B!ÄĎ"22FUŐAŽ-uŞů¨ŤöŁ2ô-߲5Ĺp9n ¸ŠŇÂ|VŚÍŇCƒ$ť:ŻýŽ€°‘ĺL<€oÇ](› LYž q(ăé’"F3˙<2†š6ú—2MR–5cäĚ2 bȓ5VsV˘Í—ÚH\jĂłšyYꘟÜNüĚÇ3÷‹ŤB!„┥˙Ü&ëiŽŽd[™ÂHDšrž‹3=q–+fŹ *vnźde ‹ˇŽćJ¸UĂnË=ˇkƒFEPŃ7’“Bçˇ2m;zˆřé“řîjŽOH˝œHńýŢ!ÜşFlVݘ;Ĺ3~ú$ąŁ‡–X‹•˛üm–`đű˙ߎVtżK)üť÷â\Wä‚ĎŘńŁ`š×îó˝‘l,FüÄQ2ýK¨Iţ“`U!„BܙĚ$ýíčo_šˇŘšQŁ2˜ ŤBa‹ż}9ĂO^ĎePúÚgtžů¤`˘˛Dc{ŁFßH>fWšfÚĚŒÇ ýě9•U8**Ż=ŽË"mÜz‰•ô࡟=‡/_Ĺ–Ë ´Yfp€ńWűEÓp”Uâ\WGŞłƒÁżţ RÓŚV’É=ŤB!„BĚCS°o[n­Í3—MţÝ÷Óüđ׹$ĒđĂ_üťď§9sŮÄŚĂý;4”Ęç‘Ő•“locř‡? =80繅ŞĂ?üÉöś•ŠÜŔŇ =ĐĎĐßţ¨N##ŤB!„BĚŁŹHąľAăŸ÷üĺ =Ă3׾,ŁS&݃i~˙[×k”i Ž}2ÖřÉă üů÷~ĺëxˇíDŮnjX†AüĚIB?}î¨*Ľ0~÷-/ŹuuňŠ^RRň˛ŮÜtĽÔľŻŤż/äťB!„7 U!ř›_„Â7Ţ.‡Θ¤3ŠD †Ć—/XŐ|%4•Ű ő2˛LIŁV’1"~üéţ>°éčNč6P , +“!ž ~ţ,cż|ą_ţŒĚ2g˙˝ÓÚ ŐÝEާ{­Ť‘Wěv;ŞŠŠÉJMeܒ`U!„Bˆ‡ ˛& ÎđŤkšŻôň­šsGSN'Žň •Őhćä$é>ŇCƒy•őWäÇ#Óβ\N IDAT€…B!„˜ĎbƒÎĹśŸV*•1ěîZ몈;”$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘w$XB!„B‘wl.‡Ľ(…R …"÷ëÔcĚü™Šçšú¸B!„BąŒddU!„B!Dޑ`U!„B!DŢą]ýá÷žňt]C×utMăo~üĘZÖK!„B!Ä'˜ŒŹ !„B!„Č;ś[o˛Jt'6ˇÝfCÓŔĘ˜é™D ëś ˇ(Ż1¸ťŇď˘ŔĆĄ^ä2T[!„B!Äň[ť`UšńnꇞM›đ—Wŕö:çÉ,lA6EzbX_ĄÓ ..ÄTÎ,O?6É35ú´ÇżÚëä˙}ÍI[ęś÷DJ/â7×°]Yôtđ%0׺Róp¸ŠxŚ˘„ˇ“€ŽĐXŢúŢ)í°Ň¤„B!ňłžgo7 şĹčŃ7ůťCăyÝG[›`U+"řČ7hÜRz‹yČ tŽ`=ĹÁzЎě¤ŕ7Gg{xŁ­{œä+50Řáäů36†-“ŰS|ą1Ĺ= ńż˝a'˛„]pÖń˝j;/utđRňöÇ~WR7ȃ^ĘJq"4Aw>‘+I9y¨Şš‡<š%˜˛ŚI ‹´•ßżĺ–/ÇĂZCö@9[6׹š.H0ŕĆ­DC#\8}Žƒ—¤oňZ­x3˙ň™íTé“}ńŢ쿍ĆÓ˝lhŮÁ˝Me”z4R‘m§Î°˙ÜؚĚúXÖ}BąftwßÝÄÖÚ"ŠÜ™D‚‰Đ(W:/sä\ˆÉŤŰŐ´ňż<Հ÷ęX‘e’I§sáôywFÉĚ*ۨ¤ľe#[j‹(ôذ’1{{9~ěÇłKŞŻ˝ š={6ąĽş€S#›ˆ1Đs…_âJle?‹ôęţőçń+°RÝüň?âR´ŕV~ďŮ-”j@v˜×~ô.'â+Z@áŤn`G• eĆh?ŐĹĐě?Ŕ'ĐŤ çś/Ń0=P5Ód&“(ˇ›~őŒ111 ĺĆá˛OŐśœ˛GżDlčďŽŢşsŤdx˛Á"Ńăâ?żî`ÔĐš2¨sÄůfcšŰy)갚{<l1cMÎ>5‚ž•é0gŇůř( |ĹĹ7;]ng˙€AÁú ězđAJoó“a–ö‘żD7Ű7ÍMĂÝ­<´ľŒ ;/ňÖ—şYT/„bM¨@=Ońn68btś]âlŘŔîőSZYAë]i:.„˜œńŻŢ"ÖÝĆáž–ŇpúŠŮ¸i÷?^AĺťoňóóńkDޞÍ|ůsۨŐctśup.œA÷Rß°‘–Ú+´Ç}ëžňŽăÉ/îa“6ÁŮÓ§93qWąkëž­ňňÂώѹJł •Ł”úrK˝ţę2Š× łˇzűZhŮA˘ç$X…ľVľ*Ęv5LMÉľČîçŇËo05ŔQNɧ‹†Ć$CŻţ˜žÎ Lě8gÓc÷âu(pn bkĂnůVzq– ::턦Ÿ=–ĆąNßŠÍR_ ,(XľłŤ´šoř,ş&Fx9­P(üŽBžRQĆC>ƒĂ)Î'Vˇ“)Li.`ɤ‘ŕŤ-Î!‹č•“üřÄ}ńiŸÖÇ{yâŮűŘ~W3MgpvÎЌ¡q'űІ8Ţ^Äݛf߲°8ZÉhňź|ˆç_ë&pnˆä—ćޖ-lşđ!çWmxőfűŚ(ÜzOo69üŢ~şŇ~śÜłƒ/Ý;Éßźé(´BˆŐŚQťs+ÜQŽźř&o3žó{ÉÎsMrr¨‹Ł§Â׌‚~tĄ™ńĚ6Öďj ââiLŔVÂ}lĽVňî/ös(tý“úƒ<˝é%ä˜Q64˛ÁcĐţĆ{ź|éę§ĘzŒĎđŰ­ëŘZu’ÎÎUčY[&YËE]M!ZoœÚšBtÓÄÔ4ÉFťĆV?Xu×ŕ LýŮł˝ô˝öQÍW…×e쭟`ś'ďSx*ËI ‘ęx™ö#uěŘWBĂUYÜ:XU:č@zža’Üc6ÝŇńĚđAw…Ľ|Ą´œďi(ŕ‘šj˘‰ ţůĘ0oÇŇd›Ż†?Ť/"fż^Č#EďX?/Ś řĺJŹtńŁp Pş‡űJŠiőyŠsÚńj`d †QŒ ńvܘ1—Üă.âóeAîň8)Đ 5O%¸81ĚOǓšQ!˝?Ř\ËÎýN?żťy;żKnß/ ´ńgĄë˙\4›—GĘ˸ßďĄT‡T&ÉĹpˆG&˜9#P§Ž¸‚Ż–Poƒ‰Éq^şq衰rUĽüűr7şăç=1jJƒlwédÓqŢčăĹXf sęĽ ü‡rĎ´{–ľeůAYŽfßSŠŰ}<\ZĘ}~7e6 #›˘+:ÁoFFgú-Ž^.ƒ ü§J/6+Á‹]ĂPTĘ}>$ŇaţŠł—ĂĆ"Ž%Ëß ?‡VŽE¸ŻoîőŠäm}śoň (˜=-ŮUɃ÷”1zěM.ůďçîýϸE°žŠ JqćB×fe'8}qŒ{î+gSóíŤt9őŚűŚQQUDôâ;|Ř1ŽÉƒö2š÷–Q˘ "3……"('%E.Huqehvç×$6]P1Ćř ]‘­Tú}h0`‚łnŰ ă'Os44ë“:;Ih)÷Ô.§eeI$§××"™JcY.ĚŐúœÉN08^HeMEÎ(ő:ÉŃ1â%A‚3*\̎4ՖR^čĆmSŠăÜ>~–cýÉAťŤt=űîndc…ŸCa$“D&Ćéšxžˇ/Läú<Ž:žü=l˜ž\GŻŕłßř ŸŔ¤÷ŔŤüÓŠë#ךˇ”–ť›ŮQWLĄ[# ÓÝŢƁc=ŒÎč>؊زƒ‡vŐPá…ŘŕŢ=xăă`aĺ*‚­đÍ=EhŮ!Ţ{cˆŇ– 4;ÉFG8qŕďw'–!AnÎŞŤĘíĹ6ղ„Ă&Ř6R˙őoPć‰2üâ÷¸Üé˘ěé?ĄĄŢĆäGĹéƒ${:H™Ő¸4P.ßÍßDłX_kP_e˘ÁĘ ĚJŢ䬰Ѐ’Ş ű2:çzt&nuBX˝ą(§˝>.܀etǢœI¤çŒ2řĽ|ÖMSl,YÇY`6ĺćň "ƒtZ >[RDšË2‰vÝN­Ż˜Ży\Ř:.ó›TîOŽ9‚|w}›ľÜś#‹Íf§Ęë ĚŒňĎWƒU 2ŚIJŚ4l †iM3ďŐTöžšž–{ęZWŐîđĐZęĄŮëŕż]ćĘTűÖđGUüSەůJřś#Í|‡ţbĘ˝ţ"OÔxąĚ, ásúy˛ś’ŢśnŽ,!’1-‹”i˘Ł°k \Űĺ⭙í Ů ůvC ­ö\}-Ŕfsąš¨‚M~˙pš›SÚbÚa1ĺÎl Վç+,Ó$ƒÂçpP ]}zÇÎ"‡•j‡ĹžCŤÇŽ×ك• :9ű9ëîŢISň˙t>ŽśçÖem}âó|Ž^ťAâĽ%~43ÄЌ|‹ččq+HIЇ־ nľo&ăăqüuuŹ?ĺJÚÇöM%Xăg_­œ˛QPęÝ *ÁŤBŹË`2™E9KhŹtĐ١ÄOUť—7X™4I@Ł˘ş').ôŒ/ăEe‹ąža˘-4íŢAwşƒž˜‰+XÍýŰ‹É žĺhß*ÍW´&étPšĽœ†zľ“ţ1ź%3BU´@ {vŐSʁe$“&6§‡˛u ă÷7X׆í×5'ůNóü[7lMňű[aü’›?}Ă~“Á6ś–×ň;A#Ɓp‚:ç&×ňď‹Kůp ‡˜¸>˘¤˛a~piâuM|ÝŤ˜ wńżŮůƒMUl˛ť¨Ö 3 –çľţ8Wb“ôg˛€f+ŕ›ľěľťŮWčâőŠ‘ż"4°Ě8ϡwňFÚ4 Ýöš3×ŰȜŕç'Ĺşň üiŠ eĹřqŰöĎiÖŮQVĹ=VŠű{ůU,KEQ5ß*óâó”ńőâ0˙u4…Š\ĘɨŸ–OßÍ]s:‹(wú˔büôۧŞ*d’t]ŸóŞeˇĐ}KqčĺW8á- Ş*HeY{>÷(j|€‹í—řŐĄáŒŠB‘2ƒgxîavßľćuë¸g]=`‘Ž qěŔQ\™œ52Şîx€==(3S ]<Ć+ĺf<)ť ‹ąě&ŠÉŁ#tu÷Đ6ń”­c÷ŽťxFłřé›W_Ľ+ŘĆđýŮznŹH˝Q“ŚYŰXŃQz&׳cOăÔ4` Mé¸sIQ(,ňacœ4ŮěTcé4í¨gô|?˝Ą$ąánł4ś6Ő;Q@˛ó,ož‘&ŽçhÝŁÜ_˘SŃPEáɋŒťƒTćúh‘‹§xŻcƒqŢ9XĆĆ'×ăSK,wúGžćÂĹÜţƒ!Âf9Ľš ŰË4żÁęÍ;5Jw˘;7U°Ň7W^ęˆÄÍ_gŃęĺ‡SżšŚ=c“ź?0wLĚÂÂĚŠ}śŚMsęÝrÓĄ5Ëř“27ÎŐKÓp)  q¨ÄË˝‚Őüq°ĂHq):ÎkóÜű¸ĘćĚĽćĆb(™źžl†•˘+ibšt4‡“Ł6;Š§űÉkYSÓÉ$ý¨Ľ•;<ŁÚY&ŻNw°ĚkiÓg_ż°š xŹ4€}úƒV 3âě:Ϛ=WP”ř~pžt;E:¨E´Ăbʝ“†ÖĘП2opÖ,îŘY¨•j‡ĽœC+Î^ČîÇöŇęc˙ŻsnĆ¨Ş˘°y'{‹Ă|řv7ąRYzOŚ÷†Ď›š{MC#ĂĽ÷Ţć'm„ú&0čpýnĹ,bß\Avślb{}!Úř mííźt6í˝‹=Ÿ^ĎݑaN<ƁnYKW!ňA*ÔĂűoôđž˛á+*˘vÝ:Zv­gďc÷cýň öO˙omn?ÉŰíq,ËÂH'™ 3žœś•%“Kˆ’ťŘşŒ< wóľGƒtźü:oôLőřŽôѕřßźo÷ ňÂrÍ'˝+˘w̤ąL‘aŘ,˜ľ…Ş=ŸćŤ­E8nP†˛Ű°i všƒóťJŮpR˝˝•Żno%›ˆĐŰŐĹĄ#mt.áŢĺöQčP€ÉřČÄőţe(d@‰ĺ÷Q  ěvM-Kd _ëŁeBă„ĚőřôĽ•;#XľŇ$§b+›˝öšZj46×ęŤYă&Ϟďr÷ľűŚćëAY˜‰Ř’ŢÚ4I,ÜśĽ´WĽcĂüE—bäv–ŮP ô•ä‚ 3ág˝|˜Čˇœ<՘}œÚˈđ÷œ).fˇĎKƒŰIŔ椚¨‚&ŸƒżlďăÔrösź{‹l‡<ˆšÚΆiĚJí>ĹşQŕxmƒe.׸Á.öŘYŒ•j‡é–ĺşz€]ŢϧĘă|ôňžuĽŔYĹýťËHu|D{ƅߠ岒Łp¸Üřź’ńôüKÝ܈•"ž°@sásĐ՝{Jsťń(‹x<š˛§Čbö-cîŕĽ##Œ§-ŔÉćÇă_ožŇGŚ˘‰G>ł—äĎßáđxžžŘBńIdÄĆF8?6Bű°É7Ÿndˆb Î苧Ƈiď ߤž&Mc)/…~áĺú_ďbă–jüFýÓ§ÄY„{ľJŠŠ.FżĐż:+mXQN˝ýƒE:<†aŸŹ:ŤŘł#¨Zń~Ţyă$g†ă$Ěűžy”űK4ŕzŽ}źňÂ[tn]ĎćÚRŞJýxÝę6o§śÚÇ/~z„Žĺ\šâ&kF€š|宆UV­T‚ě՝śáŤiŔî,š–ti6ĺŠŔ_“ MM÷4IOL,ú}G.šůĎďŘÄäţOOňćmĽ˘6ç–3Ď lŽŠQ,ˆFCź}ľăŤ9(ˇĎß(f6Áá‘>€Ňě4Uń݊ööx8™ůďćú:y–‘fԄş˘ÜĺÂE*wď¤rRçÎÝcœM§,#C¨*\Nt ŔćrSqĺ.Er˘‹łřCá†L#MȂuĘb8teF†ŕŮ o‡Ĺ”;ŸýXĘąˇ>VŞćžĎňœCK˘ůŘöČíI{MľNýúg‡Lč‹á­ú,Ű×ű92YëĎ4!„óČL„™0•Ž›Ď^œŸÉ`ß(é-ŐŹŤ-Bď -Ođ¨œxÜš‹¤sâT.čSšşíŚĹHŒĐ56U…âYUňx)Đ,âW.qŹ?–kťb˙ úŘÉqÎçüQŔćŚzk _¸ˇ Ÿż†ćŞătĚZ–Çşö):˙~[‰8á´EKٍ´ŃÜ(¨ć§ź$ÖYŃa ĚD’¸%(‚%tFrŤ–ÎYCv1厜ŐYM…Ig,ĐŞh7_Ţ}“ÚşĎĐźîęďVüç†÷ž–âÄyűT+ƒçm|}Cš˘Ő<úoŔĘ\ÍöíqşŞC–Fm°„óLľĐ˝%|Փáƒń(=†‰ifčO¤ˆ(ćžÄ"iš˜€†ƒˇŃYŁŰfœŁQƒ˝…6܁ržV”áĹX–ʢ*vĺćşwE˘ŒZ`e'iOY4ťÁ >ëcĆÁĂĺ…ÎnĎE”›˛1ŽÇ˛ě čTWńĺd?oĹRDŃ)v8iđ˛WđWR‹i‡Ĺ”ťˆę.öؙzŐ­‡•j‡|Ąyi~čAŻ38őúűźŐ3ß}Ľ`MöóÎ+1Ü3öClnĺSőŠŽŽprt2ˇţÜ :5ťZi)UD.Ÿáݎً¤[„ŽôjmfĂć*źÝS÷Éę…lo*FKőÓÖť˛ËÖ,}ߎn9ý"JîŁU-ă”!„KĄ(ŹŽÄ1:Ŕpjćm-ş*Ę5“ńđŇ.†&ťÚ9ŽŚĽy;­m3×YEwSěÍ0Yd6$+ÁD$ ÁR6Ő9iť6̨Q\_I‰f2<YQŐ°’IryŽ˘B ´aĆLeŰ6Mĺď˜IŤÜÄĂ“œi`(žĹ2Œ EIXŕS mžQłtj*w‡ćٞÜÉé+ł’N#\ěJąĽÉ…Ť~lžä@o†âć]´5 Ë`g?Ń;aQTšśq_ĎQNF}´ÜłŽ9ąőbĘ]eŤʚĂLŽ™PľŘIďi’]Ňýˌ-6™˛Ř՜Ąb(7˛zOł1ë^şľcDĘŮZ`Ăî­äO71bÚ¨tęšŢŕŹz*ÝĂĺ<\ž[O3b*üv;`ecœ˜gÎćX<ΨĺĄB9¸żŽ™}–…‰ĹĽÁ6ţ[(ƒE–SCöÖ°Űîd_u#űŚ˝>19ĚscS'‹•d˙h”O×đ랏Űȓ€‘N3a9f]XDšyÁŕĐŕ-žjvÚ<<^ťÇgm‘‰L .ŞQî",öŘšęÖÇĂJľC>ШÜ}?Onňęď$ŹgďŒ{rMF;Ú¸4a§ż;>çő‰*Đ Ň1ďBŁ•5lŽ× ˇńޜ`ĚŃvöˇŐńĹŚVžú™NŽßŔŽ`–žƒçh[éŰs–źo@f„ś^ěŰĆđGý¤Ë›Ř[ĺä2Ş*„kKQ´ńnž} Ż{€ž‘8 SÇ_VŖ†bœńn>:]Ú˙ęĚďżuŽŠ'ˇđŠ/~†Úśz"lŢBęŞŕÔë0; ˇˆ Ž6ƒk^v<ńyś™–eŇűÁoxţĚ$:ŕBőš}~ś=ôŰŚ˝>5t7ĎLľ™ćÔÉîz¨ Ł„˝O>Î^ ľlłÖE”ťĘV?XľÂDzGąŞĘŻß‡9Cďńô‚Bžvˇ ƒl*N&&9ÖGʎƒHhn§oĄJ7&řłőÉeťguůíëäďJ+đPnsPŠóNď8™`-OÎúŔLNđę˜bł×MšM§ŔŚ0˛iŽLFxgh˜Có\ÔĘ&Fř:_.öSď´áR `›Ö Vf‚^6č.+ĺ>ż‡RR™#Łüjx‚ŢiýÖń‰^ţ\ŻäkÁël0‘˜ŕ—CIöŽŻŚhÖ{/ŚÜ|Mó×íi,-á^ż‡*ťŽ‹ÉLšîÉ('Ćă×>-ŚSîÂ-îŘšV—+ŐůŔđ ŁđT5pߜľZ ΍]ĘŤ+*Eű{ďňËŘömŢŔƒëéȧöŸć˝łáźšŠ<ż$çŢű‚OľđčSŃâ#œzóC> ĺMwB!>ĄLĎç=Ł–ĆęJvÔşpŰ,Rń(Nrřh;]ˇąÄXjđĎż0AkËFśŹßH[ÇJM2ÔŰι޼ĺZČ ĺůăÜŰÚČĆÍŰht(ŒD”ţ 'xép;ÝŤ“[i’\xw?öäö4)ňřđMŒrâíNŒí÷°ˇtćPŠęáŁsuEyř<Šl*ÎŔ`'Ÿăܡ|)SżTń§Řú/Ă7ľźŠ tüĂ?2˛kôißüíIő.îeVÜÁ˙ő?]œÍłŕI!„B!>q4ýśr -™5vî“Ă×§:›¨űÂ3TmÚ€Ż¸‡ŻW°–‚Ć‹ŻâRC^B!„Bˆü°ëʤˆř;Ú˛ĎŇĐҀCWŘĘZX÷DËŹíҌţú¤Čç(IDAT‘Č"†;M‹ƒŠG­EMő ęôɨŞB!„Bä…5 V3ĚÄ˙ƒ'*đW×â))Çđ k:˜)2‘ab}™č]df1žác¨Í ÚÉÜTŘłY`¤4Îu넗ş/B!„B!–ŐÚŤSĚÉA— _ZÎB—ŻŘšźŒE !„B!„X=ŞŠŠÉJ•Ô€ŚPJË-žŤ(ízR%ĽM}żú;SɖÔ†.…B!„Bˆ…ó \žYíëČ=2ŒNKőť°ďB!„B!ÄrńxÖ&°B!„Bq3Ź !„B!„Č;Ź !„B!„Č;Ź !„B!„Č;Ź !„B!„Č;Ź !„B!„Č;Ź !„B!„Č;ׂUuƒ5SŻ>~Łç…B!„Bˆĺ&#ŤB!„B!ňΌ`UFO…B!„BäíVÓú¸B!„Bą\ćL–`T!„B!ÄZÓ@T!„B!„ůE“lżB!„B!ňͼـ%€B!„Bą–” X‚V!„B!„ŤIîYB!„B‘wćÜłzł)ŔÓ“W!„B!ÄJ™÷žU!„B!„b-iJЛޒĘŞB!„BˆŐ6o‚% P…B!„BŹ%€Űíž÷~Ô[ÝÇ*A­B!„Bˆ•đ˙68Ş#ójœÁIENDŽB`‚mastodon.el/screenshot-transient-1.jpg000066400000000000000000001255131501733112700203320ustar00rootroot00000000000000˙Ř˙ŕJFIFdd˙áExifII*  >• ^nomacs - Image Lounge 3.17.2280ˆx ˙Ř˙ŕJFIFdd˙ŰC    $.' ",#(7),01444'9=82<.342˙ŰC  2!!22222222222222222222222222222222222222222222222222˙ŔrČ"˙Ä ˙Äľ}!1AQa"q2‘Ą#BąÁRŃđ$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š˘Ł¤ĽŚ§¨ŠŞ˛ł´ľśˇ¸šşÂĂÄĹĆÇČÉĘŇÓÔŐÖ×ŘŮÚáâăäĺćçčéęńňóôőö÷řůú˙Ä ˙Äľw!1AQaq"2B‘ĄąÁ #3RđbrŃ $4á%ń&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š˘Ł¤ĽŚ§¨ŠŞ˛ł´ľśˇ¸šşÂĂÄĹĆÇČÉĘŇÓÔŐÖ×ŘŮÚâăäĺćçčéęňóôőö÷řůú˙Ú ?ó×ŐmŸOą…˘’sଜ*ň¤íääđ)† Ěrý‚1‹xMăp~lű< ËU! ŕô>´ýďýć鎽˝*9ĺs2ô÷( EöˆG$ĺ@ęAäúžüŐś¸ˇ&K‰tąófEśîzqƒŽo­cä󸞿ýz }Ł;°zgž*](żřv56 S°HżbŽu‘„˜Ü¤Şá¸ČäuˇAëLľ ťĘÖ+4f"nێŸ7­Q Ă8$d`ŕĐ—Łô5^Î:ů‹™š­$Qm‘ô¸ĘíÝţ´r7uă 8ÇňăŠsJ’…–=2~úú›{řsÚ˛|ÇÁŽÚyíéIšąÇ_óęj}ŒŚÇÎÉžÉ6 q öĆsůŒDÄ)ŕnˆÇzY;\Œ§éҙ“ZJ-äi2T°;€ 瞝g›Ě)°î8˙>ü}x¨ň}OLRďmۡúć€&6W!Aň‰8 ƒŸĽ0ŰL%XĚl†Bž 0Hŕ€łHƒn wz皑-ĺ‘w*’Ł$ˇŚ:ŇÉiíŰŰ8ĆsKPśň´…üÜdtőţ´ď˛OĄoî‚ čO#ˇCQ,Ž­šXƒëš°mÁŽzç4Ŕ6ÚĂ­6”’z’i(˘Š(˘Š(JÂâŕŘ;%Í´BÔ)Xäl;ĺłňŽüŒœ˙…LˇˇKĺ˛Ý[nhBöFĺĎŻń#ëTl!óm/œ˘0ŽŮg WçQ;žŘ÷Šc‰ Ąű ĺä“'ŻĎţxüë'N÷EŠËš+ ’ᝧŚHÚ6ÜçU×$ž˜ö˘[ťÉV[in!q>§ž~Ł“˙Ö¨š5ąűĆĆ2䃁ózńůsŠˆÄŚ+b!#p%™œ˙7oN8§É¨9˜Ům|¤Ýöˆ€p“Ďj•ôí¨[íśm…-/'şu˘8Ô!&4bT‘‡(Ăđx<ńŸŔRb?´¸{TDd„iÁÇ\÷>Őd4úeáyž˛8ÎĄÇj†k1 [ţÓnç vĆů<çü?QRź@ĆĘ,Ŕ`ťUŒ‡ł`ˇĄëßúU9"xˆ0HȤŽ+>ă(˘ŠĄ…Q@Q@Q@Q@Q@Q@Q@Q@ ‘"8,ŞăüůT‚ćpČ@ÜxŸŠüęݍܢÍÂΑ›d°Î23‘“ÎqĎCéV"žš*.mÔů;~|#篛”ű~?đ J=ĚƞsŇÉČç,y¤ó&ŰĚřŒe?ŮçˇăZI$ŃÜÍ(źˇ$BcÉl—UQ€3ÜŕΖ+ű‰Ę—žlža œtÁěF}zĐĺ>ÁîőfXšU,Ž98cÉőýiٛs1-ęO5Šw-ÍĹžeşľu)ß6p1ëÉÍg4AWp‘N@ŕsŒŐEˇş'N€nŽ n3Ę[×yĎ\˙>iŽď!٘ŽNiďĹ$ȇ8Sžř¨Ş€(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘ŠŃŇáišŽlDţ\k'œ_o’FG§9ĎLöö¤ňÔ$gěcsÂýçRAą˙5 ‹˛ŘŢštĚcrFHV]Ŕ|Ř#$pp9ëĐdŰ›™Ő6.FăÔŕ{gůšL@ć6_$ł çdp?—§ÖŽ@L' hČYša9黎;ú~ŞM6$ÚłJŃű“ž˜ţ_áS4ĘŽ ÜL2Ł,X‚NěőôëřŠL,žăLҘ\KžedšŔ?Ný•4˘…B `óż=@őúӜŰěÇÚ&uĆJžyăߜóÇZMÖć2ŚIô΀1řg?Ľ0DIk,ŽŞńˇ'Éúқ9ąšÎ1Žŕ‚AúpjȖ)o>e+÷Iąóu˙€ţżŒ°^–,—EW‚.3ÓКMą;ô3Ľ‚X1ćĄB{Ď@­GV$›ĎPŇž\gś8ŔÇJIßgîݡďÜçééŠc ˘žž^ÓźœöÇĐ˙őŠĚ!mbĂžxŚTUéOg&7uRO?(Ü1ϸÍA2ۨýËłp:ŽĽ+‰;QEĆQEQEQEQEQEMkvööתŤ-ÂmŮŕcŽ@ŠPš0Ą6€ąůxç‘ëő槲+6žKi˘á-šyś Ď8<ëŽMNMjtÔ ę>сż“ůƒ˙¸ŹÜßňţ_ćRKšOűNŕ–'gĚĽHŘ;ŒgňŚ5ôΒ)ÚCŽÓÇ8ÎG?ŸçVĽ6QÝ3}…„& ĄBs›<űđM<´&W‰tż¸DnŠ>rwŒ÷čGҗ;ţWř˜ůWr„“[Ł$M´7^˝pF"ióßĎs¤›p§# ŽqŠšU†deƒOĹW&-Œg'Ӟ?/­RxdŒe”œgĐú}}ŞâďŤV!Ĺ'rOľĘYXŕs“őĎôŚÉpňŚÖ Ć93ţ4ŚÖemĽ?ˆŽsß8ţ†˜#cœ`ăŻĺŸéLc(Ľe(pĂţf’˜‚Š( Š( Š( Š( Š( Š( Š( Š(  Vsˆôűȍ̱q˜=Ž@äöŠ BbŒ}Śáżt>N~÷?(öäţ´Ý?S’ĆĆöÝX]Ć#b‡?ăţESšŹa€ Ąž˙‰¤G™^ghœĂ‚W$“œc˙­R # Hš›ć*eäňAőÇŤ˙} mď,úŻýô(ňĎŞ˙ßB€E;Ë>Ť˙} <łęż÷Đ ŃNňĎŞ˙ßB,úŻýô(´Sźłęż÷ĐŁË>Ť˙} mď,úŻýô(ňĎŞ˙ßB€E8Ą9_űčQ@§Ýę( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ˙Ů˙á shttp://ns.adobe.com/xap/1.0/ ˙ŰC   %# , #&')*)-0-(0%()(˙ŰC   (((((((((((((((((((((((((((((((((((((((((((((((((((˙ •"˙Ä˙Ä˙Ú ř/šřO­Ĺĺs{~âđßcĘçžěţžR}=>nż=٧uqŠúNł^~żkžţ9ßťYů§sƒ×:§˛|ľĹ}6uଷż,Ďłćyť|űë9ڜGÓÓh}šż+gĐ׏đŤérűâHˇ™"$ˆ’"H‰"$ˆ’"H‰"$ˆ’"H‰"$ˆ’"H‰"$ˆ’"H‰"$ˆ’"H‰"$ˆ’"H‰"$ˆ’"H‰"$ˆ’"H‰"$ˆŻíţ"yו™ ´ôĽćśŐźßFŹxÔ­ĎşĚV&¨çž]°ĹVnŒŽ—LâŽĚĹÔٖöÝIů*ń¨Ű]ľ*#Zj÷™e›n[-ɢĘĆÓ )jĘĆŞtQÎ["ƒytŒĺľSDŁ+mFvˆ”´T@Öd,ŞÖ][))_é8Q×çE-2śĺ k24Ň@ÖdhđĄĐŹĆśUC^H ç žÚâŁé0r’ő'ČYĐŻtyĂŠ§„^Ödu9cĄł†;|Azš8dú ü}é÷šłťĂӔˇŠĆ/9Â]~0čoŕLęr5ä7áH€ŻwcŒyŃ眚AŃç ›řƒť.^žžíaĆąôŸ6,ňśâĽ8GŃćâĽŮŒł|šĂfŢ0îŕÂ'ô_4:x}ώÎ|ŮĺęOłŠď(wy4% @Žp™č+žŽăż•uňÖ'rźŢ;谜š}-ż>՗ŃĎNnÍ|ˇĘŮŤĄ›ó.Ć~™çŽ¸ŻŤĘž/[64˝jůŠzŒuÇK.5š˛ĘýÍľóXÖÖ&§K>TL€jË Z]J€Î>żß›g9:ź­[!šRô¨ËiěrÎş~sĺó´gŽ­ź›#§ł…ŻĎ˘%?Mó:ű™šą“ż‡$¤9VA‹ŸL{ř6ŻG‹ezÔ´W8Lě!˛kç쯨ÎH÷0Ë˝ź6řdĎÝĺV}Yţ„á{§ÄĎž4Ë]:č˛Ęők—„ŃFژusćâśÉň}Źj\á3×cľ'Ú-gčÓžq•ŻAĚnĚWu=#˜×鍳yÄm ĽŃ…mTw1ËĎ_jctó™lŚ1@Î7_ËHčsËŢŊľîg哣çĚŁŰŤ'f4 +œ&{ŻŻŃ™řâÖ&úWą‘1{śÓ˜čÚr])ť7k^.šĆ36ŐYíÉŠ!`Sćڌíń2{vÄĂGCnsĚËÔŚ°ş]^ʎa@W8LěÝÁHُBŰî uWQŚÜuJ ”j%m8͞dę¤5e$ś*ž}„k‡žgš%Ż%’#u™I,ťq]–WEľô­8 ŢȲľ׋ŠšÂgŐsyúŚyÝ^Unó,ĺídĹQŁÔŮֆMŐ攷űŽVtoäĘ^ˇ;0égÇ2zy˛łťĎމkߒË;ŕŚ]ńÉiś|ŽWG[ńű4ŐŻ›ěşąÓe.6ŹŤj2MP˘+ŞěN†8xy×ăé™ëdŞ™ˆuůó—_?Ú+ܡю@W8Lč_ço9řý˜úˇ\ům­g“š’9ŃÝ ć۲Ӎ˘Á’ŽžÇŤ.¤ť>Ş&%V˝ňqźÇ6ČűސŒő.ztx™çŤŐŁ.ʍW8LôڀjĄr”\¤\¤[Q@Îâ„ŕ TM1˜P iĎ ŻčţsĄÇz§ŠŢzéyŸ=ÇMz㣆ńÝžçŃĎť<ť<ý2íĺËRÚ'ćíüŤ1Šă:çôr ç žžÉ3ń§UŹYţ‹šrőéŽkż–3fŘłš˛‡XrlŰ)yŽ…örěŇň/,ç]O@Áćš­ŰĹež%Ů-ńÖsĹs„ϤĺŐd˜tgÖľËÁ\çaE´T] Ť%EöâœkŻJăŐĽ°ŽŇPŁÁuš5s™Ůš$¨i ňQ°Ěś5śĆQ@Î>Ž˙–Hîđ‹Ú— /FŢJÍŘCłçutp’ő(Äł­XčCíς—NbÍZůő'BŹ„úŹ|sŐǚÝnŐeŐ]%žyFŠę +œ&v4[ŇÎ~'f>…ÖŒ{h—O2ˊëÝűUŒÚs/O‰¤/śĺš Á-V˝Ň*ćöř‡ť°îąƒ~( ç ›e… Z]ŔŞ@Ps†ě˛´gŁn)On˛@Wô9Đ㿤LJ›ŻŐóyľzůôĎÓü–œVDzšW8Lëűż×#v-Ÿn(úŸ™űoš^gRŢŠňňlfŤ6í—ç§žvsłőš+wšôŚ ľć–šćŻaĐÍlęç1äî𬠹ÂgŤ˘Vö¤˘ł-™œęÇ)ՂóZ/L ’0şxJ•ŃË:|Âz)´ĘîrĚíĂ Ą ]†@\áq?<Îąäf.¤%e"˛#vŽ8ßćžœĂE1írĘóźů‹Ô—œá×Ɍ˝;pćzš*‚k ˜‚b ˆ& ˜‚b ˆ& ˜‚b ˆ& ˜‚b ˆ& ˜‚b ˆ& ˜‚b ˆ& ˜‚b ˆ& ˜‚b ˆ& ˜‚b ˆ& Ÿ„A\ă#Đ˙Ä1"`#4 !123$DP0@E€5p˙ÚÖqrƒËĆ$zÎk9ŹćłšÎk9Źćł+J‰üßśŹćłšÎk9ŹâœŰ -g5œÖsYÍg5œÖsYÍg5œ@Ë\ؐfł‹‚ažŕ=g5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5œÖsYÍg5ŸJĺ•ĚTVL˜kŇ-•ătâ™ČF˝śŒO‘{ k=žĹOdXňý)+K)M D!ännb3ۆȜؿ$N2UăÂiÔűĄ9“”SňzLxĹ3(Œ}Ë;DR̂$¨K‡Éßs ß8ŚÂźţ; sžńűEŚ!éß§1Rç1Óî]ė186Z,e§0}Ëy)śvŹî´Ű tb̖{§s,šƒČ|X% Qeą*°Őg)ň˛ËX1mđ s%e¤Ă´ăYr‡tîu†ş>'ÁÍŠĐؓ\{RáZ͒Ŕ%̌Ä`„”l“]+Qł d =ŠpŠ<ˆ5˜Ą€8L"K˝Ť°ĂQrYD¤Ľg (ÚQůᡀ!X‰"˛&L‹H$ĚxĐŔ@r4öË‘XĄ"Á °Ç‡qĺĄĆ\ŒIŽ1k&I¨Ă ŠÍ˜ág!$ÄĄg,Z˜c YŰ#€2d E]†5â9™7ˆůŁfČ&żŃ“Ôc††ĹfĚČvˆ‚LÄĆ@˛+śEj6D¨ŕßZU‹\ʖÂbrUÚ?óö ăeŠMAe:ߝ{[´t2*FěpHT`o÷ŤjJY‚ĘaöbP&pk§1ś7‰Ť÷Bɔ­Ď՟̊‰N/^GŻé dëS‰ŸŹ’ěËěş%’čĺ)ŇĚƓéŹÝlĺOĎ*Ä­ňš™Oňš…dŕÖ%űKąş%uYů)}ęڒ–bUóýŕ[ĚBÔľFĆĚ‘°˛[¸ËÝŻ˝[RȐą§ůMBł $~۟Î?™-{_cwůsiĽÄ˛˝ŽŤ´QUL•Wё+Ż˙`•Kü„łTzc‹ý€˜‚cbWče&^€Rţ˘đ~8‰ŸT¤›ęşÍ`|“ÇĂZ&ËĽG–˝yZÔşŁU~űˆ=Œ"ż/ŒÚ6le@SSEkfXZýťXŻ`ľŠunŚߑłÓŢOşs@đí‹!6`Uď Ý6Ô=ç×KĺV`sˆ´ľX‘ťuc~ęÉłŤ—łäî_œDO éŤ× /řVÂ^˘˛%üKŔŘň‡/ńyź•VéHÚ˝:ľgČ(" –5[ýU$ąŇ"Űţš2K¤c3mł ŞĆ”Uœô“˜ ˆ‡3ştţŞŤTĽ˙ZóAEúJ0äiĚ1(s=™™|Eˆ; 4bÜk‰qËö2=Ă`Rî:ě2asŘ`ŠĘ Ďg+ł|ěćfó{ eÇ8.`›Lôć<ćg#lŸtíö.9‘–Á÷NĹ´×2ӓ+-(SMXE&_ńԎ뼅Ó<Ů;!,“5EjÄL̨Ꮽ*ŔC&4œ*íZ™)86$× ŻôRš6ţÖZ0âcIŽэ٢–YD¤†ťH~-âĘČyŠ­UŹ–ÓˆţżdިÔŽoFƒhŁů`¤œ?¸€†ę>ڔýYMHűK"}…2Čň*ÁI8wý„:ĽšŽk \ÇŠ0çSřĘYÄŽ?)qň7äž)JmĎő w7%B+jňTqÖL‘’5@°Pä$v°%gœh†%<‚*ƒaŞ8ÓąukDćdvfJ;XłÍAu*¤•Ë ÔAƒÜśÎćîi-VÔqŹp "˘=­]×@ďtƒÜśÎćaœMj›b‡8őČuJK)kFQńp9 ˙`ĘLżňUzĆđüiQ8˙ ¨h…Ë>GN8Ń]07\ć;.1‰5”˘€Œ“ŇcĆAϸńĆCnØÓČ"J”0^DTŹYlSńL(+FDú0sî*°WÄáŸ6™ä˝’×=ŽČ´čZ^Ôç)ň˛ËX>áťĹ„,s˜éĹYr†›ápçąŘť.X*ӔaŚn°×g¸nőŘjĺ­6—ÇüD!–n€Žć"Ö#&LIŽ 1XD –C††Šyd`… ŻTšنvˆđ3zÔl–,™•ę;$Œ‚C°@‹6ÎâY D§âŢ(Ĺ~GĚTrlĺ?ÎkD­ňšŽY:*Ł@śpk„Ěš÷XĎáŁůâ@—nÔϸÝbž„›ł:7ö/ř’0XčŃ22HVéÚ=Âľ˙Č÷Îȅ颳EfŠÍ…łB-Ńř÷Îϋxޛ´x‚#4˝źóŁŽVŸmčů¤Íe&ňPF{_Ş´D­Ę•Ţ˝˘‘œ(ă›œÂă`é0Đffk|kĂŘBBó돏Á••^pç" $ żŁâtŽaĂXVbt9r9b!OyŘýűفE8,d‰ ‹l-‘ŇÖ&&+|lë´ča!&ţČœÉk&ž3|fřÁ훣$ŁOÁ¤í’&¨ŐčH`ŻÔOáţ*şM^NW> V´\˜‹6„EœCĀ0{ôSG†@m°ą…ł‰B€Ôą]éąŘ×LŹŹGĐ?‚źÇ+f$`DÄpńD´Â8ăíü|9mm†!|Jű€nW՚­çřwťí2ířłWŃĆ֋\öƒqn⛳9 XO¨ąÄ g0‚aŹäÁpń{Żę ŃĆśÄ-mϢôăÚG"ReťădˇęŽ‘öčgA˛÷#ľă0ƒk÷aXĘúC>#+úq)FĎĺ>‰^ü-5Ç*TĄ0ü@2e!Łą\â”&$őń7ŹćnONfç3s™šĚÜZᡇ‹ azŒn&D HĚGŕÜxh€VWP´˜;Ձłüż€'ݡbĐగJÜČŘť:´L†ę6‚l˜Ľv˛+W)ŃÓ,ŞďśŠúRŤ #Žu Űźt˛`yqĆ.GÓ]s mƒ&ZÜEjŻĽďşÜCjXťÂŤE$Šiôăe‚#Š•?A)˝:ľgČ4 …ź˛LyKUŠţV+X|iŞII4~؈VJÓÜAH˛ă‰?H4ňOű“.`N‹Šsdľ˙ĺŇÓK-]ąoÓ|ěĺ=ě{eŁÓ c žsł%“lÁqˆ,ÉeČ\Œq˛!ě‚[ rĆ$ÎL›‚'I"’)°Ů™,Œ¤ČÜf1a°"–™Xa ™L)“ÍeťĂd˛ĺ.F=ŒpŘ)&‘˝†83´™0E ()ˆ‘’aCN!SŁb7Ăž"PÂ6K™vU.V7t“J ü˝*í°ď)q “Ł0FZąDe*8g`WauoĂY*l@q-FĚ1,ˆŽ ľĺŇĹĘk:#ˆňrĆ(Փ…ď’“%ám”€Iá Œ’ŒaQńŐ]e˙ę*Ž‹™Ag,ŞťöBWQŮ.YžU-QłI› ‰]BeE÷ŤjJYŸŰxůŇɨÔß!3îV;ÁsöľOŰŁőHÁƕĆ$НÚu]‚Ü0’AĚâ’úzhźŃy˘óEć‹Í‚r1˙á ˜!‘ŸH‰ŸG¤“ţƓ˘OgČč´ř+ ;…ą\ÉŢ8ƒdššŻŹPŠüŠJĹ7–° …!K]U‹š ööM^ÓNJšĘ‰‡=‹K+B+ňÔBČ­†Ć|yâ ϔˬ•_Ŕ\Šĺąenyő鑲<™G˘íÄ&ɓěr*,Œ˘­€FE˜6Ě˝ç׆ë/矑š|g‹TýaC(“9'đDFĎƐädţž?N?Vɍ=Mz/á˙éýa~BIţ7’ŞĚDŢs@Ň.dRݏVZ{•ţŐ}Ľ#!ąa†gd[ŐZqËDČ¨Łş gžg‘dšŐË{ôѕ?JżËʚš ‘Sż0~(§Šađ˙h+*ŐˇÚô[q-9a˝‡çbÚkĂiœ•†”-„šÝ;˜Ňg żei2–ÉYd0›ËyXiBÜk…LžÎWbO‰(˘qÂ"’ĺ´ZC§q5_Ă륜YjŤŞÎ v˜ĘYČĚŕPÂ_Ń0 ô0ÄVDlQŻ ťG“dq—#ÇaűRáBäŮ&Á,0âcIˆ„תM QĂ ťDx˝j6K–LˆJő’FA!ˆŘ E›gq,‡"Sđż N‡yšęBń?śLš;iˇěéŸml@“_lKˇˆŘWƒ%5_Ô]QĈ)ŇY•†AĽöbŻäU‚’v3řhţx%Űľ3îwXŻĄ&ě΍ý‹ţ$Œ:4LŒ’ş@6ƒĎp­Ăň=ółńnš/4^hźŃy˘ó@Íółá~>—ť›ž>+ÔŔLqŮTŁPń§bę„OŐk€dTŞž %•L¸Â"HŐ~Řw­ZŒ×т­qkY@˘wą!íŁwĽÎŹő>-âą_”‡…Č%ą`ӏPƒk]‚*kǗT€ ‡e {ŕwec$H)ítMnP÷b`Ji ŮŞ@AĂMY5“ ŽÇîŸK˜*|Zľ–ŐeŤN´_đÂ^‘—˘Ě—,a2ň ƒŠK2ŞyĎ#ó—,’Ď–8d†>ěžľa3›U§‚ĽÂ”^ňŽ>c%¤¤7ĺJ˛ĺ GŔc^Ćçźą‹°Ő‹Zm&YsŢ3ŹüŻĆÔ÷ޏÄrľGڗĽˆf{¨AéŒńö”œBŕáœxUÚ#!0Gš‰5Ć-dĚ5Ą€!X‰)DąŽTŽXš‚LLjů Šě‘řˇƒ`C.PmAeşĺZˆÍŸmLKrÝbňjŹĹÖrě&|Ÿ•Ťc—+rî°=˝Œ¨<ëS`Ž7x'*ZnĹ'Y-=F $7ٗŘ˙tK%іĚb ‰_Ĺ×2EŽi‚:ÄţS“ Gë‹ýć>”ăUŮžÚ7JţˇžSPńÂG†ŞÔM8œZÖPéśďç˛RhĹ°Ř ˆrEŒ ÎŞH˘ˆÓŰýV*_ÄZImÍĺ Ěl5ÍD˘ lÁw"‚ŒK SËŚ?tÔ5Ć*Ɩzƒ&˝S€sp0 d{Ë7́×ĘěâkqĄîŇÁ7¸ b"VÜćŮeç¸yFđîš×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuθ c:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽuΚ×:ç\ësŽNŸţŃ˙Ä'! 1P0AQ`2@ađ˙Ú?҅˘éŁŕ¤ŕŇú:IçĽQéҒgI=M%)ŻF,Z4ăţ$EGÁHč$áŃGIô¤â!B„!B„!B„!B„!B‚fOÁ“|˛fLəjü™źa[>†ß,ľ™3-_’¸:üúťń_ž—›ä÷/jçyßѸzrpz"Źéď›:[Ą¨Ě,†žť˜9}’mxśĚٞŁ67w3fLÉÉßçÖ%˝íŁĺJjÓLY‹†;Ńhf,JzĽă”ě]Źžşď>Iě)KÉ|7öNœžăъÜéď‘ÓUźě.…ö-5!pżÓ ŻąÍ™?ɓ+bÔÖćNÚu>ПÝ2úžÇď˛óžF¨–÷ŘŻ"ěÝQÔ+}ßžwęqS)äťnf˝LůžęŸ ƒsűéoÎ÷^wľö>֕¤–˙Ý^EÎvÝ̚F[ĎÚ'9Ű>ý—V:„ô㹞•Š4mŇßýř8żČӋˆZ’bĆ*e¤oN>ĆďĘrœŸ/žSŘ/‘¸RúÉż+Ů{/&Š7ŚSŐŻ=ĎšţĎŚÄړŰéiTÇÄP|UGÄ´×­j^Ýxü róŮĎu{oeĺb˙Ä.! 1APQađ0`Ą"@qą‘˙Ú?Ş\ľeƒi&–ź~`'Źő(&ú˛iCœ§ł›ÚzƒM4˙Ô—ŸÄĂÄÎŤąˆ|=AńŹ5K0mDôƒikO™ęP,OSSk㞠–„èŐH'´ćJ[Z̔–ÉFĄL”¤Ą˘“ĚMݤÜӟ4R4š8(¤rÉG‰–—Ęnčń7tx‚šA0HCýwĆ˙b˘şŠĘ (¸T*ÄEWPiȊűuKƒ„ß„ÔE'ç˜v‘” ,9˝YŸIV9C(ů˙`ĹŹ˝ĘŞ\ŕ¤j&ć„Ść ›Ş9(]&ć}ćî˜0é0îd;(Ź Š(!ÁLË2Ěł,ZöŁgqÂWŽĎśwŕw}ľEPŮY]Y}É´b:t”âć(AŽM"ĽÎ Ľ­<~g¨¨ŇH–ľ‡iöřÔßTRT8šMO¤;I Ĺuĺ]Á ’F“wBĺ2SÍL´ŽHBU‡MZy™)IL”>Z̔$ŚZ[ëÜՔWZEŻq<áŕó šžćJłŽ8ăčfóĚ;JvV\ EŃ}€ŮEQY@"ŇĘĘ( ˛Ňuƒ‰keŻďO1(ăŽgnąčćn÷! sť p°×rĆŁ=*13ţžSu‰Uö~ŹÔĎîq(ĽŐí×Ţläœ0ĺcIůŹÝÔQ>|Â1YaŁ=úĘE{ÇÓçÎ]ĕggagŁłîm§œi4í†bşŠĘĘĘ)–.×WX8‡Üć 9ŔXbf¨Ă]ߊŞF™NYż…ţAłT–%8Ié00Nם›ő†Î8,ěăînωÇ}˝EŐÔQE÷˙Ä@!1"‘2AQa`q#3Br’á 0RsĄąPSbÁ@C€‚pŃđń˙Ú?ÚŠ‡Ńď”&:ľĽş×šŮ[+el­•˛śVĘmçÄ'iőĺnň˛L#Ü˝ÎgŠ[+el­•˛šŔí¨e[ýq el­•˛śVĘŮ[+elڞâ%9ˇĘ iÉEŽ9 el­•˛śVĘŮ[+el­•˛śVĘŮ[+el­•˛śVĘŮ[+el­•˛śVĘŮ[+el­•˛śVĘŮ[+el­•˛śVĘŮ[+el­•˛śVĘŮ[+el­•˛śVĘŮ[+el­•˛śVĘŮ[+el­•˛śVĎŮq%S5ú˝Ć˛U> ŠMĆ.ˆF“ßÉÝ÷k´¸f#h†HŕĘt_Ýž<›U_u.śaRŤEßIćëbU6‡r˝™UMŮd[+Ăš˛ŕŤŇ1e’˜ęMÎw6öČ ŇďQRßĂpkĺvÓ[XËCŠíMŹŃk<8Ňšą7ŤŸľKďɌÔsuäƒčŽbř&`A,’çýDĘt_Ýž<›U_u.śavg4Üď3lJíl¨Ńcr0ť(˘Ńńch˛‘†9ÂB{yZě|!sÝLŸźš{3ÄY¨wŽ˜V÷†˜+ˇĆŃS i¸…5+ťż“Pvč”çľÜÎŢ=ň7¤çÝĚD"hu,ęŮ]ĺDEGČŕĂ éÎŐŻy!wsÉ3›°‡6ÚóGť|Jď.7ú˘×žB´Tšn!5î3t‹\ňZUŹy]<۔GHß  ›ý=•6Ӓ\ĐTźarĚ˙FÁ0ĄâD냈ű9(:9NŸŢ×(ÂľÂîYŸâ Ą^V¸eK›ŽÁ%5Ľšv—ƒúŤ€ĺő•dC˝Ě#ŤgŐXG2 ě,)pţ¨żÜÁXšK„~)¤°dřŽ•pş™]ÝŚ˙Es›YŕÖzŁh†ů'ÚN …Äĺđ…Â[ćœĎNv01Ź‰wśTźc„0IÚ7ď*\Ü)ˇ4Yo0@8oJČć\Ł ×<$7ß|[˛BJ–ˇÝTdɌů'ę‹#˜mrŒ+\ đ/sZó8đˆ`“č„úRćáM¸ů˘×#%ş÷WËŠ”Záp¸3–Œ  Ň Ÿu8ˆ„÷Ř#ř´Ą‚J énˇŸúÎĎ>p?$9î­=ľp\D1qČ ě }Ói)u0ČĐTŻ8Ž^XůDhş”œ'ăœcƒgĎ  ŃĺŽZčţÜ)ÖoŐc>‹´w~oTX|mL¨Ń,°eU6s0ŤŇŐB0 ŚÇřď˜ôUžNţĘé?ć-§37 Ş_Ë 5Hť!Ą˛ŤQÓ_…N—Ÿ‰ÜaƒyʖŢK‰d]yy-…W:¨UÜ iď"@˜L-$ťĚ‘ŔÄb˜!v‡´s€Tj?ÇwUÚ>âśîíÄř˘SťŘ$ N—ŢńŁd*L ĺss…Yô‡0||‚ěç {„•XKo¨ Ąť-ˆEÎŮřIⓢńkąä™EÎú6xDp†ť ňeŢáCČüĄEŢÚOĂÉ ^dŤ'—ä­ŔWŐ|yĚ'?׀gŮÚť˜aZçcŇ“ł%9ÁŮv×9áâň…}ÜĘ^é^?e t}ĆďUt…ăRÇBź¸Ýęˆ/Á\Ž„\ퟄĄžâ>ˆŢ>ŽaŽ‘ž˙gJËy˘aK†2örë˝Ő„C˝Ôâ"vľ¸PwŔËuźŁ`˜Aą“¨Ę—Œ"÷5Ż3€_ φčYož“,m˛ĐaK[…| ˇ[ʖ +"îa[>ŞŕÜ|/@¸ŔšTŞöýG›Lď€ Ékň€Ÿű{üASÄ@Tęˇęń•QÁăîđĘŁ€9t*4K,TťşMŠ é8¸}U*ťęó•Ú?DÁ- 'śŽ ˆ€üĎřL-i ;(ŢŇ$Şu%€Šwt›RŇqpű Ť|ý“K%¤ČM̖´ŸR9 ÁMŠJ‹^1'†Ž‰Ášsâ'âf Ő-ȁlÝěťąÚ/ľßUÝşRvb§ŮşcŮÓ}Ŕ8…JęŸIťa:÷ŰřJlż‘Ân \fыSMZ–ÝĄ‹]ąÁÔŰRj(OquĄ¨6›äD’DBž›ďh0qšľÓt‡9k§%0;TÉßvMZ–ÝĄ‹]ąÁśUpş~Îч–žٕd˘úo¸ ⸓Ď˙˝îľƒ•ŮŘÓ2ÜĹ*K‡•ż Q{Ě5ŻŞŐ)™cŽ űHtéKrË#ú'1źźúi2ťŸ­„đÝźŸy*pââIMp0hÂ`ďÝH´Dz˘n.÷(*•/ćËjłIˢťÂEĽ9Œ}ĺÇŃ}Ťĺ5ďxm§ŃK^)ŽžÖŰl&ýԋDGŞ&âďs“FÁ2Ž}@0DA^9is|”‰uOlŽíϰÝv“Š=ÖćŕaQ q†ˆ&šę˝ëžÎ5đÄ´ÁýÉsśń-ÎdrúţâĆoö˜ó§i}3‹Yę>$ĄÎĆɸÉÚŹ"K-wşÂîŠ4wq¨ÚcčŽw;&`A,’çýEŮéâ×SΤ$œ/¤3;(˘ŃńckľŠcěéRŹ˙­Á…AÁŮtÎw<‡0Â`¨úÙŽĺ0ť=ƝaZsî‡Č"CČ3¸FçGŕi÷2„ ç:'Ůň4Ó!dý݆űS{K‹EF[€ŠvNĘóR{œDpkű\:^}ݝܧ1ź¸ú.íϰ‡NGf1hU)Ôuˇy’îOXSîŞ>ó/lD ÎđÓ#Î%xËń¸„>Aů܈şÇzŚA˜ Śě‡Ň@ól'Ä´;ÓÉ}azČű_2ł›ôoĂLń‡mszORrƒ&ZÝúŻŤoő_Vßęž­żŐŚĚ{ţŤęŰýWŁŻěϒ†‰(^#…ĺźż?Řĺř?´×í š”G„•ŘÍZˌĺÁ{//>şZ–ŔÁů!`€Z ie.÷7d'Ô¨$7É1­m“źŞś2ÂÁ#;T 1âĺ?5X´r3BbPp kŚ-•Kčî.lœŠîCłˇ>}›gú'˝Œ°łßh3ţޘş `NÚ1ÂŻŕ›‰Ę0Đ9$‘ęƒźĺG•˛‰€Ň=)ß0€-—yŇ”ü󝪐×7ŃňŤ|Â!ţ˜˜ŢﻟyE˝Ůďš7ŕúÔĹZU9ĽR Ú“iœAŕQ—‘˜W˝˜ąL‡Dxsis;“ƒ›s]°šęMśßyOéÚ_ł)Íśg^ČČšŽŘ\”íüe3kmA•)ÝnłUłěÄ"Ęl°œĘ,{.lÎá9ˇ0ć#-9ŕö’ }Šo°…k›>jčňˆ\ŹĹ;ć|L.đ*´˘˙t暡5ŢHžęZ|Ľ01śk2Žu—úʸ#á!Rvb8rşě&˛baĹÎľ­Ů\ŚG9ޏ;ÚÍć扈ý°Ń˛ŹL´>ç ăƒÍć扈\äň”ćLÇkÜÍ}cúŚĹg“ć'KëŐ}cúŻŹUőęžëÍŕ]Õ×c„7°Ş€eëű!žźRá!ąÂŇűO–›čcö‘?ćőžZöS.cOŞâŽ ąÁ…˜7œŤ›ƒá4Ÿŕ &ý^0Ş>â×]Âai%ŢdˆžĄç”öĘŻWuÁL{üwDúŽĎř˙u[ůeCI ĎŠ—1ÂҜ|Üé/˙Z­ĹŚř&ai%Ţdˆ”ć´ŔޏO­çáoÍ6ŇD”X÷ŰŐJ.úŹăŃVţYŕőN‹~ŤőP|Ţgä˜Áť‹•ă&Óý×f°Ć?ĺvˇ3ÄÝ{*%ۓ·ňʖ˜)¤îŔ™NKa*Đâ~ ŽŞKăŐ=ĚŤsŮ#\óNůŞ|Ç#*Šů.c8)ßx .6ú[´ŘÔŤ›°Š‰ń7*‹KĎäĐ \Ÿ÷“Ĺ'ŔęËS\a'&ŮSOĚzB§÷ÍĂé8ľĂĚ!ţ"ĽńŹp ű;WHiCČüĄ¤KLJç<ľ,0PźĚ+ĺô…s |Ă˝°Ąç Śě´@\†9W;%1ąŞB.;*Ňü+˜`ŠvĐkŒě­ÂsAĂśšâdˇZâŘűĄ6O‡HźÔ°Ÿ8Le×ǜG ˜`ŤńwÝ Gĺ .öŇi‚wÚ‚9ŘůG}‰Vů"<Š‘ľá@)¤úŁř˜MšĚĆ0VŠžŐys.őź!{ŘcýÍVšźŐČöýÂŞCžD! Gů¸i÷„s0Ÿ4Ł\ °<+ĄZÁ%K†2örCaÇIŘđíK[ƒîŞ‹y€ÂľR{mÓ+”aZá…Ń&az3ŐáŒłI˜ńéóÎŘM>r¤ëć 4`VB ƒ0šBƒľ$'‚<Ś~Ë.°‚rŞv‚ĎĄ0§Ű…ÁŚŘ9ü8›OöU>řTęˇęń•Qďşm'j•>ě0ůQÝ&Ÿ‹ýŢꓛL>vâí.ظMcđűŚ=•"Á6Ěű&5”ĹBŇdJ´48섦Ţ"J+˛šą Úí-;:šĂL0N9Ľ7ćSžéPţ§r†çJ“rp ¸y„Ď/Qčô`Oœ§ýÓń%¸Ű ô+ÄďĘźNüżŞń;ňţŤÄďËúŻż/ęźNüżŞń;ňţ¨˙ÉŸuCߎÝÂqű+ďń'hç<ŹÇ˛ŤVš. óTŞQ\ëH™NěíkƒŔńĘŞ;ž`Ó&vƒťžOŕšSîŰhsgj3LËŮ3rŤV¨/ u J˘ęB.zŇ÷T÷Ňí ¨ ƒ…NťčseP&Œƒ0.ŇîęS¸úĘ!Ţ’V‹K DĘŁLÓ2öLÜŞ‡s˝žĚJŽěÓƉŸ‡ęśŮźBvšá&6›{ś7 "áI˘Š^œm¸8A îç“řn_QťJ•K< ˆ•Y˘˜¨ÂfŇčTY‰kr— ”ƒË<&Wj¨č&ŮMŚĆ0fiŐĽ}ş7Bžćç˙ČTŁNĎQ3+ťĽLSi2rŠTłŔ؉Oď)_&w›Ëhh€>$śgđ/{­h1Šý‡<<ËbD ѲŁöIť›Ó÷ş÷ý‚ďE!dJ2c‹ ‡|!ۋEÎîđgŻÚÓ_lÄHáLÓÁq2Q.§1Ȃ÷Tw‘-ˆD‡ťű'Tď,•Ů]˛ď8‰]Ťĺ˙*żţЁ¤€H”CÜL> ,Ç9ʢ|Ýi?5Q“É:U$€D*´üüaR˘Č–uZj–‰Ëb#KL”ö;ţŕĹSĽçâw Ţ˝Ů_O/Ě*_ Ş‘šTÜ|E3î…PN-N>`H\ĆQţf:|!Úî}s!Ÿ4;ú…ńŽ×a^]ĎęĄÇ%gٙFš\é#H‚ěárWyísÇN kÍq‘ ňyˇ(“˛ ÇÝ ö˜ržyŚe]ƒź(iǢžŤăÍ9ţźˇě§C+%v‘ƒľ.VÎčŽóYL`đ…”^äv[:ĎćśAV[ĚĽĂ87”ůĘŻpćl!p‰á-n>j֎d.Ň2Ýo*Z0Źű_4–ăÖPw,Ďń†‡{]­hϢt *ZÜ(;ŕĚdů˘ď(ÇşîČćôEÎlƒ-ć"Q l‡ˆ)‘ćqú D4UĚJŔVĆVB~2<ţ ¨(SeIl9Ž1!P,gsQÓu¸őD;ý=z§Í1LÜ1*€ůŞÎ´:-Á]ŕ2Çä ké]OÉŔéWŚŘ|řdí5ޤ)‹§jˇÉßŮ[Ýw”ç×H˛Œš5ĹŚŰ@”1qČ „4•qind'˙Ţ2>J—wIľ!ą˝'ˇ _ŠŞß2Ü*mxƒ*§ÍQ¨"Ű!Ueˇ:ď ÄŞm, ÷JĽňUěIň ˜ Γ-ĚL¨˛öĘp˜Dwa Şż‡Ä–â?mŁĐ/ż/ęźNüżŞń;ňţŤÄďËúŻż/ęźNüżŞń;ňŤqT%â:b\óäŠ×eqUŻ0 p¨űŔÄŤAh“ř"úo¸ âsj9Śč$5ę[řLŞm–żNUsŕU$l&‡Ÿ=FŃąÄçŇ8Vd›l8\δzŤéžćĚBk;Îg NsÝkF5*“Cçźó…W>.Ť>VށćĐĎLs}ć`Š5G”qîƘ!<‘đżiĄ^áNŤ|@MŤ˛6‘.mć <ÇžÂĂéľsI°śŮó ?Äş§śQgÚžS…ýŰçĹ ł¸8žÍĘŻmK‹Ć0ŞS{­ş2šéŇĽŸn0ŰeeŇ#'0Ö5 ŞOžP§Ó{­ć¸]”Œ†ůUíŠqxĆ;jšqâh] C*iШXn‡‹‡ixěçx4ń)çřĚ…ď ű]¤ z…ńŻúoŸ˛—“HąŃ#ӁmŃxB,~ţ-ěV‚pť\dÚ¨:ˇ‹ź‰öU˜Z,kq„*¸1Ą4Ňĺ.SŠOŃ㠌ź6œx;šš>Ď ăâťXř š{šœÜt;ÇL/Ź>ŠÖ>şĄ’Ź{ĺŞÖÔ0¤ďâÂŇëŃsě‡řJ•g!ăî)—B,ŞŰ\<¸Rwn­P> Ö #i‘8<;ڔHgšäÚÁä‡uţȒÝ{ â0tšŰr쀥Ă ‚aZFTš¸Eřöć Ěo9YŽŠ¤°dřŽ•pş™]ÝŚ˙Es›YWăçđ˝j5ß2ĐJľ™0 Ží˝­ŠŢ\ŸŮű;€Ż|–Ě\•ŒźYáŮëvg0Ă-p'Iýő×ÚĽXRŠ]ÂŻÚoČuűœ ĄâTűŕÖU.Ěz'Ĺ ÖÚa×mGČÜ?ĺ<˜ć6S Úm>üOźiŘTއ˜'ÂŞá­AtŞŹn] Âeř‡ešDœ&ŽíÓq:Lűĺ˘ęP>pœŽq„ŢţŸ-żX‡Ć<ÂG˘ąľł;Ÿ† ů-ÂI€ˇ<%aIáX†¸%R–U;hE‚¤ŐP›P˜>ČSť1.öEôßpÄ&T}HöD9Äî9W#‹‡¸Žę°ăĺj ˜ćƒ ˙yP.2sýřˇerU¸ýÔÁŢCËöGź}ąí*›CĽŻÓ“í}ś™}K\ýU] f܃Řëšq¨D:§8ňˇá ér™Q8Vť Ć ĺ@šü8VŔBaqúZgáŇđŮĘskM§=ÓÍ:ňQţ%Ő=˛Š4‰” ľĽĘđîíŞilj mËn”\ÇÝ&u¤Ŕ_k™8đ:ó\•nö…IóʔđÝź™ş<—guĺÖx‰Uäř†:Ş7:ŢXŽĐ.-¸ř‡’×5ƒŤw˘ 4ˇŕýŤGŞŃę´z­ŤGŞŃę´z­ŤGŞŃę´z­ŤGŞŃę´z­ŤGŞŃę´z­ŤGŞŃę´z­ŤGŞŃę´z­ŤGŞŃę´z­Ş?ŃhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=VUŁŐhőZ=V?ůŁ˙Ä+!1AQađqĄÁń`‘ą Ń0@áP˙Ú?!9ĎÜă’Kdň‹ţ˙g)÷“ď'ŢOźŸy>ň}äűČď k‚kDÁëJŮĚgpÉ÷“ď'ŢOźŸy°˝ŹłÖY’ŒűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“6ćŻu2|Vç>ň%Ëčśe´ć}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOźŸy>ň}äűÉ÷“ď'ŢOź„˘!e/œŚbômĎJü—ž0%jŽŁ)‰ĄIAWUŕUýVŃ×q>9,üĽŚHŸśS1@)Ł,­´X0›dރ3Ţ$ÖľqŁ1/M˝#ť6ÁušV5LŘxS °­á” !ú‚P+˘ü'.,Rę k{j§`ç QÛ}ŢĘzG’Ť\Đ‰Ő żŞÚ:î'Ç%Ÿ”rĽď:Qč]*b¤gY[”BBŠqtRŒ~NŤW™C5&ÜGđ¸TĽ4_îTďNˇâi(ÁŻ8Í+ž°B™Ž“ršd ESńąw+ÓšLĂՇ€fuOTÉ,d(Oˆžta  3TĎ@ŐĹs3Čç:oOi‡"šĆ$¨Ăm̨ܕp>-š~NÝQ 0%5çĽwÖ&GbŒFȝÎçĺÔš°œ0?!ţ äC|Wú” śőaj+"{FśÚŠĹ^w9Łtł-ůĆĂ2IżĆÁää!ëĐëËpeźmP=âĹÇÁ­ś˘ąWĚIˆoFnxônăęŁyóĺáp°Ę@Ş˘>ąü%'ĺV~ąí€ŘÔ´(5żÔ5›Ş/w¨ťL kÂ28Á¨noe9œó‰@ÖŐ ý”J5ĽžAÄ[Ľhěä~łŠ †T‹X[/"=ŒaŇ<Ą3o ¸r :xUÇąŒ:N/[3ÂŰÎ)ž9ÄĆ6x#ř…¨ŹX‰íŕ’Œ`r˜E•2ôŞäkϔsŚž0BŽ1ĘUľçúĹ'Ů| ËxÚ ~ŘąCąđtJşň߁óz‹›•é sFĘ9ŞÄ›t†ÖuŸEœ ËxÚ {Ŋ… `^rŤĽ´xN/Őeé1î0äkϔsŚž3‹IBäĐSŇ œ€/Ö--ŁŔÚY’ÓËrÚř…@i”X§×P *•şŢ—)íAëŠhť }KX#ŻqK:×ýrŕIÜóhOyŐb™×źmŒľg`(”­"Ŕ˛ş1ŮhmţÇ+ž.Gƒm“ZÜľ§/޸cýMńŁB_0@wbńŕËVv‰pľ…÷šülđËŠV--φ#ňĹmŠ€š–ýXťnP1ĄŠÇࣜČ;,ąB,ӛ÷öŽ[c+Z šŔrTJÁ;Ä%pĄ´Ě U6<1^)š0ä˘,=ÔE2ć%ľ–á‡Ŕ´Y~ĺDLÓâÁąh…˛Ăő+Ŕ§9@ćŮ.”Ś {ĆߊS§ĎRąléncďšLžz—“b˜"Jƒł§źß4%ńĂv/ 9Ęć|łí=ň&ĘY8[ţçúűBźő†b ýĆŽ9ŕ%ÎĘŻŃ7ƍ |pÁ݋LJ˛QŞTĹłĄłÂb›$wž÷ÜŚîü!ěiyA5T¸ůÔX{¨ńůh”x’ q›xƒĹy[‚8TčÄ1-[ÉÂźŔ\ęa>Îp—vȊť_őˆÚćÍĎĹ‹nJ˙„#ÍíWoÍŘžM›ˆćZń@+0Ô[mß˙”Ë&Ťţé̈~dM¸ńeŔr‘ËlšjI•¨VqŃË9ž1˛ľŒM[¸~DF pŻu”›PŹmK1Ŕ˝ĽŠ )…Łœ=ĽvŸěľö”ĺmÖčkŰÁ°ŮâůŘ<Ó\Žšnć‡]“r‡Ĺ”Ƥa@ŕ~DCüjšU˛ŕl +UO/ˆœT.0eiżú|Ý+ü)+ř‰Ć ¨K‰Aeôđş%şŃ2Dyj„iiWŇ_‡:/;˜ 9ůnsÜ۝8|+ĎNŽŒęÁ9; uW^Ţ XŃ,9Śr¸šˆqąxtÜŞ9)ĄÜkŰĂâVƒËO—žă Š1]7\nŞ‘WÓ\^‘M˜MtaëPŠův+Ň Î… KW c˘<şEýĚJ”–‹`/2ţ BP'Ź7əbˇZXžž i,ŐeSV ľ‰ä?ČjTşóÜÉX‚ŽĚÜäČEo)І˝wÓтĎ&d?wŘůTf¸ýźcƒCʈ 5Â$°Ń ŰÓb2’œĄO¤\lŹŞđ\Gź&ĽšŮ )é˘Ň¸ NwĽPřIX/&‚uz­˛“ž°şQd ¤˘,Ý}ńŒć_ÄC„ÜV˜ž{›Aľ{Á4zÁ"΋Ť†ňMXŽ}"`_9Ęf~ŕ~áŤfŹďP *•şŢ—3} ¨_•Ä`A„`[Fá¸űŠ)Ö  Is$úȡꢹb'´ĄŹŤÎT„2˘Ý.X”!ľöŒ ĺó™žĐT/Ęâ0 Â0-˘ëÜRÎľYľŢ=t6őí oő­E™-ň?!ŕ›^hRyź {^„3(ŕä”{ł[­łs|/UJXTŐGđ“Í {ĆŮěŸÔ†°jdŃÍÄppIVňł!^Cńr+'¸—vČc^óŚV¨…9›‡ąňË1͝89ÄgTŃŻĹÇ .śWü ‡“8ünŽëňB'œĘž˙HIEŠÁ~ŢqG)ˆEäy“…8 ŕ>óˆ¸î*ćfňŁ"ź˘ő—7w t› \Ůšâą6S&Ž‘őçd"Ůs?€;ßÂ4})nhxóŻÜX"0ÄGU*°×I°Ő͛ž+ ŐÓ>—05´hJĎbV4ćPč^âă ĽKxE‡fYĘZ&ĄĚľ/ĺôŞ{ţ$BXá]2+š˙~îQÉą AéœMF’Ű"ŁxÉĂUú™TÉs|˜ÔĆ:Á›¸QD)]u+kE:ą?ŠYžţ]sŇVůJ0b9ćgÍ´8\˘ă* Îdě…:TŞZS˘ K+÷T–kŹ­Ź ęÄţĽgÁ˘ÎŽWQó÷ÉЊ’ҁyÇUaá§źUXĄR8Žœ‡$ĺ9ăTŒËUk­üH‡řęřOßüM›‹MľŻä„?2!ů‘Jó7ĺ˙/œą)GüiŻŽ…ʆvF­­~DLĽ.#XâĂqĺ*ä§#]!“ľĺ‚‰`Ěô%V¸1ĄŞ–Kś%bšá6-pŔW‚¤gY[”hXŽ.ľ) Ľ…dŕ™‡â§•řŘ8°ÁÖ0= ůdťb5(Ńq°×ä—ăÄG.š*ˆyşđtŔJcŤó‚#fŕ|[rüş˘uľ4Á,ÖۤTť€đč–wQ•c$řRҎÁUŐś8`ú€F§[SLćgx–!Ť?˜řobFĺK]Đ> (vË˙QĄi-EbÄOh3#ĽBüŽ{7ƒ9šĆřŸ¨ú¨ŢFźůA™[ί˜) x6=ŮçödĚĘÉęÄf;M“ŁˆY¨ľÝ%˛ő˘˜ÍîSp )NŹhâ~™Gyěœ5qV§tÂď1¸ŘœugŸâ¤ kÂ1ĄYđÁľG6|4)L@:÷˛ĎBƒšť™đ<Śĺ¨Ň8O'ĘŹ[:[˜ń8‹ÜssÜ<;NłV—ÁÎc`ąq.ätkœăE™lo9‰&і§c՞ßú™Ĺ#m\Š,ž Ôe“„+ă­Ň0=˘ĎW &…ś˙šÚuüT‡üˇƒXÉ(Š’—z´ ř„â0ÓéRJôKCąr†AŠŻIAźoĄ6] Ŕe iÇ8Z ­3ĚŐ4A6břăń’f‹)Ó~4v¨?¸ y?áoůUű˘ţ˘•Č҄Oň>×ý§Ú˙´ű_ö†ŞśÖˆŁ÷˙´bs?ő-˙•pia&&ˆ€źë#á†jÓü@/˜~B~ťƒÖ5:ëˇl_…Ä‹!w9żDÖŹť:‘Zç™ĺ,˛¨­eCjŠoěŠ=Ľvf /č¸ţĄĺ}Śm™ţ ~˝Ă¨­Œ 5G$ůpŽŮŇ\A“F>ň*&R‡÷3,-Ţ~ÇXK…/ „tšƒT•ľ+#&JRQ ˝âf`ȝ۬5¤ż$ĺ TĚ˙ń†wóg|é3łVŘ<ćŰŽ0†8ϔÇÔţ~B"źUúDž,Ž^şžI-#‹ŁC„0E‘ę˘Ĺ•|ęT3|jg˙–rJÄÍÇ#”ló“˝ęŽaDTü`c­[™S€6ÝLDRłÎpN6ńމşži4vš°eÎţĘG˜ĆĚWŠŕqÁÚšxfĺÚpęŘÍÓ5QZÉł#éc›iÝşĎN•ÔŠĽÚÓ V\ówzŐĂIźzĘW Ç&¤nĘýDaœÜ !ţqG/ŘVޞSFŽŽ °äř‰ŹwEű@œ*áV^—íŐâ§ÎPÁź=oüŔŰJ# Ř˜HĄˆxPÁź=nT9¨‡ŹŽŤŔg“îđ,đŘ#îóîóîóîń%zJ÷ë~°(­U<ź0ËĎOđÎőjŠ]L*TghŮţ9Ş­W”{`7ëá?;™V^K‘U˙Ő!‰wOMüoBŢŁD÷ÝĂ)ĽŞŻ¤Šşá\jîu:´žZx„Ŕ°Ě•ęe-Ë2Ÿg8TöŇě *'˜EúĆťň……Ź|W:4Ýp<Ľh1<´˜ëárgŸěśúh4ě¸DĘt\ %Žaš÷5 Ď~"Q,p,:Í*7üE}Ä=‡Ú7ĺą`?!]qŠáârĚĽŹüőáŮ:Bě$F–•}%řs˘ó¸ľ…PńŒź ěĺJŽ›Ĺx{LH†˙g1&ŰĚP7_Ô˅V|ź I@„÷OÔYb)Źatˇâf,ĆČŞő¸5Ŕô˜Ú^Xő•…‘Ľ^˛łţ,bŐc̟Ă˙Ő!4ghPjĄ_ŻXŕĐë1`ăĘZÄňäŤW =eĚŰqH¸ŮX1UŕŮVÎZ.ˆęä…PzDĄˇ°XŃââ˛3@´ꊌS•ž#6VąU­źcT‡@qxą‹`ŮkXí )Áiç¸EVäň= űÜ6€`°óܢ֧9P X%ř)\Żh#ƒu•ŤÎ>d0Žşâg€x€˙ďŐTľ‰ä?ČjTşóÜZZI(hCř›”ĺoׇíqi‹ËmĘ :P`ćA+CLYifŞÁ5`Ôx,ąHů°PaĄägîëě›ioćŹű˘…Öş‡<-ůâ<×ň+xl7˙Ő!śYŹ#ábLXđp@7BÔć€Ô5Uľb9ô‰|ç)ý—{âÍʧ™őƒŠ.hŔšMӎäŮ5Ěä͏Š)%Štőƒ-ăjď(v>hŽkq‰noB+rôí2GT ܓýęf,GppŒ_PÔrBË@-PšiÇQď O¸)sˆ“’ˇ)ˇő4o:…ÍF,ţ"B ÔÂEÖP‘jčß ]ŃĂŤ=8❷“77ÂřŐTFސ)ҙ@bóźÁÜJ’źő†] L3\HkŘĎHŽżUÍńŁB_0@wbńáßéČ,H¸ž3cpúŠâĎĽzÉč.VЏĎ;ˇOn.­Ęe Ž ĘĎMĺRŔ/P4Ú7hŹ)ť>˙‰qúK6s’˙ÎÚ{…%Ůä˙sčŃôhú4}>FŒ40qŸÄH~dCó"EdEđřŘXÖëÁŐ'Łţ tó†T"ů"RŸ‘śuOV˘śŮ˜DâűšŠ2Ůň…vEw]"Cť3ë1T,ł6ˆ@°ÔŁX ./ązŰxxT<Ý”Ź˛aëŚ-žemúÁÔVWď3Ć[œŽ•´6ŽD(!6ˆ@°Ô$DRű螪lj×CÝTŘŇ>$StĐo<îdŻp~%ˆ/#VO&ë>ůÜ6;´ňŸěľö–’âú3„9‡ŰiJƒqpň†šřś\š”•ř›Ú{B÷…+ƒš¤K[?Ůkí ‚*f˝Q°™Axóüx‡řŐsŤeř4ó0ącVÖOlĚyúÜŢ+Dg[˙ށ*ťő˙HrËČqe-Mž6ŰŘ*UŽj¸@ Ş…ߎČ 'ÈFC Švç„6™ĹK/úđş%şŃ+ԑɞ‰hú$ő8Á‚@<H›…da§Z ŹËu §R÷żÓČŔwΔ-x?‹ŠѨ2U´ŽˇáušÍ#ö›ö|[Ž& iÁ„Żƒq˝Çľ˝Gcú:‡‹ŤŻoœ’˙Ń.EŠĎňU÷8œ\ňÜ| 7×3y›m[WŹ&ŹpĂBNĚż!,žĚ9rÔ_—$ýx%¤łT9‡™JäeOťP ýLťeƒŹ4S°A=ââŮr—Ť.>r qcĎWČĆe]’qüđJęâ[ç‰n­ňEŇÖyZ?ůŔ”ŒŘN5÷‰„Ă@ÄľŢl ď4nŐŻ”f¸ýźƒ <Ç+ž ~ĄbŕáU: Mľ¸ÜżÍŐşÉeA­`u5Îb_"ŚČŻÈLbفŰ7ż×…dU™3BÂ̞p%5‹=§)€CV3ŹÎ ‹ ÍxnSA¸Ů¨ŮĘ(+⏬׸Ľj$ś0Şź˘Ŕ4¤ńŃś¸ÝÖă[mEbŻ;…Š,y.}BÓr˝ ™žĐT/Ęâ0 Â> ĎvyĹ=™32‡ňząŽÓdčâj-EˇIl˝hŚ3cű”ÜBJAë8ŸŚQŢ{ç \GŠÇ0ťĹĚn6'YçřQ ěxrŚ(KŘ<mÎdWrŐ{qq˘TźwlnV-űŔ_ ŕncť4o¨řSn\ o=ł?,0*<ć†h o՗vČΜÜQSS Ë L:˜şŒľg`(€V Kö7 ćpˇýĎőö•o+2ä1ż"łĂ´ë5i|ć6 rîGFšÎ1ÔY–Ćó˜’mjv=Yí˙МR6ŐʒËŕÝFQÉ8Bž:Ý#Њ,ńĺp˘h[oű§_ˆŮ\<ĆOóĆՋÎ}>FŁGŃŁčĐŇ՞O÷G&ńŸÂˆDŹű—úFŮ<YÎýźu<ŇPâ× ŚPč^âăGђ˜Öâ‹eĐăÚ8>%Uo[ÍFt.łŐ"˛@Vac‹ßÁ˜•˛Ĺâ9….d\LËäÓ÷ůd^U t™•V5˝o5<É`כ)Wƒoő*8@Â4”.ÎŕeЃŁ>/î ­—”ářüT„ŁT‹đqCÎloFošĺáqʚ1 yŁ‘¸ęŹ<4÷™;!N•wÂdł–5IJ2ć=dqšĆăł ÄĆśq YT´"ż~ lQe7ysŚ6ŽEŽ—9 ŞœQ™›6O(é"şË”zČărŞc’ľÎĺ­đň;YUz›+LltĺŕašƒŁ>$W[/(ËńřŠŃLYĄÇŹ\Ç€ô?čĺâ°˙c''KMVŽp 1AéřŃ̈~dC´+§8—ŻIáĹĽ˝_€ mĤ ň,"@”0yDŢB4nژ\¸ĹWTüiSko”P¸s–g0*?ě!*Ůr+•Ňů40•Î8V3g…ÂŚ ápú—…@TrŽŞZ)ě&ŃCQ-6ż•™Q~Jń÷ćcŔƒŒœęÄoźź `t°ë4(ćŁ+–ŞcÓ~q7e˙°Sâa “AOIłgo(……@3cSMX‰íŕřâ‹t°.WA›Şäkϔ77˛œÎyÄ*‘TUöç(ř­ /ň"˜‹t˘ œ€/Öu!Pʑk ä , éřŠVŐ o´‹WŹĹîŃfůŐ@œ7‡gňRčXşxTŹëŤ!ů+#PozŒ”4ę‹ÔčňđŒ ‚dňă,€óĄÔRăçPSR>VŁËRސŻśÍů[áH”łÓŇp ĹźŕQJĹłĽš„Ž6™5˛á™T[œĐĄ‡%aî˘)Ď0-ʎ 3˘…^Eđâ„?í„y˝ŞŕMůťńbĂQpŽ<¤ľ]2ÖĄĆ‚Ž~Ú¤śćÍ ŤůĘ×U¸9ř=G›™¤´ cƒ\#I@ňěárŤ€…[F¨6Ɍm™CĄ{‹‚°D˘î!Bˇ¸SŹ?Úđó%ƒ^lޚ­íć$CżąďšuđS÷R#Á:Ăőăuž§„sĘĹĚqí/ÓwXfffcŤÂi¸ř— ŮdĽZř^Wřq Ä)„RďŃ“kF[9ř6Ŕ Öă"Ş\ÔZmx7ꎬÍrťą6V˜ŘéĘ Hâň2ďĽÚÜŁŞ°đÓŢp6w+e™•Rp˛ @ž`Ÿß ŠŽJ×;œX0Ô°ŔüÚ–xxŐ̧'fńiűœ…UN(ĚĆäW7ÉŇRi˘os–%Žâô§Î*!ó°mC ÷HŃű™~n‹uřq°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř‚¸ZŠśŰ۔žĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>%öű‰}‡ÄžĂâ_ań/°ř—Ř|Kě>& Íđ!ů‘Ěż˙Ú ?]~ëH2×ŕ´×Ž:g7˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙Żký &1X;zŽÓŘťGmř÷~żó<÷Űî?Ďż?Ďśëlđ˙Ď<óĎ<óĎ<óËÎtŰŹöű\6—M?ÓÝU+¸ŰÍzď~|Ű~ţÓ]tߖ5˙źóĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<ăl´ťî)ĂĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ˝ą?ŢđĂźóĎ<ó˙=óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<đ+îé”X*€KšŻ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ­0)ÁvŠ9I/<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óÎÇßď˙Ţ˙óűÇĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎşCmőWíýߟˇű<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎžűż—ÚvóĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<ľĆˇÍ((g>ťď˙4óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎş×N6śŁšsďń<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<đ[WW˝–ƒÍ ‘<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ-čĎe×X6ҰÓţ‡˙×˙<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<đîÉżűCW÷ě^ž˙ WÓO4óÎ3˙î<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ1ěćĹŤzŻbĽĎn˘R÷‹S>ż=Čý<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<ňűP)nrąŚœ Ń<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ,óĎ˙˙ÜóĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<÷~=óĎ8ÇĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óʛ‰*žÇu}ƒĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óÚŚ˝ţîrÇöěmýüóĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎë•gŃč_ŰôD]§_ÎüóĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<ńËÎw÷^<ŰÎ|O_d÷ŁĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ ý­‡ËR¸Ť^ß<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<đ˙<óĎ<óË<{Ď<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎő۟<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<ăÓ×OĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ çn˜űY|ĺWĽ_<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óN°ďţřßzů÷|üóĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<š×Íţă_=Ű3Ď<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<ÓĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ˙Ä+!1AQađPqŃ‘ĄąÁ`á 0@ń˙Ú?EĘßäKˇđ$ÚßěŻ?ä=}8źţa5=&“sž:ú›QZsîbłănXˆ,÷î9s';Ďëäjză;pZşc;qî4W:]¸TNC×ӋĎć Ş\Ý}ŻzIˇĹÇ*űŒűpGpGpGpGpGpGpGpGpGpGpGpGpGpGpGpGpGpGpGp@Á,źx]} ­×D”’lłľM7Oqł[ŹĎ mÖŮԃľŠn7ÔxrđZä6"o6ľ:CŠ,ŕÂ222 _BxLR2n%IšŠ7#điŻ÷'ßH'!E‡Dˈ,2âw­ĽÄ2}őů/~ƒxHNyŹNw֎D‘´đBâsżaaŚ'ú| ˆ#&ĆîŁe×ŔÝ“§Í…ÄďoŁĽÄď_KžhžSฃ§ďƒeÚ c&ßA˛ŁW~ôŁ]é~ʉ Ú˟‘LIŃAu>ř('Ä˝ăô5wëćU+Q3Mę]Űřűóîk+ŻěmߨÇl%¤–ÝÖÚ{ őx˙4ŇUŕšzyT=ĎÄü‹ ş‰éŢĹϡÁ‚ÇB,Bxę>ß_‘ŁĽ+ž˝Ţ!¤}>Ëиô)éîit.xň¤MąŸý\ńI‚ftř&(—ěDLŻŮ*l—ča`ŇÎŹšbůbŻ8LRIź"0„ DŠ4'•Ľ–ĹƒG|OŞ\A§ŘĽ.!`Ý.‚pN%.:qśk_A˘fzkÇ?aşšŇý•ŢKNc稉2Đa+ĆÜŤî'iétëęcÚˇ?ŕúuœŽ^˛žgxó ҂mUőëÜZË ,o:”ÜfזNŹ!j‹Č™§¤ş–ţN А„'–Ľ+˝ţE‡Dç~Ĺ5Râz}„:őt&‹đ%qt…/–Ő­Żé~Í]đEߧɲć´vEŸýřڋUŢĆދ˕"]Y!4¤ Ťž˘Y#”FÄ!ƒÔ)gąůJDď| R˛˛ł0țHŹĽ„yBÔŹ@;VžćěkÔôýÍżĐŃŁ•˙ß}č,:_tOB‰ţ~ ´ďźŽŠr\4<“ëŕ™PžŢŸca´.iqŚĚ˘|÷ź+ ]k(K0IýščjB\őüQ#P–Đ„ĹĽ&M{ü Ů-P•8!ˇň4ĎD50ü4ÚŰüjpó( ¸Š›łëvɄ˝śŰߨ›Ą•ŰЌ’ϧg‘dş~îB[mÓ7œ‰5•ŹĹú~‡ĘŹ<ă3=w]qéś5âp0Ékýúq×ŰĚUÇzQdíô&Ťé÷‚GąI#Ԙž¨•i Q.ýˆJ-g”˘MÍEĐȓ+6#fgC4É’źĄ ['KŠ2Ń;”fđžN˘„㢎úBÜ‰ÁGŰě\Bĺ>ř1đ7]$‚Ô Tź}‰'… äěń}"ÔÇ~‚Ń.÷"żOěz°-'_Ĺôý(çy[ *çR6ăŃydIß9LÓkaZ’lbfŻ›íŻÚcÎů¸őämwö˛o°¸ŚŇ}˝÷]ýKÍÓ&•ІҺ‰ąŒţDś÷ĐB§ąFĄ1H“&4ď‘#ďĽÂ~b˛ç‚“Âj1]ˆFFGĺÉ̊ Râx:mňR”­}>Âq}>ĆŤü‹˙Ä+!1AaQqĄđPąŃ‘Á`á 0@ń˙Ú?2ş}Cž+ŢJż$C§đfŮdąź0h<ßÔ$B +Ô qđŕ@fÉş~8í ‰ČYŕ óŃk“lY˝6ł{Gž‹łÉź3ÔzţŔ=ŁÓYœçm¸Ž¸€Łp Ն-~Ą`ŠÍ€.­ęŤđqnř]a"A^Ľ‡¨ƒ#†{E˛€$_‹ŞŰŽŇˆIx#1˜Ěf3ŒĆc1˜Ěf3ŒĆc1˜Ěf3ŒĆc1˜Ěf3ŒĆc1˜Ěf3Œú [•ţ`€3Ŕf1€Đžqŕ„1BšBĀźĐžp€Č@ŃŮ:V˝ęâp6‰…_‡÷ !x…:Ćrœ 1C´G4.!VąBšBœďÎ. Ł€ƒ‰Şˆœp”Œz1ŒG¤$ ú0#ľ™ˆČŒF1 1ŒBVcˆœv  ăýÄ9Ďăpł€(C 3'b>pPVĺGâhó0 &áŢÂłóEŮ1[ô"á ([ÎÂ"3ŇZdá & Sh4Ŕ!˝ţ”d\AEnÂ;J`DVŕAŃ †|?'ǂ•ăĘţT$vžKâáÔ˜ťÎÜö†ˇţ8DČJJC^śúCKq$Z¤ŢŽT^­čVäLjH,0îúŔ$Šćk•×Ih0K:cÁ ľĹý˜ ű=Ěq"Ÿ¸Ťő/î‚Ďď5‹×üÁÇŁö§Űöţa G§ĚGżÜągxɘlüÄ~cč„üŻH@D;vŒÄç8HˆľQyƒž?+ĐÄżÜJŸ2oo¨I ôýFˆĄÖ]8‡Ę3P>؄8ÂTaÄq# B@ł†Ž= <`.ÄŔž#ˉíd2Úú„9—œ\IAŕ>ýÔYßĐ­ÂĐQQľÂţJ9“ýĘv-ń !ŹÁ_šŹo`2âÝđşÂ'‹ŇÇ ąŢvż¨OEđÉUŢ„VE|Á[~–°Ç…9çľof :ĂwŔE]Ą™AĄăNŠw{{!‹ (W/Ě ¨ć…ÂĐ@Ć(vІ4áŢ Z’tFaXÁpA@ŮĹAÁ@ ô¸°7SŽ8ăöŇiý}BPˇœ ‹O2ç Éóď ŐĂ@€m!Ĺś˝†ß%Ě#>súƒ&%ƒăH@*NăÎ3_F`ÉöěMkź%A„KÚˆ=&0Ô8šÇ%´ 7¤";ö‚Bľ‰Q ĺ%DŠÜNŁ ĺ5ÎđśDÉÎ^ó_ô”ßýŔČ0†%hC”hA/”`XóQ$y¤ĐŠÁ€ŃK`ƍPęçóčVá*E”5fĂˀ\ ŕ°ž0†Şƒ+ƒţĂ]O×Ě$FVÝʍç8ĘdűGŽ˙¨ÍCˆÍ\…ŹHé %N>‘ĺJbĄłţ›ädƒ,|‡Ú\ÓEĐ ‹ŰŹąnâˇƒ ? cŁÔFŚú—Q˘ę—@"ď<Ęí aüä˘\*´„aIEY"ŐźőjĄƒI Ţ,§J˘Ë °.ďscmčVńăŐî,~;• PeŸ8Ożh2G˜„Ă0QB;^†Ş0• óŹq¨IűI …+ô"œ` OxÓiN "„$ǓŽ)Jr˝łƒ ŔEć…źÝĹJ‚…œ-ßźVă%nTyʂ…&g?Ŕ€5ő1Wł‘Űű†^k$ů¤e~`Ęb4IŰî|Ú2ǚ}ŔIOhDć<Ö Ÿl ?éZú-}¸ˆ˜!`0c=bŹżw ƒ;…QZšŇWîŕgЇ ČÉÎ>ŕÖ‚=‘§H\Mžű…ő>ďB<×˙!×h šßú„€<áÄ*8H ÂQQˆ|Łą5BCÍÔ’=ĔDĚb$v˝"áZÁ =¸† a\ ¸C n$_7–?žńţE˙Ä-!1AQaqń‘Ą`Áąđ á0P@€Ńp˙Ú?˙ş°„Ą˙Nł ŠĽÖ}Ó>éŸtĎşgÝ3î™÷LűŚ ŽÓn1Đ(ř‡\H´-p/ą7ĐëzgÝ3î™÷LűŚ}Ó 1”@_Á‡2mß^3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷Lň€ďŕŚuš2š2ËŹűŚ<Ŕ B¸f ›JgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>éŸtĎşgÝ3î™÷LűŚ}Ó>ééFi‚L Ň+–Â\›|ĄóďŒĺ¸N×Ɉń5¸ZĹÜág™KzčB °ŽŽźÜŁ ˇBqäŽň`:™Đ4"íďţ1RœĚŽw5ӌ2¸8졎÷4*N4R’Cƒ@]Juän˙FĄeA˜~|âě"‹š0¸ŕ…Eě9ĆbÓ0,˜Ž2(ĄőC`ę˙ű‡ŒŔĄ85Ÿíť1r:8Ąď1ßf“CŔŃůó‰ćDAFëă u‰Řţ°„a]yšFn„ăÉ]ĺ[%Ë&Ą%ßL¤Ý“ĘFő^nu"ŚJŸ—ńăđˆ ,S[^1Ţĺ ëżńtK÷‚üćĚF!wľ:Cě21§É#áy ˛ŇtăiOXŒXáżźčž4OpéŔVŠ@Ě1f“¸˝•/ﲀGDÍyn˙O Œš Ă Ďđ^*I!ÁˆŢGIĆmÎý° ă`ŁŢ¸Óš/x 鷴ҊNuĹ>”íi8ŢŃvJŕ_œýRŸ+/ďŇrja‰ĂˆvNEÇZëŒjIé÷ˆƒƒGTŮ?S 1Ú-œHkŘÖFbÇEýçEń˘{‡N<V•ó ?XÁť˛…ž8Äwˆ ڌřŔH™Ôś÷šU’ œüR[Š4Q t˝]qn,1aP‡Y6-]ŞAń•Tľˆßâ¤BČ)‡çĽŔlAÜM'śËŁÜ^OMĐÔĄ°.ůÚq’ůI›“žŚl‡!š¸üeߘ*{TĆ'•‚ŮéUKX€đ]ńÎt~ˆlܚ6ŕaƒÄJ?ľ– eńż)čqŒXtUŕ<šBE ϜŽEŇŮÉĎ:ăŸ%Főy4¨œ™ŃĤčs”ŐEű†Ÿ&(@‡ƒDfé „biŮŹRŠ€*˝ąđ°C“Ü>pZA­;4iŽ PA!NeGŽůąâ"ˆńCO“!ˆ!‚ĆNoœHĈ2iQ93áŠ7yüMÜ>Hşo˘ÄţAŒŮU•­¸qfÁŤsn 0 ÜS›ŒÉTľ˝˜Ź1?ÂzÜI$Cł€^Rň“÷•“bŐÚ¤ž=ňi űűdíŇŘ{"cžZË2ř_”Ę[ôJ-čňă§Űy§uâył-÷ƒśŮ Î|㎸PM­Vj9wć žÔ ăĘÁlôÓE1iuŻœ=tŐĺÁd!Ëż~0ˇŃşĽš_Œ)%€Ó#~ůÖ7€Ţv@ŕ`Wvq—~`ŠíP_žV gĄ“š’ŞńĽ eDŔîoźT–ƒŮđăf8BËŔü˛–Ä˝‹z<¸Ůs°ç%ˆ˘Ý s1" šTNLl §ŁvC¸*cÓĒ쪐×8aĂLătórŇz˛ŔR^ĄX ˝×´sF̓@Şč<¸ˇŢčÄ(ţs_…‡łĚŸüËvĽ˝Đó~2–ŠXZéźą“0ęhíšľ  ‰3śœcŕÔ&AQéç.iG‚Öԛďîń7ozAŐ d’`áŔ]lU4{8?:ƒdWŃւIŤš0´Ő*ŤgwÓk@Agm8ë3ü1<˜ža ¨™žiŽGĘ óЍ{]Ěu`h"b7_ú°ˇY˜Ł:Ďď-zÁIo}gR"Gv)¤×<+ⰔJ­W7r*ś­×8ťšą •îјŢۈ†Ču”Ăâ"…ŹßŻ˝*¸umâ§)ńŹbĆ*™ ,ćœú^>q6š˝Btż×ĄŇ%č ýŚŠŔôOPqLUĂäÉŐűHťHăb`âüБĹţňĆLĂŠŁ´Bú)ŔA:hşbŕĄöc„&˘fy¤V:1ĄYýفA•ştÎNŰoľw“œxäzŒĽŁ­ “WrahŞUVÎďĽepذÝhá8?ČăÍď Ć@€Ž€ú089π“Ď8ă Ž€sc3iGŽ“ ÓM8<żë%Ł­ “WrahŞUVÎďŹE8'M źű8Tްˇ÷un4+?ťÓŞqGą.Ü;4÷°ŮMčÖ6ăLš]WA8{0@$ó‚ľlŃ5GžłĆ*3V"ÓÎI¸P/F⏀œ|G~vü]ú§L‰†Š@ßjîbŞ- öŹŘ~7s˙ą¸Ç㈠'Žţş5Ex!Îź˙áƒűŠü‡ű%(V Šč„ˆ'Gƒ"{ĂÔh" Çźq5^ŻţŸžż<“v÷˙č%BDÔňœq˙ƒĆy+Ž˜ú šŽJ;Aß­›D×2ĽřţKsť•J…ěYůÁđ0ÔVƒßœY[jăžp ¤č)8&,{'kNşXëüÜhТ:˜|TÁ&ĽŸŹŚ#4:Ź|qʇ@Ţ@—‡~p+"wyß–Š#šÜÖ×ăŒ!PH˙cCʲ×w} @%ţaŐ§ž,{'kNşXÝ |Ătţ?‘ë:-ˆë™Ć ěpěcyъ=ÓGŒŽ~­if.ŤZ~ńÓǗ)Ą…`‰Í˝đůŹ/[Mžuí‡ý ”ˇ‡k„šßÎ~żüâŞ- öŹą“0čhí¸Ă *‰uuíńŽE;šHâ š> $'Ć c„ŻăW]?0cĹ˙Á­ěI~řéuüš-MÉ#Ţp{şÂ*ČHÓŰţßN{řâŰçśpńřBéKńYQ “ÂmŁŢŮX•Ţ^^Ž“çXM—‚‡ĺ˝žĎ!Í7I.U4pŻ28^lam$œŰEiěž7źpzVĄO’yÄö¨´,é×Ç\Že´U+uŮČä ŠxehÎp,ŞGužß4ăŒ0ż Ót˘'ď%x-Ë]ąÖ¸Tjáyą…´ ~rwm§˛xL%+ŽĎ&‡bď9$Ě ĄŮDĽ8pQbŕYU‚œÔ) ÓXţĆր@ń‘WqIît/9 ëJ|s›˘-JŒe?°ţ)m-VuŰ:A§7Ÿ'Łôx% Bp뎹;Ät„}q„!­KyUéŹ,"î"*šá{řČe˛Âíź5}şßűĘžŘĐFNźäˇx…éŚöĆB—Šiĺ+ŸĄ˙9j˜WiWG+ßĆCĐ0]-ßMwĹÉ5Pń›Ť]ŞĄÔŞŕYŹeŕĹźrâŽđȍeÎuĽíăĂë,Ź”“{L–ďفÝ4ŢŘČRńM<Ľ}-Ś`tQž:9ŽÁĄ7ß<„Š  ářCbEĺĽĂľ ČĐŃGYǙRLĄ ńă!ě j‡ÍӀ!6H;Rš›ţ1% Ś„Mřđ1$ 3‰ď ŻąŻţĽÔâ9„,ßăŸüĘ WxÜŕc˙š˛–sN˜ë"††kŁţ2DíińüŽ3!]Ąë¤ŔAŃQÓŮ0b‘€:ćƒő“kŕSm–âÇĆ懀Ăóç̈‚×Ć:ëąýa´B€ť Ša8ňĺ~Ą-Ą ËĐë– Ęä^4…HŠ’§ĺüxĂÉ˝Ľ+NŐă]!TԐC§LheĆöö‡^2s‚Cc•—Ą×- ¤×˄óžĐ}ĽÓ ˘ÝK Ǘ"0ÇÔľçúĂj3;NŃĂżăôJF". 0etDŽ”@?ý´'˘QxŞ.Ŕ Ţ"\: ÖÉřš˜YŽŃlâC^Ćłô¤¨’Hňó…ĽŻ>:äÇEuŘ=9Ţ /j3ălÉěCMęć†ü(đü◡(€ó(Ě´ ŽYçh¸ďGŔÄův˝ŕĎҒ˘I#ËÎ2^y…ž‰:š*š ěä§şf áŰ\§´Uş„ íŃ×ŇsÎÍ tßlr)W+&ĹŤľI|e˜ŹśýÂübšJ”ŁNœ[ÁP,xÓeó‹Y`Ć_+ň™. ¨Dw ~ś}2Ŕ{ťôKŤÖ„č,ý`AQM#˝lë‘=•źnĎŢ>đ‰Łs‹]őĎĚ3ŰnŮŃÍ P=ˏҐł¨î=r+ľŰGő‘g(*ŹŢÄů™Éě$CÜńóš?66!áĽh°ƒ•Ăě´@/jŚ'śš;n˛{QcUxŃ˝EŸŻâőʸĄTŤĐŢ&{ 5ÜôeLÎ$:qň|˛‘Ň˙yc&aÔŃÚ!r?.Č.ˇťçëM*ozçqՄSşOŒ!53Í"ąŃƒŹLdWg9ţˇż§čäFhĘíűÉ™ƒ§ŮÇUuAр†AšĂ ůýaĺVŇ´p;N2• 4Ň˙۟˝Ëý—nYÇŢ[wç]Œ‚"Şŕ9Ťż˜ÁÜîţ2pĄÍÝɌlŤXŽCäšąĺ¨ę ýgč˙$ŞžÇcXóŠH’XĹüÇ>|ůĆ4;žă˙ćJŰÉoď˙OCQĽyţ/j'KĂMÎÇ8žňVĘě•čţ8ôЧQ!ŕ)Űž6ŽTź|<ńÓžG UKĂ+Fsƒr  té;޸Ęƞ‹L˝Xď¸ŰQ3Bű).…^Üë)-Še™ŸL\dşç.ž˛›<2Qˆă‡?ŐöăَĎ8ŚČëo"_ď5í&Wn:8Š+•˜FA2źXݓˆJĹՄ;˝˛˝ń­š"aQ'Fäţ7M$–vő†_ Płü5Îý'5)pńúČ1}Čč×ßsśn­vއRŤ€ä H&Š:í‰wô+ťGW`˘GąíœbĐęL4|nT3(,减8ľŔ–Ňą';ÂTjÚč7Ÿęűp¨Řx˘Ü*JŠÔu2™ŕtV˝đ24ŚŠŞć4†ś˜˝.ÚgŔC?ŰvÇqgyDć=đÄ­śŁiűËY๫˝œod ˛ÍÓ¨˜R˘T{yâ›ěmpɗV3žœ¨śŐZPǗřĎ@Ű|öô9ąA°ŢÜÎ.t5űăŹÍďh_Yř’_hEŰß ĂyPď+?8Q5Ąaí…ĎZłCŠŔęWľCäßoůĆł—‚ŠŞYĽ8Ä+ýä9nüÔŻj‡ÉžŘ×/ľ?ÎBdƒŹ ń^ţœÁׁĎőżďޝËt[˝oYţˇýçúß÷ŸëŢ­˙y¤đ"yŤ{zŘ ŘongŇG\Šh+ú?áŇšef•ź„1ŐpG(‹Đgüz\ş,ž3vX̆˛ĺŰCŸMݢ§^ěIóž7Á,ežĽQÚl*SĘ´|W˙oMOČ ŒęôůĹ4ŒŒÝCłżHC”xÄ|őŔ*¤â×RđŐS\@ÄhJ÷ÚÜZ ăÍ]TŮëă &=öAw5}˝AM…šÄş4ˇ¨uĆHž`;ď\ĺôŽ8=żÁvŁaŽ˝ţ2MxJÚíĄ˜QĄ9AŻőŃÁ´šM§>0’0cßdsWŰÄW% ÷s×:POˆŃň|Ś-¨žTq ]dŐ×m`Œ˜Ą iĐß9ÇëýřŕĎËOÓáěŃ knÖřÂGHôHO–|âAçpY?9uş:ťcm(cfô÷Us¨oă`ĽVAĺËXڐżßi Ż+Ţe&HĂČ]fÜfó€=xsYă_АٰŻ=0(A ľţ\˜ťÜa“܎qóȏb‡Ź4vĂMA:çőó˙ˇšţz‰Üňxq„Ę ÓËżJA\& yčb‡ž DăĆj´€°(łÇŮôL=Ę#řË]˜é.čˆ`iížŮŁf¤ˆ":O((Bđ1•-D”Œ†|LR&%ŁČŽ“Ă‹"'!8úĘÉąjď_8ž8ß=qĆŁ ň4~rŰfŕ2Ŕ0ŃŕÁ’*O.ż—C$á8ĘZ)‚ŤWX]€ĐěŁÝĹ"bP<ˆé<8Ů8Yşđ$Ń+!Âż8݀ÔěƒŮĆnp‘ Óý0Éş$~ssać%lŇߝ˝rÚjŻ@$}ŸljI>†$ěsč¤LJG‘'‡,šŃ7ĐOК„A@€@†k„ &$'ŁÎ&źŁ#>Y24`džP#Ťůô˛3Ţ7ÚĐ-–Ꞑś—˜Śž2Ł0Üiˆ=´:eúö<çBƒAěR™3äŠőۆĂÍ /txÉĽY?śůÎb˘x§ŒRâU8uáœ!đďL‹€JvRą ua^ńFkŚ*ě:l‡9Jwa˙ˇŚPBÂQXn‡^xŔߊěžIˇ::úZmŞh-g::`u°‚‚^|3ĄJ1đŕŔ 'Ź<â9-RzŚ.kŕEq*'ÎRÎI˛o­čo }ŞYĄEřÍĺ˙xĆăĺçăG`“đĺY”{„äĺߘ*{TĆ'•‚ŮčŘÂPFÚ~qĚĹJ€ ‹zçFÚîtpC•uşŢţ3Sâçśů×'3’"‡NďőŽEöM`‡—‡`üćŕśƒG4<ĺŸ&˘ńÎĎůÉvh^Ô\2öę#nŤ ”ňşŔ1Š*öœă& _p4ůÉa643őüN˝ţ|Řź^jůô<€PB[9Ź%ä4ăüq—X“J­xČŮŇÜ3‹ÔůréňçRuâf٧§kpóęv˝ç/„Ukź>pň؅¤FA§ŢXĘ ôŕ‰č;Ĺ)ƒ=ĹĒ•ÍEPĄíź˛u@îĂoœQŮ(v˛Ďhš "óOˆMsšĚąëcÚšRačÁ'ë6‚ćécRƒŢó’xÍí˝§Ą9)R94ďLƒĂ›É ´;˜öŁŕb:D$ĹTZíYЙz4F„îL)âB”ć4ž1šŽEďsk@Agm9AvâoלnƕLdčŁ = ćkh`óf>k„šßϧčäFhĘíűÉ™ƒ§ŮÇUuAр†AšĂ ůýaĺVŇ´p;N2• 4Ň˙۟˝Ëý—nYÇŢ[wç]Œ‚"Şŕ9Ťż˜ÁÜîţ2pĄÍÝɌlŤXŽCäšąĺ¨ę ýgč˙$ŞžÇcXó˙?2VŢKó0`Áƒ͝ ď˜ž†ŁJóü2´LŔ˘şzôËa{dM]n4őץRT™Ęāyßś ę—Ů‚œÔ) ÓXU#şĎošqĆđŘ:Žĺó×9bbf–m<ˆęçĺá¸ăszáÇŕUÇl.ĐÂt𴇝âSŔK jţ˝L‰[Nř%žŃĆťăyč‘(Ł+F=pƒKżľşíĂń‘˝l$z(čwǰá(4ťăĆ~^Ž9×7ŽRŔXl?CŽŁÝ‰ÜŐ^8ČPlIÎůŻźB¨Ź*/nž“Ď @r°ÂiÁâűŠs™Ž–Öż‹ÉEńÉ ĎňđöŐLœËؗ^Ń!IT:œ"uל­§M4H˘~ؑy_ép,Ö2đbŢ9srB#l.ŰĒŕĂzřăx"ąˆXTçőŽsM@“%˜†÷sŠM4“Č1üĺĺŒZX˝/˘Df*ŹE Śą&’@SR   H~lÇßm0 %gŒ’Ő" EÍN˜ÉżŹ–tťLXÄŹ*sú×8.o"łP4ß.ą Őĺů͆Đb´;7_âŮŢó‡K}‘Ś3nHíÜÎ&šwZ{Xţ/0F†ÄŒ@œ† ë@(óÇ˙Řč,ăA2 ŘŽÇt×#S-f ‚1§9“şŤčVN ł é‚îgSE:Î!T VˇOIç:6ČĄwtoL$„e‡AćÂ|ŕ§5'JB´ÖJž[šš)OÇÎtś‚i„NdéÎFV€ö•čMKUa°ý(W¤:ňbžŁŁYOŃ:˛=7ś%PUđÇÍ´_*ˇć`9°ą růðFě(k˜ą13K6žDurÓÁ°E7ĐÇš™\SœŸ|Ą ľx°ƒ•z\ŠEiX•éÖă.ʂľ,_ždţ!Ň0uCşHfő"Hă/.0ž%ôwŚ’ą˛UXő•Ÿţfč鳡Ł"ƒQnÎ5ß Ş­ňďŃŔŻńlďyĂĽ¸ëšÂěĐî)Œ}ź>ŕű5řĂđ†Ä‹Ę˙K–°ę7Ăń‹ęL*§^q(2ëŢ =ÍäVj›ĺÖ-¤‚@śsĚU#cHóŃxŔN¤TD1éščuP.PTóź,‰ Đňuř¸ű팤Źńž[2ĄĚmăę كjuÖőpţ ěmmh덉aŘFˇfć_!ÄÔ 6œŒÎqž{ŸŒÚ¤÷K!ĂÂ˙˙ĐŘú6>ŁcčŘú6>ŁcčŘú6>ŁcčŘú6>ŁcčŘú6>ŁcčŘú6>ŁcčŘú6>ŁcčŘú6>ŁcčŘžg˝ŤĚV|8‘ŐMqôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl}FÇŃąôl'łwú?ţŃ_˙Ůmastodon.el/screenshot-transient-2.jpg000066400000000000000000000604761501733112700203410ustar00rootroot00000000000000˙Ř˙ŕJFIFdd˙ážExifII*  >•ő^nomacs - Image Lounge 3.17.2280ˆ˙Ř˙ŕJFIFdd˙ŰC    $.' ",#(7),01444'9=82<.342˙ŰC  2!!22222222222222222222222222222222222222222222222222˙Ŕ5Ć"˙Ä ˙Äľ}!1AQa"q2‘Ą#BąÁRŃđ$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š˘Ł¤ĽŚ§¨ŠŞ˛ł´ľśˇ¸šşÂĂÄĹĆÇČÉĘŇÓÔŐÖ×ŘŮÚáâăäĺćçčéęńňóôőö÷řůú˙Ä ˙Äľw!1AQaq"2B‘ĄąÁ #3RđbrŃ $4á%ń&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š˘Ł¤ĽŚ§¨ŠŞ˛ł´ľśˇ¸šşÂĂÄĹĆÇČÉĘŇÓÔŐÖ×ŘŮÚâăäĺćçčéęňóôőö÷řůú˙Ú ?âc˙IŇlŘOs„b~`€P’~é뎵R{ˆ­żwsĽw yŻĘqę3žäsš­a<Ťcsţ™s•bX݂ä°ôçě‘J`hćšW14Ęs‡ÉČÝ?:ÁS““rŰçţfœÉ-?BžöţńüčŢßŢ?^xôĺbD“ČŔĆ28Ééő?ç5 Ih^A$ŽpŘøç¨Áç§ëÖśš×bžöţńüčŢßŢ?I:ÂĽ|‡g]ŁqaŒ7ĽENăĐ]íýăůŃ˝żź:J( ˝żź:ľö+͛öť™Ţ8R Ď_@jĽ_ˆżödŇy÷ *IĆ …Hb{uČ\sëS.o˛5ËԆk[ťxēG"!;C„Ő}íýăůŐťé<ÉBE=ÄЀóO ŕgnŸ…7ʡÇY^Ýy8ý1D\­ď ĽĐ­˝żź:7ˇ÷çSůQH,xî:SJÁ´âFÎ=;Ő\V"ŢßŢ?ŰűÇ󤢁X]íýăůŃ˝żź:J( ˝żź:7ˇ÷çIEawˇ÷çFöţńüé( ,.öţńüčŢßŢ?%…ŢßŢ?”P/i§ţ%ڈóaCäŻpĎóŻĘźŽ{ô<)ŁR’WK6ćÂŰ* ˆ’c\ˇĘßí1PÚ\C ĽÔR[ ^d ™ÄC‘z㏿\—3Ĺ2Ŕ"ˇXLqr|ĆüÇó•K+ž×A,LĄ{7˛ôçüŕÔÜźił‚¸Ć×4ď:ć~ŕ Žœŕâƒ<'ţ]ŔôÁ÷úR(OľËľG.1ôQÍ!šVő5/Ú"ŔÍş“€:űcҁ<_00äí‘Č>žÇó Ez*ŃšƒĚb-—nAôđďQy¨_& FĐ1ӟZ`EZ–ŇăA˝Xů‘ţíżÖH9éĎAĆF;JĄ,Š"¨H‚’H=zTŃ]C›qlÖŞóJčË9#(ró؏Ɛ2ĆĽw;jK,×ÜČŞ‡|LJž;uő÷'žj5¸ ď‡-ęyj‚ęâ+‹Ą,vÉ x\ƇŒăŸĚçéÓľ|!Ž d`“Ž3Ÿ§ľąaĽ”0F’YA Xă#ůUA22ůą€3óŕӄń…ÉgœŒôǧăCObV Œ`qÓÔ{~´ …†Ö+pq‘ĐŇUłsk`r۰OOjŠIŁu " ӑLzS 2KŞb3¸úúP˛Ä '8îOšö hŤ&x|˘˘Ün9ç=8Ś™ăݕ€sÉž}( )X‚Ä¨Ú ŕgĽ%QEQEhZ[ŘM`ŹÍ8–<™v.áƒÂŸaœdű÷ÔÔmśœüÇóëÇS×ů֗•Kľ†x„ŸzébZÜLn U9f9ČíҋˆŤE:DňädÜ­´ărœƒôŚÓ˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(˘Š(kiĄ{oćü¸vŢsœţ\T†â݁͠őĂăś8ý P~l~B ‹ć ¸ą=zqÓ>˝űԟhľŮˇě}É'Ě9ďÓßôQ@ g´hŔAYpIˇÍ˙ë4ŸiˇÜXÚš}ţ:ƒŒtÇ~4QE‚ăK`yˇvň}}¸ü¨˝˙űúęßĚŃEAEPEPEPEPEPEPEPEPEP˙Ů˙á shttp://ns.adobe.com/xap/1.0/ ˙ŰC   %# , #&')*)-0-(0%()(˙ŰC   (((((((((((((((((((((((((((((((((((((((((((((((((((˙Âő•"˙Ä˙Ä˙Ú řo¨ůŞÍçeëĺçŽWCˇËĺžFˇžčţky’¸šh  &€šh  &€šh  &€šh  &€šh  &€šh  &€šh  &€šh  &€šh  &€šh  &€šh  &€šh  &€šh  &€ŻôOÎúÜ÷ÔĺUFuĐÉYŞ|˙,éó|X€ľĎX—tJmć j€+úϓżŽţŚ+ďŸ]›ćź—ŁÉ”}|Cyěęů÷›§×rypÎť7p|Ôű?‰şŠG ç =4vsŸ’íń>ŁN?ŁůĚéŻ'VçÜÝąŽFŞĽnLÝ.nˇŐɢYĆ{.Ö|˙–Wށ@-Şäú˜űŻ…Ë ÝuŸ6.§~mQnM~-żČÍ^YžŃhÄ§Űl^p° ç žş]É>Dúzů‡[“+ß4VušŁ fCĂeciň(óEć4xP×ém@P/}Ó_sń ppŇ,Z}(†Ę×;`Ćߙ*óL×ß,+œ&}|‰1w8jěń‰Z3ŞŰ*ň/˘u*Ôʍ^ä}Ę4_‚e”PfîuŠő-Ňäćőîá,ąYwy“ŐÓî)&š`.¸ć&Éa+ÉFÂpšÂfżŚŕÎg•ö_Ń­˙?żtגęž5ÉnĹm)ŕ Ž”ú˙‡ďprúGë9âęZ3Ýę˘ uŮ&^Pyˇ™¨žQ.іK:ę‹+œ&]×ŃŇÎ~'No´ÓăĄô˙14÷Ífoz.K5V™Wm^}:üJ.†ăœžĂ$őŇ´ůdŘiôޞŚeË.ŽDĎmzžkLłÓz󧉌Pč§CçżHüß+_AmŸ*.˝–‰ĹTi°Ĺ;}3ŮpÉeł1ˇç+˛^­ßbgžŤ˜ÝYLŹń3GŮŐs†Ř˘;ë\Ëj˛ vË͎ťSşt˜*ŰZÓ&ęÎK?W”Ą`W8LöڂęEľQň#UDý­VF"~DYäžÔ%ěŇ΋ŤˆąZŚ€{ŕŸ‘€-¨'*€ż*'äU9T'äGśŇ%ěž@XŹlÉâ%ěuq•aŁ8’"Úü@N> ݙű[ĺcŮ@J W8Lôá@_Đü÷w†öó÷áóvęňľă%nIôÎŢo‰ŹÖ=\€+œ&jÓŢůl(w÷×Ⱦ䎡/ěţ{.[ˇĐŻ”ś­•UşRüűĄŞÎ+ŤĘ ÷ŠőŁ/+΅S_FG1ÚĽyn×€Žp™ˇg+ŘŻŻČôՓߥŕŮI.çŇťčŘyu4­ľCÔť5ž’”óš+Ďq%QŤ5řÚyš1nĘVœŞĽžNQP Žp¸ş¤…´zy <4QěK.ÍéWS(éęáY.Ëů1łŁ—o>S˛ŽßÓfJç.žvŠŹŮM6Œx’ö˛cŹę݃1§W*FdڐLA1ÄLA1ÄLA1ÄLA1ÄLA1ÄLA1ÄLA1ÄLA1ÄLA1ÄOÂ ŻŻÉčĹQt vôš˛âÝ+ y;ź‹!ť'N^5“žĚˇčéKĘDzVaż^Ů~v}lç_Ť<¸˝×˘°ŮťdœwÖ8t)Kř˙Aóň† $€pWéó ˙Ä0!"#2@P`134 0D5A€˙ÚîšV(ٝąmăˇfĆWŽöUą‚ˇ4lfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆlfĆl|ťçrÜŚVekúƒ×@~ŸňôęŐîwtÚÖˇŤňşŠTˇ¨ŰÚĘż)Žžu̢ćĄĆK ­Ë{*LĆ@}+|R´ÝAŽó[†íYáą­<âŰGnŚ­Ô ilEVhU‚öß_ŔÔň4ç5ýkGméăÉőÚďąô˙zÜőëN /ƒÓÔËLgmoüvÇßťdîŮÝ 1cö5fBX–6Řb;!î>ěěĂťfż‚`v;ýfšńú„Çéśß—ŽřˇřSCZ2Şâ6;Żžźz€6TklNËmĄŤQ‰a_§ŤNçU§q&>+äTřޘ~97 FzšdBÓ´w4ž|ŞĄbČV[ëY_gmśjř^×§Ýz}"ëúúVů¸ŸĄuűŢĄáIWĹvŤşÖ|=‡Áq\Ę+`˜L˘c•˘ö֜mŤkě;YôÔ§rÜú*~:-ËNoY˛ž|ožĂĚVŢŔßXqWË[(6“Š÷SF¤%ŸËhŸˇßŻúHăŔzý7‰Äâq8œN'ˆQ„âq8œN!^'zÂĘťşéřsô0ó<)ŕŮéžF‘kżZÔVĄĽˆ+˛ńĂvÓz@î*íqEŕ"bëgЏڋM6ÝsŰŃçOĹL¤ČĹJz…JĘŠOúő€c×ĂZŞą4ěv´qk*'ŢşFN>-™ď‰g‡›OŇşśRfeřTUZÍyvW˛ŹcłKh{v2˝–˛4îőlĄöQj¸xyw­żB?l6Š2zŽVW‡NČňš}O)2nđÇţBĘYtF;ŤB㶌5íiVfd˝bâݔŮXˇbˇů2ęŕŹ3ôuŤŰfN^2s9œÎg01˝'0rO3™Ěćs9€ŕÏťă˛­˝`‡Ŕ˜ýŞz7\Ľ(ę ÂÓyôťäŻćúĐJ”jŹéŁ"^sëL~ŕ#ćôîăž,ŻâÚÚôHóeśy”7 ˇť#ćö‹G ]ߡÜđňßfç[—áćßÉćĺ>eţĺCXXľť*٨'“ő¸÷5duK­Śc^Ř×ćĺ>eţ x/fó¸wV*ĺ˝Íg2˘u6|oý÷Ď(ĺŢçłx.iąŐ›a÷:ŃŹłŠŕy˘çVR­áǧ`’+QťVáŸŹ%•ńYŁ)XU€UöօŮђ2ęI•ŚÖpxՈEŘńËYS'‡ƒĆŒReŤŁ…1Ťéąkv^ŰöüJ°ŒŤÚ™Áĺ×X´DäVvŢ-8<¸ŕö_D]˜ţĺF^+ŕňAXËŞ%Lŕ‚€Rb'62‘}ľ.ÆոU-8ő*VhŃSjř şëąđ*Aś˛­ő¨I×kŹaĘ­zzü˙'ŕž´qÂH÷FţŰ/fâÜoäÇţfŢl|ĹkË+mÍħ)ôşÎw<ů^ÇýË}ŐąáęţĂüůó)őG$äűť_ËăÓű>s UoI ÁÉëĂç÷yo߯á¸ň-çśyěTXGő óZ/^ăłä|Ţž^ĺŻű+żmR8–†yňô~ŃÔĄ•óĺÇĚ aO:UüŹ8ťÝć+? \_.wďsĹWz­źöë;-C‹=Вr~Ľěw¸ýť,{[Ŕłc92śU vbÄÍۀ찒ijÉä3,f- ąǒIf3şňś;ňü˜€WeŒĹŚÍÄ‚X™ąä1žǸ⸏QŹwąźŹł”V+ ěܛŔĹg&rxî< Vlܗb™bť,,XľƒNfǒĚguŕ$I.ĹÚ+ë^ǞL8ňK6n2ř-,ł™ĎŚĆŔě,LŘó˙Ŕ Źß˜d~×P—f>25xŐUUř˜ëj=їÔĹ"ႲĹ(˙•W“IL[{śY’‚ą—@ľ/Źâć^ˇ]—m7C™]ÎĎů] kžVF ˙ ~—“[§Ć´kʞżôęuPXŸIŻłńŻřďŁ=ś8ˇ´ĹÂZąúNUŤułŽŘőŽ8Ęľ0Óő>Š‘JY(ąPYHÔ bŠÜĆ [eÝŰ4Ě] Ť|ˇíŞŇ0ńůʇ,öűą ‰ŰO2ÄYˆ 5‹bäY‹voPł-f}¸‰•{d[1úśE4ťub‘Ő.žŠ]šG˝šyŚć‹š†KíŮevićg{öZkqe–w Čö=ĽšÚűÜ uČ+řşŽĹ€sâŇ(ĺŠúĘ*-Őhˇ×‚R##$ZÝĽ8ďk:2ľť uFąŔ[/Dř5n˘ę •FyŤlQŔě5m™Ymőü>˜TˆtŐyí7<Ëhźrźw,őYˆ@˘Âť\ŒuďÓS‡ÍąţŒF' óáZę,ŕu,€EւqffÎěÝźĺIěě+x8ďŢüŇ˙đýfŚLÖDŕÍg¨š™ÁœŹîăk5]”đc5=ÜArîu€ŘěKhĽÔk51šĆţTş‘Ýc˘šfľ‹ź-c fłYŹÖk5šÍfłYŹÖk5šÍfłYŹÖk5šÍfłYŹÖk5šÍfłYŹÖk5šÍfłYŹÖk5šÍfłYŹÖk5šÍfłYŹÖk5šÍfłYŹÖk5šÍfłXG8´lšśá­§Đ´zŃKłQŚ0ǰŹ^65Ôő@„ŽŁcÚŤ@G­šĐč¸ö˛ĹRĚôXB6-uľ†Ę޸qě F9ľ;m˝ëŁĽ:ĽNçłř׊Ű)Jf>âě?SŒĽ.jÚźCjֆËśkr*˛ŞŤŠqĹČľuéfŠĹR™&śŻ ůk+ź,KE™:5SŁŽNHăÄÝq=gjÍójpn­ŽŰđˆ¨˙“ŇýťXňӃřŸ˙Ä'!1@P "A0`apą˙Ú?F•=˛ŒĂ†šŹËŠB„!B„!B„!B„!B„!B„!BÄo%ąr5ä<›ětąb߄Ă-'Şˇ=c'ŠŢÉgńƒâŚÓi(q8šüę>Y ˝‡`şîj—‚ëá>ŕÜíĺđ‹Š;6#ů÷^űî^Ńl„ˇđ—qžÍ‹Ąwťţ€Ăíi{áţăňHĎLřůŮěœçíˇ•÷ŢWĹŽK”ĺ=ďöO˙Ä,!@P1A Qaqđ"0`pą˙Ú?+‰D{As15TŹC°ENŽ9ݞ@‰A´Ě9S…Âg8Mc[ËCÄlÂu@ŠŠ­."î§,ţBî‡ÍSn†č^])˝œ†‘ěbŸ¨QálgĽ‡$T”z łR~čGd6t“˛0ŁÁq°ĺŁęŽČM(8ýXˆ œ@pŽ‘ü@UĚű&ľřšç*Iú÷~š,VŞĹĺiSyźíąxDM˛ńĆç ^/ (Ú ŚB&ĆÄÚm9)Sqů'˙Ä9 !1A"Q‘2aq #@BPR`r3bĄ0Á‚ą$s€˙Ú?‚âGDZüň™äaŽľŻGöžž‘żW–Đcőm$0ţĺJöSq,‚1ŞňÚZHNŚďéÚϞeâaFń!­˜UĎ L´c!ޯՏx™v¨îOź'u–SüŔee”Ëż5šW2:e Œkz4aeŹ 9ŔBJይĎęĘU.˙mŠ6^G@ƒK ÚößŮr4ťŕ,ţęĄŢ“Š:dÔÚšŽÜ'Ôg™sbeA1Ź â §uuގŹ~„ĄHčúíx—KĽŁFW…qiió4q’™Ěşŕ…žo¨Ď•ŞiąÍ6ýďÁ+ŃüÍÂĽJč / *ŻtĘń h—c Ä0ƒuš/*ˆḉrx‡4űżĄ1ƙŃ]{Žë+Ö[şęš\áđT¸’}˙–’˛¸“=Vj?ş–8´ű+ŽuÝeCœH÷*ŰÝ'ô/˙%Ž{N2ŞS˘ŰX#ÇXT¤Ö[ÎčNĽWÔ:q$@r¨4 EÁĚpÚUňĐßrŤZčfşŚÜDˇŕç9ÍÓŽŠĆ–¸űtľÍęҧ–NmœýĄž`%“˜^ˇ†¤iů“2g…g°ˇę…ÄU?âŰ` řęĘ0áđ…śŒhŽ€ ĘĐŠ–é*Ihž¨Ý‚=•3:ąAťœŠG˛ć‰Řţ-ÍZ+s/0â)řŠ5 Z×IӅ:wś˙:mœ˘ęokŰhËLńu"đÓ3•áĺÁÍVŤLČĺ["nŃU2ˇ›TqőçÜŘĘ!ÎiEÍN§{^ç“ků­ 7NwSöv˛ć˛L\íđěoŒđĹÔgŸ_ŽĚ Sx,tރĂéŃdHÜýđAÝS2# ͖ĚĎ2mÎfŃ7#ĐP“LˇĄŮT é* gĂS`‰lę‹`jœă÷‘N?Ĺ0Ó-çńÜÞü ĽŸĆĎôń{ąé’ź0Ťoő–ýdpo‰ńŞ&ĽČN¤ÓsuÄ?ÂĚ ŔAÄ8Ďĺۋfě‰^—ŸÚ Ě!ޛڎš\uŮZz§Ű2ÔŰɗtNoąśŁ@$uO´˝Çęq‡ˆťÍc.dnź=R]çUœm`˘ćÎ:Żü–CÂhČę´|ű§H;-á8j­7]řÓßâňď¸[˛đŢ}äóąÁžxŠ|ěZaÁ°7]8čšgůC[˘2đ}‘=x66ƒ]pŽŠr,]1&;0!\é×d.ÖUOňT宑ŒnŸóö6;Ä4şÔçâ|Ř嘴peS%ŁP:&ů ś“kAăüZÉĎUk§YÂ-3ü&kśă=SšéĎE™…se\nťń˘Ú ź„ze„ý6űĄ‘Ÿů 8ÇŮ)‰qĐ+ëR-o]~– ÔŽúg† ü~.<Ň˙+ďYŞđŽ OôŮďTđ§XřzUç[ÎÔöŇm­€`q/€LĆU#*f‘˛ś]˝ČÎ>Ý Á^)ž ž@§›˙\ĽĚŹÎa7•ĂĺRřL˛cxUfnľ2z•¸ë웇k›J Ćéż´!™7ĺ ęŤ]?ʧ8q˜=Pf˙mPť]JoîU?on-ę‡ŸR­%TýŠż+›K“î›3ŮZC˘ujp™ta:ů׊DÄVßĚŠu…Ká1¤čMĂyŃ4AŘBc­h7F&şĆ—^rBq´@eö˙ ÎąĄ× €š( DĆZáÍ?ĽĹZ.‡öR`yÁĚhcéťVcŤ‘ |ŃËnënęůî@ݑ˝ĘZřřrI-Îş#uĘËŞ{´Č™Ősžď—(/$tšmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmÝmßč9îĐ0.„ZĐŃírpśĎi˜W[U@X$4›Ľ´INsŰÍpƒ*ŕÜ|đL{'ş•ňÍnŕç†ęŻŽY„Inžę ,MŇĄş˘řĺWă€h*\Ý5öU €9ą™PÁ(^"UŸ×Tçc ĚOĘËqÖUÍn jź@pϒJx˙ľČŇ~{Úlš:Ł(°Ďr¨ÝÜÂ{Ęňҧăœa7ϧËo÷Đ ĆęW–=SąŹ6Sş§¸hŃ%Z}/ŞT ‹}_)ńH5ś˜uÚŞÝĚ +_Ę`Œü*—ˆ7 &ÔĽE݇N‰×TŞÂLĂ4T!őÍ÷׈uOKÝVcrăU›sŰŁ4•O”0Üp {ŤÓąŃëUUŁÔY…e†ţ‰Ž-6ÚŞn¤.hh íüƝBŹ¨2'OŐ |LD˙Ĺâ?úúO˙Ä+!1Qq‘AaĄ@P`ąÁŃ 0đáń˙Ú?!B!ŃhBhŐ1![Żić–ńÎŚb˛Îę§PŽäĽfpu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œN§SƒŠÁÔŕępu8:œBkbó™ť -"°…UÔ¤Pâ_s–NŁÝ0ףâh“ć˜ˆŁ„ýTD Ž’žz6™i2—ĄĂí]VŻ–,°,HX é@aUJ#?™•ŐýTCFÍÉßHI¤ˆ’śu—Ž,‹ȈO䚞ZŻŢć‘ŐíO~ya…*ćˆUŃtAĐFáěWč2Ü*ô2GA§Lá/Qî@ąbĐł>)ÄŻZńY_˜X†]}ţIí—ň §˘ĺßÎúőƚÁ ›.S1¸1ě¸Ö¨ĘSXŐľ§č"ZśßţdÎĚď_qJˇŚ™áމxÓ=wŽ]Z'˛ŻňOyéS,…ŽÎeľ‹)ˇ’{Чî6žŕŕ셐 ÝŻĐd" ÷Ą2”‚–_ ţ3>ăęG˝cň—kËD,Gž÷7ÔéŠOŢRŐRÁť‡Ň?.×?ćT5­Ř囸‡•…dSXB%4ëřtˆŽ¤ő PXUŠßă^yfÇŹC‚]öŐçM>FˇÜƒśZŹ™éVĽÄ^ĄĄ/ évaƒÍhSŠ čśłÜ@œ›]Ł‘+B‹`óÂą8˜Ľ!ôs­ő*ŇZäE‰ŸÍAÔuŜčE 4qÝöřńËuSš” §Î)] ÓU×^ŕgIdŇ4źŻ,ĹÎ Y Ř[‘ßá €‰˜¸Ĺ…ĆP…ÎŔŽĽˆÝ\J`ĄÃDĚ+ŘĆ( Çŕ&ç*ŠehR݉Ťňa!$Ö+.§…íéˆ4Ă …1€ŠŕhÄôs×Îbiß.a‹łf˛˛ďńUä ˘X†Ô€KK¨D\đ zˆkŢě?ŸÍ (Ż‚8×ý  žsđWÁkřRÄç9Îsœç9Îsœç )9ÎsœçńEV’süŕ„ ŘáhqŤ2 yřĘ:/¸Ă@U?&ĽŞęŁGšŢĘ<,•űMM´ś´řWi*ˆ3—~!Úö`VX—+šćźabjëAuPk~bnűş9‚:›`BšRŹţ N`l•Ř=k@‚ESQűK"‘C˙7… \MB\śoţTľłđOîđIjt3%ŠśOęyŚÝ9™ËWX¨jš\u7!+éč#îĺÖ9fŊúřÝPø„…@>^ťŤťw–•ą"•‰SC1˝ZëŕőXUĆf‚űÁË`śUށDsLѡŇ]ěl ôY°áGqä\JbŁK~ ]yzćĽ#_ڇOƒ;`kFúŮóŽy?‚íb湁ŇĹťŠ€U§x5>Ó ˆQ¸ÎśŐŽRët‘„BÔ4¸ęţnB!1ZWsB0^GꚥŹl–‹6Ÿě¤ÁüąĆ>ƒĚĺ>€sRŇŇŇŇŃ AőĂ ¸´5łeĽĽĽĽĽĽˆ.˛ü[ ‚ňüԄŻJqTˆ‡‡c{uđŇß%˜…A|łçŔRęXkŻĘ6B]+Ěż]đ:ń°éˇăŒ¨4FĽąĺgŐ_ Ȋ;?ö’Ą€Ňbč_ý§ÍPˇ.ŽĂ`ŠýôŃ“–“ŮR Ňnú˜ąč‰–ĺűôbi¨źV]Ŕd(°ŕó:7ČŢ/ÎíJę†ÁQĘwBŚ[ópŤP‚/x !^†Ÿ™ŽăNˆţ'ÎzŽ]Ä  |ůP Ž˜ş ĨbxűÍaڈĚfK\żŽ$ž˜lfƒHv˙U}ž Ž@(ÎIô"śIŞ˛˙š§đké0‚2˜"›uM *ľ%Á@𙔀Bk "R:2ž;•JŮ&ŞËţŕ ’Ą™ XԅŠ…QŁó"ŃV–_ jŞ…>šřteE"í1cd)>mj4ó>ŘcYH-É$<„I]ŠWh5?kŹGş›Ş~ ł7HŹÁ ­1-0ť.%J{* |¤W°żppşĺ­"˛)W_ *]ă5˘V›?АžaRmՈÈđŰ/b7‚ł2ŘA˝Ŕ›ĄkY€ÓN.*! Z—xÍh‡”Ş9ăüKß]Ő:+ý““â&P&–YÚţAZ2Ďžá0jäľřŽÓ-‚%b6TĄzœÖşŸjBćô{¸ő1쨙mŁU­;+0Ě0˛nckZÉqô#Ălý`V\lÍłí泌=•_ *U@cYzKdůű^§YGynëhR+ŽŘ _¸ ćŐ*í˘Wűľ‰ö$.XŔúO˝!S áŢ*;lIBő9­u ˛=)şŹí›•,b•‡áČEňă–mZ<ĚXŻšü=ü-_Ei¨ƒUzů(ĹśbBšţeĘ\_Ţ>ԍMăvu˜´f˘ĺ(rZžšWÍfW™łdFĽ†KfĽ ćě´ç đ"ŁCh­Ţĺć:.ł˙Ż–&­ÉjUşÇ:ďĹî "Oť›Ěég_pŕQ,݅†–ĹŻőoí„ÔśîŰŢ}éŠĚ%ë‰kYˇ‰•z҈ ”Ř0QłY_ŒÝ™Y [ü9ÖD?Yůu ĄŤÉ˙ Ôa<­Â1ŐéK¤^ÎÇŇ+gu¤vÂJÁżŹORwŢw$Őm/ŐD׋ĂĚM9řÚZş×RËŤ˘‡Ôў;A4^‘Ő‚°Ô …RU Öé­ýTBTÉ(ŐSJô˙0°[‹Ö t”›…˛ęM$ř"7×úEŇ] —iA‘ԍŻQúdB_S6ű˙Ş!ĐAď03´:ük)ÖЧÄF) ň˝|s‹˙Ş7 /B×űĚѰ#´G+O yż‡¨şČXý ˛ŕf×őüŔ¨ĺ(ĘhűĘŃ}č[ŤÜXWLűo˜,/Ú._ݧ¨ĹZ€;i™âç6şď áËÇń´o˛!‹] 6†ĺB›Š#Ő _„[žXXŚomŘySúT„Ó…˝&ĚŢň nüev{źVş€ŹÇÇšŸ3PtŁZM ÓI ~.ŕľBBuźŹáĄehaŞU !?Źů˜ĺ\ßeĚU¨D!A›04qĄ+UŐľ”´á› ÝĹQ.{ć)^ĽVe§LÇ`Vđš!@ý+A ÁđMâ"9ÇŔŃé2čьSඎ-y Ü Sg¨…ü¢Ŕľ‰"Ë5•Ům0O@&ŕTĺm°ž%ZŐŰ$°…E}ŚvŠ=ŐĘT珐KZ(@ůUՑŞK’})a˜mçʄrSŞXžęVž°¨Ü‚żGšźŘ!xTZs7óStĺđ(,ŠJŤôžO—™´4ˆ2<ćĘĹĺ˙¤şykđ­"¸Ňs0˙¨Zç<@C.˘ţ Úó™ž#äęÚgň{ř|Ŕt œK-?y{ĆńîŠR§Œüxˇœ˝10čŻÉW(.)–2JO)_V tPjžIwš™Žúe›šQâ•RóR„ ˝§ĐÄľŇЛ|zýAoŃ=BLśýB Yľ_Lśý4ôĎgD ąˇŤ†uĆ[~ˆ&€9… ]ji•ţÄyžťĽŃlmĆNO˙1  W Ń Ú1vKoŃ-@ŘÇ÷…cMTĂĂ•÷‹SXP?ymú'ł˘Qh[üËávĄ)ş´\4ä^›ú…pŻŁ˜Rśo÷1h˜F…)ěžűĘçď-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôKoŃ-żDśýŰôDŻ˘? Ű lߜâ]‰~ ígç˙b!N…˛]qŹaCś_őč*ŞÎ؅ň–ú|_dyŁ1K"™>ŸbčLFOs\š }# ˛˙ŠWî‹Ô}Ŕ+QfKx%;2˙MAÔ0Č~­§#Öm‰lÜÔtlŘýczđ]qŹśŔłĘoÎqýŻ]ékowdtT/‹—#|¤ľooŇgÄÄL´‡”‹i†]z´ş‘úÔÁ´ƒv-2˜­ŹˇŒ3˘…]‹ń+FĘ. ĽP|ĘkţĽ ęˆgžŸ×˙aT—ś°M@U.<ÔÁ´Łv;ha—-qîy˜ćŠÎq38?Ę`'đâi5‘z× |ŠäÓ Ě™.W|ĺÓxľ9}*ńęç(śOÚ×0¤ĂŠ‹ŠgĄAÖkp1T3çé ÖĘśž×úL‡á=KÖ{1żőĹÇé?˙Ú ňCóĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<ţlÓüóĎ<óĎ<óĎ<óĎ6ŰßüóĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<ňڜóĎ<óĎ<óĎ<óĎ<đ6DĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ#ĺęXšCŘ{Ď<óĎ<óĎ?ű_#R)DO<óĎ<óĎ<óĎ<óĎ<óĎ<óĎ<óN6Ł<řďśóßĎ<óĎ<ňĄAžö™ĎźńRy†Ĺ”žÄOרÖ)2ɃP™;ƒQ,YbDÇFŠrxcţôJ’ pB`™;‚\tYpŸĄńI–„Šźűôj&'š^ßΗ٧:_ĺ}é}ÂwřĂ(Ç*ýŚ:›÷ż_äI¨żÄPö†7ĹË*ż0,ÉßţŒá&űĎQ,ÇĺčŠÁ*5 Šr„äœ?˜ż XăŁt\AaÔ"´ú:fłłbm„é>œtP'ĹÄčÝmď˘x…óěA8ż‡/„.N͑&ž˘oçý b‰“ę*q‹+ďţ o24•ŒHœ rNŸnçřžÂż˙Ä*!1Aa‘đ@PQqĄąá 0ÁŃń˙Ú?weëd>”ůOQŞŠMwŚ%Ż}?2”‘Ży••••••••••••••••••••••••••••••••••••••••••••••••••••‘ĽÂánTřy"QęQ¨U§ŚƒFÖ^™“6zĽ~iꛘâE”IĄ÷˘9/9ŽLm~K~čűń ˘MϓďąÁNİBiú6’źŒ5[mű§Ě.É0ߝ,sŽťgˇqź~Żä>žPíÓĽQ%ޞ3h3k#hوZgő­GË\_!ši-˙wůĎcŐsŽ%ŮY\í'ˆJś] 7 ¸Ľ˘w?Š7Z{‡đ÷˙›)J'˜\^܊Śő:ţˆHśMÄÍŮB E?Jˇ% éŚ÷lk$؛űy[‰_(VĄBűN›Ţ#mO_KőËc&ŁFţcXÁ3HGחkri.°ú˙‡×ť„”xEŽš+)po)Dép‡„6\ěC›wŹ" /ýżű…”ş ęRä¸7”Ľ×cÂĽ°¸ŁpĽĎ^­ ŽĹ7ţpŸ­Ť˛~bSô͓°Ug|[r]8ډöĐÝ÷¸˛ƒŻ&ĺŃÝ&ńʖG獦V|;Ţźx/^ƒD›đmdk­Ś}‡ŁU˜*Çtn8hžEu"ętçëŘŐ´ÚMF$’ˆJ™¨zdŒˆ…†)F*BI5.ËÝÍU}xŽ›™Ł%ŔJ f9ŸëÜtůűš;ŁAŁK­Ĺ3Čđ8|‰ÖĐËđ"Şâ7ň˙Gŕën”ů’)Ś7ĄuŢőJcńZžę˙Ä,!1AđQaq‘ĄÁŃ`ą @P0áń€˙Ú?˘yŘş (ĐÄN%T*ő15í֜Ţwíń퉚 ÚôÓYÂ".ŽşŁQ…Ö38O䢣*օUgŹá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNů8Oäá?“„ţNůáÉÇ V*˘5•76!`J ˘ČŢ {v Ť€ !7Ö+çѕC×Ya¤MÜb˝ĽMřŤÁ¤&ÔR;?Ęě?” WLF¤ĆŽ\Šaz¨v2VĄ@l ÷Ý|K€Ü[$Ńk}›Ýˇú íĆqš×9ˇ2‰‹˘Ę­Ú×hĽŞ*ťżĘ÷5'âÍóżIŠ Ę݁Ń}bđŞ-ä lI¤vޚ&FŻDÎԅ#Ü˙‰–ŔmăU“żHŞ5 Čbłyť6ƒŘô(ú¤?ŁC{A .˛ďG]/tքR:Ž”ëNŒŤ‘—žŤř$s7E‹đž° UF_-Y:ĹJę% ŽLĐהfeRh]ސkĚꕖjŤNŇŔAŰśŸńFiO[ßÄEŽ# ďĄĚ@źşFƒgh’†Ńf‡Ł ă%XíO™ď.ŠUJÍú3@vŁm+՚U-‹éü11ŤžŽ]÷\ë:ä쳇źĄ`őŐë5Cš'͍ĂV'Ő˙ˆ|ĄáęFJm§­ëpR-Zťrv‰ Vë̀"KQwm×”(ş ď0ójO+ŻŕąÓăU€#UzKMw´r—UßÁŠrçźtRĐRšŇ-6ĐÄz#ㄽĺΗ¨Pp-ůʛ"n—wĹĽŇî* lŞśÄąIŹ:ĹK´uGż…Œ : đÖ @nÚ2oohľ´=°ŠúŔ˙ÜF #łţť2‰őw"ëQ ]uŇľđ6R°2í"ŹÚMÖ"]0Ń×§ˆ3=ĘňŔĘŘDUçY_1Š›­ŽŞűš 3h;p´Ň&7ŸHŘÄęZŚ6u’đÓZĄů‹€Ô˝ÁS*VCfĎî-¨`–e§(ىWVƒĄ/V˜‹…ňśť šłĽ{żőŤĎĽQ‘Ő†t˝%˘ƒkŐÜđÄśešĹŽťédšBdXĽřÔ먌_§ő+ů[€5„mšĂ+4ĄĘʋ˘Ý1™[jjđ§5­CŁ uňî%]P֚ţźçŤ=_X‚˙ԏúB°¤¨Ť+×4Ś@”n3ˆ$č-˙Ž$„˛FćÁˇŚ›HkŠŽţŮÉ áWa™Sť(čzߋ´ěÜ r@9ę#Ą&ĄTlJ/mĽZPۨ*ľbŔ-`$HŒ&‡œi⪠/5ż´Ń[…‚ŔŮš˘ŒŕÖ­*€ƒSm•zˑřhą¤őˆ’č/Ľ0÷4źHáĂű„”Ń]`+Qś´˙š)B -Xí˙ U ąŃđR…@Z°)&ŰýZ†ţ' œ*pŠÂ§ œ*pŠÂ§ š%i`Î8TáS…BÍÄZCĂA' ‰Jt˙łi&Teŕ(–ßF_œ€ÓĽnůŮ<F˜ľęŽ !㥋ÓXł>.3R˝taŠĎTe% -%nj}fz pŞ;áĎ´ŢšbőŻUńF]Óăć5#č řs4Š)u›Ś›,ŔM/´ŠőH4%䬞ŃI(5+×Fg9Űh˝|ćď™YN ˜ &–š.őŒhuQţ–”Ö%ô™7Öŕ$JÚÁ(§ÓŔĺFĐ"˝šĘ Úě Ťśň˝üH\qÔPąU4 ˆÖKžžHůTEőĂýB1JVZnaužaŮ•4$]yÓaä8:fžĽ3ZśÚóaĐ )Ľjϝ˙f§ăľŰxŮM;Ŕ+2Xî)nď_žkR‡+ĎJď žKSOŸIk­ĽDĺCLíKúlXťť1Ú]ě-&Ś—xů˜v­đ ß˝#ĘĆaWë{÷Ě4‡D ęLGT WbށQm)ŹŔ˘ŚEźŢm*WĄŠŽˇŠ[€{ `ć†k‚[ľzÇ$UIçţ–”@‹$i)A.Ź˝.;Ę 8J^ž Ԇˆ€ ëzíÎ(k`Ś˝ö˛ËNŤţňwQÂ"nRÄçfIM•żáĽápR "šÄÖa ŻW]üDJJřHĆě†Q6M4˘óc¤ą˝O(Žoća}rąíđ_4zKÓdoc~ŘcœVĹ7Źté(›0@–îfó늈+GŘ;3;@ŻţŰůŒa`ŔheS]:[fëâRDôëeţŔ¤aۖš÷˙ŠPjHŃ÷BřÔθÓOŔó;-RĐâ&´#˘9ąC‚ŇvÝÓXč ˘ľmŒ$JązĐŔ­ˇŹY5žŃ´ŞĆoĘ<ş]oy›-˛ƒŹšŽďmv™ĺľp}Ľ}˛M%ż…GBÚŽh5i˝a›–HŘşŢđEΏVŤý™”~7`P6Uď‰6Ł…ŮwYôx]EQJ-Yľ„ŕÝÂţXHľœÄř"ÇS9Ië‰w Lž k6QˆTXĘR°Ušž%Úę`›điůá †^‘ţŐ0úĂŤď((aŽËV!Őjđيphўő|@žĆ ¤tŃ*ęśŢ [ʏŠjŽ”Ď2ôĺ]§‘Ě:ę• WYŐzßXE zƀ"Î͌.RbtŢ[•JóN<•Z´!‹°„ŚĄÇăŠůޜŤ´˙ë*—ţ $ÚŃB˘€Ę+ŤŤVč_o €.3+úzŨgqĂĺýźm÷3W}gNˇ›Ń˝ee€] ł^:6qqBSQ ă4iˆK”ďţkˇâëľT%ƒ&ÔióĂśŐ—Чő;ÂP:Q4;i ¤kŤv Ľ‰Fu!<˜M[XNŽfŻ=ĺFĽE1yݚ—/-.<Óq_{FBŁ€‹ĐÓ˙Č$8;˜ČÁç."šŁĽ"oVĄäŇf{Íe!–8tÓŔ•fVŤ€Ëw:ŻHs Ľ°CU I×M/Ľmí’=œ+ĽYŞ’ôŸ'J•ârÄáTěĘ Ž;žłűó^Ź/´c .”Őó- č*Ő UÔ´Ş!—)ß—ÖĆΊ˝uT–=AĘwŤ™{*ż]âÎ;×-żÚť#Žő † \ľ+U÷Ö-tTšŤâőhŤeńzoËĘńŇ SZŞűşĂ€%˜:wŸŚô”ÉĐň¸ §?ÂfťÝĄń6Çv—ť–č´'JIbĘҘňG+vó¨Ąd°(ő=Ś”&=.*ZʖžłÍao˘ôŠˆ í˙˛ŹfĹŽH˝   3ĺ ôĐ<ÝcĹ-RĐ Möö‹§ô+OyCĎő~x)Ń)=e^%Ô9ëç:–‹VŢśŔÁZ/ÎŚ ĐZśń2Ej\íŕt´&ˆ™l\4Qi_T-ŞĄĺ0e/eE—w‹ŞnŤŰÚw  }âé7OX=:”‡ć<ŠşÝoh ‹EfĂżYźj–Ŕő¨‰0¤XOxÁ Uż¤ ŸAüŁĺTžË,rúßohBśűyÔJPÝPŢŽU ‰ MїĄęű[Z€:5OY †SŢ*"ƒˇţČ`§D¤ő—őRž˛…şF°xXCˇUWy×xĄLşËÎ SZŞűşÍ(Lz\lˇŞZúÍrt<ŽLhÝ=!ˆ ¨ööěŢYžąáDŇę{Ăí;Ѐ8 ÓŞ/gH=:”‡ćwłD= A‘‘´ö…Ú÷KEŤo[üR7âZ|müĂĚufNŒc¨™ÓL@ŽěÜ;* ŠEkŚŃÓzèLnĺěGŇň3Ž b°ÝM•LŃ fëć.ŹęóvU÷í+iP4QŻĺr˝tVIЗ›jÜ"eäk ¸1śbńŤÚ h˝ËŰI_ʨ +VÓWŹŞ-<2—eĆ`ýRਧžGÔâŃq}ĄâPYBâ×WżňČ ?!ą¸†Śşâ7; jޞSçţ:ç@fŚšeÄ&ăľCIţŇV Ő\œÇŁj–šŇ“ü.ČĆÍ: FfUv‚]"#ł2›e8¨N™×řÝD.š,vz‘“ßš×\ǢŮ´şĺeç3GԖnĺĎÄÖ 2‡KéáwĽŮˇ¸Ő—xˆ‚ ŚEŠy,ÁŰuHQ źâŕšA=ăŃŮ×ŔĄĄŔ­ą/”jLlZ6nG’ľ"Äƍ&EL jŤzë)ub–Ťu.ôD-ފ˛:ăŔÍ[yÔR]U)e—ŠMn˜ÍV%…D.š%ą,Z{uXËąFĘ6cđ¨)ŠÎwA~˛Ű…´EBő˜ŁiJ§_] ^ŐÇ]-ş•‘ÚÓÓ\LH?BNF˝Š‰M:˙Šń%ŤPÜc>şéJ+o‚ËCÉŕł87؈§Ő>Plx:~1m„ÓkşŽ Ô%ś˙pÂ% Aą=e=` •†ýśİR}4GɘŚd§˜Şăv š(SyÇ\VcRíŤPFŹČ˜•D h˛Úˆę0˜ĘĹę­Šđ €p´Žˆ‰ďŠ”2űÍéŞf‡Č&­"e&Žő‡›Bśw8v"(,őńZŔ`ĐCRűHżĽˆ9wÓ› 81‚ׄ)úŒX™¤ČVÎU1zzŇҘŤÖŻ˝EśÝ‹XžbŐĐ §3H^ RÄ@Q˛W€ľí w…Ý5p”"SQ€R-]yř4á ŤK"ďk j ÓŢ čţMTž˝^‚šÓźčFuĄ-_Ęŕč;/Ö¨ÍCĐěíŒ.•Ţ ](ŚiđDŠG¨DŁ –­ľs¨[%…5ëFĹÜ đ2Ń4¨€’‘ź]ć-ĄA„j3=˘Aƒi~}+[ŽÜ(R=-#€JX<Йë/ĎĽksZíŞňeëwĹóŞţ!!ś <ĐBáh¸Š†]/ŢooTŠĺAÝ^ ɍ™OHbşălEj›¨'{ż…Î#t<ŃŞ+Ü:*ş§SŁć&=p… Ź™ÄöMŃODĘ-" cV[uVÝąĽ,Ö›ĹX żv5K€óaÍżŸt8ĚęĆVšşAIh;+-ę°ź łb–,é鏳ůŸŢ§ę~1w‹•ŞŔť7¸’ä˔JhŘÄ­ŒS*×h…YaŚ+ô=N–<ďhĂŰZߑڶŇCě™jcFĄ4†ëpSąśĆ‡ř[ű€6 ËyE†ŇÇÜćßqKK¨>âĺŽę}Îm÷C@žçűƒ'éPnڎžg6űE@L–^a9 HŇËĚ(eJ¨Ă˝qŽĽŽ`Aą,>a]7ńrb˝‹kEââ˘ëfâeĂĽŹćßqĘöR ÓЊ×+ŐVhvkKÂ`ÄFů€Ęso¸eꎚDaä1­TJ )ť*h¨q^d`¤ŰmŻ nűŔ$ÁŞnóœć ¸P*Üß ľc“)o ÇhNžě"u˛öNm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßs›}Îm÷9ˇÜćßrЙ§â>1˘p”ŘAjâ,¤ÖŠĐ¨űłŚńPa¨˜=MčwŠ\óła(ŤĂ="qZX} , VCźÚÓ˛:‰´ň< W˝`ްĺŒ3V4§ˇ…\ť0ZŐĎIÚšš]şJą =PŘy’šçfÂQW†zMŠcakžÄťĹ“0ފ×f( ŐO"˘zEŒąkÝIJÂ(bt ŻŞĽôˆl ‹[lMd¨U@Ö( ,€;’†ŸSz{@‰$€(6ĺ¨%ečú/ö†ˆ• ŞÚS:ÔšŠŐŰó ôç%MeP!ŠęGř™œD\Z”^°ëTÄJZ끉 ˆÎ[ÚtŻH/eśkAž:[Ć×§ŹKŽF,j&×őDě@EŞşarźŞ!$—‹ç¤HÔV*ß°Řő›ŠĐŚťKŁVŰJA¤5: oĐŁŇš{ä2Yœ‚öZf´;áŠÄsD‚ŢvMn›% É /ę ËŠö”M(”$ L[ľŽT­î†Ią` f9CUŐĽö˜˜'pĽ×Z¸kX ÖZֈˑm‡Z”Ł˝\œPÉŠ]˛:n(ďC2E"ŰpŤÓĘ3QĂ /[”üPş źg7Ţ<îś”#×%‘0&ăZşľŰßůAł˘ÁŇö˜ާKŽ“˙Ůmastodon.el/test/000077500000000000000000000000001501733112700142605ustar00rootroot00000000000000mastodon.el/test/ert-helper.el000066400000000000000000000015571501733112700166610ustar00rootroot00000000000000(load-file "lisp/mastodon-http.el") (load-file "lisp/mastodon-iso.el") (load-file "lisp/mastodon-tl.el") (load-file "lisp/mastodon-toot.el") (load-file "lisp/mastodon-search.el") (load-file "lisp/mastodon.el") (load-file "lisp/mastodon-search.el") (load-file "lisp/mastodon-client.el") (load-file "lisp/mastodon-auth.el") (load-file "lisp/mastodon-discover.el") (load-file "lisp/mastodon-inspect.el") (load-file "lisp/mastodon-media.el") (load-file "lisp/mastodon-notifications.el") (load-file "lisp/mastodon-profile.el") (load-file "lisp/mastodon-async.el") ;; load tests in bulk to avoid using deprecated `cask exec' (let* ((all-test-files (directory-files "test/." t directory-files-no-dot-files-regexp)) (tests (cl-remove-if-not (lambda (x) (string-suffix-p "-tests.el" x)) all-test-files))) (mapc #'load-file tests)) mastodon.el/test/fixture000077700000000000000000000000001501733112700175102../fixtureustar00rootroot00000000000000mastodon.el/test/mastodon-auth-tests.el000066400000000000000000000111771501733112700205340ustar00rootroot00000000000000;;; mastodon-auth-test.el --- Tests for mastodon-auth.el -*- lexical-binding: nil -*- (require 'el-mock) (require 'mastodon) (require 'mastodon-auth) (ert-deftest mastodon-auth--handle-token-response--good () "Should extract the access token from a good response." (should (string= "foo" (mastodon-auth--handle-token-response '(:access_token "foo" :token_type "Bearer" :scope "read write follow" :created_at 0))))) (ert-deftest mastodon-auth--handle-token-response--unknown () "Should throw an error when the response is unparsable." (should (equal '(error "Unknown response from mastodon-auth--get-token!") (condition-case error (progn (mastodon-auth--handle-token-response '(:herp "derp")) nil) (t error))))) (ert-deftest mastodon-auth--handle-token-response--failure () "Should throw an error when the response indicates an error." (let ((error-message "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.")) (should (equal `(error ,(format "Mastodon-auth--access-token: invalid_grant: %s" error-message)) (condition-case error (mastodon-auth--handle-token-response `(:error "invalid_grant" :error_description ,error-message)) (t error)))))) (ert-deftest mastodon-auth--get-token () "Should generate token and return JSON response." (with-temp-buffer (with-mock (mock (mastodon-auth--generate-token) => (progn (insert "\n\n{\"access_token\":\"abcdefg\"}") (current-buffer))) (should (equal (mastodon-auth--get-token) '(:access_token "abcdefg")))))) (ert-deftest mastodon-auth--access-token-found () "Should return value in `mastodon-auth--token-alist' if found." (let ((mastodon-instance-url "https://instance.url") (mastodon-auth--token-alist '(("https://instance.url" . "foobar")) )) (should (string= (mastodon-auth--access-token) "foobar")))) (ert-deftest mastodon-auth--access-token-not-found () "Should set and return `mastodon-auth--token' if nil." (let ((mastodon-instance-url "https://instance.url") (mastodon-active-user "user") (mastodon-auth--token-alist nil)) (with-mock (mock (mastodon-auth--get-token) => '(:access_token "foobaz")) (mock (mastodon-client--store-access-token "foobaz")) (stub mastodon-client--make-user-active) (should (string= (mastodon-auth--access-token) "foobaz")) (should (equal mastodon-auth--token-alist '(("https://instance.url" . "foobaz"))))))) (ert-deftest mastodon-auth--user-unaware () (let ((mastodon-instance-url "https://instance.url") (mastodon-active-user nil) (mastodon-auth--token-alist nil)) (with-mock (mock (mastodon-client--active-user)) (should-error (mastodon-auth--access-token))))) (ert-deftest mastodon-auth-plstore-token-check () (let ((mastodon-instance-url "https://mastodon.example") (mastodon-active-user "test8000") (user-details ;; order changed for new encrypted auth flow: '( :client_id "id" :client_secret "secret" :access_token "token" :username "test8000@mastodon.example" :instance "https://mastodon.example")) ;; save token to plstore encrypted: (mastodon-auth-use-auth-source nil)) ;; FIXME: test auth source ;; setup plstore: store access token (with-mock (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) (mock (mastodon-client--token-file) => "stubfile.plstore") (should (equal (mastodon-client--store-access-token "token") user-details)) ;; should non-nil if we check with auth-source: ;; because we saved with non auth-source: (should (equal (let ((mastodon-auth-use-auth-source t)) (mastodon-auth--plstore-access-token-member :auth-source)) '(:secret-access_token t :username "test8000@mastodon.example" :instance "https://mastodon.example"))) ;; should nil if we don't check with auth source: (should (equal (mastodon-auth--plstore-access-token-member) nil))) ;; FIXME: ideally we would also mock up a non-encrypted plstore and ;; test against it too, as that's the work we really want ;; `mastodon-auth--plstore-access-token-member' to do ;; but we don't currently have a way to mock one up. (delete-file "stubfile.plstore"))) mastodon.el/test/mastodon-client-tests.el000066400000000000000000000217171501733112700210520ustar00rootroot00000000000000;;; mastodon-client-test.el --- Tests for mastodon-client.el -*- lexical-binding: nil -*- (require 'el-mock) (require 'mastodon-client) (require 'mastodon-http) (ert-deftest mastodon-client--register () "Should POST to /apps." (with-mock (mock (mastodon-http--api "apps") => "https://instance.url/api/v1/apps") (mock (mastodon-http--post "https://instance.url/api/v1/apps" '(("client_name" . "mastodon.el") ("redirect_uris" . "urn:ietf:wg:oauth:2.0:oob") ("scopes" . "read write follow") ("website" . "https://codeberg.org/martianh/mastodon.el")) nil :unauthenticated)) (mastodon-client--register))) (ert-deftest mastodon-client--fetch () "Should return client registration JSON." (with-temp-buffer (with-mock (mock (mastodon-client--register) => (progn (insert "\n\n{\"foo\":\"bar\"}") (current-buffer))) (should (equal (mastodon-client--fetch) '(:foo "bar")))))) ;; FIXME: broken by new encrypted plstore flow ;; (asks for gpg passphrase) ;; otherwise test passes (ert-deftest mastodon-client--store () "Test the value `mastodon-client--store' returns/stores." (let ((mastodon-instance-url "http://mastodon.example") (plist '(:client_id "id" :client_secret "secret"))) (with-mock (mock (mastodon-client--token-file) => "stubfile.plstore") (mock (mastodon-client--fetch) => plist) (should (equal (mastodon-client--store) plist))) (let* ((plstore (plstore-open "stubfile.plstore")) (client (mastodon-client--remove-key-from-plstore (plstore-get plstore "mastodon-http://mastodon.example")))) (plstore-close plstore) (should (equal client plist)) ;; clean up - delete the stubfile (delete-file "stubfile.plstore")))) (ert-deftest mastodon-client--read-finds-match () "Should return mastodon client from `mastodon-token-file' if it exists." (let ((mastodon-instance-url "http://mastodon.example")) (with-mock (mock (mastodon-client--token-file) => "fixture/client.plstore") (should (equal (mastodon-client--read) '(:client_id "id2" :client_secret "secret2")))))) (ert-deftest mastodon-client--general-read-finds-match () (with-mock (mock (mastodon-client--token-file) => "fixture/client.plstore") (should (equal (mastodon-client--general-read "user-test8000@mastodon.example") '(:username "test8000@mastodon.example" :instance "http://mastodon.example" :client_id "id2" :client_secret "secret2" :access_token "token2"))))) (ert-deftest mastodon-client--general-read-finds-no-match () (with-mock (mock (mastodon-client--token-file) => "fixture/client.plstore") (should (equal (mastodon-client--general-read "nonexistant-key") nil)))) (ert-deftest mastodon-client--general-read-empty-store () (with-mock (mock (mastodon-client--token-file) => "fixture/empty.plstore") (should (equal (mastodon-client--general-read "something") nil)))) (ert-deftest mastodon-client--read-finds-no-match () "Should return mastodon client from `mastodon-token-file' if it exists." (let ((mastodon-instance-url "http://mastodon.social")) (with-mock (mock (mastodon-client--token-file) => "fixture/client.plstore") (should (equal (mastodon-client--read) nil))))) (ert-deftest mastodon-client--read-empty-store () "Should return nil if mastodon client is not present in the plstore." (with-mock (mock (mastodon-client--token-file) => "fixture/empty.plstore") (should (equal (mastodon-client--read) nil)))) (ert-deftest mastodon-client--client-set-and-matching () "Should return `mastondon-client' if `mastodon-client--client-details-alist' is non-nil and instance url is included." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist '(("https://other.example" . :no-match) ("http://mastodon.example" . :matches)))) (should (eq (mastodon-client) :matches)))) (ert-deftest mastodon-client--client-set-but-not-matching () "Should read from `mastodon-token-file' if wrong data is cached." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist '(("http://other.example" :wrong)))) (with-mock (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) (should (equal mastodon-client--client-details-alist '(("http://mastodon.example" :client_id "foo" :client_secret "bar") ("http://other.example" :wrong))))))) (ert-deftest mastodon-client--client-unset () "Should read from `mastodon-token-file' if available." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist nil)) (with-mock (mock (mastodon-client--read) => '(:client_id "foo" :client_secret "bar")) (should (equal (mastodon-client) '(:client_id "foo" :client_secret "bar"))) (should (equal mastodon-client--client-details-alist '(("http://mastodon.example" :client_id "foo" :client_secret "bar"))))))) (ert-deftest mastodon-client--client-unset-and-not-in-storage () "Should store client data in plstore if it can't be read." (let ((mastodon-instance-url "http://mastodon.example") (mastodon-client--client-details-alist nil)) (with-mock (mock (mastodon-client--read)) (mock (mastodon-client--store) => '(:client_id "foo" :client_secret "baz")) (should (equal (mastodon-client) '(:client_id "foo" :client_secret "baz"))) (should (equal mastodon-client--client-details-alist '(("http://mastodon.example" :client_id "foo" :client_secret "baz"))))))) (ert-deftest mastodon-client--form-user-from-vars () (let ((mastodon-active-user "test9000") (mastodon-instance-url "https://mastodon.example")) (should (equal (mastodon-client--form-user-from-vars) "test9000@mastodon.example")))) (ert-deftest mastodon-client--current-user-active-p () (let ((mastodon-active-user "test9000") (mastodon-instance-url "https://mastodon.example")) ;; when the current user /is/ the active user (with-mock (mock (mastodon-client--general-read "active-user") => '(:username "test9000@mastodon.example" :client_id "id1")) (should (equal (mastodon-client--current-user-active-p) '(:username "test9000@mastodon.example" :client_id "id1")))) ;; when the current user is /not/ the active user (with-mock (mock (mastodon-client--general-read "active-user") => '(:username "user@other.example" :client_id "id1")) (should (null (mastodon-client--current-user-active-p)))))) ;; FIXME: broken by new encrypted plstore flow ;; (asks for gpg passphrase) ;; otherwise test passes (ert-deftest mastodon-client--store-access-token () (let ((mastodon-instance-url "https://mastodon.example") (mastodon-active-user "test8000") (user-details ;; order changed for new encrypted auth flow: '( :client_id "id" :client_secret "secret" :access_token "token" :username "test8000@mastodon.example" :instance "https://mastodon.example")) (mastodon-auth-use-auth-source nil)) ;; FIXME: test auth source ;; test if mastodon-client--store-access-token /returns/ right ;; value (with-mock (mock (mastodon-client) => '(:client_id "id" :client_secret "secret")) (mock (mastodon-client--token-file) => "stubfile.plstore") (should (equal (mastodon-client--store-access-token "token") user-details))) ;; test if mastodon-client--store-access-token /stores/ right value (with-mock (mock (mastodon-client--token-file) => "stubfile.plstore") (should (equal (mastodon-client--general-read "user-test8000@mastodon.example") user-details))) (delete-file "stubfile.plstore"))) ;; FIXME: broken by new encrypted plstore flow ;; (asks for gpg passphrase) ;; otherwise test passes (ert-deftest mastodon-client--make-user-active () ;; match new encrypted plstore return value: (let ((user-details '( :access_token nil :client_id nil :client_secret nil :username "test@mastodon.example")) (mastodon-auth-use-auth-source nil)) ;; FIXME: test auth source (with-mock (mock (mastodon-client--token-file) => "stubfile.plstore") (mastodon-client--make-user-active user-details) (should (equal (mastodon-client--general-read "active-user") user-details))) (delete-file "stubfile.plstore"))) mastodon.el/test/mastodon-http-tests.el000066400000000000000000000102201501733112700205360ustar00rootroot00000000000000;;; mastodon-http-test.el --- Tests for mastodon-http.el -*- lexical-binding: nil -*- (require 'el-mock) (defconst mastodon-http--example-200 "HTTP/1.1 200 OK Date: Mon, 20 Dec 2021 13:42:29 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: Mastodon X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Permissions-Policy: interest-cohort=() X-RateLimit-Limit: 300 X-RateLimit-Remaining: 298 X-RateLimit-Reset: 2021-12-20T13:45:00.630990Z Cache-Control: no-store Vary: Accept, Accept-Encoding, Origin ETag: W/\"bee52f489c87e9a305e5d0b7bdca7ac1\" X-Request-Id: 5be9a64e-7d97-41b4-97f3-17b5e972a675 X-Runtime: 0.371914 Strict-Transport-Security: max-age=63072000; includeSubDomains Strict-Transport-Security: max-age=31536000 {\"id\":\"18173\",\"following\":true,\"showing_reblogs\":true,\"notifying\":true,\"followed_by\":true,\"blocking\":false,\"blocked_by\":false,\"muting\":false,\"muting_notifications\":false,\"requested\":false,\"domain_blocking\":false,\"endorsed\":false,\"note\":\"\"}") (defconst mastodon-http--example-400 "HTTP/1.1 444 OK Date: Mon, 20 Dec 2021 13:42:29 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: Mastodon X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Permissions-Policy: interest-cohort=() X-RateLimit-Limit: 300 X-RateLimit-Remaining: 298 X-RateLimit-Reset: 2021-12-20T13:45:00.630990Z Cache-Control: no-store Vary: Accept, Accept-Encoding, Origin ETag: W/\"bee52f489c87e9a305e5d0b7bdca7ac1\" X-Request-Id: 5be9a64e-7d97-41b4-97f3-17b5e972a675 X-Runtime: 0.371914 Strict-Transport-Security: max-age=63072000; includeSubDomains Strict-Transport-Security: max-age=31536000 {\"error\":\"some unhappy complaint\"}") (ert-deftest mastodon-http--get-retrieves-endpoint () "Should make a `url-retrieve' of the given URL." (with-mock (mock (mastodon-http--url-retrieve-synchronously "https://foo.bar/baz" nil)) (mock (mastodon-auth--access-token) => "test-token") (mastodon-http--get "https://foo.bar/baz" nil))) (ert-deftest mastodon-http--triage-success () "Should run success function for 200 HTML response." (let ((response-buffer (get-buffer-create "mastodon-http--triage-buffer"))) (with-mock (mock (url-http-parse-response) => 200) (with-current-buffer response-buffer (erase-buffer) (insert mastodon-http--example-200)) (should (equal (mastodon-http--triage response-buffer (lambda (_) (message "success call"))) "success call"))))) (ert-deftest mastodon-http--triage-failure () "Should return formatted JSON error from bad HTML response buffer. Should not run success function." (let ((response-buffer (get-buffer-create "mastodon-http--triage-buffer"))) (with-mock (mock (url-http-parse-response) => 444) (with-current-buffer response-buffer (erase-buffer) (insert mastodon-http--example-400)) (should (equal (mastodon-http--triage response-buffer (lambda (_) (message "success call"))) "Error 444: some unhappy complaint"))))) (ert-deftest mastodon-http-params-build () "Should correctly format parameters from an alist." (let ((params '(("q" . "test") ("foo" . "bar")))) (should (string= (mastodon-http--build-params-string params) "q=test&foo=bar")))) (ert-deftest mastodon-http-params-array-build () "Should correctly format parameters from an alist." (let ((array '("option" "option2")) (param-str "poll[x][]")) (should (equal (mastodon-http--build-array-params-alist param-str array) '(("poll[x][]" . "option") ("poll[x][]" . "option2")))))) (ert-deftest mastodon-http-concat-params-url () "" (let ((url "https://example.com") (params '(("q" . "query")))) (should (equal (mastodon-http--concat-params-to-url url params) "https://example.com?q=query")))) mastodon.el/test/mastodon-media-tests.el000066400000000000000000000271771501733112700206610ustar00rootroot00000000000000;;; mastodon-media-test.el --- Tests for mastodon-media.el -*- lexical-binding: nil -*- (require 'el-mock) (ert-deftest mastodon-media--get-avatar-rendering () "Should return text with all expected properties." (with-mock ;; (mock (image-type-available-p 'imagemagick) => t) (mock (create-image * (when (version< emacs-version "27.1") 'imagemagick) t :height 123) => :mock-image) (let* ((mastodon-media--avatar-height 123) (result (mastodon-media--get-avatar-rendering "http://example.org/img.png")) (result-no-properties (substring-no-properties result)) (properties (text-properties-at 0 result))) (should (string= " " result-no-properties)) (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) (should (eq 'needs-loading (plist-get properties 'media-state))) (should (eq 'avatar (plist-get properties 'media-type))) (should (eq :mock-image (plist-get properties 'display)))))) (ert-deftest mastodon-media--get-media-link-rendering () "Should return text with all expected properties." (with-mock (mock (create-image * nil t) => :mock-image) (let* ((mastodon-media--preview-max-height 123) (result (mastodon-media--get-media-link-rendering "http://example.org/img.png" "http://example.org/remote/img.png" "image")) (result-no-properties (substring-no-properties result)) (properties (text-properties-at 0 result))) (should (string= "[img] " result-no-properties)) (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) (should (eq 'needs-loading (plist-get properties 'media-state))) (should (eq 'media-link (plist-get properties 'media-type))) (should (eq :mock-image (plist-get properties 'display))) (should (eq 'highlight (plist-get properties 'mouse-face))) (should (eq 'image (plist-get properties 'mastodon-tab-stop))) (should (string= "http://example.org/remote/img.png" (plist-get properties 'image-url))) (should (eq mastodon-tl--shr-image-map-replacement (plist-get properties 'keymap))) (should (string= "image" (plist-get properties 'mastodon-media-type))) (should (string= "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview, S: toggle sensitive media" (plist-get properties 'help-echo)))))) (ert-deftest mastodon-media:get-media-link-rendering-gif () "Should return text with all expected properties." (with-mock (mock (create-image * nil t) => :mock-image) (let* ((mastodon-media--preview-max-height 123) (result (mastodon-media--get-media-link-rendering "http://example.org/img.png" "http://example.org/remote/img.png" "gifv")) (result-no-properties (substring-no-properties result)) (properties (text-properties-at 0 result))) (should (string= "[img] " result-no-properties)) (should (string= "http://example.org/img.png" (plist-get properties 'media-url))) (should (eq 'needs-loading (plist-get properties 'media-state))) (should (eq 'media-link (plist-get properties 'media-type))) (should (eq :mock-image (plist-get properties 'display))) (should (eq 'highlight (plist-get properties 'mouse-face))) (should (eq 'image (plist-get properties 'mastodon-tab-stop))) (should (string= "http://example.org/remote/img.png" (plist-get properties 'image-url))) (should (eq mastodon-tl--shr-image-map-replacement (plist-get properties 'keymap))) (should (string= "gifv" (plist-get properties 'mastodon-media-type))) (should (string= "RET/i: load full image (prefix: copy URL), +/-: zoom, r: rotate, o: save preview, S: toggle sensitive media\nC-RET: play gifv with mpv" (plist-get properties 'help-echo)))))) (ert-deftest mastodon-media--load-image-from-url-avatar-with-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png") (mastodon-media--avatar-height 123)) (with-mock ;; (mock (image-type-available-p 'imagemagick) => t) (mock (create-image * (when (version< emacs-version "27.1") 'imagemagick) t :height 123) => '(image foo)) (mock (copy-marker 7) => :my-marker ) (mock (url-retrieve url #'mastodon-media--process-image-response `(:my-marker (:height 123) 1 ,url)) => :called-as-expected) (with-temp-buffer (insert (concat "Start:" (mastodon-media--get-avatar-rendering "http://example.org/img.png") ":rest")) (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) (ert-deftest mastodon-media--load-image-from-url-avatar-without-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock ;; (mock (image-type-available-p 'imagemagick) => nil) ;; (mock (image-transforms-p) => nil) (mock (create-image * nil t) => '(image foo)) (mock (copy-marker 7) => :my-marker ) (mock (url-retrieve url #'mastodon-media--process-image-response `(:my-marker () 1 ,url)) => :called-as-expected) (with-temp-buffer (insert (concat "Start:" (mastodon-media--get-avatar-rendering "http://example.org/img.png") ":rest")) (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'avatar 7 1))))))) (ert-deftest mastodon-media--load-image-from-url-media-link-with-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock ;; (mock (image-type-available-p 'imagemagick) => t) (mock (create-image * nil t) => '(image foo)) (mock (copy-marker 7) => :my-marker ) (mock (url-retrieve "http://example.org/image.png" #'mastodon-media--process-image-response '(:my-marker (:max-height 321) 5 "http://example.org/image.png")) => :called-as-expected) (with-temp-buffer (insert (concat "Start:" (mastodon-media--get-media-link-rendering url) ":rest")) (let ((mastodon-media--preview-max-height 321)) (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) (ert-deftest mastodon-media--load-image-from-url-media-link-without-imagemagic () "Should make the right call to url-retrieve." (let ((url "http://example.org/image.png")) (with-mock ;; (mock (image-type-available-p 'imagemagick) => nil) ;; (mock (image-transforms-p) => nil) (mock (create-image * nil t) => '(image foo)) (mock (copy-marker 7) => :my-marker ) (mock (url-retrieve "http://example.org/image.png" #'mastodon-media--process-image-response '(:my-marker () 5 "http://example.org/image.png")) => :called-as-expected) (with-temp-buffer (insert (concat "Start:" (mastodon-media--get-avatar-rendering url) ":rest")) (let ((mastodon-media--preview-max-height 321)) (should (eq :called-as-expected (mastodon-media--load-image-from-url url 'media-link 7 5)))))))) (ert-deftest mastodon-media--load-image-from-url-url-fetching-fails () "Should cope with failures in url-retrieve." (let ((url "http://example.org/image.png") (mastodon-media--avatar-height 123)) (with-mock ;; (mock (image-type-available-p 'imagemagick) => t) (mock (create-image * (when (version< emacs-version "27.1") 'imagemagick) t :height 123) => '(image foo)) (stub url-retrieve => (error "url-retrieve failed")) (with-temp-buffer (insert (concat "Start:" (mastodon-media--get-avatar-rendering "http://example.org/img.png") ":rest")) (should (eq :loading-failed (mastodon-media--load-image-from-url url 'avatar 7 1))) ;; the media state was updated so we won't load this again: (should (eq 'loading-failed (get-text-property 7 'media-state))))))) (ert-deftest mastodon-media--process-image-response () "Should process the HTTP response and adjust the source buffer." (with-temp-buffer (with-mock (let ((source-buffer (current-buffer)) used-marker saved-marker) (insert "start:") (setq used-marker (copy-marker (point)) saved-marker (copy-marker (point))) ;; Mock needed for the preliminary image created in ;; mastodon-media--get-avatar-rendering (stub create-image => :fake-image) (insert (mastodon-media--get-avatar-rendering "http://example.org/image.png.") ":end") (with-temp-buffer (insert "some irrelevant\n" "http headers\n" "which will be ignored\n\n" "fake\nimage\ndata") (goto-char (point-min)) (mock (create-image "fake\nimage\ndata" (when (version< emacs-version "27.1") 'imagemagick) t ':image :option) => :fake-image) (mastodon-media--process-image-response () used-marker '(:image :option) 1 "http://example.org/image.png") ;; the used marker has been unset: (should (null (marker-position used-marker))) ;; the media-state has been set to loaded and the image is being displayed (should (eq 'loaded (get-text-property saved-marker 'media-state source-buffer))) (should (eq ':fake-image (get-text-property saved-marker 'display source-buffer)))))))) (ert-deftest mastodon-media--inline-images () "Should process all media in buffer." (with-mock ;; Stub needed for the test setup: (stub create-image => '(image ignored)) (let (marker-media-link marker-media-link-bad-url marker-false-media marker-avatar) (with-temp-buffer (insert "Some text before\n") (setq marker-media-link (copy-marker (point))) (insert (mastodon-media--get-media-link-rendering "http://example.org/i.jpg") " some more text ") (setq marker-media-link-bad-url (copy-marker (point))) (insert (mastodon-media--get-media-link-rendering "/files/small/missing.png") " some more text ") (setq marker-false-media (copy-marker (point))) (insert ;; text that looks almost like an avatar but lacks the media-url property (propertize "this won't be processed" 'media-state 'needs-loading 'media-type 'avatar) "even more text ") (setq marker-avatar (copy-marker (point))) (insert (mastodon-media--get-avatar-rendering "http://example.org/avatar.png") " end of text") (goto-char (point-min)) ;; stub for the actual test: (stub mastodon-media--load-image-from-url) (mastodon-media--inline-images (point-min) (point-max)) (should (eq 'loading (get-text-property marker-media-link 'media-state))) (should (eq 'invalid-url (get-text-property marker-media-link-bad-url 'media-state))) (should (eq 'loading (get-text-property marker-avatar 'media-state))) (should (eq 'needs-loading (get-text-property marker-false-media 'media-state))))))) mastodon.el/test/mastodon-notifications-tests.el000066400000000000000000000211171501733112700224370ustar00rootroot00000000000000;;; mastodon-notifications-tests.el --- Tests for mastodon-notifications.el -*- lexical-binding: nil -*- (require 'cl-lib) (require 'cl-macs) (require 'el-mock) (defconst mastodon-notifications--test-base-mentioned '((id . "1234") (type . "mention") (created_at . "2018-03-06T04:27:21.288Z" ) (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (status (id . 61208) (created_at . "2017-04-24T19:01:02.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (media_attachments . []) (mentions . []) (tags . []) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (url . "https://example.space/users/acct42/updates/123456789") (content . "

Just some text

") (reblogs_count . 0) (favourites_count . 0) (reblog)))) (defconst mastodon-notifications--test-base-favourite '((id . "1234") (type . "favourite") (created_at . "2018-03-06T04:27:21.288Z" ) (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (status (id . 61208) (created_at . "2017-04-24T19:01:02.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (media_attachments . []) (mentions . []) (tags . []) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (url . "https://example.space/users/acct42/updates/123456789") (content . "

Just some text

") (reblogs_count . 0) (favourites_count . 0) (reblog)))) (defconst mastodon-notifications--test-base-boosted '((id . "1234") (type . "reblog") (created_at . "2018-03-06T04:27:21.288Z" ) (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (status (id . 61208) (created_at . "2017-04-24T19:01:02.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (media_attachments . []) (mentions . []) (tags . []) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (url . "https://example.space/users/acct42/updates/123456789") (content . "

Just some text

") (reblogs_count . 0) (favourites_count . 0) (reblog)))) (defconst mastodon-notifications--test-base-followed '((id . "1234") (type . "follow") (created_at . "2018-03-06T04:27:21.288Z" ) (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (status (id . 61208) (created_at . "2017-04-24T19:01:02.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (media_attachments . []) (mentions . []) (tags . []) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (url . "https://example.space/users/acct42/updates/123456789") (content . "

Just some text

") (reblogs_count . 0) (favourites_count . 0) (reblog)))) (defconst mastodon-notifications--test-base-favourite '((id . "1234") (type . "mention") (created_at . "2018-03-06T04:27:21.288Z" ) (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")))) ;; (ert-deftest mastodon-notifications--notification-get () ;; "Ensure get request format for notifictions is accurate." ;; (let ((mastodon-instance-url "https://instance.url")) ;; (with-mock ;; (mock (mastodon-http--get-json "https://instance.url/api/v1/notifications" nil)) ;; (mock (mastodon-profile--fetch-server-account-settings) ;; => '(max_toot_chars 1312 privacy "public" display_name "Eugen" discoverable t locked :json-false bot :json-false sensitive :json-false language "")) ;; (mastodon-notifications-get)))) (defun mastodon-notifications--test-type (fun sample) "Test notification draw functions. FUN is the notificiation function to be called and SAMPLE is the notification to be tested." (let ((mastodon-tl--show-avatars-p nil) (timestamp (cdr (assoc 'created_at sample)))) (with-temp-buffer (funcall fun sample) (buffer-substring-no-properties (point-min) (point-max))))) (ert-deftest mastodon-notifications--test-byline-action-str () "Ensure proper suffix is appended to action." (should (and (string= " Mentioned you\n" (mastodon-notifications--byline-action-str "Mentioned")) (string= " Followed you\n" (mastodon-notifications--byline-action-str "Followed")) (string= " Favourited your post\n" (mastodon-notifications--byline-action-str "Favourited")) (string= " Boosted your post\n" (mastodon-notifications--byline-action-str "Boosted")) (string= " Posted a post\n" (mastodon-notifications--byline-action-str "Posted"))))) mastodon.el/test/mastodon-profile-tests.el000066400000000000000000000324371501733112700212350ustar00rootroot00000000000000;;; mastodon-profile-test.el --- Tests for mastodon-profile.el -*- lexical-binding: nil -*- (require 'el-mock) (defconst gargron-profile-json '((id . "1") (username . "Gargron") (acct . "Gargron") (display_name . "Eugen") (locked . :json-false) (bot . :json-false) (discoverable . t) (group . :json-false) (created_at . "2016-03-16T00:00:00.000Z") (note . "

Developer of Mastodon and administrator of mastodon.social. I post service announcements, development updates, and personal stuff.

") (url . "https://mastodon.social/@Gargron") (avatar . "https://files.mastodon.social/accounts/avatars/000/000/001/original/d96d39a0abb45b92.jpg") (avatar_static . "https://files.mastodon.social/accounts/avatars/000/000/001/original/d96d39a0abb45b92.jpg") (header . "https://files.mastodon.social/accounts/headers/000/000/001/original/c91b871f294ea63e.png") (header_static . "https://files.mastodon.social/accounts/headers/000/000/001/original/c91b871f294ea63e.png") (followers_count . 470905) (following_count . 451) (statuses_count . 70741) (last_status_at . "2021-11-14") (emojis . []) (fields . (((name . "Patreon") (value . "https://www.patreon.com/mastodon") (verified_at)) ((name . "Homepage") (value . "https://zeonfederated.com") (verified_at . "2019-07-15T18:29:57.191+00:00")))))) (defconst ccc-profile-json '((id . "369027") (username . "CCC") (acct . "CCC@social.bau-ha.us") (display_name . "") (locked . :json-false) (bot . :json-false) (discoverable . :json-false) (group . :json-false) (created_at . "2018-06-03T00:00:00.000Z") (note . "

https://www.ccc.de/

") (url . "https://social.bau-ha.us/@CCC") (avatar . "https://files.mastodon.social/cache/accounts/avatars/000/369/027/original/6cfeb310f40e041a.jpg") (avatar_static . "https://files.mastodon.social/cache/accounts/avatars/000/369/027/original/6cfeb310f40e041a.jpg") (header . "https://files.mastodon.social/cache/accounts/headers/000/369/027/original/0d20bef6131b8139.jpg") (header_static . "https://files.mastodon.social/cache/accounts/headers/000/369/027/original/0d20bef6131b8139.jpg") (followers_count . 2733) (following_count . 120) (statuses_count . 1357) (last_status_at . "2021-11-02") (emojis . []) (fields . []))) (defconst gargon-statuses-json `(((id . "123456789012345678") (created_at . "2021-11-11T11:11:11.111Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (language) (uri . "https://mastodon.social/users/Gargron/statuses/123456789012345678/activity") (url . "https://mastodon.social/users/Gargron/statuses/123456789012345678/activity") (replies_count . 0) (reblogs_count . 0) (favourites_count . 0) (favourited . :json-false) (reblogged . :json-false) (muted . :json-false) (bookmarked . :json-false) (content . "

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.

") (reblog) (application) (account ,@gargron-profile-json) (media_attachments . []) (mentions . []) (tags . []) (emojis . []) (card) (poll)) ((id . "107279356043066700") (created_at . "2021-11-11T00:00:00.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (language . "en") (uri . "https://mastodon.social/users/Gargron/statuses/107279356043066700") (url . "https://mastodon.social/@Gargron/107279356043066700") (replies_count . 0) (reblogs_count . 2) (favourites_count . 0) (favourited . :json-false) (reblogged . :json-false) (muted . :json-false) (bookmarked . :json-false) (content . "

@CCC At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

") (reblog) (application (name . "Web") (website)) (account ,@gargron-profile-json) (media_attachments . []) (mentions . (((id . "369027") (username . "CCC") (url . "https://social.bau-ha.us/@CCC") (acct . "CCC@social.bau-ha.us")))) (tags . []) (emojis . []) (card) (poll)))) (ert-deftest mastodon-profile--add-author-bylines () "Should correctly format short infos about one account. When formatting Gargon's state we want to see - the short description of that profile, - the url of the avatar (yet to be loaded) - the info attached to the name" (with-mock ;; Don't start any image loading: (mock (mastodon-media--inline-images * *) => nil) ;; Let's not do formatting as that makes it hard to not rely on ;; window width and reflowing the text. (mock (shr-render-region * *) => nil) (if (version< emacs-version "27.1") (mock (image-type-available-p 'imagemagick) => t) (mock (image-transforms-p) => t)) (with-temp-buffer (let ((mastodon-tl--show-avatars t) (mastodon-tl--display-media-p t)) (mastodon-profile--format-user (list gargron-profile-json))) (should (equal (buffer-substring-no-properties (point-min) (point-max)) "\n Eugen (@Gargron)\n

Developer of Mastodon and administrator of mastodon.social. I post service announcements, development updates, and personal stuff.

\n")) ;; Check the avatar at pos 2 (should (equal (get-text-property 2 'media-url) "https://files.mastodon.social/accounts/avatars/000/000/001/original/d96d39a0abb45b92.jpg")) (should (equal (get-text-property 2 'media-state) 'needs-loading)) ;; Check the byline state (should (equal (get-text-property 4 'byline) t)) (should (equal (get-text-property 4 'item-id) (alist-get 'id gargron-profile-json))) (should (equal (get-text-property 4 'item-json) gargron-profile-json))))) (ert-deftest mastodon-profile--search-account-by-handle--removes-at () "Should ignore a leading at-sign in user handle. The search will happen as if called without the \"@\"." (with-mock (mock (mastodon-http--get-json "https://instance.url/api/v2/search" '(("q" . "gargron") ("type" . "accounts")))) (let ((mastodon-instance-url "https://instance.url")) ;; We don't check anything from the return value. We only care ;; that the mocked fetch was called with the expected URL. (mastodon-profile--search-account-by-handle "@gargron")))) (ert-deftest mastodon-profile--search-account-by-handle--filters-out-false-results () "Should ignore results that don't match the searched handle." (with-mock (mock (mastodon-http--get-json "https://instance.url/api/v2/search" '(("q" . "Gargron") ("type" . "accounts"))) => `((accounts ,ccc-profile-json ,gargron-profile-json))) (let ((mastodon-instance-url "https://instance.url")) (should (equal (mastodon-profile--search-account-by-handle "Gargron") gargron-profile-json))))) (ert-deftest mastodon-profile--search-account-by-handle--filtering-is-case-sensitive () "Should ignore results that don't match the searched handle with exact case. TODO: We need to decide if this is actually desired or not." (with-mock (mock (mastodon-http--get-json "https://instance.url/api/v2/search" '(("q" . "gargron") ("type" . "accounts"))) => `((accounts ,ccc-profile-json ,gargron-profile-json))) (let ((mastodon-instance-url "https://instance.url")) (should (null (mastodon-profile--search-account-by-handle "gargron")))))) (ert-deftest mastodon-profile--account-from-id--correct-url () "Should use the expected url for looking up by account id." (with-mock (mock (mastodon-http--get-json "https://instance.url/api/v1/accounts/1234567")) (let ((mastodon-instance-url "https://instance.url")) ;; We don't check anything from the return value. We only care ;; that the mocked fetch was called with the expected URL. (mastodon-profile--account-from-id "1234567")))) (ert-deftest mastodon-profile--make-author-buffer () "Should set up the buffer as expected for the given author. This is a far more complicated test as the mastodon-profile--make-author-buffer function does so much. There is a bit too much mocking and this may be brittle but it should help identify when things change unexpectedly. TODO: Consider separating the data retrieval and the actual content generation in the function under test." (with-mock ;; Don't start any image loading: (mock (mastodon-media--inline-images * *) => nil) ;; (if (version< emacs-version "27.1") ;; (mock (image-type-available-p 'imagemagick) => t) ;; (mock (image-transforms-p) => t)) (mock (mastodon-http--get-json * *) ;"https://instance.url/api/v1/accounts/1/statuses" => gargon-statuses-json) (mock (mastodon-profile--get-statuses-pinned *) => ()) (mock (mastodon-profile--relationships-get *) ;"1") => '(((id . "1") (following . :json-false) (showing_reblogs . :json-false) (notifying . :json-false) (followed_by . :json-false) (blocking . :json-false) (blocked_by . :json-false) (muting . :json-false) (muting_notifications . :json-false) (requested . :json-false) (domain_blocking . :json-false) (endorsed . :json-false) (note . "")))) ;; Let's not do formatting as that makes it hard to not rely on ;; window width and reflowing the text. (mock (shr-render-region * *) => nil) ;; Don't perform the actual update call at the end. ;; (mock (mastodon-tl--timeline *)) (mock (mastodon-profile--fetch-server-account-settings) => '(max_toot_chars 1312 privacy "public" display_name "Eugen" discoverable t locked :json-false bot :json-false sensitive :json-false language "")) (mock (mastodon-profile--format-joined-date-string *) => "Joined March 2016") (let ((mastodon-tl--show-avatars t) (mastodon-tl--display-media-p t) (mastodon-instance-url "https://instance.url")) (mastodon-profile--make-author-buffer gargron-profile-json) (should (equal (with-current-buffer "*mastodon-Gargron-statuses*" (buffer-substring-no-properties (point-min) (point-max))) (concat "\n" "[img] [img] \n" "Eugen\n" "@Gargron\n" " ――――――――――――\n" "

Developer of Mastodon and administrator of mastodon.social. I post service announcements, development updates, and personal stuff.

\n" "_ Patreon __ :: https://www.patreon.com/mastodon_ Homepage _ :: https://zeonfederated.com" "\n" "Joined March 2016" "\n\n " mastodon-tl--horiz-bar "\n" " TOOTS: 70741 | FOLLOWERS: 470905 | FOLLOWING: 451\n " mastodon-tl--horiz-bar "\n" "\n " mastodon-tl--horiz-bar "\n" " TOOTS \n " mastodon-tl--horiz-bar "\n" "\n" "

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.

\n" " Eugen (@Gargron) 2021-11-11 12:11:11\n " mastodon-tl--horiz-bar " 0 ⭐ | 0 🔁 | 0 💬\n" "\n" "\n" "

@CCC At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

\n" " Eugen (@Gargron) 2021-11-11 01:00:00\n " mastodon-tl--horiz-bar " 0 ⭐ | 2 🔁 | 0 💬\n" "\n" ))) ;; Until the function gets refactored this creates a non-temp ;; buffer with Gargron's statuses which we want to delete (if ;; the tests succeed). (kill-buffer)))) mastodon.el/test/mastodon-search-tests.el000066400000000000000000000227651501733112700210450ustar00rootroot00000000000000;;; mastodon-search-test.el --- Tests for mastodon-search.el -*- lexical-binding: nil -*- (defconst mastodon-search--single-account-query '((id . "242971") (username . "mousebot") (acct . "mousebot") (display_name . ": ( ) { : | : & } ; :") (locked . t) (bot . :json-false) (discoverable . t) (group . :json-false) (created_at . "2020-04-14T00:00:00.000Z") (note . "

poetry, writing, dmt, desertion, trash, black metal, translation, hegel, language, autonomia....

https://anarchive.mooo.com
https://pleasantlybabykid.tumblr.com/
IG: https://bibliogram.snopyta.org/u/martianhiatus
photos alt: @goosebot
git: https://git.blast.noho.st/mouse

want to trade chapbooks or zines? hmu!

he/him or they/them

") (url . "https://todon.nl/@mousebot") (avatar . "https://todon.nl/system/accounts/avatars/000/242/971/original/0a5e801576af597b.jpg") (avatar_static . "https://todon.nl/system/accounts/avatars/000/242/971/original/0a5e801576af597b.jpg") (header . "https://todon.nl/system/accounts/headers/000/242/971/original/f85f7f1048237fd4.jpg") (header_static . "https://todon.nl/system/accounts/headers/000/242/971/original/f85f7f1048237fd4.jpg") (followers_count . 226) (following_count . 634) (statuses_count . 3807) (last_status_at . "2021-11-05") (emojis . []) (fields . [((name . "dark to") (value . "themselves") (verified_at)) ((name . "its raining") (value . "plastic") (verified_at)) ((name . "dis") (value . "integration") (verified_at)) ((name . "ungleichzeitigkeit und") (value . "gleichzeitigkeit, philosophisch") (verified_at))])) "A sample mastodon account search result (parsed json)") (defconst mastodon-search--test-single-tag '((name . "TeamBringBackVisibleScrollbars") (url . "https://todon.nl/tags/TeamBringBackVisibleScrollbars") (history . [((day . "1636156800") (uses . "0") (accounts . "0")) ((day . "1636070400") (uses . "0") (accounts . "0")) ((day . "1635984000") (uses . "0") (accounts . "0")) ((day . "1635897600") (uses . "0") (accounts . "0")) ((day . "1635811200") (uses . "0") (accounts . "0")) ((day . "1635724800") (uses . "0") (accounts . "0")) ((day . "1635638400") (uses . "0") (accounts . "0"))]))) (defconst mastodon-search--test-single-status '((id . "107230316503209282") (created_at . "2021-11-06T13:19:40.628Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "direct") (language . "en") (uri . "https://todon.nl/users/mousebot/statuses/107230316503209282") (url . "https://todon.nl/@mousebot/107230316503209282") (replies_count . 0) (reblogs_count . 0) (favourites_count . 0) (favourited . :json-false) (reblogged . :json-false) (muted . :json-false) (bookmarked . :json-false) (content . "

This is a nice test toot, for testing purposes. Thank you.

") (reblog) (application (name . "mastodon.el") (website . "https://github.com/jdenen/mastodon.el")) (account (id . "242971") (username . "mousebot") (acct . "mousebot") (display_name . ": ( ) { : | : & } ; :") (locked . t) (bot . :json-false) (discoverable . t) (group . :json-false) (created_at . "2020-04-14T00:00:00.000Z") (note . "

poetry, writing, dmt, desertion, trash, black metal, translation, hegel, language, autonomia....

https://anarchive.mooo.com
https://pleasantlybabykid.tumblr.com/
IG: https://bibliogram.snopyta.org/u/martianhiatus
photos alt: @goosebot
git: https://git.blast.noho.st/mouse

want to trade chapbooks or zines? hmu!

he/him or they/them

") (url . "https://todon.nl/@mousebot") (avatar . "https://todon.nl/system/accounts/avatars/000/242/971/original/0a5e801576af597b.jpg") (avatar_static . "https://todon.nl/system/accounts/avatars/000/242/971/original/0a5e801576af597b.jpg") (header . "https://todon.nl/system/accounts/headers/000/242/971/original/f85f7f1048237fd4.jpg") (header_static . "https://todon.nl/system/accounts/headers/000/242/971/original/f85f7f1048237fd4.jpg") (followers_count . 226) (following_count . 634) (statuses_count . 3807) (last_status_at . "2021-11-05") (emojis . []) (fields . [((name . "dark to") (value . "themselves") (verified_at)) ((name . "its raining") (value . "plastic") (verified_at)) ((name . "dis") (value . "integration") (verified_at)) ((name . "ungleichzeitigkeit und") (value . "gleichzeitigkeit, philosophisch") (verified_at))])) (media_attachments . []) (mentions . [((id . "242971") (username . "mousebot") (url . "https://todon.nl/@mousebot") (acct . "mousebot"))]) (tags . []) (emojis . []) (card) (poll))) (ert-deftest mastodon-search--get-user-info-@ () "Should build a list from a single account for company completion." (should (equal (mastodon-search--get-user-info-@ mastodon-search--single-account-query) '("@mousebot" "https://todon.nl/@mousebot" ": ( ) { : | : & } ; :")))) (ert-deftest mastodon-search--get-user-info () "Should build a list from a single account for company completion." (should (equal (mastodon-search--get-user-info mastodon-search--single-account-query) '(": ( ) { : | : & } ; :" "mousebot" "https://todon.nl/@mousebot" "

poetry, writing, dmt, desertion, trash, black metal, translation, hegel, language, autonomia....

https://anarchive.mooo.com
https://pleasantlybabykid.tumblr.com/
IG: https://bibliogram.snopyta.org/u/martianhiatus
photos alt: @goosebot
git: https://git.blast.noho.st/mouse

want to trade chapbooks or zines? hmu!

he/him or they/them

")))) (ert-deftest mastodon-search--get-hashtag-info () "Should build a list of hashtag name and URL." (should (equal (mastodon-search--get-hashtag-info mastodon-search--test-single-tag) '("TeamBringBackVisibleScrollbars" "https://todon.nl/tags/TeamBringBackVisibleScrollbars")))) ;; (ert-deftest mastodon-search--get-status-info () ;; "Should return a list of ID, timestamp, content, and spoiler." ;; (should ;; (equal ;; (mastodon-search--get-status-info mastodon-search--test-single-status) ;; '("107230316503209282" ;; "2021-11-06T13:19:40.628Z" ;; "" ;; "

This is a nice test toot, for testing purposes. Thank you.

")))) mastodon.el/test/mastodon-tl-tests.el000066400000000000000000001631521501733112700202130ustar00rootroot00000000000000;;; mastodon-tl-test.el --- Tests for mastodon-tl.el -*- lexical-binding: nil -*- (require 'cl-lib) (require 'cl-macs) (require 'el-mock) (defconst mastodon-tl--test-instance-rules ;; brief ones calqued off todon.nl '(((id . "1") (text . "We do not accept racism.")) ((id . "2") (text . "We do not accept homophobia.")) ((id . "3") (text . "We do not accept sexism.")) ((id . "4") (text . "We do not accept ableism.")) ((id . "5") (text . "We do not accept harassment.")) ((id . "6") (text . "We also do not accept hate speech.")) ((id . "7") (text . "We do not accept abuse of minors.")) ((id . "8") (text . "We do not accept glorification of violence.")))) (defconst mastodon-tl-test-base-toot '((id . 61208) (created_at . "2017-04-24T19:01:02.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (media_attachments . ()) (mentions . ()) (tags . ()) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (url . "https://example.space/users/acct42/updates/123456789") (content . "

Just some text

") (reblogs_count . 0) (favourites_count . 0) (reblog)) "A sample toot (parsed json)") (defconst mastodon-tl-test-base-boosted-toot '((id . 61208) (created_at . "2017-04-24T20:59:59.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (media_attachments . ()) (mentions . ()) (tags . ()) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (url . "https://example.space/users/acct42/updates/123456789") (reblogs_count . 0) (favourites_count . 0) (reblog (id . 4543919) (created_at . "2017-04-24T19:01:02.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (application) (account (id . 43) (username . "acct43") (acct . "acct43@example.space") (display_name . "Account 43") (locked . :json-false) (created_at . "2017-04-02T00:00:00.000Z") (followers_count . 1) (following_count . 1) (statuses_count . 1) (note . "Other account")) (media_attachments . ()) (mentions . (((url . "https://mastodon.social/@johnson") (acct . "acct42") (id . 42) (username . "acct42")))) (tags . ()) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (content . "

@acct42 boost

") (url . "https://example.space/users/acct42/updates/123456789") (reblogs_count . 1) (favourites_count . 1) (favourited) (reblogged))) "A sample reblogged/boosted toot (parsed json)") (defconst mastodon-tl-test-empty-display-name '((id . 61208) (created_at . "2017-04-24T19:01:02.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . nil) (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (media_attachments . ()) (mentions . ()) (tags . ()) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (url . "https://example.space/users/acct42/updates/123456789") (content . "

Just some text

") (reblogs_count . 0) (favourites_count . 0) (reblog)) "A sample toot (parsed json)") (defconst mastodon-tl--follow-notify-true-response "HTTP/1.1 200 OK Date: Mon, 20 Dec 2021 13:42:29 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: Mastodon X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Permissions-Policy: interest-cohort=() X-RateLimit-Limit: 300 X-RateLimit-Remaining: 298 X-RateLimit-Reset: 2021-12-20T13:45:00.630990Z Cache-Control: no-store Vary: Accept, Accept-Encoding, Origin ETag: W/\"bee52f489c87e9a305e5d0b7bdca7ac1\" X-Request-Id: 5be9a64e-7d97-41b4-97f3-17b5e972a675 X-Runtime: 0.371914 Strict-Transport-Security: max-age=63072000; includeSubDomains Strict-Transport-Security: max-age=31536000 {\"id\":\"123456789\",\"following\":true,\"showing_reblogs\":true,\"notifying\":true,\"followed_by\":true,\"blocking\":false,\"blocked_by\":false,\"muting\":false,\"muting_notifications\":false,\"requested\":false,\"domain_blocking\":false,\"endorsed\":false,\"note\":\"\"}") (defconst mastodon-tl--follow-notify-false-response "HTTP/1.1 200 OK Date: Mon, 20 Dec 2021 13:42:29 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: Mastodon X-Frame-Options: DENY X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Permissions-Policy: interest-cohort=() X-RateLimit-Limit: 300 X-RateLimit-Remaining: 298 X-RateLimit-Reset: 2021-12-20T13:45:00.630990Z Cache-Control: no-store Vary: Accept, Accept-Encoding, Origin ETag: W/\"bee52f489c87e9a305e5d0b7bdca7ac1\" X-Request-Id: 5be9a64e-7d97-41b4-97f3-17b5e972a675 X-Runtime: 0.371914 Strict-Transport-Security: max-age=63072000; includeSubDomains Strict-Transport-Security: max-age=31536000 {\"id\":\"123456789\",\"following\":true,\"showing_reblogs\":true,\"notifying\":false,\"followed_by\":true,\"blocking\":false,\"blocked_by\":false,\"muting\":false,\"muting_notifications\":false,\"requested\":false,\"domain_blocking\":false,\"endorsed\":false,\"note\":\"\"}") (ert-deftest mastodon-tl--remove-html-1 () "Should remove all tags." (let ((input "foobar foobaz")) (should (string= (mastodon-tl--remove-html input) "foobar foobaz")))) (ert-deftest mastodon-tl--remove-html-2 () "Should replace <\p> tags with two new lines." (let ((input "foobar

")) (should (string= (mastodon-tl--remove-html input) "foobar\n\n")))) (ert-deftest mastodon-tl--item-id-boosted () "If a toot is boostedm, return the reblog id." (should (string= (mastodon-tl--as-string (mastodon-tl--item-id mastodon-tl-test-base-boosted-toot)) "4543919"))) (ert-deftest mastodon-tl--item-id () "If a toot is boostedm, return the reblog id." (should (string= (mastodon-tl--as-string (mastodon-tl--item-id mastodon-tl-test-base-toot)) "61208"))) (ert-deftest mastodon-tl--as-string-1 () "Should accept a string or number and return a string." (let ((id "1000")) (should (string= (mastodon-tl--as-string id) id)))) (ert-deftest mastodon-tl--as-string-2 () "Should accept a string or number and return a string." (let ((id 1000)) (should (string= (mastodon-tl--as-string id) (number-to-string id))))) (ert-deftest mastodon-tl--more-json () "Should request toots older than max_id." (let ((mastodon-instance-url "https://instance.url")) (with-mock (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo" '(("max_id" . "12345")))) (mastodon-tl--more-json "timelines/foo" "12345")))) (ert-deftest mastodon-tl--more-json-id-string () "Should request toots older than max_id. `mastodon-tl--more-json' should accept and id that is either a string or a numeric." (let ((mastodon-instance-url "https://instance.url")) (with-mock (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo" '(("max_id" . "12345")))) (mastodon-tl--more-json "timelines/foo" "12345")))) (ert-deftest mastodon-tl--update-json-id-string () "Should request toots more recent than since_id. `mastodon-tl--updated-json' should accept and id that is either a string or a numeric." (let ((mastodon-instance-url "https://instance.url")) (with-mock (mock (mastodon-http--get-json "https://instance.url/api/v1/timelines/foo" '(("since_id" . "12345")))) (mastodon-tl--updated-json "timelines/foo" "12345")))) ;; broken by monnier's `mastodon-tl--human-duration', which uses "secs" rather ;; than "just now". its not just the abbrevs, also the rounding works ;; differently (ert-deftest mastodon-tl--relative-time-description () "Should format relative time as expected" (cl-labels ((minutes (n) (* n 60)) (hours (n) (* n (minutes 60))) (days (n) (* n (hours 24))) (weeks (n) (* n (days 7))) (years (n) (* n (days 365))) (format-seconds-since (seconds) (let ((timestamp (time-subtract (current-time) (seconds-to-time seconds)))) (mastodon-tl--relative-time-description timestamp))) (check (seconds expected) (should (string= (format-seconds-since seconds) expected)))) (check 1 "just now") (check 59 "just now") (check 60 "1 min ago") (check 89 "1 min ago") ;; rounding down (check 91 "1 min ago") ;"2 minutes ago") ;; rounding up (check (minutes 3.49) "3 mins ago") ;; rounding down (check (minutes 3.52) "3 mins ago") ;"4 minutes ago") (check (minutes 59) "59 mins ago") (check (minutes 60) "1 hour ago") (check (minutes 89) "1 hour, 29 mins ago") (check (minutes 91) "1 hour, 31 mins ago") ;"2 hours ago") (check (hours 3.49) "3 hours, 29 mins ago") ; "3 hours ago") ;; rounding down (check (hours 3.51) "3 hours, 30 mins ago") ; "4 hours ago") ;; rounding down (check (hours 23.4) "23 hours, 24 mins ago"); "23 hours ago") (check (hours 23.6) "23 hours, 36 mins ago") ; "1 day ago") ;; rounding up (check (days 1.48) "1 day, 11 hours ago") ; "1 day ago") ;; rounding down (check (days 1.52) "1 day, 12 hours ago"); "2 days ago") ;; rounding up (check (days 6.6) "6 days, 14 hours ago"); "1 week ago") ;; rounding up (check (weeks 2.49) "2 weeks, 3 days ago"); "2 weeks ago") ;; rounding down (check (weeks 2.51) "2 weeks, 3 days ago"); "3 weeks ago") ;; rounding down (check (1- (weeks 52)) "11 months, 4 weeks ago") ;"52 weeks ago") (check (weeks 52) "11 months, 4 weeks ago") ;"1 year ago") (check (years 2.49) "2 years, 5 months ago"); "2 years ago") ;; rounding down (check (years 2.51) "2 years, 6 months ago"); "3 years ago") ;; rounding down )) ;; broken by monnier's `mastodon-tl--human-duration', which uses "secs" rather ;; than "just now". its not just the abbrevs, also the rounding works ;; differently (ert-deftest mastodon-tl--relative-time-details--next-update () "Should calculate the next update time information as expected" :expected-result :failed (let ((current-time (current-time))) (cl-labels ((minutes (n) (* n 60)) (hours (n) (* n (minutes 60))) (days (n) (* n (hours 24))) (weeks (n) (* n (days 7))) (years (n) (* n (days 365.25))) (next-update (seconds-ago) (let* ((timestamp (time-subtract current-time (seconds-to-time seconds-ago)))) (cdr (mastodon-tl--relative-time-details timestamp current-time)))) (check (seconds-ago) (let* ((timestamp (time-subtract current-time (seconds-to-time seconds-ago))) (at-now (mastodon-tl--relative-time-description timestamp current-time)) (at-one-second-before (mastodon-tl--relative-time-description timestamp (time-subtract (next-update seconds-ago) (seconds-to-time 1)))) (at-result (mastodon-tl--relative-time-description timestamp (next-update seconds-ago)))) (when nil ;; change to t to debug test failures (prin1 (format "\nFor %s: %s / %s" seconds-ago (time-to-seconds (time-subtract (next-update seconds-ago) timestamp)) (round (time-to-seconds (time-subtract (next-update seconds-ago) current-time)))))) ;; a second earlier the description is the same as at current time (should (string= at-now at-one-second-before)) ;; but at the result time it is different (should-not (string= at-one-second-before at-result))))) (check 0) (check 1) (check 59) (check 60) (check 89) (check 90) (check 149) (check 150) (check (1- (hours 1.5))) ;; just before we switch from "one hour" to "2 hours" (check (hours 1.5)) (check (hours 2.1)) (check (1- (hours 23.5))) ;; just before "23 hours" -> "one day" (check (hours 23.5)) (check (1- (days 1.5))) ;; just before "one day" -> "2 days" (check (days 1.5)) ;; just before "one day" -> "2 days" (check (days 2.1)) (check (1- (days 6.5))) ;; just before "6 days" -> "one week" (check (days 6.5)) ;; "one week" -> "2 weeks" (check (weeks 2.1)) (check (1- (weeks 52))) ;; just before "52 weeks" -> "one year" (check (weeks 52)) (check (days 365)) (check (days 366)) (check (years 2.1)) ))) (ert-deftest mastodon-tl--byline-regular () "Should format the regular toot correctly." (let ((mastodon-tl--show-avatars-p nil) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock (mock (date-to-time timestamp) => '(22782 21551)) (mock (mastodon-tl--toot-stats mastodon-tl-test-base-toot) => "") (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") (let ((byline (mastodon-tl--byline mastodon-tl-test-base-toot)) (handle-location 20)) (should (string= (substring-no-properties byline) (concat "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 " mastodon-tl--horiz-bar " "))) (should (eq (get-text-property handle-location 'mastodon-tab-stop byline) 'user-handle)) (should (string= (get-text-property handle-location 'mastodon-handle byline) "@acct42@example.space")) (should (equal (get-text-property handle-location 'help-echo byline) "Browse user profile of @acct42@example.space")))))) (ert-deftest mastodon-tl--byline-regular-with-avatar () "Should format the regular toot correctly." (let ((mastodon-tl--show-avatars-p t) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock (stub create-image => '(image "fake data")) (mock (date-to-time timestamp) => '(22782 21551)) (mock (mastodon-tl--toot-stats mastodon-tl-test-base-toot) => "") (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") (should (string= (substring-no-properties (mastodon-tl--byline mastodon-tl-test-base-toot)) (concat "Account 42 (@acct42@example.space) 2999-99-99 00:11:22 " mastodon-tl--horiz-bar " ")))))) (ert-deftest mastodon-tl--byline-boosted () "Should format the boosted toot correctly." (let* ((mastodon-tl--show-avatars-p nil) (toot (cons '(reblogged . t) mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock (mock (date-to-time timestamp) => '(22782 21551)) (mock (mastodon-tl--symbol 'boost) => "B") (mock (mastodon-tl--toot-stats toot) => "") (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") (should (string= (substring-no-properties (mastodon-tl--byline toot)) (concat "(B) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 " mastodon-tl--horiz-bar " ")))))) (ert-deftest mastodon-tl--byline-favorited () "Should format the favourited toot correctly." (let* ((mastodon-tl--show-avatars-p nil) (toot (cons '(favourited . t) mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock (mock (mastodon-tl--symbol 'favourite) => "F") (mock (date-to-time timestamp) => '(22782 21551)) (mock (mastodon-tl--toot-stats toot) => "") (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") (should (string= (substring-no-properties (mastodon-tl--byline toot)) (concat "(F) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 " mastodon-tl--horiz-bar " ")))))) (ert-deftest mastodon-tl--byline-boosted/favorited () "Should format the boosted & favourited toot correctly." (let* ((mastodon-tl--show-avatars-p nil) (toot `((favourited . t) (reblogged . t) ,@mastodon-tl-test-base-toot)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock (mock (mastodon-tl--toot-stats toot) => "") (mock (date-to-time timestamp) => '(22782 21551)) ;; FIXME this mock refuses to recognise our different args ;; (mock (mastodon-tl--symbol 'favourite) => "F") ;; (mock (mastodon-tl--symbol 'boost) => "B") (mock (mastodon-tl--symbol *) => "?") (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") (should (string= (substring-no-properties (mastodon-tl--byline toot)) (concat "(?) (?) Account 42 (@acct42@example.space) 2999-99-99 00:11:22 " mastodon-tl--horiz-bar " ")))))) ;; FIXME: In recent mastodon versions the `mastodon-tl--byline' behavior changed ;; as well as the reblogged behavior, and as a result this test behaves similar ;; to `mastodon-tl--byline-regular' and may require some work. (ert-deftest mastodon-tl--byline-reblogged () "Should format the reblogged toot correctly." :expected-result :failed (let* ((mastodon-tl--show-avatars-p nil) (toot mastodon-tl-test-base-boosted-toot) (original-toot (cdr (assoc 'reblog mastodon-tl-test-base-boosted-toot))) (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock ;; We don't expect to use the toot's timestamp but the timestamp of the ;; reblogged toot: (mock (date-to-time timestamp) => '(1 2)) (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") (mock (date-to-time original-timestamp) => '(3 4)) (mock (mastodon-tl--toot-stats toot) => "") (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") (let ((byline (mastodon-tl--byline toot)) (handle1-location 20) (handle2-location 65)) (should (string= (substring-no-properties byline) (concat "Account 43 (@acct43@example.space) original time " mastodon-tl--horiz-bar " "))) (should (eq (get-text-property handle1-location 'mastodon-tab-stop byline) 'user-handle)) (should (equal (get-text-property handle1-location 'help-echo byline) "Browse user profile of @acct43@example.space")) (should (eq (get-text-property handle2-location 'mastodon-tab-stop byline) 'nil)) (should (equal (get-text-property handle2-location 'help-echo byline) nil)))))) (ert-deftest mastodon-tl--byline-reblogged-with-avatars () "Should format the reblogged toot correctly." (let* ((mastodon-tl--show-avatars-p t) (toot mastodon-tl-test-base-boosted-toot) (original-toot (cdr (assoc 'reblog mastodon-tl-test-base-boosted-toot))) (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock ;; We don't expect to use the toot's timestamp but the timestamp of the ;; reblogged toot: (stub create-image => '(image "fake data")) (mock (date-to-time timestamp) => '(1 2)) (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") (mock (date-to-time original-timestamp) => '(3 4)) (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") (mock (mastodon-tl--toot-stats toot) => "") (should (string= (substring-no-properties (mastodon-tl--byline toot)) (concat "Account 43 (@acct43@example.space) original time " mastodon-tl--horiz-bar " ")))))) (ert-deftest mastodon-tl--byline-reblogged-boosted/favorited () "Should format the reblogged toot that was also boosted & favoritedcorrectly." (let* ((mastodon-tl--show-avatars-p nil) (toot `((favourited . t) (reblogged . t) ,@mastodon-tl-test-base-boosted-toot)) (original-toot (cdr (assoc 'reblog mastodon-tl-test-base-boosted-toot))) (timestamp (cdr (assoc 'created_at toot))) (original-timestamp (cdr (assoc 'created_at original-toot)))) (with-mock ;; We don't expect to use the toot's timestamp but the timestamp of the ;; reblogged toot: (mock (date-to-time timestamp) => '(1 2)) ;; FIXME this mock refuses to recognise our different args ;; (mock (mastodon-tl--symbol 'favourite) => "F") ;; (mock (mastodon-tl--symbol 'boost) => "B") ;; (mock (mastodon-tl--symbol *) => "?") (mock (mastodon-tl--toot-stats toot) => "") (mock (format-time-string mastodon-toot-timestamp-format '(1 2)) => "reblogging time") (mock (date-to-time original-timestamp) => '(3 4)) (mock (format-time-string mastodon-toot-timestamp-format '(3 4)) => "original time") (should (string= (substring-no-properties (mastodon-tl--byline toot)) (concat "Account 43 (@acct43@example.space) original time " mastodon-tl--horiz-bar " ")))))) (ert-deftest mastodon-tl--byline-timestamp-has-relative-display () "Should display the timestamp with a relative time." (let ((mastodon-tl--show-avatars-p nil) (timestamp (cdr (assoc 'created_at mastodon-tl-test-base-toot)))) (with-mock (mock (date-to-time timestamp) => '(22782 21551)) ;; (mock (current-time) => '(22782 22000)) ; not sure why this breaks it (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") (let* ((formatted-string (mastodon-tl--byline mastodon-tl-test-base-toot)) (timestamp-start (string-match "2999-99-99" formatted-string)) (properties (text-properties-at timestamp-start formatted-string))) (should (equal '(22782 21551) (plist-get properties 'timestamp))) (should (string-equal ;;"7 minutes ago" ;; "7 mins ago" ;; not sure why its diff now ;; FIXME: this value has become really relative so we will have to ;; keep changing it! "7 years, 4 months ago" (plist-get properties 'display))))))) (ert-deftest mastodon-tl--byline-no-displayname () "Should not fail when display_name is nil." (let* ((mastodon-tl--show-avatars-p nil) (toot (cons '(reblogged . t) mastodon-tl-test-empty-display-name)) (timestamp (cdr (assoc 'created_at toot)))) (with-mock (mock (date-to-time timestamp) => '(22782 21551)) (mock (mastodon-tl--symbol 'boost) => "B") (mock (mastodon-tl--toot-stats toot) => "") (mock (format-time-string mastodon-toot-timestamp-format '(22782 21551)) => "2999-99-99 00:11:22") (should (string= (substring-no-properties (mastodon-tl--byline toot)) (concat "(B) acct42 (@acct42@example.space) 2999-99-99 00:11:22 " mastodon-tl--horiz-bar " ")))))) (ert-deftest mastodon-tl--consider-timestamp-for-updates-no-active-callback () "Should update the timestamp update variables as expected." (let* ((now (current-time)) (soon-in-the-future (time-add now (seconds-to-time 10000))) (long-in-the-future (time-add now (seconds-to-time 10000000)))) (with-temp-buffer ;; start with timer way into the future and no active callback (setq mastodon-tl--timestamp-next-update long-in-the-future mastodon-tl--timestamp-update-timer nil) ;; something a later update doesn't update: (with-mock (mock (mastodon-tl--relative-time-details 'fake-timestamp) => (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) (should (null mastodon-tl--timestamp-update-timer)) (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something only shortly sooner doesn't update: (with-mock (mock (mastodon-tl--relative-time-details 'fake-timestamp) => (cons "xxx ago" (time-subtract long-in-the-future (seconds-to-time 9)))) (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) (should (null mastodon-tl--timestamp-update-timer)) (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something much sooner, does update (with-mock (mock (mastodon-tl--relative-time-details 'fake-timestamp) => (cons "xxx ago" soon-in-the-future)) (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) (should (null mastodon-tl--timestamp-update-timer)) (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) ))) (ert-deftest mastodon-tl--consider-timestamp-for-updates-with-active-callback () "Should update the timestamp update variables as expected." (let* ((now (current-time)) (soon-in-the-future (time-add now (seconds-to-time 10000))) (long-in-the-future (time-add now (seconds-to-time 10000000)))) (with-temp-buffer ;; start with timer way into the future and no active callback (setq mastodon-tl--timestamp-next-update long-in-the-future mastodon-tl--timestamp-update-timer 'initial-timer) ;; something a later update doesn't update: (with-mock (mock (mastodon-tl--relative-time-details 'fake-timestamp) => (cons "xxx ago" (time-add long-in-the-future (seconds-to-time 100)))) (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) (should (eq 'initial-timer mastodon-tl--timestamp-update-timer)) (should (eq mastodon-tl--timestamp-next-update long-in-the-future))) ;; something much sooner, does update (with-mock (mock (mastodon-tl--relative-time-details 'fake-timestamp) => (cons "xxx ago" soon-in-the-future)) (mock (cancel-timer 'initial-timer)) (mock (run-at-time * nil #'mastodon-tl--update-timestamps-callback (current-buffer) nil) => 'new-timer) (mastodon-tl--consider-timestamp-for-updates 'fake-timestamp) (should (eq 'new-timer mastodon-tl--timestamp-update-timer)) (should (eq mastodon-tl--timestamp-next-update soon-in-the-future))) ))) (ert-deftest mastodon-tl--find-property-range--no-tag () "Should cope with a buffer completely lacking the tag." (with-temp-buffer (insert "Just some random text") (insert (propertize "More text with a different property" 'other-property 'set)) (should (null (mastodon-tl--find-property-range 'test-property 2 nil))) (should (null (mastodon-tl--find-property-range 'test-property 2 t))))) (ert-deftest mastodon-tl--find-property-range--earlier-tag () "Should cope with a buffer completely lacking the tag." (with-temp-buffer (insert (propertize "Just some text with a the sought property" 'test-property 'set)) (let ((end-of-region (point))) (insert "More random text") (should (null (mastodon-tl--find-property-range 'test-property end-of-region nil))) (should (equal (cons (point-min) end-of-region) (mastodon-tl--find-property-range 'test-property end-of-region t)))))) (ert-deftest mastodon-tl--find-property-range--successful-finding () "Should find the sought tag in all expected circumstances." (with-temp-buffer (insert "Previous text") (let ((start-of-region (point)) end-of-region) (insert (propertize "Just some text with a the sought property" 'test-property 'set)) (setq end-of-region (point)) (insert "More random text") ;; before the region (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property 1 nil))) (should (null (mastodon-tl--find-property-range 'test-property 1 t))) ;; in the region (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property (+ 2 start-of-region) nil))) (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property (+ 2 start-of-region) t))) ;; at end of region (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property (1- end-of-region) nil))) (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property (1- end-of-region) t)))))) (ert-deftest mastodon-tl--find-property-range--successful-finding-consecutive-ranges () "Should find the sought tag even from in between consecutive ranges." (with-temp-buffer (insert "Previous text") (let ((start-of-region-1 (point)) between-regions end-of-region-2) (insert (propertize "region1" 'test-property 'region1)) (setq between-regions (point)) (insert (propertize "region2" 'test-property 'region2)) (setq end-of-region-2 (point)) (insert "More random text") ;; before (should (equal (cons start-of-region-1 between-regions) (mastodon-tl--find-property-range 'test-property 1 nil))) (should (null (mastodon-tl--find-property-range 'test-property 1 t))) ;; between the regions (should (equal (cons between-regions end-of-region-2) (mastodon-tl--find-property-range 'test-property between-regions nil))) (should (equal (cons between-regions end-of-region-2) (mastodon-tl--find-property-range 'test-property between-regions t))) ;; after (should (null (mastodon-tl--find-property-range 'test-property end-of-region-2 nil))) (should (equal (cons between-regions end-of-region-2) (mastodon-tl--find-property-range 'test-property end-of-region-2 t)))))) (ert-deftest mastodon-tl--find-property-range--successful-finding-at-start () "Should cope with a tag at start." (with-temp-buffer (insert (propertize "Just some text with a the sought property" 'test-property 'set)) (let ((end-of-region (point))) (insert "More random text") ;; at start of the region (should (equal (cons 1 end-of-region) (mastodon-tl--find-property-range 'test-property 1 nil))) (should (equal (cons 1 end-of-region) (mastodon-tl--find-property-range 'test-property 1 t))) ;; in the region (should (equal (cons 1 end-of-region) (mastodon-tl--find-property-range 'test-property 3 nil))) (should (equal (cons 1 end-of-region) (mastodon-tl--find-property-range 'test-property 3 t))) ;; at end of region (should (equal (cons 1 end-of-region) (mastodon-tl--find-property-range 'test-property (1- end-of-region) t)))))) (ert-deftest mastodon-tl--find-property-range--successful-finding-at-end () "Should cope with a tag at end." (with-temp-buffer (insert "More random text") (let ((start-of-region (point)) end-of-region) (insert (propertize "Just some text with a the sought property" 'test-property 'set)) (setq end-of-region (point-max)) ;; before the region (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property 1 nil))) (should (null (mastodon-tl--find-property-range 'test-property 1 t))) ;; in the region (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property (1+ start-of-region) nil))) (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property (1+ start-of-region) t))) ;; at end of region (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property (1- end-of-region) nil))) (should (equal (cons start-of-region end-of-region) (mastodon-tl--find-property-range 'test-property (1- end-of-region) t)))))) (ert-deftest mastodon-tl--find-property-range--successful-finding-whole-buffer () "Should cope with a tag being set for the whole buffer." (with-temp-buffer (insert (propertize "Just some text with a the sought property" 'test-property 'set)) (should (equal (cons (point-min) (point-max)) (mastodon-tl--find-property-range 'test-property 2 nil))) (should (equal (cons (point-min) (point-max)) (mastodon-tl--find-property-range 'test-property 2 t))))) (defun tl-tests--all-regions-with-property (property) "Returns a list with (start . end) regions where PROPERTY is set." (let (result region) (goto-char (point-min)) (while (and (< (point) (point-max)) (setq region (mastodon-tl--find-property-range property (point)))) (push region result) (goto-char (min (point-max) (cdr region)))) (nreverse result))) (ert-deftest mastodon-tl--next-tab-item--with-spaces-at-ends () "Should do the correct tab actions." (with-temp-buffer ;; We build a buffer with 3 tab stops: "...R1...R2R3..." (a dot ;; represents text that is not part of a link, so R1 and R2 have a ;; gap in between each other, R2 and R3 don't. (insert "Random text at start") (let ((start 2) (r1 (point)) r2 gap r3 end) (insert (propertize "R1 R1 R1" 'mastodon-tab-stop 'region1)) (setq gap (+ (point) 2)) (insert " a gap ") (setq r2 (point)) (insert (propertize "R2 R2 R2" 'mastodon-tab-stop 'region2)) (setq r3 (point)) (insert (propertize "R3 R3 R3" 'mastodon-tab-stop 'region3)) (setq end (+ (point) 2)) (insert " more text at end") (let ((test-cases ;; a list 4-elemet lists of (test-name start-point ;; expected-prev-stop expected-next-stop): (list (list 'start start start r1) (list 'r1 r1 r1 r2) (list 'gap gap r1 r2) (list 'r2 r2 r1 r3) (list 'r3 r3 r2 r3) (list 'end end r3 end)))) (with-mock (stub message => nil) ;; don't mess up our test output with the function's messages (cl-dolist (test test-cases) (let ((test-name (cl-first test)) (test-start (cl-second test)) (expected-prev (cl-third test)) (expected-next (cl-fourth test))) (goto-char test-start) ;; (mastodon-tl--previous-tab-item) (should (equal (list 'prev test-name expected-prev) (list 'prev test-name (point)))) (goto-char test-start) (mastodon-tl-next-tab-item) (should (equal (list 'next test-name expected-next) (list 'next test-name (point))))))))))) (ert-deftest mastodon-tl--next-tab-item--no-spaces-at-ends () "Should do the correct tab actions even with regions right at buffer ends." (with-temp-buffer ;; We build a buffer with 3 tab stops: "R1...R2R3...R4" (a dot ;; represents text that is not part of a link, so R1 and R2, and ;; R3 and R4 have a gap in between each other, R2 and R3 don't. (let ((r1 (point)) gap1 r2 r3 gap2 r4) (insert (propertize "R1 R1 R1" 'mastodon-tab-stop 'region1)) (setq gap1 (+ (point) 2)) (insert " a gap ") (setq r2 (point)) (insert (propertize "R2 R2 R2" 'mastodon-tab-stop 'region2)) (setq r3 (point)) (insert (propertize "R3 R3 R3" 'mastodon-tab-stop 'region3)) (setq gap2 (+ (point) 2)) (insert " another gap ") (setq r4 (point)) (insert (propertize "R4 R4 R4" 'mastodon-tab-stop 'region4)) (let ((test-cases ;; a list 4-elemet lists of (test-name start-point ;; expected-prev-stop expected-next-stop): (list (list 'r1 r1 r1 r2) (list 'gap1 gap1 r1 r2) (list 'r2 r2 r1 r3) (list 'r3 r3 r2 r4) (list 'gap2 gap2 r3 r4) (list 'r4 r4 r3 r4)))) (with-mock (stub message => nil) ;; don't mess up our test output with the function's messages (cl-dolist (test test-cases) (let ((test-name (cl-first test)) (test-start (cl-second test)) (expected-prev (cl-third test)) (expected-next (cl-fourth test))) (goto-char test-start) ;; (mastodon-tl--previous-tab-item) (should (equal (list 'prev test-name expected-prev) (list 'prev test-name (point)))) (goto-char test-start) (mastodon-tl-next-tab-item) (should (equal (list 'next test-name expected-next) (list 'next test-name (point))))))))))) (defun tl-tests--property-values-at (property ranges) "Returns a list with property values at the given ranges. The property value for PROPERTY within a region is assumed to be constant." (let (result) (dolist (range ranges (nreverse result)) (push (get-text-property (car range) property) result)))) (ert-deftest mastodon-tl--update-timestamps-callback () "Should update the 5 timestamps at a time as expected." (let ((now (current-time)) markers) (cl-labels ((insert-timestamp (n) (insert (format "\nSome text before timestamp %s:" n)) (insert (propertize (format "timestamp #%s" n) 'timestamp (time-subtract now (seconds-to-time (* 60 n))) 'display (format "unset %s" n))) (push (copy-marker (point)) markers) (insert " some more text."))) (with-temp-buffer (cl-dotimes (n 12) (insert-timestamp (+ n 2))) (setq markers (nreverse markers)) (with-mock (mock (current-time) => now) (stub run-at-time => 'fake-timer) ;; make the initial call (mastodon-tl--update-timestamps-callback (current-buffer) nil) (should (equal '("2 mins ago" "3 mins ago" "4 mins ago" "5 mins ago" "6 mins ago" "unset 7" "unset 8" "unset 9" "unset 10" "unset 11" "unset 12" "unset 13") (tl-tests--property-values-at 'display (tl-tests--all-regions-with-property 'timestamp)))) ;; fake the follow-up call (mastodon-tl--update-timestamps-callback (current-buffer) (nth 4 markers)) (should (equal '("2 mins ago" "3 mins ago" "4 mins ago" "5 mins ago" "6 mins ago" "7 mins ago" "8 mins ago" "9 mins ago" "10 mins ago" "11 mins ago" "unset 12" "unset 13") (tl-tests--property-values-at 'display (tl-tests--all-regions-with-property 'timestamp)))) (should (null (marker-position (nth 4 markers)))) ;; fake the follow-up call (mastodon-tl--update-timestamps-callback (current-buffer) (nth 9 markers)) (should (equal '("2 mins ago" "3 mins ago" "4 mins ago" "5 mins ago" "6 mins ago" "7 mins ago" "8 mins ago" "9 mins ago" "10 mins ago" "11 mins ago" "12 mins ago" "13 mins ago") (tl-tests--property-values-at 'display (tl-tests--all-regions-with-property 'timestamp)))) (should (null (marker-position (nth 9 markers))))))))) (ert-deftest mastodon-tl--has-spoiler () "Should be able to detect toots with spoiler text as expected" (let* ((normal-toot mastodon-tl-test-base-toot) (normal-toot-with-spoiler (cons '(spoiler_text . "spoiler") normal-toot)) (boosted-toot mastodon-tl-test-base-boosted-toot) (boosted-toot-with-spoiler (cons (cons 'reblog normal-toot-with-spoiler) boosted-toot))) (should (null (mastodon-tl--has-spoiler normal-toot))) (should-not (null (mastodon-tl--has-spoiler normal-toot-with-spoiler))) (should (null (mastodon-tl--has-spoiler boosted-toot))) (should-not (null (mastodon-tl--has-spoiler boosted-toot-with-spoiler))))) (ert-deftest mastodon-tl--spoiler () "Should render a toot with spoiler properly, with link that toggles the body." (let ((normal-toot-with-spoiler (cons '(spoiler_text . "This is the spoiler warning text") mastodon-tl-test-base-toot)) toot-start toot-end link-region body-position) (with-temp-buffer (insert "some text before\n") (setq toot-start (point)) (with-mock (mock (mastodon-profile--get-preferences-pref 'reading:expand:spoilers) => :json-false) (stub create-image => '(image "fake data")) (stub shr-render-region => nil) ;; Travis's Emacs doesn't have libxml (insert (mastodon-tl--spoiler normal-toot-with-spoiler))) (setq toot-end (point)) (insert "\nsome more text.") (add-text-properties toot-start toot-end (list 'item-json normal-toot-with-spoiler 'item-id (cdr (assoc 'id normal-toot-with-spoiler)))) (goto-char toot-start) ;; (should (eq t (looking-at "This is the spoiler warning text"))) (setq link-region (mastodon-tl--find-next-or-previous-property-range 'mastodon-tab-stop toot-start nil)) ;; There should be a link following the text: (should-not (null link-region)) (goto-char (car link-region)) (should (eq t (looking-at "CW: This is the spoiler warning text"))) ;Content Warning"))) (setq body-position (+ 25 (cdr link-region))) ;; 25 is enough to skip the "\n--------------...." ;; The text a bit after the link should be invisible: (should (eq t (get-text-property body-position 'invisible))) ;; Click the link: (mastodon-tl-do-link-action-at-point (car link-region)) ;; The body is now visible: (should (eq nil (get-text-property body-position 'invisible))) ;; Click the link once more: (mastodon-tl-do-link-action-at-point (car link-region)) ;; The body is invisible again: (should (eq t (get-text-property body-position 'invisible))) ;; Go back to the toot's beginning (goto-char toot-start) ;; Press 'c' and the body is visible again and point hasn't changed: (mastodon-tl-toggle-spoiler-text-in-toot) (should (eq nil (get-text-property body-position 'invisible))) (should (eq toot-start (point))) ;; Go to the toot's end (goto-char toot-end) ;; Press 'c' and the body is invisible again and point hasn't changed: (mastodon-tl-toggle-spoiler-text-in-toot) (should (eq t (get-text-property body-position 'invisible))) (should (eq toot-end (point))) ))) (ert-deftest mastodon-tl--hashtag () "Should recognise hashtags in a toot and add the required properties to it." ;; Travis's Emacs doesn't have libxml so we fake things by inputting ;; propertized text and stubbing shr-render-region (let* ((fake-input-text (concat "Tag:" (propertize "sampletag" 'shr-url "https://example.space/tags/sampletag" 'keymap shr-map 'help-echo "https://example.space/tags/sampletag") " some text after")) (rendered (with-mock (stub shr-render-region => nil) (mastodon-tl--render-text fake-input-text mastodon-tl-test-base-toot))) (tag-location 7)) (should (eq (get-text-property tag-location 'mastodon-tab-stop rendered) 'hashtag)) (should (equal (get-text-property tag-location 'mastodon-tag rendered) "sampletag")) (should (equal (get-text-property tag-location 'help-echo rendered) "Browse tag #sampletag")))) (ert-deftest mastodon-tl--extract-hashtag-from-url-mastodon-link () "Should extract the hashtag from a tags url." (should (equal (mastodon-tl--hashtag-from-url "https://example.org/tags/foo" "https://example.org") "foo"))) (ert-deftest mastodon-tl--extract-hashtag-from-url-other-link () "Should extract the hashtag from a tag url." (should (equal (mastodon-tl--hashtag-from-url "https://example.org/tag/foo" "https://example.org") "foo"))) (ert-deftest mastodon-tl--extract-hashtag-from-url-wrong-instance () "Should not find a tag when the instance doesn't match." (should (null (mastodon-tl--hashtag-from-url "https://example.org/tags/foo" "https://other.example.org")))) (ert-deftest mastodon-tl--extract-hashtag-from-url-not-tag () "Should not find a hashtag when not a tag url" (should (null (mastodon-tl--hashtag-from-url "https://example.org/@userid" "https://example.org")))) (ert-deftest mastodon-tl--userhandles () "Should recognise userhandles in a toot and add the required properties to it." ;; Travis's Emacs doesn't have libxml so we fake things by inputting ;; propertized text and stubbing shr-render-region (let* ((fake-input-text (concat "mention: " (propertize "@foo" 'shr-url "https://bar.example/@foo" 'keymap shr-map 'help-echo "https://bar.example/@foo") " some text after")) (rendered (with-mock (stub shr-render-region => nil) (mastodon-tl--render-text fake-input-text mastodon-tl-test-base-toot))) (mention-location 11)) (should (eq (get-text-property mention-location 'mastodon-tab-stop rendered) 'user-handle)) (should (equal (get-text-property mention-location 'help-echo rendered) "Browse user profile of @foo@bar.example")))) (ert-deftest mastodon-tl--extract-userhandle-from-url-correct-case () "Should extract the user handle from url." (should (equal (mastodon-tl--userhandle-from-url "https://example.org/@someuser" "@SomeUser") "@SomeUser@example.org"))) (ert-deftest mastodon-tl--extract-userhandle-from-url-missing-at-in-text () "Should not extract a user handle from url if the text is wrong." (should (null (mastodon-tl--userhandle-from-url "https://example.org/@someuser" "SomeUser")))) (ert-deftest mastodon-tl--extract-userhandle-from-url-query-in-url () "Should not extract a user handle from url if there is a query param." (should (null (mastodon-tl--userhandle-from-url "https://example.org/@someuser?shouldnot=behere" "SomeUser")))) (ert-deftest mastodon-tl--do-user-action-function-follow-notify-block-mute () "Should triage a follow request response buffer and return correct value for following, as well as notifications enabled or disabled." (let* ((user-handle "some-user@instance.url") (user-name "some-user") (user-id "123456789") (url-follow-only "https://instance.url/accounts/123456789/follow") (url-mute "https://instance.url/accounts/123456789/mute") (url-block "https://instance.url/accounts/123456789/block") (url-true "https://instance.url/accounts/123456789/follow?notify=true") (url-false "https://instance.url/accounts/123456789/follow?notify=false")) (with-temp-buffer (let ((response-buffer-true (current-buffer))) (insert mastodon-tl--follow-notify-true-response) (with-mock (mock (mastodon-http--post url-follow-only nil nil nil nil) => response-buffer-true) (should (equal (mastodon-tl--do-user-action-function url-follow-only user-name user-handle "follow") "User some-user (@some-user@instance.url) followed!"))))) (with-temp-buffer (let ((response-buffer-true (current-buffer))) (insert mastodon-tl--follow-notify-true-response) (with-mock (mock (mastodon-http--post url-mute nil nil nil nil) => response-buffer-true) (should (equal (mastodon-tl--do-user-action-function url-mute user-name user-handle "mute") "User some-user (@some-user@instance.url) muted!"))))) (with-temp-buffer (let ((response-buffer-true (current-buffer))) (insert mastodon-tl--follow-notify-true-response) (with-mock (mock (mastodon-http--post url-block nil nil nil nil) => response-buffer-true) (should (equal (mastodon-tl--do-user-action-function url-block user-name user-handle "block") "User some-user (@some-user@instance.url) blocked!"))))) (with-temp-buffer (let ((response-buffer-true (current-buffer))) (insert mastodon-tl--follow-notify-true-response) (with-mock (with-mock (mock (mastodon-http--post url-true nil nil nil nil) => response-buffer-true) (should (equal (mastodon-tl--do-user-action-function url-true user-name user-handle "follow" "true") "Receiving notifications for user some-user (@some-user@instance.url)!")))))) (with-temp-buffer (let ((response-buffer-false (current-buffer))) (insert mastodon-tl--follow-notify-false-response) (with-mock (mock (mastodon-http--post url-false nil nil nil nil) => response-buffer-false) (should (equal (mastodon-tl--do-user-action-function url-false user-name user-handle "follow" "false") "Not receiving notifications for user some-user (@some-user@instance.url)!"))))))) (ert-deftest mastodon-tl--report-to-mods-params-alist () "" (with-temp-buffer (let* ((toot mastodon-tl-test-base-toot) (account (alist-get 'account toot))) (with-mock ;; no longer needed after our refactor ;; (mock (mastodon-http--api "reports") => "https://instance.url/api/v1/reports") ;; (mock (mastodon-tl--toot-or-base ;; (mastodon-tl--property 'item-json :no-move)) ;; => mastodon-tl-test-base-toot) (mock (read-string "Add comment [optional]: ") => "Dummy complaint") (stub y-or-n-p => nil) ; no to all (should (equal (mastodon-tl--report-params account toot) '(("account_id" . 42) ("comment" . "Dummy complaint") ("category" . "other")))) (with-mock (stub y-or-n-p => t) ; yes to all (mock (mastodon-tl--read-rules-ids) => '(1 2 3)) (should (equal (mastodon-tl--report-params account toot) '(("rule_ids[]" . 1) ("rule_ids[]" . 2) ("rule_ids[]" . 3) ("account_id" . 42) ("comment" . "Dummy complaint") ("status_ids[]" . 61208) ("forward" . "true"))))))))) (ert-deftest mastodon-tl--report-build-params () "" (should (equal (mastodon-tl--report-build-params 42 "Dummy complaint" 61208 "true" nil '(1 2 3)) '(("rule_ids[]" . 1) ("rule_ids[]" . 2) ("rule_ids[]" . 3) ("account_id" . 42) ("comment" . "Dummy complaint") ("status_ids[]" . 61208) ("forward" . "true")))) (should (equal (mastodon-tl--report-build-params 42 "Dummy complaint" nil "true" nil nil) '(("account_id" . 42) ("comment" . "Dummy complaint") ("forward" . "true")))) (should (equal (mastodon-tl--report-build-params 42 "Dummy complaint" 61208 "true" "spam" nil) '(("account_id" . 42) ("comment" . "Dummy complaint") ("status_ids[]" . 61208) ("forward" . "true") ("category" . "spam")))) (should (equal (mastodon-tl--report-build-params 42 "Dummy complaint" 61208 "true" "other" nil) '(("account_id" . 42) ("comment" . "Dummy complaint") ("status_ids[]" . 61208) ("forward" . "true") ("category" . "other")))) (should (equal (mastodon-tl--report-build-params 42 "Dummy complaint" 61208 nil "spam" nil) '(("account_id" . 42) ("comment" . "Dummy complaint") ("status_ids[]" . 61208) ("category" . "spam"))))) (ert-deftest mastodon-tl--read-rules () "Should return a list of string numbers based on `mastodon-tl--test-instance-rules'" (let ((crm-separator "[ ]*,[ ]*")) (with-mock (stub mastodon-tl--instance-rules => mastodon-tl--test-instance-rules) (stub completing-read-multiple => '("We do not accept homophobia." "We do not accept harassment." "We also do not accept hate speech.")) (should (equal '("2" "5" "6") (mastodon-tl--read-rules-ids)))))) ;;; UTILS tests (ert-deftest mastodon-tl--map-alist () "Should return a list of values from `mastodon-tl--test-instance-rules'. The key is 'id." (should (equal (mastodon-tl--map-alist 'id mastodon-tl--test-instance-rules) '("1" "2" "3" "4" "5" "6" "7" "8")))) (ert-deftest mastodon-tl--map-alist-vals-to-alist () "Should return an alist of value1 value2, using key1 id, and key2 text." (should (equal (mastodon-tl--map-alist-vals-to-alist 'id 'text mastodon-tl--test-instance-rules) '(("1" . "We do not accept racism.") ("2" . "We do not accept homophobia.") ("3" . "We do not accept sexism.") ("4" . "We do not accept ableism.") ("5" . "We do not accept harassment.") ("6" . "We also do not accept hate speech.") ("7" . "We do not accept abuse of minors.") ("8" . "We do not accept glorification of violence."))))) mastodon.el/test/mastodon-toot-tests.el000066400000000000000000000225351501733112700205600ustar00rootroot00000000000000;;; mastodon-toot-test.el --- Tests for mastodon-toot.el -*- lexical-binding: nil -*- (require 'el-mock) (require 'mastodon-http) (defconst mastodon-toot--200-html "HTTP/1.1 200 OK Date: Mon, 20 Dec 2021 13:42:29 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked") (defconst mastodon-toot-test-base-toot '((id . 61208) (created_at . "2017-04-24T19:01:02.000Z") (in_reply_to_id) (in_reply_to_account_id) (sensitive . :json-false) (spoiler_text . "") (visibility . "public") (account (id . 42) (username . "acct42") (acct . "acct42@example.space") (display_name . "Account 42") (locked . :json-false) (created_at . "2017-04-01T00:00:00.000Z") (followers_count . 99) (following_count . 13) (statuses_count . 101) (note . "E")) (media_attachments . []) (mentions . []) (tags . []) (uri . "tag:example.space,2017-04-24:objectId=654321:objectType=Status") (url . "https://example.space/users/acct42/updates/123456789") (content . "

Just some text

") (reblogs_count . 0) (favourites_count . 0) (reblog)) "A sample toot (parsed json)") (defconst mastodon-toot--mock-toot (propertize "here is a mock toot text." 'item-json mastodon-toot-test-base-toot)) (defconst mastodon-toot--multi-mention '((mentions . [((id . "1") (username . "federated") (url . "https://site.cafe/@federated") (acct . "federated@federated.cafe")) ((id . "1") (username . "federated") (url . "https://site.cafe/@federated") (acct . "federated@federated.social")) ((id . "1") (username . "local") (url . "") (acct . "local"))]))) (defconst mastodon-toot--multi-mention-list '((mentions . (((id . "1") (username . "federated") (url . "https://site.cafe/@federated") (acct . "federated@federated.cafe")) ((id . "1") (username . "federated") (url . "https://site.cafe/@federated") (acct . "federated@federated.social")) ((id . "1") (username . "local") (url . "") (acct . "local")))))) (defconst mastodon-toot-no-mention '((mentions . []))) (defconst mastodon-toot--multi-mention-extracted '("local" "federated@federated.social" "federated@federated.cafe")) (ert-deftest mastodon-toot--multi-mentions () "Should build a correct mention string from the test toot data. Even the local name \"local\" gets a domain name added." (let ((mastodon-auth--acct-alist '(("https://local.social". "null"))) (mastodon-instance-url "https://local.social") (status mastodon-toot-test-base-toot)) (with-mock ;; test-base-toot has no mentions so we mock some, using a list not an ;; array as formerly (mock (mastodon-tl--field 'mentions status) => (alist-get 'mentions mastodon-toot--multi-mention-list)) (should (equal (mastodon-toot--mentions mastodon-toot-test-base-toot) ;; mastodon-toot--multi-mention) ; how did that ever work? '("local" "federated@federated.social" "federated@federated.cafe")))))) (ert-deftest mastodon-toot--multi-mentions-to-string () "Should build a correct mention string from the test toot data. Even the local name \"local\" gets a domain name added." (let ((mastodon-auth--acct-alist '(("https://local.social". "null"))) (mastodon-instance-url "https://local.social")) (should (string= (mastodon-toot--mentions-to-string mastodon-toot--multi-mention-extracted) "@local@local.social @federated@federated.social @federated@federated.cafe")))) (ert-deftest mastodon-toot--multi-mentions-with-name-to-string () "Should build a correct mention string omitting self. Here \"local\" is the user themselves and gets omitted from the mention string." (let ((mastodon-auth--acct-alist '(("https://local.social". "local"))) (mastodon-instance-url "https://local.social")) (should (string= (mastodon-toot--mentions-to-string mastodon-toot--multi-mention-extracted) "@federated@federated.social @federated@federated.cafe")))) (ert-deftest mastodon-toot--no-mention-to-string () "Should return and empty string." (let ((mastodon-auth--acct-alist '(("https://local.social". "local"))) (mastodon-instance-url "https://local.social")) (should (string= (mastodon-toot--mentions-to-string nil) "")))) (ert-deftest mastodon-toot--no-mention () "Should construct an empty mention list without mentions." (let ((mastodon-auth--acct-alist '(("https://local.social". "null"))) (mastodon-instance-url "https://local.social")) (should (equal (mastodon-toot--mentions mastodon-toot-no-mention) nil)))) ;; TODO: test y-or-no-p with mastodon-toot-cancel ;; This test is useless, commenting ;; (ert-deftest mastodon-toot--kill () ;; "Should kill the buffer when cancelling the toot." ;; (let ((mastodon-toot-previous-window-config ;; (list (current-window-configuration) ;; (point-marker)))) ;; (with-mock ;; (mock (mastodon--kill-window)) ;; (mastodon-toot--kill) ;; (mock-verify)))) (ert-deftest mastodon-toot--own-toot-p-fail () "Should not return t if not own toot." (let ((toot mastodon-toot-test-base-toot)) (with-mock (mock (mastodon-auth--user-acct) => "joebogus@bogus.space") (should (not (equal (mastodon-toot--own-toot-p toot) t)))))) (ert-deftest mastodon-toot--own-toot-p () "Should return 't' if own toot." (let ((toot mastodon-toot-test-base-toot)) (with-mock (mock (mastodon-auth--user-acct) => "acct42@example.space") (should (equal (mastodon-toot--own-toot-p toot) t))))) ;; FIXME: these tests are actually really useless. we mock a toot, user, and ;; we mock the response, so all we are testing is the triage! and triage ;; itself is already tested. ;; (ert-deftest mastodon-toot--delete-toot-fail () ;; "Should refuse to delete toot." ;; (let ((toot mastodon-toot-test-base-toot)) ;; (with-mock ;; (mock (mastodon-auth--user-acct) => "joebogus") ;; ;; (mock (mastodon-toot--own-toot-p toot) => nil) ;; (mock (mastodon-tl--property 'item-json) => mastodon-toot-test-base-toot) ;; (mock (mastodon-tl--property 'base-toot) => toot) ;; (should (equal (mastodon-toot-delete-toot) ;; "You can only delete (and redraft) your own toots."))))) ;; (ert-deftest mastodon-toot-delete-toot () ;; "Should return correct triaged response to a legitimate DELETE request." ;; (with-temp-buffer ;; (insert mastodon-toot--200-html) ;; (let ((delete-response (current-buffer)) ;; (toot mastodon-toot-test-base-toot) ;; (no-redraft t)) ;; (with-mock ;; ;; (mock (mastodon-toot--base-toot-or-item-json) => toot) ;; (mock (mastodon-tl--property 'item-json) => toot) ;; (mock (mastodon-tl--property 'base-toot) => toot) ;; ;; (mock (mastodon-toot--own-toot-p toot) => t) ;; (mock (mastodon-auth--user-acct) => "acct42@example.space") ;; (mock (mastodon-http--api (format "statuses/61208")) ;; => "https://example.space/statuses/61208") ;; (mock ;(y-or-n-p "Delete this toot? ") ;; (y-or-n-p (if no-redraft ;; (format "Delete this toot? ") ;; (format "Delete and redraft this toot? "))) ;; => t) ;; (mock (mastodon-http--delete "https://example.space/statuses/61208") ;; => delete-response) ;; (should (equal (mastodon-toot-delete-toot :no-redraft) ;; "Toot deleted!")))))) (ert-deftest mastodon-toot-action-pin () "Should return callback provided by `mastodon-toot-pin-toot-toggle'." (with-temp-buffer (insert mastodon-toot--200-html) (let ((pin-response (current-buffer)) (toot mastodon-toot-test-base-toot) (id 61208)) (with-mock (mock (url-http-parse-response) => 200) (mock (mastodon-tl--property 'base-item-id) => id) (mock (mastodon-http--api "statuses/61208/pin") => "https://example.space/statuses/61208/pin") (mock (mastodon-http--post "https://example.space/statuses/61208/pin") => pin-response) (should (equal (mastodon-toot--action "pin" (lambda (_) (message "Toot pinned!"))) "Toot pinned!")))))) ;; TODO: how to test if an error is signalled? or need we even? ;; (ert-deftest mastodon-toot--pin-toot-fail () ;; (with-temp-buffer ;; (insert mastodon-toot--200-html) ;; (let ((pin-response (current-buffer)) ;; (toot mastodon-toot-test-base-toot)) ;; (with-mock ;; (mock (mastodon-tl--property 'item-json) => toot) ;; (mock (mastodon-tl--property 'base-toot) => toot) ;; (mock (mastodon-auth--user-acct) => "joebogus@example.space") ;; (should (equal (mastodon-toot-pin-toot-toggle) ;; "You can only pin your own toots"))))))