fractalnow-0.8.1/0000775000175000017500000000000011777362041012334 5ustar mpegmpegfractalnow-0.8.1/Makefile.configure0000664000175000017500000000233011777357367015771 0ustar mpegmpegDEL_FILE = rm -f CHK_DIR_EXISTS= test -d MKDIR = mkdir -p COPY = cp -fp COPY_FILE = $(COPY) COPY_DIR = $(COPY) -r INSTALL_FILE = install -m 644 -p INSTALL_PROGRAM = install -m 755 -p STRIP_BINARY = strip --remove-section=.comment --remove-section=.note INSTALL_DIR = $(COPY_DIR) DEL_FILE = rm -f SYMLINK = ln -f -s DEL_EMPTY_DIR = rmdir --ignore-fail-on-non-empty DEL_DIR = rm -rf MOVE = mv -f CHK_DIR_EXISTS= test -d MKDIR = mkdir -p all: $(call quiet-command,make -C ${LIB_DIR},"") $(call quiet-command,make -C ${COMMAND_LINE_DIR},"") $(call quiet-command,make -C ${GUI_DIR},"") %: $(call quiet-command,make -C ${LIB_DIR} $@,"") $(call quiet-command,make -C ${COMMAND_LINE_DIR} $@,"") $(call quiet-command,make -C ${GUI_DIR} $@,"") Makefile: configure Makefile.configure ${LIB_DIR}/Makefile.configure ${COMMAND_LINE_DIR}/Makefile.configure ${GUI_DIR}/${GUI_PRO_FILE}.configure ./config.status distclean: clean make -C ${COMMAND_LINE_DIR} $@ make -C ${LIB_DIR} $@ make -C ${GUI_DIR} $@ $(DEL_FILE) "${LIB_DIR}/Makefile" $(DEL_FILE) "${COMMAND_LINE_DIR}/Makefile" $(DEL_FILE) "${GUI_DIR}/${GUI_NAME}.pro" $(DEL_FILE) Makefile $(DEL_FILE) config.status fractalnow-0.8.1/README0000664000175000017500000000430211764667445013227 0ustar mpegmpegFractalNow Version 0.8.0 (2012-05-13) Copyright: 2011-2012 Marc Pegon Homepage: http://fractalnow.sourceforge.net/ Description =========== FractalNow is an open source, multi-platform fractal generator. It provides users with tools to generate pictures of various types of fractals quickly and easily. It is made of both a command line (FractalNow) and a graphical tool (QFractalNow). The graphical tool, based on Qt library, allows users to explore fractals intuitively and generate pictures. Both tools are entirely multi-threaded and implement advanced algorithms and heuristics that make computation very fast compared to most existing free fractal generators. Features ======== - Intuitive graphical user-interface (QFractalNow) to explore fractal space easily - A command-line tool (FractalNow) that can work on machines without a desktop, and could be used by scripts to produce animations - Several formulas available (Mandelbrot, Julia, Multibrot, Mandelbar, Burning ship, Rudy, and more...) - Various types of coloring available (Iteration counts, Average coloring methods) - Multiple anti-aliasing methods (Gaussian blur, Oversampling, Adaptive (intelligent)) to produce high quality images - Advanced algorithms and heuristics to speed up computation (Solid guessing, Adaptive anti-aliasing, Caching) - Entirely multi-threaded to work even faster on multi-core processors - Ability to save/load configuration and gradient files - Support for multiple precision (arbitrary precision) floats License ======= This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. fractalnow-0.8.1/COPYING0000664000175000017500000010451311754747533013403 0ustar mpegmpeg 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 . fractalnow-0.8.1/doc/0000775000175000017500000000000011764667445013115 5ustar mpegmpegfractalnow-0.8.1/doc/configuration_file_syntax.txt0000664000175000017500000001237611764667445021143 0ustar mpegmpegConfiguration files contain all parameters necessary to generate a fractal image (fractal parameters and rendering parameters). Hence it is merely a fractal file body followed by a rendering file body. Configuration file syntax: CONFIGURATION_FILE_FORMAT FRACTAL_TYPE [MAIN_POWER] [CX CY] CENTER_X CENTER_Y SPAN_X SPAN_Y ESCAPE_RADIUS NB_ITER_MAX BYTES_PER_COMPONENT SPACE_COLOR COLORING_METHOD [ITERATION_COUNT | [ADDEND_FUNCTION [STRIPE_DENSITY] INTERPOLATION_METHOD]] COLOR_SCALING COLOR_OFFSET NB_TRANSITIONS Pos1 Color1 ... PosN ColorN Text characters can be upper-case or lower-case. Arguments separators can be tabs, blank spaces, carriage return. CONFIGURATION_FILE_FORMAT should be C075, which is the format described in this document. Other format values (of older versions) may still be supported though. FRACTAL_TYPE can be : - MANDELBROT for classic Mandelbrot (z_n = z_{n-1}^2 + c) - MANDELBROTP for custom Mandelbrot (z_n = z_{n-1}^p + c, with p parameter) - JULIA for classic Julia (z_n = z_{n-1}^2 + c, with c parameter) - JULIAP for custom Julia (z_n = z_{n-1}^p + c, with c, p parameters) - BURNINGSHIP for mandelbrot-type burning ship (z_n = (|real(z_{n-1}) + I*|imag(z_{n-1})|)^p + c, with p parameter) - JULIABURNINGSHIP for julia-type burning ship (z_n = (|real(z_{n-1}) + I*|imag(z_{n-1})|)^p + c, with c, p parameters) - MANDELBAR for mandelbar (z_n = conj(z_{n-1})^p + c, with p parameter) - JULIABAR for juliabar (z_n = conj(z_{n-1})^p + c, with c, p parameters) - RUDY for Rudy (z_n = z_{n-1}^p + c*z + d, with c, p parameters) FOR MANDELBROTP, JULIAP, BURNINGSHIP, JULIABURNINGSHIP, MANDELBAR, JULIABAR and RUDY, p parameter is a complex number that must be specified through REAL_MAIN_POWER and IMAG_MAIN_POWER values. For the others, REAL_MAIN_POWER and IMAG_MAIN_POWER are of no use, so they should *not* be specified. For JULIA, JULIAP, JULIABURNINGSHIP, JULIABAR and RUDY, a parameter c (complex number) MUST be specified, hence the optional parameters CX and CY. For the others, CX and CY are of no use, so they should *not* be specified. CENTER_X, CENTER_Y, SPAN_X and SPAN_Y are floating point numbers specifying the part of fractal space to draw. ESCAPE RADIUS (often called bailout value) is a floating point number used as a condition for breaking the fractal loop. NB_ITER_MAX is an integer specifying the maximum number of iterations used to determine if a point is inside fractal or not. BYTES_PER_COMPONENT specifies the number of bytes per component used for colors. It can be : - 1 for RGB8 (8 bits per component) - 2 for RGB16 (16 bits per component) SPACE_COLOR specifies the color of points inside fractal. COLORING_METHOD can be : - ITERATIONCOUNT : the value returned by the iteration count is directly used - AVERAGECOLORING : average sum(s) is/are computed using the specified addend function. ITERATION_COUNT is only needed for ITERATIONCOUNT coloring method, and should *not* be specified for AVERAGECOLORING coloring method. Symmetrically, ADDEND_FUNCTION and INTERPOLATION_METHOD are only needed for AVERAGECOLORING coloring method, and should *not* be specified for ITERATIONCOUNT coloring method. ITERATION_COUNT can be : - DISCRETE for discrete iteration count (simply the number of iterations). - CONTINUOUS for continuous iteration count - SMOOTH for smooth iteration count ADDEND_FUNCION can be : - TRIANGLEINEQUALITY - CURVATURE - STRIPE STRIPE_DENSITY is a positive integer used only for STRIPE addend function. It should not be specified for other addend functions. INTERPOLATION_METHOD can be : - NONE : only 1 average sum is computed and is directly used - LINEAR : 2 average sums are computed and interpolated linearly using smooth iteration count to produce one value - SPLINE : 4 average sums are computed and interpolated with polynomials using smooth iteration count to produce one value TRANSFER_FUNCTION specifies the transfer function to apply to the (nearly) final value, in order to map it better to the gradient. It can be : - LOG for logarithm (base e) - SQUAREROOT for square root - CUBEROOT for cube root - IDENTITY for identity function (value unchanged) - SQUARE for square - CUBE for cube - EXP for exponential COLOR_SCALING specifies a (floating point) multiplicand to be applied after transfer function, again to fit better to the gradient. COLOR_OFFSET specifies a (floating point) addend to be applied after multiplicand, again, to fit better to the gradient. It must be between 0 and 1. POSi : position of COLORi in gradient (between 0 and 1). First position must be 0, and last position must be 1. Positions must be strictly increasing. COLORi : colors composing gradient. Gradient must be made of at least 2 colors. Colors must be specified as hexadecimal numbers. Red, green, and blue are respectively the 1st, 2nd and 3rd component. Some RGB8 color examples : - 0x0 for black - 0xFF for blue - 0xFF00 for green - 0xFF0000 for red - 0xFFFFFF for white Some RGB16 color examples : - 0x0 for black - 0xFFFF for blue - 0xFFFF0000 for green - 0xFFFF00000000 for red - 0xFFFFFFFFFFFF for white In order for the gradient not to be discontinuous, the first and last color should be the same, for example 0x0 0xFFFFFF 0x0 for a black and white continuous gradient. Acceptable floating numbers are for example : 2.567 4.146E-5 8.26e2 fractalnow-0.8.1/doc/fractal_file_syntax.txt0000664000175000017500000000426711754747533017704 0ustar mpegmpegFractal files describe a subset of some fractal space, as well as some parameters used for computation. Fractal file syntax: FRACTAL_FILE_FORMAT FRACTAL_TYPE [REAL_MAIN_POWER IMAG_MAIN_POWER] [CX CY] CENTER_X CENTER_Y SPAN_X SPAN_Y ESCAPE_RADIUS NB_ITER_MAX Text characters can be upper-case or lower-case. Arguments separators can be tabs, blank spaces, carriage return. FRACTAL_FILE_FORMAT should be F075, which is the format described in this document. Other format values (of older versions) may still be supported though. FRACTAL_TYPE can be : - MANDELBROT for classic Mandelbrot (z_n = z_{n-1}^2 + c) - MANDELBROTP for custom Mandelbrot (z_n = z_{n-1}^p + c, with p parameter) - JULIA for classic Julia (z_n = z_{n-1}^2 + c, with c parameter) - JULIAP for custom Julia (z_n = z_{n-1}^p + c, with c, p parameters) - BURNINGSHIP for mandelbrot-type burning ship (z_n = (|real(z_{n-1}) + I*|imag(z_{n-1})|)^p + c, with p parameter) - JULIABURNINGSHIP for julia-type burning ship (z_n = (|real(z_{n-1}) + I*|imag(z_{n-1})|)^p + c, with c, p parameters) - MANDELBAR for mandelbar (z_n = conj(z_{n-1})^p + c, with p parameter) - JULIABAR for juliabar (z_n = conj(z_{n-1})^p + c, with c, p parameters) - RUDY for Rudy (z_n = z_{n-1}^p + c*z + d, with c, p parameters) FOR MANDELBROTP, JULIAP, BURNINGSHIP, JULIABURNINGSHIP, MANDELBAR, JULIABAR and RUDY, p parameter is a complex number that must be specified through REAL_MAIN_POWER and IMAG_MAIN_POWER values. For the others, REAL_MAIN_POWER and IMAG_MAIN_POWER are of no use, so they should *not* be specified. For JULIA, JULIAP, JULIABURNINGSHIP, JULIABAR and RUDY, a parameter c (complex number) MUST be specified, hence the optional parameters CX and CY. For the others, CX and CY are of no use, so they should *not* be specified. CENTER_X, CENTER_Y, SPAN_X and SPAN_Y are floating point numbers specifying the part of fractal space to draw. ESCAPE RADIUS (often called bailout value) is a floating point number used as a condition for breaking the fractal loop. NB_ITER_MAX is an integer specifying the maximum number of iterations used to determine if a point is inside fractal or not. Acceptable floating numbers are for example : 2.567 4.146E-5 8.26e2 fractalnow-0.8.1/doc/gradient_file_syntax.txt0000664000175000017500000000254411754747533020061 0ustar mpegmpegGradient file syntax: GRADIENT_FILE_FORMAT BYTES_PER_COMPONENT Pos1 Color1 ... PosN ColorN Text characters can be upper-case or lower-case. Arguments separators can be tabs, blank spaces, carriage return. GRADIENT_FILE_FORMAT should be G073, which is the format described in this document. Other format values (of older versions) may still be supported though. BYTES_PER_COMPONENT specifies the number of bytes per component used for colors. It can be : - 1 for RGB8 (8 bits per component) - 2 for RGB16 (16 bits per component) POSi : position of COLORi in gradient (between 0 and 1). First position must be 0, and last position must be 1. Positions must be strictly increasing. COLORi : colors composing gradient. Gradient must be made of at least 2 colors. Colors must be specified as hexadecimal numbers. Red, green, and blue are respectively the 1st, 2nd and 3rd component. Some RGB8 color examples : - 0x0 for black - 0xFF for blue - 0xFF00 for green - 0xFF0000 for red - 0xFFFFFF for white Some RGB16 color examples : - 0x0 for black - 0xFFFF for blue - 0xFFFF0000 for green - 0xFFFF00000000 for red - 0xFFFFFFFFFFFF for white In order for the gradient not to be discontinuous, the first and last color should be the same, for example 0x0 0xFFFFFF 0x0 for a black and white continuous gradient. Acceptable floating numbers are for example : 2.567 4.146E-5 8.26e2 fractalnow-0.8.1/doc/rendering_file_syntax.txt0000664000175000017500000000700211764667445020237 0ustar mpegmpegRendering files contain all parameters necessary to render a fractal file. Remark: The end of a rendering file is merely the body of a gradient file. Rendering file syntax: RENDERING_FILE_FORMAT BYTES_PER_COMPONENT SPACE_COLOR COLOR_SCALING COLOR_OFFSET NB_TRANSITIONS COLORING_METHOD [ITERATION_COUNT | [ADDEND_FUNCTION [STRIPE_DENSITY] INTERPOLATION_METHOD]] Pos1 Color1 ... PosN ColorN Text characters can be upper-case or lower-case. Arguments separators can be tabs, blank spaces, carriage return. RENDERING_FILE_FORMAT should be R073, which is the format described in this document. Other format values (of older versions) may still be supported though. BYTES_PER_COMPONENT specifies the number of bytes per component used for colors. It can be : - 1 for RGB8 (8 bits per component) - 2 for RGB16 (16 bits per component) SPACE_COLOR specifies the color of points inside fractal. COLORING_METHOD can be : - ITERATIONCOUNT : the value returned by the iteration count is directly used - AVERAGECOLORING : average sum(s) is/are computed using the specified addend function ITERATION_COUNT is only needed for ITERATIONCOUNT coloring method, and should *not* be specified for AVERAGECOLORING coloring method. Symmetrically, ADDEND_FUNCTION and INTERPOLATION_METHOD are only needed for AVERAGECOLORING coloring method, and should *not* be specified for ITERATIONCOUNT coloring method. ITERATION_COUNT can be : - DISCRETE for discrete iteration count (simply the number of iterations). - CONTINUOUS for continuous iteration count - SMOOTH for smooth iteration count ADDEND_FUNCION can be : - TRIANGLEINEQUALITY - CURVATURE - STRIPE STRIPE_DENSITY is a positive integer used only for STRIPE addend function. It should not be specified for other addend functions. INTERPOLATION_METHOD can be : - NONE : only 1 average sum is computed and is directly used - LINEAR : 2 average sums are computed and interpolated linearly using smooth iteration count to produce one value - SPLINE : 4 average sums are computed and interpolated with polynomials using smooth iteration count to produce one value TRANSFER_FUNCTION specifies the transfer function to apply to the (nearly) final value, in order to map it better to the gradient. It can be : - LOG for logarithm (base e) - SQUAREROOT for square root - CUBEROOT for cube root - IDENTITY for identity function (value unchanged) - SQUARE for square - CUBE for cube - EXP for exponential COLOR_SCALING specifies a (floating point) multiplicand to be applied after transfer function, again to fit better to the gradient. COLOR_OFFSET specifies a (floating point) addend to be applied after multiplicand, again, to fit better to the gradient. It must be between 0 and 1. POSi : position of COLORi in gradient (between 0 and 1). First position must be 0, and last position must be 1. Positions must be strictly increasing. COLORi : colors composing gradient. Gradient must be made of at least 2 colors. Colors must be specified as hexadecimal numbers. Red, green, and blue are respectively the 1st, 2nd and 3rd component. Some RGB8 color examples : - 0x0 for black - 0xFF for blue - 0xFF00 for green - 0xFF0000 for red - 0xFFFFFF for white Some RGB16 color examples : - 0x0 for black - 0xFFFF for blue - 0xFFFF0000 for green - 0xFFFF00000000 for red - 0xFFFFFFFFFFFF for white In order for the gradient not to be discontinuous, the first and last color should be the same, for example 0x0 0xFFFFFF 0x0 for a black and white continuous gradient. Acceptable floating numbers are for example : 2.567 4.146E-5 8.26e2 fractalnow-0.8.1/configure0000775000175000017500000003424311777357367014270 0ustar mpegmpeg#!/bin/bash version_number="0.8.1" win32=`uname -o | grep -i "msys\|cygwin\|mingw"` if test -n "${win32}"; then echo "Windows system detected." binary_extension=".exe" prefix="install_dir" else binary_extension= prefix="/usr/local" fi debug= no_spinlock= qt_debug_char= project_pretty_name="FractalNow" project_name="fractalnow" bin_dir="bin" lib_dir="lib" lib_pretty_name="libFractalNow" lib_name="fractalnow" lib_bin="lib${lib_name}.a" command_line_dir="command-line" command_line_pretty_name="FractalNow" command_line_name="fractalnow" command_line_bin="${command_line_name}${binary_extension}" gui_dir="gui" gui_pretty_name="QFractalNow" gui_name="qfractalnow" gui_bin="${gui_name}${binary_extension}" gui_pro_file="${gui_name}.pro" gui_icons_dir="${gui_dir}/icons" doc_dir="doc" examples_dir="examples" generate_samples_script="generate_samples.sh" usage="Usage: configure [-prefix DIR] [-debug] [-no-spinlock] Options: -prefix DIR Set the instalation directory to DIR (default: ${prefix}) -debug Build with debugging symbols -no-spinlock Disable POSIX spinlocks (use mutexes only) " while test $# -gt 0; do case "$1" in "-prefix" ) prefix="$2" shift ; shift ;; "-debug" ) debug="-debug" shift ;; "-no-spinlock" ) no_spinlock="-no-spinlock" shift ;; "-help" | "--help" ) echo "$usage" exit ;; *) echo "*** ERROR: Unrecognized option '$1'" >&2 echo "$usage" exit 1 ;; esac done if test -n "${debug}"; then qt_debug_char='d'; fi if test -n "${no_spinlock}"; then spinlock_define="NO_SPINLOCK" else spinlock_define="_POSIX_C_SOURCE=200809L" fi is_absolute=`echo "${prefix}" | grep '^/'` if test -z "${is_absolute}"; then system_pwd="`which pwd`" prefix="`\"${system_pwd}\"`/${prefix}" fi; echo "Prefix: '${prefix}'" if test -n "${debug}"; then echo "Debug: yes" else echo "Debug: no" fi if test -n "${no_spinlock}"; then echo "Spin locks: no" else echo "Spin locks: yes" fi echo "Testing for qmake..." if qmake -v &>/dev/null; then qt_version=`qmake -query QT_VERSION` echo "Found qmake (Qt ${qt_version})" major=`echo $qt_version | sed -e "s/\([0-9][0-9]*\).*/\1/"` minor=`echo $qt_version | sed -e "s/[0-9][0-9]*\.\([0-9][0-9]*\).*/\1/"` if test ${major} -ne 4 -o ${minor} -lt 6; then echo "*** ERROR: ${gui_pretty_name} requires Qt 4.6 or greater." exit 1 fi; else echo "*** ERROR: qmake not found. Install qmake and make sure it is in your PATH." >&2 exit 1 fi; if test -n "${win32}"; then which_qmake=`which qmake 2>/dev/null` if test -n "${which_qmake}"; then qt_bin_dir=`dirname "${which_qmake}"` qtcore4=`ls "${qt_bin_dir}" | grep "QtCore${qt_debug_char}4\.dll"` if test -f "${qt_bin_dir}/${qtcore4}"; then qtcore4_dll="${qtcore4}" echo "Found '${qtcore4_dll}'." fi; qtgui4=`ls "${qt_bin_dir}" | grep "QtGui${qt_debug_char}4\.dll"` if test -f "${qt_bin_dir}/${qtgui4}"; then qtgui4_dll="${qtgui4}" echo "Found '${qtgui4_dll}'." fi; fi fi #Used for common part of Makefiles config="VERSION_NUMBER = ${version_number} DEBUG = ${debug} SPINLOCK_DEFINE = ${spinlock_define} quiet-command = "'$(if $(VERB),$1,$(if $(2),@echo $2 && $1, @$1)) ' #Generate lib Makefile echo "Generating library Makefile..." echo "${config} TARGET_NAME = ${lib_bin} "> "${lib_dir}/Makefile" cat "${lib_dir}/Makefile.configure" >> "${lib_dir}/Makefile" #Generate command-line Makefile echo "Generating command-line Makefile..." echo "${config} TARGET_NAME = ${command_line_name} FRACTAL2D_LIB = ${lib_name} " > "${command_line_dir}/Makefile" cat "${command_line_dir}/Makefile.configure" >> "${command_line_dir}/Makefile" #Generate gui qmake project file echo "Generating gui qmake project file..." echo "${config} TARGET_NAME = ${gui_name} FRACTAL2D_LIB = ${lib_name} " > "${gui_dir}/${gui_pro_file}" cat "${gui_dir}/${gui_pro_file}.configure" >> "${gui_dir}/${gui_pro_file}" #Run qmake echo "Running qmake..." qmake -makefile "${gui_dir}/${gui_pro_file}" -o "${gui_dir}/Makefile" 2>/dev/null if test $? -ne 0; then echo "*** ERROR: Running qmake failed." exit 1 fi; #Generate main Makefile echo "Generating main Makefile..." #Set variables for installing/uninstalling echo "${config} PROJECT_NAME = ${project_name} LIB_DIR = ${lib_dir} BIN_DIR = ${bin_dir} COMMAND_LINE_DIR = ${command_line_dir} COMMAND_LINE_NAME = ${command_line_name} COMMAND_LINE_BINARY = ${command_line_bin} GUI_DIR = ${gui_dir} GUI_NAME = ${gui_name} GUI_BINARY = ${gui_bin} GUI_ICONS_DIR = ${gui_icons_dir} GUI_PRO_FILE = ${gui_pro_file} DOC_DIR = ${doc_dir} EXAMPLES_DIR = ${examples_dir} GENERATE_SAMPLES_SCRIPT = ${generate_samples_script} PREFIX = ${prefix}" > Makefile #Set specific variable for installing Qt DLLs on WIndows if test -n "${win32}"; then echo " GNU_BIN_DIR = ${gnu_bin_dir} QT_BIN_DIR = ${qt_bin_dir} QTCORE4_DLL = ${qtcore4_dll} QTGUI4_DLL = ${qtgui4_dll}" >> Makefile fi #Define main commands to installing/uninstalling cat Makefile.configure >> Makefile if test -z "${win32}"; then echo 'install: all $(CHK_DIR_EXISTS) "${PREFIX}/bin" || $(MKDIR) "${PREFIX}/bin" $(INSTALL_PROGRAM) "${COMMAND_LINE_DIR}/${BIN_DIR}/${COMMAND_LINE_BINARY}" "${PREFIX}/bin/" $(INSTALL_PROGRAM) "${GUI_DIR}/${BIN_DIR}/${GUI_BINARY}" "${PREFIX}/bin/"' >> Makefile if test -z "${debug}"; then echo ' $(STRIP_BINARY) "${PREFIX}/bin/${COMMAND_LINE_BINARY}"' >> Makefile echo ' $(STRIP_BINARY) "${PREFIX}/bin/${GUI_BINARY}"' >> Makefile fi echo ' $(CHK_DIR_EXISTS) "${PREFIX}/share/doc/${PROJECT_NAME}" || $(MKDIR) "${PREFIX}/share/doc/${PROJECT_NAME}" $(INSTALL_DIR) "${DOC_DIR}/." "${PREFIX}/share/doc/${PROJECT_NAME}/" $(CHK_DIR_EXISTS) "${PREFIX}/share/${PROJECT_NAME}" || $(MKDIR) "${PREFIX}/share/${PROJECT_NAME}" cd "${PREFIX}/share/${PROJECT_NAME}" && $(SYMLINK) "../doc/${PROJECT_NAME}" "${DOC_DIR}" && (cd - >/dev/null) $(INSTALL_DIR) "${EXAMPLES_DIR}" "${PREFIX}/share/${PROJECT_NAME}/" $(CHK_DIR_EXISTS) "${PREFIX}/share/${PROJECT_NAME}/${BIN_DIR}" || $(MKDIR) "${PREFIX}/share/${PROJECT_NAME}/${BIN_DIR}" cd "${PREFIX}/share/${PROJECT_NAME}/${BIN_DIR}" && $(SYMLINK) "../../../bin/${COMMAND_LINE_BINARY}" && (cd - >/dev/null) cd "${PREFIX}/share/${PROJECT_NAME}/${BIN_DIR}" && $(SYMLINK) "../../../bin/${GUI_BINARY}" && (cd - >/dev/null) $(INSTALL_PROGRAM) "${GENERATE_SAMPLES_SCRIPT}" "${PREFIX}/share/${PROJECT_NAME}/" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/16x16/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/16x16/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon16x16.png" "${PREFIX}/share/icons/hicolor/16x16/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/22x22/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/22x22/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon22x22.png" "${PREFIX}/share/icons/hicolor/22x22/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/24x24/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/24x24/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon24x24.png" "${PREFIX}/share/icons/hicolor/24x24/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/32x32/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/32x32/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon32x32.png" "${PREFIX}/share/icons/hicolor/32x32/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/36x36/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/36x36/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon36x36.png" "${PREFIX}/share/icons/hicolor/36x36/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/48x48/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/48x48/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon48x48.png" "${PREFIX}/share/icons/hicolor/48x48/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/64x64/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/64x64/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon64x64.png" "${PREFIX}/share/icons/hicolor/64x64/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/72x72/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/72x72/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon72x72.png" "${PREFIX}/share/icons/hicolor/72x72/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/96x96/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/96x96/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon96x96.png" "${PREFIX}/share/icons/hicolor/96x96/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/128x128/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/128x128/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon128x128.png" "${PREFIX}/share/icons/hicolor/128x128/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/192x192/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/192x192/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon192x192.png" "${PREFIX}/share/icons/hicolor/192x192/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/icons/hicolor/256x256/apps" || $(MKDIR) "${PREFIX}/share/icons/hicolor/256x256/apps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon256x256.png" "${PREFIX}/share/icons/hicolor/256x256/apps/${GUI_NAME}.png" $(CHK_DIR_EXISTS) "${PREFIX}/share/pixmaps" || $(MKDIR) "${PREFIX}/share/pixmaps" $(INSTALL_FILE) "${GUI_ICONS_DIR}/icon.xpm" "${PREFIX}/share/pixmaps/${GUI_NAME}.xpm" cd "${PREFIX}/share/pixmaps" && $(SYMLINK) "../icons/hicolor/256x256/apps/${GUI_NAME}.png" && (cd - >/dev/null) $(CHK_DIR_EXISTS) "${PREFIX}/share/applications" || $(MKDIR) "${PREFIX}/share/applications" $(INSTALL_FILE) "${GUI_DIR}/${GUI_NAME}.desktop" "${PREFIX}/share/applications/" uninstall: $(DEL_FILE) "${PREFIX}/bin/${COMMAND_LINE_BINARY}" $(DEL_FILE) "${PREFIX}/bin/${GUI_BINARY}" $(DEL_EMPTY_DIR) "${PREFIX}/bin" $(DEL_DIR) "${PREFIX}/share/doc/${PROJECT_NAME}" $(DEL_EMPTY_DIR) "${PREFIX}/share/doc" $(DEL_FILE) "${PREFIX}/share/${PROJECT_NAME}/${DOC_DIR}" $(DEL_DIR) "${PREFIX}/share/${PROJECT_NAME}/${EXAMPLES_DIR}" $(DEL_FILE) "${PREFIX}/share/${PROJECT_NAME}/${BIN_DIR}/${COMMAND_LINE_BINARY}" $(DEL_FILE) "${PREFIX}/share/${PROJECT_NAME}/${BIN_DIR}/${GUI_BINARY}" $(DEL_EMPTY_DIR) "${PREFIX}/share/${PROJECT_NAME}/${BIN_DIR}" $(DEL_FILE) "${PREFIX}/share/${PROJECT_NAME}/${GENERATE_SAMPLES_SCRIPT}" $(DEL_EMPTY_DIR) "${PREFIX}/share/${PROJECT_NAME}" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/16x16/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/16x16/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/22x22/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/22x22/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/24x24/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/24x24/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/32x32/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/32x32/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/36x36/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/36x36/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/48x48/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/48x48/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/64x64/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/64x64/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/72x72/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/72x72/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/96x96/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/96x96/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/128x128/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/128x128/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/192x192/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/192x192/apps" $(DEL_FILE) "${PREFIX}/share/icons/hicolor/256x256/apps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/icons/hicolor/256x256/apps" $(DEL_FILE) "${PREFIX}/share/applications/${GUI_NAME}.desktop" $(DEL_EMPTY_DIR) "${PREFIX}/share/applications" $(DEL_FILE) "${PREFIX}/share/pixmaps/${GUI_NAME}.xpm" $(DEL_FILE) "${PREFIX}/share/pixmaps/${GUI_NAME}.png" $(DEL_EMPTY_DIR) -p "${PREFIX}/share/pixmaps" ' >> Makefile else echo 'install: all $(CHK_DIR_EXISTS) "${PREFIX}/${PROJECT_NAME}" || $(MKDIR) "${PREFIX}/${PROJECT_NAME}" $(INSTALL_PROGRAM) "${COMMAND_LINE_DIR}/${BIN_DIR}/${COMMAND_LINE_BINARY}" "${PREFIX}/${PROJECT_NAME}/" $(INSTALL_PROGRAM) "${GUI_DIR}/${BIN_DIR}/${GUI_BINARY}" "${PREFIX}/${PROJECT_NAME}/"' >> Makefile if test -z "${debug}"; then echo ' $(STRIP_BINARY) "${PREFIX}/${PROJECT_NAME}/${COMMAND_LINE_BINARY}"' >> Makefile echo ' $(STRIP_BINARY) "${PREFIX}/${PROJECT_NAME}/${GUI_BINARY}"' >> Makefile fi echo ' $(INSTALL_PROGRAM) "${GENERATE_SAMPLES_SCRIPT}" "${PREFIX}/${PROJECT_NAME}/" $(INSTALL_DIR) "${DOC_DIR}" "${PREFIX}/${PROJECT_NAME}/" $(INSTALL_DIR) "${EXAMPLES_DIR}" "${PREFIX}/${PROJECT_NAME}/"' >> Makefile if test -n "${qtcore4_dll}"; then echo ' $(INSTALL_FILE) "${QT_BIN_DIR}/${QTCORE4_DLL}" "${PREFIX}/${PROJECT_NAME}/"' >> Makefile fi if test -n "${qtgui4_dll}"; then echo ' $(INSTALL_FILE) "${QT_BIN_DIR}/${QTGUI4_DLL}" "${PREFIX}/${PROJECT_NAME}/"' >> Makefile fi echo ' $(INSTALL_FILE) "ChangeLog" "${PREFIX}/${PROJECT_NAME}/"' >> Makefile echo ' $(INSTALL_FILE) "README" "${PREFIX}/${PROJECT_NAME}/"' >> Makefile echo ' uninstall: $(DEL_FILE) "${PREFIX}/${PROJECT_NAME}/${COMMAND_LINE_BINARY}" $(DEL_FILE) "${PREFIX}/${PROJECT_NAME}/${GUI_BINARY}" $(DEL_FILE) "${PREFIX}/${PROJECT_NAME}/${GENERATE_SAMPLES_SCRIPT}" $(DEL_DIR) "${PREFIX}/${PROJECT_NAME}/${DOC_DIR}" $(DEL_DIR) "${PREFIX}/${PROJECT_NAME}/${EXAMPLES_DIR}"' >> Makefile if test -n "${qtcore4_dll}"; then echo ' $(DEL_FILE) "${PREFIX}/${PROJECT_NAME}/${QTCORE4_DLL}"' >> Makefile fi if test -n "${qtgui4_dll}"; then echo ' $(DEL_FILE) "${PREFIX}/${PROJECT_NAME}/${QTGUI4_DLL}"' >> Makefile fi echo ' $(DEL_FILE) "${PREFIX}/${PROJECT_NAME}/ChangeLog"' >> Makefile echo ' $(DEL_FILE) "${PREFIX}/${PROJECT_NAME}/README"' >> Makefile echo ' $(DEL_EMPTY_DIR) "${PREFIX}/${PROJECT_NAME}"' >> Makefile echo ' $(DEL_EMPTY_DIR) "${PREFIX}"' >> Makefile fi echo "#!/bin/bash ./configure -prefix \"${prefix}\" ${debug} ${no_spinlock} " > config.status chmod +x config.status >/dev/null echo "Configure finished. Run 'make' to build ${project_pretty_name} and 'make install' to install it." if test -n "${win32}"; then echo "You might need to add some DLLs manually to complete install." fi; fractalnow-0.8.1/ChangeLog0000664000175000017500000000077511777303657014127 0ustar mpegmpeg0.8.1 2012-07-11 Marc Pegon * Made gradient offset spin box circular. * Improved icons. * Updated file formats documentation. * Minor bug fixes * Source cleaning 0.8.0 2012-05-13 Marc Pegon * Added support for Multiple Precision floats using MPFR and MPC libraries. * Added possibility to change float type (float, double, long double, mpfr_t) at runtime. 0.7.5 2012-04-12 Marc Pegon * Initial release fractalnow-0.8.1/generate_samples.sh0000775000175000017500000001566711777336364016241 0ustar mpegmpeg#!/bin/bash # # generate_samples.sh -- part of FractalNow # # Copyright (c) 2012 Marc Pegon # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # QUIET=0; VERBOSE=0; DRY_RUN=0; DEBUG=0; EXAMPLES_DIR="examples" FRACTAL_DIR="${EXAMPLES_DIR}/fractal_files" RENDER_DIR="${EXAMPLES_DIR}/rendering_files" CONFIG_DIR="${EXAMPLES_DIR}/config_files" FRACTAL_SUFFIX=".fractal" RENDER_SUFFIX=".render" CONFIG_SUFFIX=".config" IMGS_DIR="imgs" FRACTAL_FILE_PREFIX="fractal" RENDER_FILE_PREFIX="render" EXE="fractalnow" usage(){ cat< : Specify full path to fractalnow executable -f : Specify fractal files directory (default: '${FRACTAL_DIR}') -r : Specify rendering files directory (default: '${RENDER_DIR}') -c : Specify configuration files directory (default: '${CONFIG_DIR}') -o : Specify output directory for image files (default: '${IMGS_DIR}') FRACTALNOW OPTIONS (see fractalnow help) : -d -q -v -x -y -l -L -a -s -j EOF } function error { echo $1 >> /dev/stderr; if [ ! -z $2 ]; then exit $2; else exit 1; fi; } while getopts ":hc:e:f:r:o:qvdnx:y:a:s:j:l:L:" opt; do case "$opt" in 'h') usage; exit 1; ;; 'c') CONFIG_DIR="$OPTARG"; ;; 'e') EXE="$OPTARG"; ;; 'f') FRACTAL_DIR="$OPTARG"; ;; 'r') RENDER_DIR="$OPTARG"; ;; 'o') IMGS_DIR="$OPTARG"; ;; 'q') QUIET=1; ;; 'v') VERBOSE=1; ;; 'd') DEBUG=1; ;; 'n') DRY_RUN=1; ;; 'x') if eval [ "$OPTARG" -eq "$OPTARG" 2>/dev/null ]; then WIDTH=`eval echo "$OPTARG"`; else error 'Width is not a number.'; fi; ;; 'y') if eval [ "$OPTARG" -eq "$OPTARG" 2>/dev/null ]; then HEIGHT=`eval echo "$OPTARG"`; else error 'Height is not a number.'; fi; ;; 'l') FLOATTYPE="$OPTARG"; ;; 'L') MPFLOATPRECISION="$OPTARG"; ;; 'a') AAM="$OPTARG"; ;; 's') if eval [ "$OPTARG" -eq "$OPTARG" 2>/dev/null ]; then AAM_SIZE=`eval echo "$OPTARG"`; else error 'AAM_Size is not a number.'; fi; ;; 'j') if eval [ "$OPTARG" -eq "$OPTARG" 2>/dev/null ]; then NB_THREADS=`eval echo "$OPTARG"`; else error 'Number of threads is not a number.'; fi; ;; *) echo "Invalid option '$OPTARG'." >&2; usage; exit 1; ;; esac; done; shift $(($OPTIND - 1)) if [ $# -ne 0 ]; then echo "Unknown arguments remaining on command line."; usage; exit 1; fi; if [ -z "${WIDTH}" -a -z "${HEIGHT}" ]; then echo "At least width or height should be specified."; usage; exit 1; fi; `${EXE} -h &>/dev/null` if [ $? -ne 0 ]; then echo "Could not find '${EXE}' executable." exit 1; fi; if [ ${DRY_RUN} -eq 0 ]; then function cmd { echo "$@"; eval "$@"; } else function cmd { echo "$@"; } fi; # Make sure that FRACTAL_DIR exists and is a directory. if [ ! -e "${FRACTAL_DIR}" ]; then error "'${FRACTAL_DIR}' doesn't exist."; elif [ ! -d "${FRACTAL_DIR}" ]; then error "'${FRACTAL_DIR}' is not a directory."; fi; # Make sure that RENDER_DIR is a directory. if [ ! -e "${RENDER_DIR}" ]; then error "'${RENDER_DIR}' doesn't exist."; elif [ ! -d "${RENDER_DIR}" ]; then error "'${RENDER_DIR}' is not a directory."; fi; # Check whether IMGS_DIR exists or not if [ -e "${IMGS_DIR}" ]; then # IMGS_DIR already exists, make sure it is a directory. if [ ! -d "${IMGS_DIR}" ]; then error "'${IMGS_DIR}' is not a directory."; fi; else # IMGS_DIR doesn't exist, create it. cmd mkdir -p "\"${IMGS_DIR}\""; fi; #Set fractalnow flags if [ ${VERBOSE} -eq 1 ]; then FLAGS="$FLAGS -v"; fi; if [ ${QUIET} -eq 1 ]; then FLAGS="$FLAGS -q"; fi; if [ ! -z ${NB_THREADS} ]; then FLAGS="$FLAGS -j ${NB_THREADS}"; fi; if [ ! -z ${WIDTH} ]; then FLAGS="$FLAGS -x ${WIDTH}"; IMG_SUFFIX="${IMG_SUFFIX}_x${WIDTH}"; fi; if [ ! -z ${HEIGHT} ]; then FLAGS="$FLAGS -y ${HEIGHT}"; IMG_SUFFIX="${IMG_SUFFIX}_y${HEIGHT}"; fi; if [ ! -z ${FLOATTYPE} ]; then FLAGS="$FLAGS -l ${FLOATTYPE}"; IMG_SUFFIX="${IMG_SUFFIX}_l${FLOATTYPE}"; fi if [ ! -z ${MPFLOATPRECISION} ]; then FLAGS="$FLAGS -L ${MPFLOATPRECISION}"; IMG_SUFFIX="${IMG_SUFFIX}_L${MPFLOATPRECISION}"; fi if [ ! -z ${AAM} ]; then FLAGS="$FLAGS -a ${AAM}"; IMG_SUFFIX="${IMG_SUFFIX}_a${AAM}"; fi; if [ ! -z ${AAM_SIZE} ]; then FLAGS="$FLAGS -s ${AAM_SIZE}"; IMG_SUFFIX="${IMG_SUFFIX}_s${AAM_SIZE}"; fi; IMG_SUFFIX="${IMG_SUFFIX}.ppm"; fractal_files=`eval ls \"${FRACTAL_DIR}\" --quoting-style=c -1 | grep ^\""${FRACTAL_FILE_PREFIX}.*${FRACTAL_SUFFIX}"\"$ | sort`; IFS=$'\n'; for i in ${fractal_files} ; do fractal_file=`eval echo -e "${i}"`; fractal_file_basename=`basename "${fractal_file}" "${FRACTAL_SUFFIX}"`; fractal_file_suffix=`eval echo \"${fractal_file_basename}\" | sed "s/.*${FRACTAL_FILE_PREFIX}\(.*\)/\1/"` current_render_prefix="${RENDER_FILE_PREFIX}${fractal_file_suffix}" render_files=`eval ls \"${RENDER_DIR}\" --quoting-style=c | grep ^\""${current_render_prefix}.*${RENDER_SUFFIX}" | sort`; for j in ${render_files} ; do render_file=`eval echo -e "$j"`; render_file_basename=`basename "${render_file}" "${RENDER_SUFFIX}"`; cmd \"${EXE}\" -f \"${FRACTAL_DIR}/${fractal_file}\" -r \"${RENDER_DIR}/${render_file}\" -o \"${IMGS_DIR}/${fractal_file_basename}_${render_file_basename}${IMG_SUFFIX}\" ${FLAGS}; if [ $? -ne 0 ]; then error "Error occured when running executable. Interrupting." fi; echo; done; done; config_files=`eval ls \"${CONFIG_DIR}\" --quoting-style=c -1 | grep ^\""${CONFIG_FILE_PREFIX}.*${CONFIG_SUFFIX}"\"$ | sort`; for i in ${config_files} ; do config_file=`eval echo -e "${i}"`; config_file_basename=`basename "${config_file}" "${CONFIG_SUFFIX}"`; cmd \"${EXE}\" -c \"${CONFIG_DIR}/${config_file}\" -o \"${IMGS_DIR}/${config_file_basename}${IMG_SUFFIX}\" ${FLAGS}; if [ $? -ne 0 ]; then error "Error occured when running executable. Interrupting." fi; echo; done; fractalnow-0.8.1/examples/0000775000175000017500000000000011754747533014162 5ustar mpegmpegfractalnow-0.8.1/examples/fractal_files/0000775000175000017500000000000011754747533016760 5ustar mpegmpegfractalnow-0.8.1/examples/fractal_files/fractal04.fractal0000664000175000017500000000005511754747533022076 0ustar mpegmpegF075 JULIA 0.5 0.25 0.0 0.0 2.5 2.5 1E20 100 fractalnow-0.8.1/examples/fractal_files/fractal03.fractal0000664000175000017500000000005511754747533022075 0ustar mpegmpegF075 JULIA 0.5 0.25 0.0 0.0 2.5 2.5 1E30 100 fractalnow-0.8.1/examples/fractal_files/fractal01.fractal0000664000175000017500000000013411754747533022071 0ustar mpegmpegF075 RUDY 3 0 -0.7198 0.9111 0.820152733159133 -0.6681182654649595 1.5E-4 0.75E-4 1E5 10000 fractalnow-0.8.1/examples/fractal_files/fractal02.fractal0000664000175000017500000000005411754747533022073 0ustar mpegmpegF075 JULIA 0.5 0.25 0.0 0.0 2.5 2.5 1E7 100 fractalnow-0.8.1/examples/config_files/0000775000175000017500000000000011765410151016572 5ustar mpegmpegfractalnow-0.8.1/examples/config_files/config14.config0000664000175000017500000000022111754747533021405 0ustar mpegmpegc075 julia 0.5 0.25 0 0 2.57775119617225 2.57775119617225 1E+20 100 1 0x0 averagecoloring stripe 1 spline cube 1 0 0 0xffffff 0.5 0x0 1 0xffffff fractalnow-0.8.1/examples/config_files/config01.config0000664000175000017500000000021011754747533021377 0ustar mpegmpegc075 mandelbrot -0.7 0 3 3 1000 250 1 0x0 iterationcount smooth identity 0.025 0 0 0xff 0.25 0xffffff 0.5 0xffff00 0.75 0xff0000 1 0xff fractalnow-0.8.1/examples/config_files/config16.config0000664000175000017500000000030211754747533021407 0ustar mpegmpegC075 MANDELBROT -0.743643887037151 0.131825904205330 5.1299E-11 5.1299E-11 128. 7500 1 0x0 ITERATIONCOUNT SMOOTH SQUAREROOT 3.0E-2 0 0 0x39A0 0.25 0xFFFFFF 0.5 0xFFFE43 0.75 0xBF0800 1 0x39A0 fractalnow-0.8.1/examples/config_files/config04.config0000664000175000017500000000031111754747533021404 0ustar mpegmpegc075 mandelbrot -0.74364421961 0.13182604688 6.82671004784689E-07 6.82671004784689E-07 16 5000 1 0x0 iterationcount smooth squareroot 0.028 0 0 0x39a0 0.25 0xffffff 0.5 0xfffe43 0.75 0xbf0800 1 0x39a0 fractalnow-0.8.1/examples/config_files/config08.config0000664000175000017500000000026111754747533021414 0ustar mpegmpegc075 julia 0.285 0.01 0 0 2.47464114832536 2.47464114832536 10000000 1000 1 0x0 iterationcount smooth identity 0.01 0 0 0x39a0 0.25 0xffffff 0.5 0xfffe43 0.75 0xbf0800 1 0x39a0 fractalnow-0.8.1/examples/config_files/config03.config0000664000175000017500000000023411754747533021407 0ustar mpegmpegc075 mandelbrot -0.87591 0.25464 0.53184 0.53184 16 1000 1 0x0 iterationcount smooth identity 0.01 0 0 0xff 0.25 0xffffff 0.5 0xffff00 0.75 0xff0000 1 0xff fractalnow-0.8.1/examples/config_files/config05.config0000664000175000017500000000031311754747533021407 0ustar mpegmpegc075 mandelbrot -0.743643925055 0.131825905901 5.08373779904306E-08 5.08373779904306E-08 64 7500 1 0x0 iterationcount smooth squareroot 0.035 0 0 0x389f 0.25 0xffffff 0.5 0xfffd42 0.75 0xbe0700 1 0x389f fractalnow-0.8.1/examples/config_files/config18.config0000664000175000017500000000026211754747533021416 0ustar mpegmpegC075 JULIA 0.28294016280463 -0.016304694643679 0.0 0.0 3. 3. 16.0 1000 1 0x0 ITERATIONCOUNT SMOOTH IDENTITY 3.0E-2 0 0 0x39A0 0.25 0xFFFFFF 0.5 0xFFFE43 0.75 0xBF0800 1 0x39A0 fractalnow-0.8.1/examples/config_files/config02.config0000664000175000017500000000023611754747533021410 0ustar mpegmpegc075 mandelbrot -0.7 0 3 3 10000000 250 1 0x0 averagecoloring triangleinequality linear identity 0.5 0 0 0xff 0.25 0xffffff 0.5 0xffff00 0.75 0xff0000 1 0xff fractalnow-0.8.1/examples/config_files/config17.config0000664000175000017500000000032111754747533021411 0ustar mpegmpegc075 julia -0.743643887037151 0.13182590420533 0 0 0.0116645442238616 0.0116645442238616 10000000 7500 1 0x0 iterationcount smooth identity 0.00035 0 0 0x39a0 0.25 0xffffff 0.5 0xfffe43 0.75 0xbf0800 1 0x39a0 fractalnow-0.8.1/examples/config_files/config13.config0000664000175000017500000000023011754747533021404 0ustar mpegmpegc075 julia 0.5 0.25 0 0 2.57775119617225 2.57775119617225 1E+30 100 1 0x0 averagecoloring curvature linear cube 0.075 0.5 0 0xffffff 0.5 0x0 1 0xffffff fractalnow-0.8.1/examples/config_files/config22.config0000664000175000017500000000034311754747533021411 0ustar mpegmpegc075 burningship 2 0 -1.93690187628336 -0.00325452399171512 0.0159734941326134 0.0159734941326134 1000 250 1 0x0 iterationcount smooth identity 0.0155125997538578 0.87 0 0x39a0 0.25 0xffffff 0.5 0xfffe43 0.75 0xbf0800 1 0x39a0 fractalnow-0.8.1/examples/config_files/config07.config0000664000175000017500000000030311754747533021410 0ustar mpegmpegc075 julia -0.4 0.6 0 0 3.15902076051223 3.15902076051223 1000000 1000 1 0x0 averagecoloring triangleinequality linear identity 1.875 0 0 0x39a0 0.25 0xffffff 0.5 0xfffe43 0.75 0xbf0800 1 0x39a0 fractalnow-0.8.1/examples/config_files/config11.config0000664000175000017500000000032111754747533021403 0ustar mpegmpegc075 rudy 3 0 -0.7198 0.9111 0.820152733159133 -0.668118265464959 0.000130552070959935 0.000130552070959935 100000 10000 1 0x0 averagecoloring triangleinequality linear log 6.3 0 0 0xffffff 0.5 0x0 1 0xffffff fractalnow-0.8.1/examples/config_files/config21.config0000664000175000017500000000065011754747533021411 0ustar mpegmpegc075 mandelbrot -0.743643925055 0.131825905901 1.84674112479512E-05 1.47739289983609E-05 1E+57 7500 1 0x0 averagecoloring curvature spline square 0.77352474 0.22 0 0x0 0.05 0x271108 0.1 0xaf4f2a 0.15 0xf7aa62 0.2 0xf9ecaf 0.25 0xe4fee2 0.3 0xb1edf9 0.35 0x6db7fa 0.4 0x2c52b4 0.45 0xb1430 0.5 0x0 0.55 0x6200e 0.6 0x27a74a 0.65 0x60f6a8 0.7 0xabfaea 0.75 0xdfe6fe 0.8 0xf9b4ef 0.85 0xf96ab4 0.9 0xbb2f58 0.95 0x270811 1 0x0 fractalnow-0.8.1/examples/config_files/config15.config0000664000175000017500000000025711754747533021417 0ustar mpegmpegC075 JULIA 0.25964774188509 -0.002329242091954 0.0 0.0 3 3 64. 1000 1 0x0 ITERATIONCOUNT SMOOTH IDENTITY 1.6E-2 0 0 0x39A0 0.25 0xFFFFFF 0.5 0xFFFE43 0.75 0xBF0800 1 0x39A0 fractalnow-0.8.1/examples/config_files/config09.config0000664000175000017500000000030611754747533021415 0ustar mpegmpegc075 julia 0.285 0.01 0 0 2.47464114832536 2.47464114832536 10000000 1000 1 0x0 averagecoloring triangleinequality linear squareroot 1.3 0 0 0x39a0 0.25 0xffffff 0.5 0xfffe43 0.75 0xbf0800 1 0x39a0 fractalnow-0.8.1/examples/config_files/config19.config0000664000175000017500000000022411754747533021415 0ustar mpegmpegC075 MANDELBROT -0.7 0 3. 3. 1E30 250 1 0x0 AVERAGECOLORING CURVATURE LINEAR IDENTITY 0.5 0 0 0xFF 0.25 0xFFFFFF 0.5 0xFFFF00 0.75 0xFF0000 1 0xFF fractalnow-0.8.1/examples/config_files/config06.config0000664000175000017500000000025611754747533021416 0ustar mpegmpegc075 julia -0.4 0.6 0 0 3.15902076051223 3.15902076051223 1000000 1000 1 0x0 iterationcount smooth identity 0.01 0 0 0x39a0 0.25 0xffffff 0.5 0xfffe43 0.75 0xbf0800 1 0x39a0 fractalnow-0.8.1/examples/config_files/config20.config0000664000175000017500000000023711754747533021411 0ustar mpegmpegC075 MANDELBROT -1.50185049 0 7.406E-4 7.406E-4 1E3 500 1 0x0 ITERATIONCOUNT SMOOTH IDENTITY 0.00297 0 0 0xFF 0.25 0xFFFFFF 0.5 0xFFFF00 0.75 0xFF0000 1 0xFF fractalnow-0.8.1/examples/config_files/config10.config0000664000175000017500000000027311754747533021410 0ustar mpegmpegc075 julia 0.285 0.01 0 0 2.47464114832536 2.47464114832536 10000000 1000 1 0x0 averagecoloring stripe 1 linear cuberoot 1.35 0 0 0x39a0 0.25 0xffffff 0.5 0xfffe43 0.75 0xbf0800 1 0x39a0 fractalnow-0.8.1/examples/config_files/config12.config0000664000175000017500000000023611754747533021411 0ustar mpegmpegc075 julia 0.5 0.25 0 0 2.57775119617225 2.57775119617225 10000000 100 1 0x0 averagecoloring triangleinequality linear cube 1 0 0 0xffffff 0.5 0x0 1 0xffffff fractalnow-0.8.1/examples/rendering_files/0000775000175000017500000000000011754747533017321 5ustar mpegmpegfractalnow-0.8.1/examples/rendering_files/render01d.render0000664000175000017500000000013511754747533022305 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING TRIANGLEINEQUALITY SPLINE LOG 6.3 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render03a.render0000664000175000017500000000011611754747533022303 0ustar mpegmpegR075 1 0x0 ITERATIONCOUNT SMOOTH LOG 2.5E-1 0.5 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render02b.render0000664000175000017500000000013211754747533022301 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING TRIANGLEINEQUALITY NONE CUBE 1 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render01c.render0000664000175000017500000000013511754747533022304 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING TRIANGLEINEQUALITY LINEAR LOG 6.3 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render02a.render0000664000175000017500000000011611754747533022302 0ustar mpegmpegR075 1 0x0 ITERATIONCOUNT SMOOTH LOG 2.5E-1 0.5 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render01a.render0000664000175000017500000000011511754747533022300 0ustar mpegmpegR075 1 0x0 ITERATIONCOUNT SMOOTH LOG 3.25E-1 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render02d.render0000664000175000017500000000013411754747533022305 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING TRIANGLEINEQUALITY SPLINE CUBE 1 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render04e.render0000664000175000017500000000012211754747533022305 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING STRIPE 1 SPLINE CUBE 1 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render04a.render0000664000175000017500000000011611754747533022304 0ustar mpegmpegR075 1 0x0 ITERATIONCOUNT SMOOTH LOG 2.5E-1 0.5 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render04b.render0000664000175000017500000000012011754747533022300 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING STRIPE 1 NONE CUBE 1 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render03b.render0000664000175000017500000000013011754747533022300 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING CURVATURE NONE CUBE 7.5E-2 0.5 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render01b.render0000664000175000017500000000013311754747533022301 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING TRIANGLEINEQUALITY NONE LOG 6.3 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render03d.render0000664000175000017500000000013211754747533022304 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING CURVATURE SPLINE CUBE 7.5E-2 0.5 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render04c.render0000664000175000017500000000012211754747533022303 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING STRIPE 1 LINEAR CUBE 1 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render02c.render0000664000175000017500000000013411754747533022304 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING TRIANGLEINEQUALITY LINEAR CUBE 1 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render04d.render0000664000175000017500000000012211754747533022304 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING STRIPE 3 LINEAR CUBE 1 0 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/rendering_files/render03c.render0000664000175000017500000000013211754747533022303 0ustar mpegmpegR075 1 0x0 AVERAGECOLORING CURVATURE LINEAR CUBE 7.5E-2 0.5 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/gradient_files/0000775000175000017500000000000011754747533017141 5ustar mpegmpegfractalnow-0.8.1/examples/gradient_files/gradient01a.gradient0000664000175000017500000000007611754747533022762 0ustar mpegmpegG073 1 0 0xFF 0.25 0xFFFFFF 0.5 0xFFFF00 0.75 0xFF0000 1 0xFF fractalnow-0.8.1/examples/gradient_files/gradient04b.gradient0000664000175000017500000000027611754747533022770 0ustar mpegmpegG073 2 0 0x0 0.1 0x270011000800 0.2 0xAF004F002A00 0.3 0xF700AA006200 0.4 0xF900EC00AF00 0.5 0xE400FE00E200 0.6 0xB100ED00F900 0.7 0x6D00B700FA00 0.8 0x2C005200B400 0.9 0x0B0014003000 1 0x0 fractalnow-0.8.1/examples/gradient_files/gradient03a.gradient0000664000175000017500000000004511754747533022760 0ustar mpegmpegG073 1 0 0xFFFFFF 0.5 0x0 1 0xFFFFFF fractalnow-0.8.1/examples/gradient_files/gradient03b.gradient0000664000175000017500000000006111754747533022757 0ustar mpegmpegG073 2 0 0xFFFFFFFFFFFF 0.5 0x0 1 0xFFFFFFFFFFFF fractalnow-0.8.1/examples/gradient_files/gradient06a.gradient0000664000175000017500000000041711754747533022766 0ustar mpegmpegG073 1 0 0x0 0.05 0x271108 0.1 0xAF4F2A 0.15 0xF7AA62 0.2 0xF9ECAF 0.25 0xE4FEE2 0.3 0xB1EDF9 0.35 0x6DB7FA 0.4 0x2C52B4 0.45 0x0B1430 0.5 0x0 0.55 0x06200E 0.6 0x27A74A 0.65 0x60F6A8 0.7 0xABFAEA 0.75 0xDFE6FE 0.8 0xF9B4EF 0.85 0xF96AB4 0.9 0xBB2F58 0.95 0x270811 1 0x0 fractalnow-0.8.1/examples/gradient_files/gradient01b.gradient0000664000175000017500000000012411754747533022755 0ustar mpegmpegG073 2 0 0xFFFF 0.25 0xFFFFFFFFFFFF 0.5 0xFFFFFFFF0000 0.75 0xFFFF00000000 1 0xFFFF fractalnow-0.8.1/examples/gradient_files/gradient02a.gradient0000664000175000017500000000010211754747533022751 0ustar mpegmpegG073 1 0 0x39A0 0.25 0xFFFFFF 0.5 0xFFFE43 0.75 0xBF0800 1 0x39A0 fractalnow-0.8.1/examples/gradient_files/gradient02b.gradient0000664000175000017500000000013411754747533022757 0ustar mpegmpegG073 2 0 0x3900A000 0.25 0xFFFFFFFFFFFF 0.5 0xFFFFFE004300 0.75 0xBF0008000000 1 0x3900A000 fractalnow-0.8.1/examples/gradient_files/gradient04a.gradient0000664000175000017500000000021011754747533022753 0ustar mpegmpegG073 1 0 0x0 0.1 0x271108 0.2 0xAF4F2A 0.3 0xF7AA62 0.4 0xF9ECAF 0.5 0xE4FEE2 0.6 0xB1EDF9 0.7 0x6DB7FA 0.8 0x2C52B4 0.9 0x0B1430 1 0x0 fractalnow-0.8.1/examples/gradient_files/gradient05a.gradient0000664000175000017500000000021011754747533022754 0ustar mpegmpegG073 1 0 0x0 0.1 0x06200E 0.2 0x27A74A 0.3 0x60F6A8 0.4 0xABFAEA 0.5 0xDFE6FE 0.6 0xF9B4EF 0.7 0xF96AB4 0.8 0xBB2F58 0.9 0x270811 1 0x0 fractalnow-0.8.1/examples/gradient_files/gradient05b.gradient0000664000175000017500000000027611754747533022771 0ustar mpegmpegG073 2 0 0x0 0.1 0x060020000E00 0.2 0x2700A7004A00 0.3 0x6000F600A800 0.4 0xAB00FA00EA00 0.5 0xDF00E600FE00 0.6 0xF900B400EF00 0.7 0xF9006A00B400 0.8 0xBB002F005800 0.9 0x270008001100 1 0x0 fractalnow-0.8.1/examples/gradient_files/gradient06b.gradient0000664000175000017500000000057311754747533022772 0ustar mpegmpegG073 2 0 0x0 0.05 0x270011000800 0.1 0xAF004F002A00 0.15 0xF700AA006200 0.2 0xF900EC00AF00 0.25 0xE400FE00E200 0.3 0xB100ED00F900 0.35 0x6D00B700FA00 0.4 0x2C005200B400 0.45 0x0B0014003000 0.5 0x0 0.55 0x060020000E00 0.6 0x2700A7004A00 0.65 0x6000F600A800 0.7 0xAB00FA00EA00 0.75 0xDF00E600FE00 0.8 0xF900B400EF00 0.85 0xF9006A00B400 0.9 0xBB002F005800 0.95 0x270008001100 1 0x0 fractalnow-0.8.1/man/0000775000175000017500000000000011777362001013103 5ustar mpegmpegfractalnow-0.8.1/man/qfractalnow.10000664000175000017500000000626011777336364015527 0ustar mpegmpeg.TH "QFRACTALNOW" "1" "2012-07-11" "QFractalNow" "Fractal explorer/generator" .SH NAME qfractalnow \- Explore fractals and generate fractal images. .SH SYNOPSYS .B qfractalnow [OPTIONS] .SH DESCRIPTION QFractalNow is a graphical tool, based on Qt library, that allows users to explore fractals intuitively and generate pictures. .br It is multi-threaded and implements advanced algorithms and heuristics that make computation very fast compared to most existing free fractal generators. .br See FractalNow, a command-line tool to generate fractal images. .SH OPTIONS .TP .B \-h Print help. . .TP .B \-q Quiet mode, only errors are displayed. . .TP .B \-v Verbose mode. . .TP .B \-j Specify number of threads (see help for default value). . .TP .B \-c Specify configuration file, overriding default configuration. . .TP .B \-f Specify fractal file, overriding parameters from default configuration or configuration file. . .TP .B \-r Specify rendering file, overriding parameters from default configuration or configuration file. . .TP .B \-g Specify gradient file, overriding gradient from default configuration, configuration file, or rendering file. . .TP .B \-x Specify image width. . .TP .B \-y Specify image height. . .TP .B \-l Specify float type: .RS single Single precision. .br double Double precision. .br ldouble Long double precision. .br mp Multiple precision. .RE . .TP .B \-L Specify precision of Multiple Precision (MP) floats (see help for default value). . .TP .B \-a Specify anti-aliasing method: .RS none By default. .br blur Gaussian blur. .br oversampling Oversampling. .br adaptive Smart oversampling. .RE . .TP .B \-m Specify minimum size of adaptive anti-aliasing (see help for default value). .br Must be an integer strictly greater than 1. . .TP .B \-M Specify maximum size of adaptive anti-aliasing (see help for default value). .br Must be an integer strictly greater than 1 and MinAAMSize. . .TP .B \-n Anti-aliasing size iteration. .br Anti-aliasing size will increase by steps of AAMSizeIteration from MinAAMSize to MaxAAMSize. . .TP .B \-p Threshold for adaptive anti-aliasing (see help for default value). . .TP .B \-i Maximum size of quadrilaterals for linear interpolation. .RS Default is good for no visible loss of quality (see help for default value). .br 1 means no interpolation (all pixels are computed). .RE . .TP .B \-t Dissimilarity threshold for quad interpolation. .RS Default is good for no visible loss of quality (see help for default value). .br A quadrilateral that shows too dissimilar values at its corners will be computed, as opposed to interpolated. .RE .SH AUTHOR QFractalNow was written by Marc Pegon . .SH COPYRIGHT QFractalNow is licensed under the terms of the GNU Lesser General Public License, Version 3 or any later version published by the Free Software Foundation. .SH "SEE ALSO" FractalNow manual page. .br Documentation files describing configuration, fractal, rendering and gradient files formats. fractalnow-0.8.1/man/fractalnow.10000664000175000017500000000520111777362001015323 0ustar mpegmpeg.TH "FRACTALNOW" "1" "2012-07-11" "FractalNow" "Fractal generator" .SH NAME fractalnow \- Generate fractal images. .SH SYNOPSYS .B fractalnow [OPTIONS] \-c [\-x |\-y ] \-o . .br .B fractalnow [OPTIONS] \-f \-r [\-x |\-y ] \-o .SH DESCRIPTION FractalNow is a command line tool that generates pictures of fractals as Portable PixMap (PPM) files. .br It is multi-threaded and implements advanced algorithms and heuristics that make computation very fast compared to most existing free fractal generators. .br See QFractalNow, a graphical tool to explore fractals. .SH OPTIONS .TP .B \-h Print help. . .TP .B \-q Quiet mode, only errors are displayed. . .TP .B \-v Verbose mode. . .TP .B \-j Specify number of threads (see help for default value). . .TP .B \-g Specify gradient file, overriding gradient from configuration/ rendering file. . .TP .B \-l Specify float type: .RS single Single precision. .br double Double precision. .br ldouble Long double precision. .br mp Multiple precision. .RE . .TP .B \-L Specify precision of Multiple Precision (MP) floats (see help for default value). . .TP .B \-a Specify anti-aliasing method: .RS none By default. .br blur Gaussian blur. .br oversampling Oversampling. .br adaptive Smart oversampling. .RE . .TP .B \-s Specify size for anti-aliasing: .RS Radius for blur (values in [2.5, 4] are generally good). .br Scale factor for oversampling ([3, 5] is good for a high quality image). .br Scale factor for adaptive (integers between 3-5 are good for a high quality image). .RE . .TP .B \-p Threshold for adaptive anti-aliasing (see help for default value). . .TP .B \-i Maximum size of quadrilaterals for linear interpolation. .RS Default is good for no visible loss of quality (see help for default value). .br 1 means no interpolation (all pixels are computed). .RE . .TP .B \-t Dissimilarity threshold for quad interpolation. .RS Default is good for no visible loss of quality (see help for default value). .br A quadrilateral that shows too dissimilar values at its corners will be computed, as opposed to interpolated. .RE .SH AUTHOR FractalNow was written by Marc Pegon . .SH COPYRIGHT FractalNow is licensed under the terms of the GNU Lesser General Public License, Version 3 or any later version published by the Free Software Foundation. .SH "SEE ALSO" QFractalNow manual page. .br Documentation files describing configuration, fractal, rendering and gradient files formats. fractalnow-0.8.1/INSTALL0000664000175000017500000000303711764667445013404 0ustar mpegmpegInstallation ============ Requirements: * Qt 4.7.0 or newer * MPC 0.8 or newer * MPFR 3.0.0 or newer (consistent with MPC) * GMP library (consistent with MPFR) Note that Qt is only needed for the graphical tool, QFractalNow. Linux ===== You will need gcc to build the command-line tool (although any C99 compiler would do, just edit the CC variable in Makefile.configure files from lib and command-line directories) and a modern C++ compiler (preferably g++) to build the graphical tool. The typical procedure for building and installing FractalNow is: $ ./configure $ make # make install This will install FractalNow in /usr/local. See configure help for more options: $ ./configure -h Windows ======= The easiest way to build FractalNow for Windows is to use MSYS and mingw. Make sure MPC, MPFR, and GMP are correctly installed in your mingw directory (most mingw builds do not include them, so you will probably have to build them yourself). Make sure MSYS is configured correctly to find your mingw installation (run /postinstall/pi.sh if it is not the case). Under MSYS, add Qt binary directory to your path, and then type: $ ./configure $ make $ make install This will install FractalNow in ./install_dir. The configure script will normally detect that you are running MSYS on Windows and install (i.e. copy) the needed Qt DLLs (if Qt was not compiled statically) as well. You may have to add some other DLLs manually (e.g. pthread, gmp, mpfr, and mpc libraries if not linked statically). See configure help for more options: $ ./configure -h fractalnow-0.8.1/gui/0000775000175000017500000000000011777336375013133 5ustar mpegmpegfractalnow-0.8.1/gui/qfractalnow.rc0000664000175000017500000000005511754747533015777 0ustar mpegmpegIDI_ICON1 ICON DISCARDABLE "icons/icon.ico" fractalnow-0.8.1/gui/qfractalnow.qrc0000664000175000017500000000074011754747533016161 0ustar mpegmpeg icons/icon16x16.png icons/icon22x22.png icons/icon24x24.png icons/icon32x32.png icons/icon36x36.png icons/icon48x48.png icons/icon64x64.png icons/icon72x72.png icons/icon96x96.png icons/icon128x128.png icons/icon192x192.png icons/icon256x256.png fractalnow-0.8.1/gui/qfractalnow.pro.configure0000664000175000017500000000322311754747533020153 0ustar mpegmpegTEMPLATE = app TARGET = $${TARGET_NAME} RESOURCES = $${TARGET_NAME}.qrc RCC_DIR = rcc/ win32:RC_FILE = $${TARGET_NAME}.rc macx:ICON = icons/$${TARGET_NAME}.icns unix:ICON = icons/$${TARGET_NAME}.svg OBJECTS_DIR = objs/ MOC_DIR = mocs/ DESTDIR = bin/ FRACTALLIBPATH = ../lib DEPENDPATH += . include src INCLUDEPATH += . include $${FRACTALLIBPATH}/include LIBS += -L$${FRACTALLIBPATH}/bin -l$${FRACTAL2D_LIB} -lmpc -lmpfr -lgmp -lpthread -lm DEFINES += __STDC_LIMIT_MACROS __STDC_FORMAT_MACROS $${SPINLOCK_DEFINE} QMAKE_LFLAGS += $${STATIC_FLAG} CONFIG += warn_on qt CONFIG -= debug_and_release !isEmpty(DEBUG) { DEFINES += DEBUG CONFIG -= release CONFIG += debug console } else { CONFIG -= debug CONFIG += release } # Input HEADERS += \ include/color_button.h \ include/command_line.h \ include/export_fractal_image_dialog.h \ include/fractal_config_widget.h \ include/fractal_explorer.h \ include/fractal_rendering_widget.h \ include/gradient_box.h \ include/gradient_dialog.h \ include/gradient_editor.h \ include/gradient_label.h \ include/help.h \ include/hoverpoints.h \ include/main_window.h \ include/main.h \ include/mpfr_spin_box.h \ include/shade_widget.h \ include/task_progress_dialog.h SOURCES += \ src/color_button.cpp \ src/command_line.cpp \ src/export_fractal_image_dialog.cpp \ src/fractal_explorer.cpp \ src/fractal_config_widget.cpp \ src/fractal_rendering_widget.cpp \ src/gradient_box.cpp \ src/gradient_dialog.cpp \ src/gradient_editor.cpp \ src/gradient_label.cpp \ src/help.cpp \ src/hoverpoints.cpp \ src/main_window.cpp \ src/main.cpp \ src/mpfr_spin_box.cpp \ src/shade_widget.cpp \ src/task_progress_dialog.cpp fractalnow-0.8.1/gui/src/0000775000175000017500000000000011777357367013726 5ustar mpegmpegfractalnow-0.8.1/gui/src/command_line.cpp0000664000175000017500000001545711754747533017064 0ustar mpegmpeg/* * command_line.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "command_line.h" #include "help.h" #include #include #include int FileExists(const char *fileName) { FILE *file; int res = 0; if ((file = fopen(fileName,"r")) != NULL) { res = 1; fclose(file); } return res; } CommandLineArguments::CommandLineArguments(int argc, char *argv[]) { FractalNow_traceLevel = T_NORMAL; FractalNow_debug = 0; int help = 0; long int tmp = 0; fractalConfigFileName = NULL; fractalFileName = NULL; renderingFileName = NULL; gradientFileName = NULL; int minAntiAliasingSizeSpecified = 0; int maxAntiAliasingSizeSpecified = 0; int antiAliasingSizeIterationSpecified = 0; adaptiveAAMThreshold = DEFAULT_ADAPTIVE_AAM_THRESHOLD; colorDissimilarityThreshold = DEFAULT_COLOR_DISSIMILARITY_THRESHOLD; quadInterpolationSize = DEFAULT_QUAD_INTERPOLATION_SIZE; nbThreads = -1; floatPrecision = FP_DOUBLE; MPFloatPrecision = fractalnow_mpfr_precision; width = 0; height = 0; int o; while ((o = getopt(argc, argv, "hvda:f:i:j:l:L:m:nM:r:x:y:t:c:g:r:p:q")) != -1) { switch (o) { case 'h': help = 1; break; case 'v': FractalNow_traceLevel = T_VERBOSE; break; case 'q': FractalNow_traceLevel = T_QUIET; break; case 'd': #ifndef DEBUG FractalNow_message(stdout, T_QUIET, "Debug unavailable: %s was not built in \ debug mode.\n", QApplication::applicationName().toStdString().c_str()); #else FractalNow_debug = 1; #endif break; case 'c': fractalConfigFileName = optarg; break; case 'f': fractalFileName = optarg; break; case 'r': renderingFileName = optarg; break; case 'g': gradientFileName = optarg; break; case 'l': if (GetFloatPrecision(&floatPrecision, optarg)) { invalid_use_error("\n"); } break; case 'L': if (sscanf(optarg, "%ld", &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n", optarg); } if (tmp < MPFR_PREC_MIN || tmp > MPFR_PREC_MAX) { invalid_use_error("MP floats precision must be between %ld and %ld.\n", (long int)MPFR_PREC_MIN, (long int)MPFR_PREC_MAX); } else { MPFloatPrecision = (mpfr_prec_t)tmp; } break; case 'i': if (sscanf(optarg, "%ld", &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n", optarg); } if (tmp <= 0) { invalid_use_error("Quad interpolation size must be positive.\n"); } else { quadInterpolationSize = (uint_fast32_t)tmp; } break; case 'j': if (sscanf(optarg, "%d", &nbThreads) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n ", optarg); } if (nbThreads <= 0) { invalid_use_error("Number of threads must be positive.\n"); } break; case 'm': if (sscanf(optarg, "%ld", &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n ", optarg); } if (tmp < 2) { invalid_use_error("Minimum anti-aliasing size must be >= 2.\n"); } minAntiAliasingSize = (uint_fast32_t)tmp; minAntiAliasingSizeSpecified = 1; break; case 'n': if (sscanf(optarg, "%ld", &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n ", optarg); } if (tmp < 1) { invalid_use_error("Anti-aliasing size iteration must be >= 1.\n"); } antiAliasingSizeIteration = (uint_fast32_t)tmp; antiAliasingSizeIterationSpecified = 1; break; case 'M': if (sscanf(optarg, "%ld", &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n ", optarg); } if (tmp < 2) { invalid_use_error("Maximum anti-aliasing size must be >= 2.\n"); } maxAntiAliasingSize = (uint_fast32_t)tmp; maxAntiAliasingSizeSpecified = 1; break; case 'x': if (sscanf(optarg, "%ld", &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n ", optarg); } if (tmp < 2) { invalid_use_error("Output image width must be >= 2.\n"); } else { width = (uint_fast32_t)tmp; } break; case 'y': if (sscanf(optarg, "%ld", &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n ", optarg); } if (tmp < 2) { invalid_use_error("Output image height must be >= 2.\n"); } else { height = (uint_fast32_t)tmp; } break; case 'p': if (sscanf(optarg, "%lf", &adaptiveAAMThreshold) < 1) { invalid_use_error("Command-line argument \'%s\' is not a floating-point number.\n", optarg); } if (adaptiveAAMThreshold < 0.) { invalid_use_error("Adaptive anti-aliasing threshold must be >= 0.\n"); } break; case 't': if (sscanf(optarg, "%lf", &colorDissimilarityThreshold) < 1) { invalid_use_error("Command-line argument \'%s\' is not a floating-point number.\n", optarg); } if (colorDissimilarityThreshold < 0.) { invalid_use_error("Quad dissimilarity threshold must be between >= 0.\n"); } break; default: Help::Print(); exit(EXIT_FAILURE); break; } } if (argv[optind] != NULL) { invalid_use_error("Remaining argument on command line : '%s'.\n", argv[optind]); } if (help) { Help::Print(); exit(EXIT_SUCCESS); } if (!antiAliasingSizeIterationSpecified) { antiAliasingSizeIteration = DEFAULT_ANTIALIASING_SIZE_ITERATION; } if (!minAntiAliasingSizeSpecified) { minAntiAliasingSize = DEFAULT_MIN_ANTIALIASING_SIZE; } if (!maxAntiAliasingSizeSpecified) { maxAntiAliasingSize = DEFAULT_MAX_ANTIALIASING_SIZE; } if (minAntiAliasingSize > maxAntiAliasingSize) { invalid_use_error("Maximum anti-aliasing size must be greater than minimum anti-aliasing size.\n"); } if (fractalConfigFileName != NULL && !FileExists(fractalConfigFileName)) { FractalNow_existence_error(fractalConfigFileName); } if (fractalFileName != NULL && !FileExists(fractalFileName)) { FractalNow_existence_error(fractalFileName); } if (renderingFileName != NULL && !FileExists(renderingFileName)) { FractalNow_existence_error(renderingFileName); } if (gradientFileName != NULL && !FileExists(gradientFileName)) { FractalNow_existence_error(gradientFileName); } } fractalnow-0.8.1/gui/src/hoverpoints.cpp0000664000175000017500000002172111777303657017006 0ustar mpegmpeg/**************************************************************************** ** ** This file is based on some files of the demonstration applications of the ** Qt Toolkit. ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Modified to be used as a part of FractalNow: ** Copyright (c) 2012 Marc Pegon ** ** This file can be distributed and/or modified under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation. ** You should have received a copy of the GNU General Public License ** along with this file; if not, write to the Free Software Foundation, Inc., ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ****************************************************************************/ #include "hoverpoints.h" HoverPoints::HoverPoints(QWidget *widget, PointShape shape) : QObject(widget) { m_widget = widget; widget->installEventFilter(this); widget->setAttribute(Qt::WA_AcceptTouchEvents); m_connectionType = CurveConnection; m_sortType = NoSort; m_shape = shape; m_pointPen = QPen(QColor(255, 255, 255, 191), 1); m_connectionPen = QPen(QColor(255, 255, 255, 127), 2); m_pointBrush = QBrush(QColor(191, 191, 191, 127)); m_pointSize = QSize(11, 11); m_currentIndex = -1; m_editable = true; m_enabled = true; connect(this, SIGNAL(pointsChanged(QPolygonF)), m_widget, SLOT(update())); } void HoverPoints::setEnabled(bool enabled) { if (m_enabled != enabled) { m_enabled = enabled; m_widget->update(); } } bool HoverPoints::eventFilter(QObject *object, QEvent *event) { if (object == m_widget && m_enabled) { switch (event->type()) { case QEvent::MouseButtonPress: { if (!m_fingerPointMapping.isEmpty()) { return true; } QMouseEvent *me = (QMouseEvent *) event; QPointF clickPos = me->pos(); int index = -1; for (int i=0; ibutton() == Qt::LeftButton) { if (index == -1) { if (!m_editable) return false; int pos = 0; // Insert sort for x or y if (m_sortType == XSort) { for (int i=0; i clickPos.x()) { pos = i; break; } } } else if (m_sortType == YSort) { for (int i=0; i clickPos.y()) { pos = i; break; } } } m_points.insert(pos, clickPos); m_locks.insert(pos, 0); m_currentIndex = pos; firePointChange(); } else { m_currentIndex = index; } return true; } else if (me->button() == Qt::RightButton) { if (index >= 0 && m_editable) { if (m_locks[index] == 0) { m_locks.remove(index); m_points.remove(index); } firePointChange(); return true; } } } break; case QEvent::MouseButtonRelease: if (!m_fingerPointMapping.isEmpty()) { return true; } m_currentIndex = -1; break; case QEvent::MouseMove: if (!m_fingerPointMapping.isEmpty()) { return true; } if (m_currentIndex >= 0) { movePoint(m_currentIndex, ((QMouseEvent *)event)->pos()); } break; case QEvent::TouchBegin: case QEvent::TouchUpdate: { const QTouchEvent *const touchEvent = static_cast(event); const QList points = touchEvent->touchPoints(); const qreal pointSize = qMax(m_pointSize.width(), m_pointSize.height()); foreach (const QTouchEvent::TouchPoint &touchPoint, points) { const int id = touchPoint.id(); switch (touchPoint.state()) { case Qt::TouchPointPressed: { // find the point, move it QSet activePoints = QSet::fromList(m_fingerPointMapping.values()); int activePoint = -1; qreal distance = -1; const int pointsCount = m_points.size(); const int activePointCount = activePoints.size(); if (pointsCount == 2 && activePointCount == 1) { // only two points activePoint = activePoints.contains(0) ? 1 : 0; } else { for (int i=0; i::iterator it = m_fingerPointMapping.find(id); movePoint(it.value(), touchPoint.pos()); m_fingerPointMapping.erase(it); } break; case Qt::TouchPointMoved: { // move the point const int pointIdx = m_fingerPointMapping.value(id, -1); if (pointIdx >= 0) { // do we track this point? movePoint(pointIdx, touchPoint.pos()); } } break; default: break; } } if (m_fingerPointMapping.isEmpty()) { event->ignore(); return false; } else { return true; } } break; case QEvent::TouchEnd: if (m_fingerPointMapping.isEmpty()) { event->ignore(); return false; } return true; break; case QEvent::Resize: { QResizeEvent *e = (QResizeEvent *) event; if (e->oldSize().width() == 0 || e->oldSize().height() == 0) { break; } qreal stretch_x = e->size().width() / qreal(e->oldSize().width()); qreal stretch_y = e->size().height() / qreal(e->oldSize().height()); for (int i=0; i right || (lock & HoverPoints::LockToRight)) p.setX(right); if (p.y() < top || (lock & HoverPoints::LockToTop)) p.setY(top); else if (p.y() > bottom || (lock & HoverPoints::LockToBottom)) p.setY(bottom); return p; } void HoverPoints::setPoints(const QPolygonF &points) { if (points.size() != m_points.size()) { m_fingerPointMapping.clear(); } m_points.clear(); for (int i=0; i 0) { m_locks.resize(m_points.size()); m_locks.fill(0); } } void HoverPoints::movePoint(int index, const QPointF &point, bool emitUpdate) { m_points[index] = bound_point(point, boundingRect(), m_locks.at(index)); if (emitUpdate) { firePointChange(); } } inline static bool x_less_than(const QPointF &p1, const QPointF &p2) { return p1.x() < p2.x(); } inline static bool y_less_than(const QPointF &p1, const QPointF &p2) { return p1.y() < p2.y(); } void HoverPoints::firePointChange() { if (m_sortType != NoSort) { QPointF oldCurrent; if (m_currentIndex != -1) { oldCurrent = m_points[m_currentIndex]; } if (m_sortType == XSort) { qSort(m_points.begin(), m_points.end(), x_less_than); } else if (m_sortType == YSort) { qSort(m_points.begin(), m_points.end(), y_less_than); } // Compensate for changed order... if (m_currentIndex != -1) { for (int i=0; i * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "color_button.h" void ColorButton::updateIcon() { QPixmap pixmap(sizeHint()); pixmap.fill(color); QIcon icon(pixmap); setIcon(icon); } ColorButton::ColorButton(QWidget *parent) : QPushButton(parent) { color = Qt::white; updateIcon(); colorDialog = new QColorDialog(this); connect(this, SIGNAL(clicked()), this, SLOT(openColorDialog())); } const QColor &ColorButton::currentColor() const { return color; } void ColorButton::setCurrentColor(const QColor &color) { if (color != this->color) { this->color = color; updateIcon(); emit currentColorChanged(color); } } void ColorButton::openColorDialog() { colorDialog->open(this, SLOT(setCurrentColor(QColor))); } fractalnow-0.8.1/gui/src/fractal_rendering_widget.cpp0000664000175000017500000001562311764667445021452 0ustar mpegmpeg/* * fractal_rendering_widget.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal_rendering_widget.h" #include #include #include #include FractalRenderingWidget::FractalRenderingWidget(const RenderingParameters &render) : QWidget() { coloringMethodComboBox = new QComboBox; for (uint_fast32_t i = 0; i < nbColoringMethods; ++i) { coloringMethodComboBox->addItem(coloringMethodDescStr[i]); } coloringMethodComboBox->setCurrentIndex((int)render.coloringMethod); iterationCountComboBox = new QComboBox; for (uint_fast32_t i = 0; i < nbIterationCounts; ++i) { iterationCountComboBox->addItem(iterationCountDescStr[i]); } iterationCountComboBox->setCurrentIndex((int)render.iterationCount); addendFunctionComboBox = new QComboBox; for (uint_fast32_t i = 0; i < nbAddendFunctions; ++i) { addendFunctionComboBox->addItem(addendFunctionDescStr[i]); } addendFunctionComboBox->setCurrentIndex((int)render.addendFunction); stripeDensitySpinBox = new QSpinBox; stripeDensitySpinBox->setRange(1, std::numeric_limits::max()); stripeDensitySpinBox->setValue((int)render.stripeDensity); stripeDensitySpinBox->setAccelerated(true); interpolationMethodComboBox = new QComboBox; for (uint_fast32_t i = 0; i < nbInterpolationMethods; ++i) { interpolationMethodComboBox->addItem(interpolationMethodDescStr[i]); } interpolationMethodComboBox->setCurrentIndex((int)render.interpolationMethod); transferFunctionComboBox = new QComboBox; for (uint_fast32_t i = 0; i < nbTransferFunctions; ++i) { transferFunctionComboBox->addItem(transferFunctionDescStr[i]); } transferFunctionComboBox->setCurrentIndex((int)render.transferFunction); spaceColorButton = new ColorButton; spaceColorButton->setCurrentColor(QColor(render.spaceColor.r, render.spaceColor.g, render.spaceColor.b)); colorScalingSpinBox = new QDoubleSpinBox; colorScalingSpinBox->setDecimals(8); colorScalingSpinBox->setRange(0, std::numeric_limits::max()); colorScalingSpinBox->setValue(render.multiplier); colorScalingSpinBox->setAccelerated(true); colorOffsetSpinBox = new QDoubleSpinBox; colorOffsetSpinBox->setDecimals(6); colorOffsetSpinBox->setRange(0, 1); colorOffsetSpinBox->setWrapping(true); colorOffsetSpinBox->setSingleStep(0.01); colorOffsetSpinBox->setValue(render.offset); colorOffsetSpinBox->setAccelerated(true); gradientBox = new GradientBox(render.gradient); QFormLayout *formLayout = new QFormLayout; formLayout->addRow(tr("Coloring method:"), coloringMethodComboBox); formLayout->addRow(tr("Iteration count:"), iterationCountComboBox); formLayout->addRow(tr("Addend function:"), addendFunctionComboBox); formLayout->addRow(tr("Stripe density:"), stripeDensitySpinBox); formLayout->addRow(tr("Interpolation method:"), interpolationMethodComboBox); formLayout->addRow(tr("Transfer function:"), transferFunctionComboBox); formLayout->addRow(tr("Color scaling:"), colorScalingSpinBox); formLayout->addRow(tr("Color offset:"), colorOffsetSpinBox); formLayout->addRow(tr("Space color:"), spaceColorButton); QVBoxLayout *vBoxLayout = new QVBoxLayout; vBoxLayout->addLayout(formLayout); vBoxLayout->addWidget(new QLabel(tr("Gradient:"))); vBoxLayout->addWidget(gradientBox); vBoxLayout->addStretch(1); this->setLayout(vBoxLayout); updateBoxesEnabledValue(); updateColorScalingSingleStep(); connect(coloringMethodComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateBoxesEnabledValue())); connect(addendFunctionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateBoxesEnabledValue())); connect(colorScalingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateColorScalingSingleStep())); } void FractalRenderingWidget::blockBoxesSignals(bool block) { iterationCountComboBox->blockSignals(block); coloringMethodComboBox->blockSignals(block); addendFunctionComboBox->blockSignals(block); stripeDensitySpinBox->blockSignals(block); interpolationMethodComboBox->blockSignals(block); transferFunctionComboBox->blockSignals(block); colorScalingSpinBox->blockSignals(block); colorOffsetSpinBox->blockSignals(block); spaceColorButton->blockSignals(block); gradientBox->blockSignals(block); } void FractalRenderingWidget::updateBoxesValues(const RenderingParameters &render) { blockBoxesSignals(true); iterationCountComboBox->setCurrentIndex((int)render.iterationCount); coloringMethodComboBox->setCurrentIndex((int)render.coloringMethod); addendFunctionComboBox->setCurrentIndex((int)render.addendFunction); stripeDensitySpinBox->setValue(render.stripeDensity); interpolationMethodComboBox->setCurrentIndex((int)render.interpolationMethod); transferFunctionComboBox->setCurrentIndex((int)render.transferFunction); colorScalingSpinBox->setValue(render.multiplier); colorOffsetSpinBox->setValue(render.offset); spaceColorButton->setCurrentColor(QColor(render.spaceColor.r, render.spaceColor.g, render.spaceColor.b)); gradientBox->setGradient(render.gradient); updateColorScalingSingleStep(); updateBoxesEnabledValue(); blockBoxesSignals(false); } void FractalRenderingWidget::updateBoxesEnabledValue() { ColoringMethod coloringMethod = (ColoringMethod)coloringMethodComboBox->currentIndex(); AddendFunction addendFunction = (AddendFunction)addendFunctionComboBox->currentIndex(); switch (coloringMethod) { case CM_ITERATIONCOUNT: iterationCountComboBox->setEnabled(true); addendFunctionComboBox->setEnabled(false); stripeDensitySpinBox->setEnabled(false); interpolationMethodComboBox->setEnabled(false); break; case CM_AVERAGECOLORING: iterationCountComboBox->setEnabled(false); addendFunctionComboBox->setEnabled(true); stripeDensitySpinBox->setEnabled(addendFunction == AF_STRIPE); interpolationMethodComboBox->setEnabled(true); break; default: iterationCountComboBox->setEnabled(true); addendFunctionComboBox->setEnabled(true); stripeDensitySpinBox->setEnabled(true); interpolationMethodComboBox->setEnabled(true); break; } } void FractalRenderingWidget::updateColorScalingSingleStep() { double colorScaling = colorScalingSpinBox->value(); colorScalingSpinBox->setSingleStep(colorScaling / 10); } void FractalRenderingWidget::editGradient() { gradientBox->openGradientDialog(); } fractalnow-0.8.1/gui/src/export_fractal_image_dialog.cpp0000664000175000017500000003471311754747533022131 0ustar mpegmpeg/* * export_fractal_image_dialog.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "export_fractal_image_dialog.h" #include "task_progress_dialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include ExportFractalImageDialog::ExportFractalImageDialog(const FractalConfig &config, uint_fast32_t nbThreads, QString imageDir, QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f), config(CopyFractalConfig(&config)), fractal(this->config.fractal), render(this->config.render) { this->floatPrecision = FP_DOUBLE; this->imageDir = imageDir; if (this->imageDir.isEmpty()) { this->imageDir = QDesktopServices::storageLocation(QDesktopServices::PicturesLocation); } setWindowTitle(tr("Export image")); QVBoxLayout *vBoxLayout = new QVBoxLayout; /* Image parameters (width, height, depth) .*/ QGroupBox *imageParamBox = new QGroupBox(tr("&Image parameters"), this); QHBoxLayout *hBoxLayout1 = new QHBoxLayout; QFormLayout *formLayout = new QFormLayout; imageWidthBox = new QSpinBox(this); imageWidthBox->setRange(2, 20000); imageWidthBox->setValue(1280); imageHeightBox = new QSpinBox(this); imageHeightBox->setRange(2, 20000); imageHeightBox->setValue(1024); colorDepthBox = new QComboBox(this); colorDepthBox->addItem(tr("8 bits")); colorDepthBox->addItem(tr("16 bits")); colorDepthBox->setCurrentIndex(0); formLayout->addRow(tr("Width:"), imageWidthBox); formLayout->addRow(tr("Height:"), imageHeightBox); formLayout->addRow(tr("Color depth:"), colorDepthBox); hBoxLayout1->addLayout(formLayout); hBoxLayout1->addStretch(1); imageParamBox->setLayout(hBoxLayout1); /* Anti-aliasing methods */ QGroupBox *antiAliasingBox = new QGroupBox(tr("&Anti-aliasing method"), this); QGridLayout *gridLayout = new QGridLayout; noAAMButton = new QRadioButton(tr("&None")); connect(noAAMButton, SIGNAL(toggled(bool)), this, SLOT(onAAMNoneToggled(bool))); gaussianBlurAAMButton = new QRadioButton(tr("Gaussian &blur")); connect(gaussianBlurAAMButton, SIGNAL(toggled(bool)), this, SLOT(onAAMBlurToggled(bool))); QLabel *blurRadiusLabel = new QLabel(tr("Radius:")); blurRadiusBox = new QDoubleSpinBox; blurRadiusBox->setRange(0.5, 5); blurRadiusBox->setValue(2); adaptiveAAMButton = new QRadioButton(tr("&Adaptive")); connect(adaptiveAAMButton, SIGNAL(toggled(bool)), this, SLOT(onAAMAdaptiveToggled(bool))); QLabel *adaptiveSizeLabel = new QLabel(tr("Size:")); adaptiveSizeBox = new QSpinBox; adaptiveSizeBox->setRange(2, 7); adaptiveSizeBox->setValue(3); oversamplingAAMButton = new QRadioButton(tr("&Oversampling")); connect(oversamplingAAMButton, SIGNAL(toggled(bool)), this, SLOT(onAAMOversamplingToggled(bool))); QLabel *oversamplingSizeLabel = new QLabel(tr("Size:")); oversamplingSizeBox = new QDoubleSpinBox; oversamplingSizeBox->setRange(1.5, 7); oversamplingSizeBox->setValue(5); adaptiveAAMButton->setChecked(true); gridLayout->addWidget(noAAMButton, 0, 0); gridLayout->addWidget(gaussianBlurAAMButton, 1, 0); gridLayout->addWidget(blurRadiusLabel, 2, 1); gridLayout->addWidget(blurRadiusBox, 2, 2); gridLayout->addWidget(adaptiveAAMButton, 3, 0); gridLayout->addWidget(adaptiveSizeLabel, 4, 1); gridLayout->addWidget(adaptiveSizeBox, 4, 2); gridLayout->addWidget(oversamplingAAMButton, 5, 0); gridLayout->addWidget(oversamplingSizeLabel, 6, 1); gridLayout->addWidget(oversamplingSizeBox, 6, 2); gridLayout->setColumnStretch(3, 1); gridLayout->setRowStretch(7, 1); antiAliasingBox->setLayout(gridLayout); /* Set dialog main layouts. */ QHBoxLayout *hBoxLayout2 = new QHBoxLayout; hBoxLayout2->addWidget(antiAliasingBox); hBoxLayout2->addSpacing(20); hBoxLayout2->addWidget(imageParamBox); dialogButtonBox = new QDialogButtonBox(this); cancelButton = dialogButtonBox->addButton(QDialogButtonBox::Cancel); connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); exportButton = dialogButtonBox->addButton(tr("Export"), QDialogButtonBox::AcceptRole); connect(exportButton, SIGNAL(clicked()), this, SLOT(exportImage())); vBoxLayout->addLayout(hBoxLayout2); vBoxLayout->addWidget(dialogButtonBox); setLayout(vBoxLayout); threads = CreateThreads(nbThreads); } ExportFractalImageDialog::~ExportFractalImageDialog() { DestroyThreads(threads); FreeFractalConfig(config); } void ExportFractalImageDialog::resetFractalConfig(const FractalConfig &config) { FractalConfig newConfig = CopyFractalConfig(&config); FreeFractalConfig(this->config); this->config = newConfig; } void ExportFractalImageDialog::setFloatPrecision(FloatPrecision floatPrecision) { this->floatPrecision = floatPrecision; } QString ExportFractalImageDialog::exportedFile() { return m_exportedFile; } void ExportFractalImageDialog::onAAMNoneToggled(bool checked) { if (checked) { blurRadiusBox->setEnabled(false); adaptiveSizeBox->setEnabled(false); oversamplingSizeBox->setEnabled(false); } } void ExportFractalImageDialog::onAAMBlurToggled(bool checked) { if (checked) { blurRadiusBox->setEnabled(true); adaptiveSizeBox->setEnabled(false); oversamplingSizeBox->setEnabled(false); } } void ExportFractalImageDialog::onAAMAdaptiveToggled(bool checked) { if (checked) { blurRadiusBox->setEnabled(false); adaptiveSizeBox->setEnabled(true); oversamplingSizeBox->setEnabled(false); } } void ExportFractalImageDialog::onAAMOversamplingToggled(bool checked) { if (checked) { blurRadiusBox->setEnabled(false); adaptiveSizeBox->setEnabled(false); oversamplingSizeBox->setEnabled(true); } } ExportFractalImageDialog::AntiAliasingMethod ExportFractalImageDialog::getAntiAliasingMethod() const { if (noAAMButton->isChecked()) { return AAM_NONE; } else if (gaussianBlurAAMButton->isChecked()) { return AAM_GAUSSIANBLUR; } else if (oversamplingAAMButton->isChecked()) { return AAM_OVERSAMPLING; } else { return AAM_ADAPTIVE; } } void ExportFractalImageDialog::exportImage() { int depth = colorDepthBox->currentIndex() + 1; QString imageFormats = (depth == 1) ? "(*.png *.jpg *.tiff *.ppm)" : "(*.ppm)"; QString imageSuffix = (depth == 1) ? ".png" : ".ppm"; QString fileName = QFileDialog::getSaveFileName(this, tr("Export image"), imageDir + "/fractal" + imageSuffix, tr("Images ") + imageFormats); /* It is not very clear in Qt documentation, * but I think a file dialog cannot return * an empty string if user clicks OK. * (one thing for sure is that it returns a * null string when user clicks Cancel) */ if (fileName.isEmpty()) { return; } QFileInfo fileInfo(fileName); QString imageFormat; RenderingParameters render = CopyRenderingParameters(&this->render); if (depth == 2) { /* Check that extension is PPM (only format supported for 16 bits).*/ if (fileInfo.suffix().compare(QString("PPM"), Qt::CaseInsensitive)) { QMessageBox::warning(this, tr("File name extension is not PPM"), tr("16-bits image will be exported as PPM, ignoring file extension.")); } Gradient gradient16 = Gradient16(&render.gradient); ResetGradient(&render, gradient16); FreeGradient(gradient16); } else { /* Get image format from extension (suffix). */ QString allowedFormats[] = {"PNG","JPG","JPEG","TIFF","PPM"}; int nbAllowedFormats = sizeof(allowedFormats) / sizeof(QString); int i; for (i = 0; i < nbAllowedFormats; ++i) { if (!fileInfo.suffix().compare(allowedFormats[i], Qt::CaseInsensitive)) { imageFormat = allowedFormats[i]; break; } } if (i == nbAllowedFormats) { imageFormat = allowedFormats[0]; QMessageBox::warning(this, tr("Unknown image format"), tr("Could not guess image format from file name extension. Image " "will be exported as PNG.")); } } mpfr_t spanX, spanY; mpfr_init(spanX); mpfr_init(spanY); /* Adjust spanX & spanY to image width and height (keep ratio). */ int width = imageWidthBox->value(); int height = imageHeightBox->value(); if (height / (double)width < 1) { mpfr_mul_ui(spanX, fractal.spanY, width, MPFR_RNDN); mpfr_div_ui(spanX, spanX, height, MPFR_RNDN); mpfr_set(spanY, fractal.spanY, MPFR_RNDN); } else { mpfr_set(spanX, fractal.spanX, MPFR_RNDN); mpfr_mul_ui(spanY, fractal.spanX, height, MPFR_RNDN); mpfr_div_ui(spanY, spanY, width, MPFR_RNDN); } Fractal fractal; InitFractal(&fractal, this->fractal.fractalFormula, this->fractal.p, this->fractal.c, this->fractal.centerX, this->fractal.centerY, spanX, spanY, this->fractal.escapeRadius, this->fractal.maxIter); mpfr_clear(spanX); mpfr_clear(spanY); /* Now generate fractal image according to anti-aliasing method. */ Image fractalImg, tmpImg; CreateImage(&fractalImg, width, height, render.bytesPerComponent); Task *task; int canceled = 0; switch (getAntiAliasingMethod()) { case AAM_NONE: { task = CreateDrawFractalTask(&fractalImg, &fractal, &render, DEFAULT_QUAD_INTERPOLATION_SIZE, DEFAULT_COLOR_DISSIMILARITY_THRESHOLD, floatPrecision, NULL, threads->N); LaunchTask(task, threads); canceled = TaskProgressDialog::progress(task, tr("Drawing fractal..."), tr("Abort"), this); break; } case AAM_GAUSSIANBLUR: CreateImage(&tmpImg, width, height, render.bytesPerComponent); task = CreateDrawFractalTask(&fractalImg, &fractal, &render, DEFAULT_QUAD_INTERPOLATION_SIZE, DEFAULT_COLOR_DISSIMILARITY_THRESHOLD, floatPrecision, NULL, threads->N); LaunchTask(task, threads); canceled = TaskProgressDialog::progress(task, tr("Drawing fractal..."), tr("Abort"), this); if (!canceled) { FreeTask(task); task = CreateApplyGaussianBlurTask(&fractalImg, &tmpImg, &fractalImg, blurRadiusBox->value(), threads->N); LaunchTask(task, threads); canceled = TaskProgressDialog::progress(task, tr("Applying blur..."), tr("Abort"), this); } FreeImage(tmpImg); break; case AAM_OVERSAMPLING: CreateImage(&tmpImg, width*oversamplingSizeBox->value(), height*oversamplingSizeBox->value(), render.bytesPerComponent); task = CreateDrawFractalTask(&tmpImg, &fractal, &render, DEFAULT_QUAD_INTERPOLATION_SIZE, DEFAULT_COLOR_DISSIMILARITY_THRESHOLD, floatPrecision, NULL, threads->N); LaunchTask(task, threads); canceled = TaskProgressDialog::progress(task, tr("Drawing fractal..."), tr("Abort"), this); if (!canceled) { FreeTask(task); task = CreateDownscaleImageTask(&fractalImg, &tmpImg, threads->N); LaunchTask(task, threads); canceled = TaskProgressDialog::progress(task, tr("Downscaling image..."), tr("Abort"), this); } FreeImage(tmpImg); break; case AAM_ADAPTIVE: task = CreateDrawFractalTask(&fractalImg, &fractal, &render, DEFAULT_QUAD_INTERPOLATION_SIZE, DEFAULT_COLOR_DISSIMILARITY_THRESHOLD, floatPrecision, NULL, threads->N); LaunchTask(task, threads); canceled = TaskProgressDialog::progress(task, tr("Drawing fractal..."), tr("Abort"), this); if (!canceled) { FreeTask(task); task = CreateAntiAliaseFractalTask(&fractalImg, &fractal, &render, adaptiveSizeBox->value(), DEFAULT_ADAPTIVE_AAM_THRESHOLD, floatPrecision, NULL, threads->N); LaunchTask(task, threads); canceled = TaskProgressDialog::progress(task, tr("Anti-aliasing fractal..."), tr("Abort"), this); } break; default: FractalNow_error("Unknown anti-aliasing method.\n"); break; } FreeTask(task); if (canceled) { FreeImage(fractalImg); } else { setEnabled(false); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QApplication::processEvents(); /* Export image. */ int exportError = 0; if (depth == 2) { if ((exportError = ExportPPM(fileName.toStdString().c_str(), &fractalImg)) != 0) { QMessageBox::critical(this, tr("Failed to export image"), tr("Error occured while exporting image.")); } } else { QImage qImage(fractalImg.data, fractalImg.width, fractalImg.height, QImage::Format_RGB32); qImage.setText("Description", tr("Fractal image generated by ") + QApplication::applicationName()); qImage.setText("Fractal formula", fractalFormulaDescStr[(int)fractal.fractalFormula]); char *rePStr, *imPStr, *reCStr, *imCStr; char *centerXStr, *centerYStr, *spanXStr, *spanYStr; mpfr_asprintf(&rePStr, "%Rf", mpc_realref(fractal.p)); mpfr_asprintf(&imPStr, "%Rf", mpc_imagref(fractal.p)); mpfr_asprintf(&reCStr, "%Rf", mpc_realref(fractal.c)); mpfr_asprintf(&imCStr, "%Rf", mpc_imagref(fractal.c)); mpfr_asprintf(¢erXStr, "%Rf", fractal.centerX); mpfr_asprintf(¢erYStr, "%Rf", fractal.centerY); mpfr_asprintf(&spanXStr, "%Rf", fractal.spanX); mpfr_asprintf(&spanYStr, "%Rf", fractal.spanY); qImage.setText("Fractal p", QString(rePStr) + " + i*" + QString(imPStr)); qImage.setText("Fractal c", QString(reCStr) + " + i*" + QString(imCStr)); qImage.setText("Fractal center", "(" + QString(centerXStr) + ", " + QString(centerYStr) + ")"); qImage.setText("Fractal span X", QString(spanXStr)); qImage.setText("Fractal span Y", QString(spanYStr)); qImage.setText("Fractal bailout radius", QString::number(fractal.escapeRadius, 'G', LDBL_DIG)); qImage.setText("Fractal max iterations", QString::number(fractal.maxIter)); if ((exportError = !qImage.save(fileName, imageFormat.toStdString().c_str())) != 0) { QMessageBox::critical(this, tr("Failed to export image"), tr("Error occured while exporting image.")); } mpfr_free_str(rePStr); mpfr_free_str(imPStr); mpfr_free_str(reCStr); mpfr_free_str(imCStr); mpfr_free_str(centerXStr); mpfr_free_str(centerYStr); mpfr_free_str(spanXStr); mpfr_free_str(spanYStr); } FreeImage(fractalImg); setEnabled(true); QApplication::restoreOverrideCursor(); if (!exportError) { m_exportedFile = fileName; this->accept(); } } FreeFractal(fractal); FreeRenderingParameters(render); } fractalnow-0.8.1/gui/src/main_window.cpp0000664000175000017500000011161211777357367016747 0ustar mpegmpeg/* * main_window.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "main_window.h" #include "main.h" #include "mpfr_spin_box.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void initDefaultFractal(Fractal &fractal) { InitFractal2(&fractal, FRAC_MANDELBROT, 2, 0.4+I*0.25, -0.7, 0, 3, 3, 1E3, 1000); } void initDefaultGradient(Gradient &gradient) { uint32_t hex_color[5] = { 0x39A0, 0xFFFFFF, 0xFFFE43, 0xBF0800, 0x39A0 }; Color color[5]; for (uint_fast32_t i = 0; i < 5; ++i) { color[i] = ColorFromUint32(hex_color[i]); } GenerateGradient2(&gradient, 5, color, DEFAULT_GRADIENT_TRANSITIONS); } void initDefaultRenderingParameters(RenderingParameters &render) { Gradient gradient; initDefaultGradient(gradient); /* Init rendering parameters. */ InitRenderingParameters(&render, 1, ColorFromUint32(0x0), IC_SMOOTH, CM_ITERATIONCOUNT, AF_TRIANGLEINEQUALITY, 1, IM_NONE, TF_LOG, 4.5E-1, 0.2, gradient); } inline void initDefaultConfig(FractalConfig &config) { initDefaultFractal(config.fractal); initDefaultRenderingParameters(config.render); } void MainWindow::loadSettings() { QSettings settings; imageDir = settings.value("imageDir", QDesktopServices::storageLocation( QDesktopServices::PicturesLocation)).toString(); configDir = settings.value("configDir", QDesktopServices::storageLocation( QDesktopServices::DocumentsLocation)).toString(); gradientDir = settings.value("gradientDir", QDesktopServices::storageLocation( QDesktopServices::DocumentsLocation)).toString(); adaptExplorerSize = settings.value("adaptExplorerSize", false).toBool(); lastPreferredExplorerWidth = settings.value("preferredExplorerWidth", DEFAULT_EXPLORER_WIDTH).toUInt(); lastPreferredExplorerHeight = settings.value("preferredExplorerHeight", DEFAULT_EXPLORER_HEIGHT).toUInt(); lastWindowWidth = settings.value("windowWidth", width()).toUInt(); lastWindowHeight = settings.value("windowHeight", height()).toUInt(); useCache = settings.value("useCache", true).toBool(); cacheSize = settings.value("cacheSize", (unsigned int)DEFAULT_FRACTAL_CACHE_SIZE).toUInt(); solidGuessing = settings.value("solidGuessing", true).toBool(); fractalnow_mpfr_precision = settings.value("MPFRPrec", (unsigned int)DEFAULT_MPFR_PRECISION).toUInt(); } void MainWindow::saveSettings() { QSettings settings; settings.setValue("imageDir", imageDir); settings.setValue("configDir", configDir); settings.setValue("gradientDir", gradientDir); settings.setValue("adaptExplorerSize", adaptExplorerToWindowAction->isChecked()); settings.setValue("preferredExplorerWidth", preferredImageWidthSpinBox->value()); settings.setValue("preferredExplorerHeight", preferredImageHeightSpinBox->value()); settings.setValue("windowWidth", width()); settings.setValue("windowHeight", height()); settings.setValue("useCache", fractalExplorer->getFractalCacheEnabled()); settings.setValue("cacheSize", fractalExplorer->getFractalCacheSize()); settings.setValue("solidGuessing", fractalExplorer->getSolidGuessingEnabled()); settings.setValue("MPFRPrec", MPFloatPrecisionSpinBox->value()); } MainWindow::MainWindow(int argc, char *argv[]) { /* Set icon */ QString iconSizes[12] = {"16x16", "22x22", "24x24", "32x32", "36x36", "48x48", "64x64", "72x72", "96x96", "128x128", "192x192", "256x256"}; QIcon icon; for (int i = 0; i < 12; ++i) { icon.addFile(":icons/icon" + iconSizes[i] + ".png"); } this->setWindowIcon(icon); this->setWindowTitle(QApplication::applicationName()); setAcceptDrops(true); /* Set C numeric locale and codecs for strings. */ QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); setlocale(LC_NUMERIC, "C"); /* Load settings. */ loadSettings(); /* Read arguments on command-line. */ CommandLineArguments args(argc, argv); fractalnow_mpfr_precision = args.MPFloatPrecision; mpfr_set_default_prec(fractalnow_mpfr_precision); FractalConfig config; Fractal &fractal = config.fractal; RenderingParameters &render = config.render; /* Deal with arguments on command-line. */ initDefaultConfig(config); if (args.fractalConfigFileName) { /* Read config file. */ FreeFractalConfig(config); if (ReadFractalConfigFile(&config, args.fractalConfigFileName)) { FractalNow_message(stderr, T_QUIET, "Failed to read config file. Falling back to default.\n"); initDefaultConfig(config); } } if (args.fractalFileName) { /* Read fractal file. */ Fractal newFractal; if (ReadFractalFile(&newFractal, args.fractalFileName)) { FractalNow_message(stderr, T_QUIET, "Failed to read fractal file. Falling back to default.\n"); initDefaultFractal(newFractal); } ResetFractal(&config, newFractal); FreeFractal(newFractal); } if (args.renderingFileName) { /* Read rendering file. */ RenderingParameters newRender; if (ReadRenderingFile(&newRender, args.renderingFileName)) { FractalNow_message(stderr, T_QUIET, "Failed to read rendering file. Falling back to default.\n"); initDefaultRenderingParameters(newRender); } ResetRenderingParameters(&config, newRender); FreeRenderingParameters(newRender); } if (args.gradientFileName) { /* Read gradient file. */ Gradient newGradient; if (ReadGradientFile(&newGradient, args.gradientFileName)) { FractalNow_message(stderr, T_QUIET, "Failed to read gradient file. Falling back to default.\n"); initDefaultGradient(newGradient); } ResetGradient(&render, newGradient); FreeGradient(newGradient); } if (config.render.bytesPerComponent == 2) { QMessageBox::critical(this, tr("Gradient color depth is 16 bits."), tr("16-bits gradient will be converted to 8-bits gradient.")); Gradient newGradient = Gradient8(&config.render.gradient); ResetGradient(&config.render, newGradient); FreeGradient(newGradient); } uint_fast32_t explorerWidth = args.width; uint_fast32_t explorerHeight = args.height; if (explorerWidth == 0 && explorerHeight == 0) { /* If both width and height were omitted : set to default. */ explorerWidth = lastPreferredExplorerWidth; explorerHeight = lastPreferredExplorerHeight; } if (explorerWidth == 0) { /* If only width was omitted, compute it to keep ratio. */ mpfr_t spanRatio; mpfr_init(spanRatio); mpfr_div(spanRatio, fractal.spanX, fractal.spanY, MPFR_RNDN); explorerWidth = roundl(mpfr_get_ld(spanRatio, MPFR_RNDN) * explorerHeight); mpfr_clear(spanRatio); } else if (explorerHeight == 0) { /* If only height was omitted, compute it to keep ratio. */ mpfr_t spanRatio; mpfr_init(spanRatio); mpfr_div(spanRatio, fractal.spanX, fractal.spanY, MPFR_RNDN); explorerHeight = roundl(explorerWidth / mpfr_get_ld(spanRatio,MPFR_RNDN)); mpfr_clear(spanRatio); } else { /* If both width and height were specified (or set do default), * adapt spanX and spanY. */ mpfr_t spanX, spanY; mpfr_init(spanX); mpfr_init(spanY); if (explorerHeight / (double)explorerWidth < 1) { mpfr_mul_d(spanX, fractal.spanY, explorerWidth / (double)explorerHeight, MPFR_RNDN); mpfr_set(spanY, fractal.spanY, MPFR_RNDN); } else { mpfr_set(spanX, fractal.spanX, MPFR_RNDN); mpfr_mul_d(spanY, fractal.spanX, explorerHeight / (double)explorerWidth, MPFR_RNDN); } /* Reinit fractal, since we changed spanX or spanY. */ Fractal newFractal; InitFractal(&newFractal, fractal.fractalFormula, fractal.p, fractal.c, fractal.centerX, fractal.centerY, spanX, spanY, fractal.escapeRadius, fractal.maxIter); ResetFractal(&config, newFractal); FreeFractal(newFractal); mpfr_clear(spanX); mpfr_clear(spanY); } if (args.nbThreads <= 0) { /* Number of threads not specified. */ if (QThread::idealThreadCount() > 0) { fractalExplorerNbThreads = QThread::idealThreadCount(); /* To export image we decide to use more threads that the actual * number of cores, because some parts of image may need much * more calculations than others, so we may have one thread * taking much more time that the others, which is not good * (action finishes when all thread have finished). * In short, with more threads, we "average" the time taken by each * thread. * However, having more threads than number of cores is not good * for real-time, which is why fractal explorer uses exactly ideal * thread count. */ exportImageNbThreads = 4*QThread::idealThreadCount(); } else { fractalExplorerNbThreads = DEFAULT_NB_THREADS; exportImageNbThreads = DEFAULT_NB_THREADS; } } else { fractalExplorerNbThreads = args.nbThreads; exportImageNbThreads = args.nbThreads; } /* Create fractalImage label which will be the central widget. */ fractalExplorer = new FractalExplorer(config, explorerWidth, explorerHeight, args.minAntiAliasingSize, args.maxAntiAliasingSize, args.antiAliasingSizeIteration, args.quadInterpolationSize, args.colorDissimilarityThreshold, args.adaptiveAAMThreshold, fractalExplorerNbThreads); fractalExplorer->resizeFractalCache(cacheSize); fractalExplorer->useFractalCache(useCache); fractalExplorer->setSolidGuessingEnabled(solidGuessing); fractalExplorer->setFocus(); /* Make it the central widget with correct size policies. */ QWidget *centralWidget = new QWidget; QGridLayout *centralLayout = new QGridLayout; centralLayout->addWidget(fractalExplorer, 1, 1); if (adaptExplorerSize) { fractalExplorer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } else { fractalExplorer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } centralWidget->setLayout(centralLayout); centralWidget->updateGeometry(); this->setCentralWidget(centralWidget); /* Create fractal config widget. */ fractalConfigWidget = new FractalConfigWidget(fractal); /* Connect the fractal config widget spin boxes to slots. */ connect(fractalExplorer, SIGNAL(fractalChanged(const Fractal &)), fractalConfigWidget, SLOT(updateBoxesValues(const Fractal &))); connect(fractalConfigWidget->fractalFormulaComboBox, SIGNAL(currentIndexChanged(int)), fractalExplorer, SLOT(setFractalFormula(int))); connect(fractalConfigWidget->pParamReSpinBox, SIGNAL(valueChanged(const mpfr_t *)), fractalExplorer, SLOT(setPParamRe(const mpfr_t *))); connect(fractalConfigWidget->pParamImSpinBox, SIGNAL(valueChanged(const mpfr_t *)), fractalExplorer, SLOT(setPParamIm(const mpfr_t *))); connect(fractalConfigWidget->cParamReSpinBox, SIGNAL(valueChanged(const mpfr_t *)), fractalExplorer, SLOT(setCParamRe(const mpfr_t *))); connect(fractalConfigWidget->cParamImSpinBox, SIGNAL(valueChanged(const mpfr_t *)), fractalExplorer, SLOT(setCParamIm(const mpfr_t *))); connect(fractalConfigWidget->centerXSpinBox, SIGNAL(valueChanged(const mpfr_t *)), fractalExplorer, SLOT(setCenterX(const mpfr_t *))); connect(fractalConfigWidget->centerYSpinBox, SIGNAL(valueChanged(const mpfr_t *)), fractalExplorer, SLOT(setCenterY(const mpfr_t *))); connect(fractalConfigWidget->spanXSpinBox, SIGNAL(valueChanged(const mpfr_t *)), fractalExplorer, SLOT(setSpanX(const mpfr_t *))); connect(fractalConfigWidget->bailoutRadiusSpinBox, SIGNAL(valueChanged(double)), fractalExplorer, SLOT(setBailoutRadius(double))); connect(fractalConfigWidget->maxIterationsSpinBox, SIGNAL(valueChanged(int)), fractalExplorer, SLOT(setMaxIterations(int))); /* Create rendering config widget.*/ fractalRenderingWidget = new FractalRenderingWidget(render); /* Connect the fractal rendering widget combo and spin boxes to slots. */ connect(fractalExplorer, SIGNAL(renderingParametersChanged(const RenderingParameters &)), fractalRenderingWidget, SLOT(updateBoxesValues(const RenderingParameters &))); connect(fractalRenderingWidget->addendFunctionComboBox, SIGNAL(currentIndexChanged(int)), fractalExplorer, SLOT(setAddendFunction(int))); connect(fractalRenderingWidget->stripeDensitySpinBox, SIGNAL(valueChanged(int)), fractalExplorer, SLOT(setStripeDensity(int))); connect(fractalRenderingWidget->iterationCountComboBox, SIGNAL(currentIndexChanged(int)), fractalExplorer, SLOT(setIterationCount(int))); connect(fractalRenderingWidget->coloringMethodComboBox, SIGNAL(currentIndexChanged(int)), fractalExplorer, SLOT(setColoringMethod(int))); connect(fractalRenderingWidget->interpolationMethodComboBox, SIGNAL(currentIndexChanged(int)), fractalExplorer, SLOT(setInterpolationMethod(int))); connect(fractalRenderingWidget->transferFunctionComboBox, SIGNAL(currentIndexChanged(int)), fractalExplorer, SLOT(setTransferFunction(int))); connect(fractalRenderingWidget->colorScalingSpinBox, SIGNAL(valueChanged(double)), fractalExplorer, SLOT(setColorScaling(double))); connect(fractalRenderingWidget->colorOffsetSpinBox, SIGNAL(valueChanged(double)), fractalExplorer, SLOT(setColorOffset(double))); connect(fractalRenderingWidget->spaceColorButton, SIGNAL(currentColorChanged(const QColor &)), fractalExplorer, SLOT(setSpaceColor(const QColor &))); connect(fractalRenderingWidget->gradientBox, SIGNAL(gradientStopsChanged( const QGradientStops&)), fractalExplorer, SLOT(setGradient(const QGradientStops&))); /* Free fractal config (copied by fractal explorer). */ FreeFractalConfig(config); /* Create "other" dock widget. */ /* Create content and connect signals to slots first. */ QWidget *otherParametersWidget = new QWidget; QFormLayout *otherParamLayout = new QFormLayout; preferredImageWidthSpinBox = new QSpinBox; preferredImageWidthSpinBox->setRange(2, 2048); preferredImageWidthSpinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); connect(preferredImageWidthSpinBox, SIGNAL(editingFinished()), this, SLOT(onPreferredImageWidthChanged())); preferredImageHeightSpinBox = new QSpinBox; preferredImageHeightSpinBox->setRange(2, 2048); preferredImageHeightSpinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); connect(preferredImageHeightSpinBox, SIGNAL(editingFinished()), this, SLOT(onPreferredImageHeightChanged())); solidGuessingCheckBox = new QCheckBox; connect(solidGuessingCheckBox, SIGNAL(toggled(bool)), fractalExplorer, SLOT(setSolidGuessingEnabled(bool))); useCacheCheckBox = new QCheckBox; connect(useCacheCheckBox, SIGNAL(toggled(bool)), fractalExplorer, SLOT(useFractalCache(bool))); cacheSizeSpinBox = new QSpinBox; cacheSizeSpinBox->setRange(0, 10000000); cacheSizeSpinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); cacheSizeSpinBox->setEnabled(fractalExplorer->getFractalCacheEnabled()); connect(cacheSizeSpinBox, SIGNAL(editingFinished()), this, SLOT(onCacheSizeChanged())); connect(useCacheCheckBox, SIGNAL(toggled(bool)), cacheSizeSpinBox, SLOT(setEnabled(bool))); floatTypeComboBox = new QComboBox; for (uint_fast32_t i = 0; i < nbFloatPrecisions; ++i) { floatTypeComboBox->addItem(floatPrecisionDescStr[i]); } connect(floatTypeComboBox, SIGNAL(currentIndexChanged(int)), fractalExplorer, SLOT(setFloatPrecision(int))); QHBoxLayout *hBoxLayout = new QHBoxLayout; MPFloatPrecisionSpinBox = new QSpinBox; MPFloatPrecisionSpinBox->setRange(MPFR_PREC_MIN, std::min(std::numeric_limits::max(),(long long int)MPFR_PREC_MAX)); MPFloatPrecisionSpinBox->setButtonSymbols(QAbstractSpinBox::NoButtons); MPFloatPrecisionSpinBox->setReadOnly(true); QToolButton *editMPFloatPrecisionButton = new QToolButton(); editMPFloatPrecisionButton->setText(tr("...")); connect(editMPFloatPrecisionButton, SIGNAL(clicked()), this, SLOT(editMPFloatPrecision())); hBoxLayout->addWidget(MPFloatPrecisionSpinBox); hBoxLayout->addWidget(editMPFloatPrecisionButton); hBoxLayout->setStretch(1, 0); editMPFloatPrecisionWidget = new QWidget(); editMPFloatPrecisionWidget->setLayout(hBoxLayout); editMPFloatPrecisionWidget->setEnabled((int)args.floatPrecision); connect(floatTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onFloatTypeChanged(int))); connect(fractalExplorer, SIGNAL(fractalCacheSizeChanged(int)), cacheSizeSpinBox, SLOT(setValue(int))); /* Set widgets values... */ preferredImageWidthSpinBox->setValue((int)lastPreferredExplorerWidth); preferredImageHeightSpinBox->setValue((int)lastPreferredExplorerHeight); solidGuessingCheckBox->setChecked(fractalExplorer->getSolidGuessingEnabled()); useCacheCheckBox->setChecked(fractalExplorer->getFractalCacheEnabled()); cacheSizeSpinBox->setValue(fractalExplorer->getFractalCacheSize()); floatTypeComboBox->setCurrentIndex((int)args.floatPrecision); MPFloatPrecisionSpinBox->setValue((int)fractalnow_mpfr_precision); /* Add widgets to layout. */ otherParamLayout->addRow(tr("Preferred image width:"), preferredImageWidthSpinBox); otherParamLayout->addRow(tr("Preferred image height:"), preferredImageHeightSpinBox); otherParamLayout->addRow(tr("Solid guessing:"), solidGuessingCheckBox); otherParamLayout->addRow(tr("Use cache:"), useCacheCheckBox); otherParamLayout->addRow(tr("Cache size:"), cacheSizeSpinBox); otherParamLayout->addRow(tr("Float type:"), floatTypeComboBox); otherParamLayout->addRow(tr("MP Float precision:"), editMPFloatPrecisionWidget); /* Set layout. */ otherParametersWidget->setLayout(otherParamLayout); /* Create dock widgets. */ fractalDock = new QDockWidget(tr("Fractal"), this); renderDock = new QDockWidget(tr("Rendering"), this); otherDock = new QDockWidget(tr("Other"), this); /* Set dock widget properties. */ fractalDock->setWidget(fractalConfigWidget); fractalDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); renderDock->setWidget(fractalRenderingWidget); renderDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); otherDock->setWidget(otherParametersWidget); otherDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); /* Add dock widgets. */ this->addDockWidget(Qt::RightDockWidgetArea, fractalDock); this->addDockWidget(Qt::RightDockWidgetArea, renderDock); this->addDockWidget(Qt::RightDockWidgetArea, otherDock); setTabPosition(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea, QTabWidget::North); tabifyDockWidget(fractalDock, renderDock); tabifyDockWidget(renderDock, otherDock); /* Set current tabified dock to fractaldock. */ QList tabList = findChildren(); if (!tabList.isEmpty()) { QTabBar *tabBar = tabList.at(0); tabBar->setCurrentIndex(0); } QMenuBar *mainMenuBar = new QMenuBar(0); setMenuBar(mainMenuBar); QMenu *fileMenu = menuBar()->addMenu(tr("&File")); QAction *openConfigAction = new QAction(tr("&Open config"), this); openConfigAction->setToolTip(tr("Open configuration file")); openConfigAction->setShortcut(QKeySequence::Open); connect(openConfigAction, SIGNAL(triggered()), this, SLOT(openConfigFile())); fileMenu->addAction(openConfigAction); addAction(openConfigAction); QAction *saveConfigAction = new QAction(tr("&Save config"), this); saveConfigAction->setToolTip(tr("Save configuration file")); QList saveConfigShortcuts; saveConfigShortcuts << QKeySequence::Save << QKeySequence::SaveAs; saveConfigAction->setShortcuts(saveConfigShortcuts); connect(saveConfigAction, SIGNAL(triggered()), this, SLOT(saveConfigFile())); fileMenu->addAction(saveConfigAction); addAction(saveConfigAction); fileMenu->addSeparator(); QAction *openGradientAction = new QAction(tr("Open &gradient"), this); openGradientAction->setToolTip(tr("Open gradient file")); connect(openGradientAction, SIGNAL(triggered()), this, SLOT(openGradientFile())); fileMenu->addAction(openGradientAction); addAction(openGradientAction); QAction *saveGradientAction = new QAction(tr("Save gradient"), this); saveGradientAction->setToolTip(tr("Save gradient file")); connect(saveGradientAction, SIGNAL(triggered()), this, SLOT(saveGradientFile())); fileMenu->addAction(saveGradientAction); addAction(saveGradientAction); fileMenu->addSeparator(); QAction *exportImageAction = new QAction(tr("E&xport image"), this); exportImageAction->setToolTip(tr("Export fractal as image")); exportImageAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_DriveFDIcon)); exportImageAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X)); connect(exportImageAction, SIGNAL(triggered()), this, SLOT(exportImage())); fileMenu->addAction(exportImageAction); addAction(exportImageAction); fileMenu->addSeparator(); QAction *quitAction = new QAction(tr("&Quit"), this); quitAction->setShortcut(QKeySequence::Quit); connect(quitAction, SIGNAL(triggered()), this, SLOT(close())); fileMenu->addSeparator(); fileMenu->addAction(quitAction); addAction(quitAction); QMenu *editMenu = menuBar()->addMenu(tr("&Edit")); editMenu->addAction(fractalExplorer->restoreInitialStateAction); editMenu->addSeparator(); editMenu->addAction(fractalExplorer->stopDrawingAction); addAction(fractalExplorer->stopDrawingAction); editMenu->addAction(fractalExplorer->refreshAction); addAction(fractalExplorer->refreshAction); editMenu->addSeparator(); editMenu->addAction(fractalExplorer->zoomInAction); addAction(fractalExplorer->zoomInAction); editMenu->addAction(fractalExplorer->zoomOutAction); addAction(fractalExplorer->zoomOutAction); editMenu->addSeparator(); editMenu->addAction(fractalExplorer->moveLeftAction); addAction(fractalExplorer->moveLeftAction); editMenu->addAction(fractalExplorer->moveRightAction); addAction(fractalExplorer->moveRightAction); editMenu->addAction(fractalExplorer->moveUpAction); addAction(fractalExplorer->moveUpAction); editMenu->addAction(fractalExplorer->moveDownAction); addAction(fractalExplorer->moveDownAction); editMenu->addSeparator(); QAction *editGradientAction = new QAction(tr("Edit &gradient"), this); editGradientAction->setIconText(tr("Gradient")); editGradientAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_G)); connect(editGradientAction, SIGNAL(triggered()), fractalRenderingWidget, SLOT(editGradient())); editMenu->addAction(editGradientAction); addAction(editGradientAction); toolBar = addToolBar(tr("Tool bar")); toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); QMenu *viewMenu = menuBar()->addMenu(tr("&View")); viewMenu->addAction(fractalDock->toggleViewAction()); addAction(fractalDock->toggleViewAction()); viewMenu->addAction(renderDock->toggleViewAction()); addAction(renderDock->toggleViewAction()); viewMenu->addAction(toolBar->toggleViewAction()); addAction(toolBar->toggleViewAction()); viewMenu->addSeparator(); adaptExplorerToWindowAction = new QAction(tr("Adapt to &window"), this); adaptExplorerToWindowAction->setToolTip(tr("Adapt fractal explorer size to window")); adaptExplorerToWindowAction->setCheckable(true); adaptExplorerToWindowAction->setChecked(false); adaptExplorerToWindowAction->setShortcut(Qt::Key_F); connect(adaptExplorerToWindowAction, SIGNAL(toggled(bool)), this, SLOT(adaptExplorerToWindow(bool))); viewMenu->addAction(adaptExplorerToWindowAction); addAction(adaptExplorerToWindowAction); switchFullScreenAction = new QAction(tr("&Full Screen mode"), this); switchFullScreenAction->setToolTip(tr("Switch to Full Screen mode")); switchFullScreenAction->setCheckable(true); QList switchFullScreenShortcuts; switchFullScreenShortcuts << QKeySequence(Qt::Key_F11) << QKeySequence(Qt::ALT + Qt::Key_Return); switchFullScreenAction->setShortcuts(switchFullScreenShortcuts); connect(switchFullScreenAction, SIGNAL(toggled(bool)), this, SLOT(switchFullScreenMode(bool))); viewMenu->addAction(switchFullScreenAction); addAction(switchFullScreenAction); QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); QAction *aboutQtAction = new QAction(tr("About &Qt"), this); connect(aboutQtAction, SIGNAL(triggered()), this, SLOT(aboutQt())); helpMenu->addAction(aboutQtAction); addAction(aboutQtAction); QAction *aboutQFractalNowAction = new QAction(tr("&About QFractalNow"), this); connect(aboutQFractalNowAction, SIGNAL(triggered()), this, SLOT(aboutQFractalNow())); helpMenu->addAction(aboutQFractalNowAction); addAction(aboutQFractalNowAction); QAction *escapeFullScreenAction = new QAction(this); escapeFullScreenAction->setShortcut(QKeySequence(Qt::Key_Escape)); addAction(escapeFullScreenAction); connect(escapeFullScreenAction, SIGNAL(triggered()), this, SLOT(escapeFullScreen())); toolBar->addAction(openConfigAction); toolBar->addAction(saveConfigAction); toolBar->addSeparator(); toolBar->addAction(exportImageAction); toolBar->addSeparator(); toolBar->addAction(editGradientAction); toolBar->addSeparator(); toolBar->addAction(fractalExplorer->restoreInitialStateAction); toolBar->addSeparator(); toolBar->addAction(fractalExplorer->stopDrawingAction); toolBar->addAction(fractalExplorer->refreshAction); toolBar->addSeparator(); toolBar->addAction(adaptExplorerToWindowAction); if (adaptExplorerSize) { resize(lastWindowWidth, lastWindowHeight); adaptExplorerToWindowAction->trigger(); } exportFractalImageDialog = new ExportFractalImageDialog(fractalExplorer->getFractalConfig(), exportImageNbThreads, imageDir, this); /* Eventually launch fractal drawing. */ fractalExplorer->refresh(); QTimer::singleShot(5, this, SLOT(delayedInit())); } void MainWindow::delayedInit() { if (adaptExplorerSize) { fractalExplorer->restoreInitialState(); } } MainWindow::~MainWindow() { saveSettings(); mpfr_free_cache(); } void MainWindow::aboutQt() { QApplication::aboutQt(); } void MainWindow::aboutQFractalNow() { QString applicationName(QApplication::applicationName()); QString applicationVersion(QApplication::applicationVersion()); QString homepage = "" "fractalnow.sourceforge.net"; QString title(tr("About %1 %2").arg(applicationName).arg(applicationVersion)); QString message; message += QString(" %1 v%2

").arg(applicationName) .arg(applicationVersion); message += tr("%1 is a program to explore fractal sets easily and generate \ fractal images efficiently.").arg(applicationName) + "

"; message += tr("Copyright (c) 2011-2012 Marc Pegon ") + "

"; message += tr("Visit %1 for more information.").arg(homepage) + "

"; message += tr("This program is licensed under the Lesser GNU General Public \ License."); QMessageBox::about(this, title, message); } void MainWindow::adaptExplorerToWindow(bool checked) { if (checked) { fractalExplorer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } else { fractalExplorer->resize(preferredImageWidthSpinBox->value(), preferredImageHeightSpinBox->value()); fractalExplorer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); } centralWidget()->updateGeometry(); } void MainWindow::loadConfigFile(const char *fileName) { FractalConfig newConfig; /* Set locale each time, because apparently some Qt * methods change locale. * For example a single call to QPixmap(QString filename) * changes back locale... */ setlocale(LC_NUMERIC, "C"); if (ReadFractalConfigFile(&newConfig, fileName)) { QMessageBox::critical(this, tr("Failed to read config file"), tr("Error occured while reading config file.")); } else { int finished = fractalExplorer->stopDrawing(); UNUSED(finished); fractalExplorer->setFractalConfig(newConfig); /* Config is copied by fractal explorer. */ FreeFractalConfig(newConfig); } } void MainWindow::loadFractalFile(const char *fileName) { Fractal newFractal; setlocale(LC_NUMERIC, "C"); if (ReadFractalFile(&newFractal, fileName)) { QMessageBox::critical(this, tr("Failed to read fractal file"), tr("Error occured while reading fractal file.")); } else { int finished = fractalExplorer->stopDrawing(); UNUSED(finished); fractalExplorer->setFractal(newFractal); /* Fractal is copied by fractal explorer. */ FreeFractal(newFractal); } } void MainWindow::loadRenderingFile(const char *fileName) { RenderingParameters newRender; setlocale(LC_NUMERIC, "C"); if (ReadRenderingFile(&newRender, fileName)) { QMessageBox::critical(this, tr("Failed to read rendering file"), tr("Error occured while reading rendering file.")); } else { int finished = fractalExplorer->stopDrawing(); UNUSED(finished); fractalExplorer->setRenderingParameters(newRender); /* Rendering parameters are copied by fractal explorer. */ FreeRenderingParameters(newRender); } } void MainWindow::loadGradientFile(const char *fileName) { Gradient newGradient; setlocale(LC_NUMERIC, "C"); if (ReadGradientFile(&newGradient, fileName)) { QMessageBox::critical(this, tr("Failed to read rendering file"), tr("Error occured while reading rendering file.")); } else { int finished = fractalExplorer->stopDrawing(); UNUSED(finished); fractalExplorer->setGradient(newGradient); /* Gradient is copied by fractal explorer. */ FreeGradient(newGradient); } } void MainWindow::exportImage() { fractalExplorer->pauseDrawing(); exportFractalImageDialog->resetFractalConfig(fractalExplorer->getFractalConfig()); exportFractalImageDialog->setFloatPrecision((FloatPrecision) floatTypeComboBox->currentIndex()); if (exportFractalImageDialog->exec()) { imageDir = QFileInfo(exportFractalImageDialog->exportedFile()).absolutePath(); } fractalExplorer->resumeDrawing(); } void MainWindow::openConfigFile() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Config File"), configDir, tr("Configuration (*.config)")); if (!fileName.isEmpty()) { configDir = QFileInfo(fileName).absolutePath(); loadConfigFile(fileName.toStdString().c_str()); } } void MainWindow::saveConfigFile() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save Config File"), configDir + "/config.config", tr("Configuration (*.config)")); if (!fileName.isEmpty()) { configDir = QFileInfo(fileName).absolutePath(); const Fractal &expFractal = fractalExplorer->getFractalConfig().fractal; mpfr_t spanY; mpfr_init(spanY); mpfr_set(spanY, expFractal.spanX, MPFR_RNDN); Fractal fractal; InitFractal(&fractal, expFractal.fractalFormula, expFractal.p, expFractal.c, expFractal.centerX, expFractal.centerY, expFractal.spanX, spanY, expFractal.escapeRadius, expFractal.maxIter); RenderingParameters render = CopyRenderingParameters( &fractalExplorer->getFractalConfig().render); FractalConfig fractalConfig; InitFractalConfig(&fractalConfig, fractal, render); if (WriteFractalConfigFile(&fractalConfig, fileName.toStdString().c_str())) { QMessageBox::critical(this, tr("Failed to write configuration file"), tr("Error occured while writing configuration file.")); } mpfr_clear(spanY); FreeFractalConfig(fractalConfig); } } void MainWindow::openGradientFile() { QString fileName = QFileDialog::getOpenFileName(this, tr("Open Gradient File"), gradientDir, tr("Gradient (*.gradient)")); if (!fileName.isEmpty()) { gradientDir = QFileInfo(fileName).absolutePath(); loadGradientFile(fileName.toStdString().c_str()); } } void MainWindow::saveGradientFile() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save Gradient File"), gradientDir + "/gradient.gradient", tr("Gradient (*.gradient)")); if (!fileName.isEmpty()) { gradientDir = QFileInfo(fileName).absolutePath(); if (WriteGradientFile(&fractalExplorer->getRender().gradient, fileName.toStdString().c_str())) { QMessageBox::critical(this, tr("Failed to write gradient file"), tr("Error occured while writing gradient file.")); } } } void MainWindow::onPreferredImageWidthChanged() { if (!adaptExplorerToWindowAction->isChecked() && preferredImageWidthSpinBox->value() != fractalExplorer->width()) { fractalExplorer->resize(preferredImageWidthSpinBox->value(), preferredImageHeightSpinBox->value()); centralWidget()->updateGeometry(); if (sizeHint().width() > width()) { adjustSize(); } } } void MainWindow::onPreferredImageHeightChanged() { if (!adaptExplorerToWindowAction->isChecked() && preferredImageHeightSpinBox->value() != fractalExplorer->height()) { fractalExplorer->resize(preferredImageWidthSpinBox->value(), preferredImageHeightSpinBox->value()); centralWidget()->updateGeometry(); if (sizeHint().height() > height()) { adjustSize(); } } } void MainWindow::onCacheSizeChanged() { fractalExplorer->resizeFractalCache(cacheSizeSpinBox->value()); } void MainWindow::onFloatTypeChanged(int index) { if ((FloatPrecision)index == FP_MP) { editMPFloatPrecisionWidget->setEnabled(true); } else { editMPFloatPrecisionWidget->setEnabled(false); } } void MainWindow::editMPFloatPrecision() { bool ok; int new_mpfr_precision = QInputDialog::getInt(this, tr("Change value"), tr("MP Float Precision"), MPFloatPrecisionSpinBox->value(), MPFR_PREC_MIN, std::min(std::numeric_limits::max(),(long long int)MPFR_PREC_MAX), 1, &ok); if (ok) { MPFloatPrecisionSpinBox->setValue(new_mpfr_precision); if (fractalnow_mpfr_precision != new_mpfr_precision) { QMessageBox::information(this, tr("Restart application"), tr("You must restart application to apply changes.")); } } } enum MainWindow::FileType MainWindow::getFileType(const char *fileName) { enum MainWindow::FileType res = MainWindow::UNKNOWN_FILE; if (isSupportedFractalConfigFile(fileName)) { res = MainWindow::CONFIG_FILE; } else if (isSupportedFractalFile(fileName)) { res = MainWindow::FRACTAL_FILE; } else if (isSupportedRenderingFile(fileName)) { res = MainWindow::RENDER_FILE; } else if (isSupportedGradientFile(fileName)) { res = MainWindow::GRADIENT_FILE; } return res; } void MainWindow::openFile(QString fileName) { const char *cFileName = fileName.toStdString().c_str(); enum MainWindow::FileType fileType = getFileType(cFileName); switch (fileType) { case MainWindow::CONFIG_FILE: loadConfigFile(cFileName); break; case MainWindow::FRACTAL_FILE: loadFractalFile(cFileName); break; case MainWindow::RENDER_FILE: loadRenderingFile(cFileName); break; case MainWindow::GRADIENT_FILE: loadGradientFile(cFileName); break; default: /* This should never happen. */ QMessageBox::critical(this, tr("Unexpected error"), tr("Unknown file type.")); break; } } void MainWindow::dragEnterEvent(QDragEnterEvent *event) { const QMimeData *mimeData = event->mimeData(); if (mimeData->hasUrls()) { QList urls(event->mimeData()->urls()); QString fileName(urls.at(0).toLocalFile()); if (urls.size() == 1 && !fileName.isEmpty()) { const char *cFileName = fileName.toStdString().c_str(); if (getFileType(cFileName) != MainWindow::UNKNOWN_FILE) { event->acceptProposedAction(); } } } } void MainWindow::dropEvent(QDropEvent *event) { if (event->mimeData()->hasUrls()) { QList urls(event->mimeData()->urls()); QString path(urls.at(0).toLocalFile()); openFile(path); } } void MainWindow::switchFullScreenMode(bool checked) { static const QMargins margins = centralWidget()->layout()->contentsMargins(); static bool fractalDockHidden = false; static bool renderDockHidden = false; static bool otherDockHidden = false; static bool toolBarHidden = false; if (checked) { fractalDockHidden = fractalDock->isHidden(); renderDockHidden = renderDock->isHidden(); otherDockHidden = otherDock->isHidden(); toolBarHidden = toolBar->isHidden(); fractalDock->hide(); renderDock->hide(); otherDock->hide(); toolBar->hide(); menuBar()->hide(); if (!adaptExplorerToWindowAction->isChecked()) { adaptExplorerToWindow(true); } centralWidget()->layout()->setContentsMargins(0, 0, 0, 0); adaptExplorerToWindowAction->setDisabled(true); fractalDock->toggleViewAction()->setDisabled(true); renderDock->toggleViewAction()->setDisabled(true); otherDock->toggleViewAction()->setDisabled(true); toolBar->toggleViewAction()->setDisabled(true); showFullScreen(); } else { if (!fractalDockHidden) { fractalDock->show(); } if (!renderDockHidden) { renderDock->show(); } if (!otherDockHidden) { otherDock->show(); } if (!toolBarHidden) { toolBar->show(); } menuBar()->show(); if (!adaptExplorerToWindowAction->isChecked()) { adaptExplorerToWindow(false); } centralWidget()->layout()->setContentsMargins(margins); adaptExplorerToWindowAction->setEnabled(true); fractalDock->toggleViewAction()->setEnabled(true); renderDock->toggleViewAction()->setEnabled(true); otherDock->toggleViewAction()->setEnabled(true); toolBar->toggleViewAction()->setEnabled(true); showNormal(); } } void MainWindow::escapeFullScreen() { if (isFullScreen()) { switchFullScreenAction->trigger(); } } fractalnow-0.8.1/gui/src/task_progress_dialog.cpp0000664000175000017500000000306311754776133020630 0ustar mpegmpeg/* * task_progress_dialog.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "task_progress_dialog.h" #include #include #include #include #include int TaskProgressDialog::progress(Task *task, QString labelText, QString cancelButtonText, QWidget *parent) { QProgressDialog progress(labelText, cancelButtonText, 0, 1000, parent); progress.setWindowModality(Qt::WindowModal); progress.setWindowTitle(labelText); progress.setMinimumDuration(0); progress.setValue(0); while (!TaskIsFinished(task)) { if (progress.wasCanceled()) { CancelTask(task); break; } else { progress.setValue(GetTaskProgress(task) * 1000); } QApplication::processEvents(); } progress.setValue(1000); return GetTaskResult(task); } fractalnow-0.8.1/gui/src/help.cpp0000664000175000017500000000750411777357367015370 0ustar mpegmpeg/* * help.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "help.h" #include "main.h" #include #include void Help::Print() { printf("qfractalnow v%s - Explore fractals and generate \ fractal images.\n\n\ Usage : qfractalnow [OPTIONS]\n\n\ OPTIONS:\n\ -h Prints this help.\n\ -q Quiet mode.\n\ -v Verbose mode.\n" #ifdef DEBUG " -d Debug mode.\n" #endif " -j Specify number of threads \ (%"PRIuFAST32" by default).\n\ -c Specify configuration file, \ overriding default configuration.\n\ -f Specify fractal file, overriding \ parameters from default configuration or configuration file.\n\ -r Specify rendering file, overriding \ parameters from default configuration or configuration file.\n\ -g Specify gradient file, overriding \ gradient from default configuration, configuration file, or \ rendering file.\n\ -x Specify image width.\n\ -y Specify image height.\n\ -l Specify float precision:\n\ single Single precision.\n\ double Double precision.\n\ ldouble Long double \ precision.\n\ mp Multiple \ precision.\n\ -L Specify precision for Multiple \ Precision (MP) floats (%ld by default).\n\ -m Specify minimum size of adaptive \ anti-aliasing (%"PRIuFAST32" by default).\n\ Must be an integer strictly greater \ than 1.\n\ -M Specify maximum size of adaptive \ anti-aliasing (%"PRIuFAST32" by default).\n\ Must be an integer strictly greater \ than 1 and MinAAMSize.\n\ -n Anti-aliasing size iteration.\n\ Anti-aliasing size will increase by \ steps of AAMSizeIteration from MinAAMSize to MaxAAMSize.\n\ -p Threshold for adaptive \ anti-aliasing (%.*lf by default).\n\ -i Maximum size of quadrilaterals for \ linear interpolation.\n\ %"PRIuFAST32" by default, which is \ good for no visible loss of quality.\n\ 1 means no interpolation (all \ pixels are computed).\n\ -t Dissimilarity threshold for quad \ interpolation.\n\ %.*lf by default, which is \ good for no visible loss of quality.\n\ A quadrilateral that shows too \ dissimilar values at its corners will be computed, \ as opposed to interpolated.\n", FractalNow_VersionNumber(), DEFAULT_NB_THREADS, (long int)DEFAULT_MPFR_PRECISION, DEFAULT_MIN_ANTIALIASING_SIZE, DEFAULT_MAX_ANTIALIASING_SIZE, DBL_DIG, DEFAULT_ADAPTIVE_AAM_THRESHOLD, DEFAULT_QUAD_INTERPOLATION_SIZE, DBL_DIG, DEFAULT_COLOR_DISSIMILARITY_THRESHOLD); } fractalnow-0.8.1/gui/src/mpfr_spin_box.cpp0000664000175000017500000001476411754747533017304 0ustar mpegmpeg/* * mpfr_spin_box.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mpfr_spin_box.h" #include MPFRSpinBox::MPFRSpinBox(QWidget * parent) : QAbstractSpinBox(parent) { m_notation = ClassicNotation; m_decimals = -1; mpfr_init(m_value); mpfr_set_ui(m_value, 0, MPFR_RNDN); mpfr_init(m_singleStep); mpfr_set_ui(m_singleStep, 1, MPFR_RNDN); mpfr_init(m_minimum); mpfr_init(m_maximum); mpfr_set_ui_2exp(m_maximum, 1, 99.99, MPFR_RNDN); mpfr_set_ui(m_minimum, 0, MPFR_RNDN); mpfr_t initValue; mpfr_init(initValue); mpfr_set_d(initValue, 0.5, MPFR_RNDN); setValue(&initValue); mpfr_clear(initValue); connect(lineEdit(), SIGNAL(textEdited(const QString &)), this, SLOT(onTextEdited(const QString &))); connect(lineEdit(), SIGNAL(editingFinished()), this, SLOT(onEditingFinished())); } MPFRSpinBox::~MPFRSpinBox() { mpfr_clear(m_value); mpfr_clear(m_singleStep); mpfr_clear(m_minimum); mpfr_clear(m_maximum); } void MPFRSpinBox::aux_setMaximum() { /* Update m_value and/or m_minimum if needed after maximum has changed. */ if (mpfr_cmp(m_maximum, m_minimum) < 0) { mpfr_set(m_minimum, m_maximum, MPFR_RNDN); } if (mpfr_cmp(m_value, m_minimum) < 0) { setValue(&m_minimum); } } void MPFRSpinBox::setMaximum ( const mpfr_t * max ) { mpfr_set(m_maximum, *max, MPFR_RNDN); aux_setMaximum(); } void MPFRSpinBox::setMaximum ( long double max ) { mpfr_set_ld(m_maximum, max, MPFR_RNDN); aux_setMaximum(); } void MPFRSpinBox::aux_setMinimum() { /* Update m_value and/or m_maximum if needed after minimum has changed. */ if (mpfr_cmp(m_minimum, m_maximum) > 0) { mpfr_set(m_maximum, m_minimum, MPFR_RNDN); } if (mpfr_cmp(m_value, m_maximum) > 0) { setValue(&m_maximum); } } void MPFRSpinBox::setMinimum ( const mpfr_t * min ) { mpfr_set(m_minimum, *min, MPFR_RNDN); aux_setMinimum(); } void MPFRSpinBox::setMinimum ( long double min ) { mpfr_set_ld(m_minimum, min, MPFR_RNDN); aux_setMinimum(); } void MPFRSpinBox::setRange ( const mpfr_t * min, const mpfr_t * max) { setMinimum(min); setMaximum(max); } void MPFRSpinBox::setRange ( long double min, long double max ) { setMinimum(min); setMaximum(max); } void MPFRSpinBox::setSingleStep ( const mpfr_t * val ) { mpfr_set(m_singleStep, *val, MPFR_RNDN); } void MPFRSpinBox::setSingleStep ( long double val ) { mpfr_set_ld(m_singleStep, val, MPFR_RNDN); } void MPFRSpinBox::setNotation ( Notation notation ) { if (notation != m_notation) { m_notation = notation; updateText(); } } void MPFRSpinBox::setDecimals ( int prec ) { if (prec != m_decimals) { m_decimals = prec; updateText(); } } void MPFRSpinBox::updateText() { lineEdit()->setText(textFromValue(&m_value)); } void MPFRSpinBox::fixup( QString & input ) const { Q_UNUSED(input); } void MPFRSpinBox::stepBy(int step) { mpfr_t newValue; mpfr_init(newValue); mpfr_mul_si(newValue, m_singleStep, step, MPFR_RNDN); mpfr_add(newValue, newValue, m_value, MPFR_RNDN); setValue(&newValue); mpfr_clear(newValue); } const mpfr_t *MPFRSpinBox::value() { return &m_value; } long double MPFRSpinBox::value_d() { return mpfr_get_ld(m_value, MPFR_RNDN); } inline bool MPFRSpinBox::isInRange(const mpfr_t val) const { return (mpfr_cmp(val,m_minimum) >= 0 && mpfr_cmp(val,m_maximum) <= 0); } inline void MPFRSpinBox::aux_setValue(const mpfr_t *val) { bool changed = (mpfr_cmp(m_value, *val) != 0); mpfr_set(m_value, *val, MPFR_RNDN); if (changed) { emit valueChanged(&m_value); } } inline void MPFRSpinBox::setValue(const mpfr_t *val, bool updateText) { if (mpfr_cmp(*val, m_minimum) < 0) { aux_setValue(&m_minimum); } else if (mpfr_cmp(*val, m_maximum) > 0) { aux_setValue(&m_maximum); } else { aux_setValue(val); } if (updateText) this->updateText(); } void MPFRSpinBox::setValue(const mpfr_t *val) { setValue(val, true); } inline void MPFRSpinBox::aux_setValue(long double val) { bool changed = (mpfr_cmp_ld(m_value, val) != 0); mpfr_set_ld(m_value, val, MPFR_RNDN); if (changed) { emit valueChanged(&m_value); } } void MPFRSpinBox::setValue(long double val) { if (mpfr_cmp_ld(m_minimum, val) > 0) { aux_setValue(&m_minimum); } else if (mpfr_cmp_ld(m_maximum, val) < 0) { aux_setValue(&m_maximum); } else { aux_setValue(val); } this->updateText(); } QValidator::State MPFRSpinBox::validate ( QString & input, int & pos ) const { Q_UNUSED(pos); FILE *tmp = tmpfile(); fputs(input.toStdString().c_str(), tmp); rewind(tmp); mpfr_t dst; mpfr_init(dst); QValidator::State res = QValidator::Invalid; if (mpfr_inp_str(dst, tmp, 10, MPFR_RNDN) != 0 && isInRange(dst)) { res = QValidator::Acceptable; } mpfr_clear(dst); fclose(tmp); return res; } mpfr_t *MPFRSpinBox::valueFromText(const QString &text) const { FILE *tmp = tmpfile(); fputs(text.toStdString().c_str(), tmp); rewind(tmp); mpfr_t *res = (mpfr_t *)malloc(sizeof(mpfr_t)); mpfr_init(*res); mpfr_inp_str(*res, tmp, 10, MPFR_RNDN); return res; } QString MPFRSpinBox::textFromValue(const mpfr_t *val) const { char *str; switch(m_notation) { case ClassicNotation: mpfr_asprintf(&str, "%.*Rf", (m_decimals < 0) ? mpfr_get_prec(*val) : m_decimals, *val); break; case ScientificNotation: if (m_decimals < 0) { mpfr_asprintf(&str, "%RE", *val); } else { mpfr_asprintf(&str, "%.*RE", m_decimals, *val); } break; } QString res(str); mpfr_free_str(str); return res; } QAbstractSpinBox::StepEnabled MPFRSpinBox::stepEnabled() const { StepEnabled res = 0; if (mpfr_cmp(m_value, m_minimum) > 0) { res |= StepDownEnabled; } if (mpfr_cmp(m_value, m_maximum) < 0) { res |= StepUpEnabled; } return res; } void MPFRSpinBox::onTextEdited(const QString & text) { mpfr_t *value = valueFromText(text); setValue(value, false); mpfr_clear(*value); free(value); } void MPFRSpinBox::onEditingFinished() { updateText(); } fractalnow-0.8.1/gui/src/fractal_explorer.cpp0000664000175000017500000011105711754747533017764 0ustar mpegmpeg/* * fractal_explorer.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal_explorer.h" #include #include #include #include #include #include #include #include #include FractalExplorer::FractalExplorer(const FractalConfig &fractalConfig, uint_fast32_t width, uint_fast32_t height, uint_fast32_t minAntiAliasingSize, uint_fast32_t maxAntiAliasingSize, uint_fast32_t antiAliasingSizeIteration, uint_fast32_t quadInterpolationSize, double colorDissimilarityThreshold, double adaptiveAAMThreshold, uint_fast32_t nbThreads, QWidget *parent, Qt::WindowFlags f) : QLabel(parent, f), fractal(this->fractalConfig.fractal), render(this->fractalConfig.render), quadInterpolationSize(quadInterpolationSize), colorDissimilarityThreshold(colorDissimilarityThreshold), adaptiveAAMThreshold(adaptiveAAMThreshold) { setCursor(QCursor(Qt::OpenHandCursor)); setContextMenuPolicy(Qt::DefaultContextMenu); mpfr_init(fractalCenterXOnPress); mpfr_init(fractalCenterYOnPress); this->fractalConfig = CopyFractalConfig(&fractalConfig); if (fractalConfig.render.bytesPerComponent == 2) { QMessageBox::critical(this, tr("Gradient color depth is 16 bits."), tr("16-bits gradient will be converted to 8-bits gradient.")); Gradient newGradient = Gradient8(&this->render.gradient); ResetGradient(&this->render, newGradient); FreeGradient(newGradient); } this->initialFractalConfig = CopyFractalConfig(&this->fractalConfig); this->initialWidth = width; this->initialHeight = height; this->minAntiAliasingSize = minAntiAliasingSize; this->maxAntiAliasingSize = maxAntiAliasingSize; this->antiAliasingSizeIteration = antiAliasingSizeIteration; drawingPaused = false; redrawFractal = false; movingFractalDeferred = false; movingFractalRealTime = false; fractalMoved = false; /* Create QImage and Image (from fractal lib) */ fractalQImage = new QImage(width, height, QImage::Format_RGB32); fractalQImage->fill(0); CreateImage2(&fractalImage, fractalQImage->bits(), width, height, 1); adjustSpan(); restoreInitialStateAction = new QAction(tr("Restore &initial state"), this); restoreInitialStateAction->setIconText(tr("Initial state")); restoreInitialStateAction->setShortcut(QKeySequence::MoveToStartOfDocument); restoreInitialStateAction->setIcon(QApplication::style()->standardIcon( QStyle::SP_DirHomeIcon)); connect(restoreInitialStateAction, SIGNAL(triggered()), this, SLOT(restoreInitialState())); stopDrawingAction = new QAction(tr("&Stop drawing"), this); stopDrawingAction->setIconText(tr("Stop")); stopDrawingAction->setShortcut(Qt::Key_S); stopDrawingAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_BrowserStop)); connect(stopDrawingAction, SIGNAL(triggered()), this, SLOT(stopDrawing())); refreshAction = new QAction(tr("&Refresh"), this); refreshAction->setShortcut(QKeySequence::Refresh); refreshAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_BrowserReload)); connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); zoomInAction = new QAction(tr("Zoom in"), this); QList zoomInShortcuts; zoomInShortcuts << Qt::Key_Plus << QKeySequence::ZoomIn; zoomInAction->setShortcuts(zoomInShortcuts); connect(zoomInAction, SIGNAL(triggered()), this, SLOT(zoomInFractal())); zoomOutAction = new QAction(tr("Zoom out"), this); QList zoomOutShortcuts; zoomOutShortcuts << Qt::Key_Minus << QKeySequence::ZoomOut; zoomOutAction->setShortcuts(zoomOutShortcuts); connect(zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOutFractal())); moveLeftAction = new QAction(tr("Move left"), this); moveLeftAction->setShortcut(Qt::Key_Left); connect(moveLeftAction, SIGNAL(triggered()), this, SLOT(moveLeftFractal())); moveRightAction = new QAction(tr("Move right"), this); moveRightAction->setShortcut(Qt::Key_Right); connect(moveRightAction, SIGNAL(triggered()), this, SLOT(moveRightFractal())); moveUpAction = new QAction(tr("Move up"), this); moveUpAction->setShortcut(Qt::Key_Up); connect(moveUpAction, SIGNAL(triggered()), this, SLOT(moveUpFractal())); moveDownAction = new QAction(tr("Move down"), this); moveDownAction->setShortcut(Qt::Key_Down); connect(moveDownAction, SIGNAL(triggered()), this, SLOT(moveDownFractal())); int failure = CreateFractalCache(&cache, 0); if (failure) { emit fractalCacheSizeChanged(cache.size); QMessageBox::critical(this, tr("Failed to resize cache"), tr("Could not allocate memory for cache.")); } pCache = NULL; solidGuessing = true; floatPrecision = FP_DOUBLE; threads = CreateThreads(nbThreads); task = DoNothingTask(); LaunchTask(task, threads); /* Create timer to repaint fractalImageLabel regularly. */ timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout())); timer->start(10); } FractalExplorer::~FractalExplorer() { cancelActionIfNotFinished(); FreeTask(task); DestroyThreads(threads); FreeFractalConfig(fractalConfig); FreeFractalConfig(initialFractalConfig); FreeImage(fractalImage); FreeFractalCache(&cache); mpfr_clear(fractalCenterXOnPress); mpfr_clear(fractalCenterYOnPress); delete fractalQImage; } bool FractalExplorer::getFractalCacheEnabled() const { return (pCache != NULL); } void FractalExplorer::useFractalCache(bool enabled) { bool changed = (enabled == (pCache == NULL)); if (changed) { cancelActionIfNotFinished(); if (enabled) { pCache = &cache; } else { pCache = NULL; } refresh(); } } int FractalExplorer::getFractalCacheSize() const { return (int)cache.size; } void FractalExplorer::resizeFractalCache(int size) { if (size < 0) { size = 0; } int failure = ResizeCacheThreadSafe(&cache, size); if (failure) { emit fractalCacheSizeChanged(cache.size); QMessageBox::critical(this, tr("Failed to resize cache"), tr("Could not allocate memory for cache.")); } } bool FractalExplorer::getSolidGuessingEnabled() const { return solidGuessing; } void FractalExplorer::setSolidGuessingEnabled(bool enabled) { bool changed = (enabled != solidGuessing); if (changed) { cancelActionIfNotFinished(); solidGuessing = enabled; refresh(); } } void FractalExplorer::setFractalConfig(const FractalConfig &fractalConfig) { cancelActionIfNotFinished(); FractalConfig oldFractalConfig = this->fractalConfig; this->fractalConfig = CopyFractalConfig(&fractalConfig); if (this->fractalConfig.render.bytesPerComponent == 2) { QMessageBox::critical(this, tr("Gradient color depth is 16 bits."), tr("16-bits gradient will be converted to 8-bits gradient.")); Gradient newGradient = Gradient8(&this->fractalConfig.render.gradient); ResetGradient(&this->fractalConfig.render, newGradient); FreeGradient(newGradient); } FreeFractalConfig(oldFractalConfig); adjustSpan(); emit fractalChanged(fractal); emit renderingParametersChanged(render); refresh(); } void FractalExplorer::setFractal(const Fractal &fractal) { cancelActionIfNotFinished(); ResetFractal(&fractalConfig, fractal); adjustSpan(); emit fractalChanged(this->fractal); refresh(); } void FractalExplorer::setRenderingParameters(const RenderingParameters &render) { cancelActionIfNotFinished(); RenderingParameters newRender = CopyRenderingParameters(&render); if (newRender.bytesPerComponent == 2) { QMessageBox::critical(this, tr("Gradient color depth is 16 bits."), tr("16-bits gradient will be converted to 8-bits gradient.")); Gradient newGradient = Gradient8(&newRender.gradient); ResetGradient(&newRender, newGradient); FreeGradient(newGradient); } ResetRenderingParameters(&fractalConfig, newRender); FreeRenderingParameters(newRender); adjustSpan(); emit renderingParametersChanged(this->render); refresh(); } void FractalExplorer::setGradient(const Gradient &gradient) { cancelActionIfNotFinished(); if (gradient.bytesPerComponent == 2) { QMessageBox::critical(this, tr("Gradient color depth is 16 bits."), tr("16-bits gradient will be converted to 8-bits gradient.")); } ResetGradient(&fractalConfig.render, gradient); adjustSpan(); emit renderingParametersChanged(render); refresh(); } void FractalExplorer::adjustSpan() { uint_fast32_t width = fractalImage.width; uint_fast32_t height = fractalImage.height; if (width != 0 && height != 0) { if (height / (double)width < 1) { mpfr_set(fractal.spanX, fractal.spanY, MPFR_RNDN); mpfr_mul_ui(fractal.spanX, fractal.spanX, width, MPFR_RNDN); mpfr_div_ui(fractal.spanX, fractal.spanX, height, MPFR_RNDN); } else { mpfr_set(fractal.spanY, fractal.spanX, MPFR_RNDN); mpfr_mul_ui(fractal.spanY, fractal.spanY, height, MPFR_RNDN); mpfr_div_ui(fractal.spanY, fractal.spanY, width, MPFR_RNDN); } reInitFractal(); } } void FractalExplorer::restoreInitialState() { setFractalConfig(initialFractalConfig); } const FractalConfig &FractalExplorer::getFractalConfig() const { return fractalConfig; } const Fractal &FractalExplorer::getFractal() const { return fractal; } const RenderingParameters &FractalExplorer::getRender() const { return render; } void FractalExplorer::resizeImage(uint_fast32_t width, uint_fast32_t height) { if (height == 0) { if (mpfr_cmp_ui(fractal.spanX, 0) == 0) { height = width; } else { mpfr_t tmp; mpfr_div(tmp, fractal.spanY, fractal.spanX, MPFR_RNDN); mpfr_mul_ui(tmp, tmp, width, MPFR_RNDN); height = mpfr_get_ld(tmp, MPFR_RNDN); } } double dx = width - (double)fractalImage.width; double dy = height - (double)fractalImage.height; if (fractalImage.width != 0) { mpfr_mul_d(fractal.spanX, fractal.spanX, 1. + dx/fractalImage.width, MPFR_RNDN); } if (fractalImage.height != 0) { mpfr_mul_d(fractal.spanY, fractal.spanY, 1. + dy/fractalImage.height, MPFR_RNDN); } reInitFractal(); cancelActionIfNotFinished(); Image newImage, oldImage; QImage *newQImage, *oldQImage; newQImage = new QImage(width, height, QImage::Format_RGB32); newQImage->fill(0); QPainter painter(newQImage); painter.setRenderHint(QPainter::SmoothPixmapTransform); QRectF srcRect(std::max(0.,-dx/2), std::max(0.,-dy/2), fractalImage.width+std::min(0.,dx), fractalImage.height+std::min(0.,dy)); QRectF dstRect(std::max(0.,dx/2), std::max(0.,dy/2), fractalImage.width-std::max(0.,-dx), fractalImage.height-std::max(0.,-dy)); painter.drawImage(dstRect, *fractalQImage, srcRect); CreateImage2(&newImage, newQImage->bits(), width, height, 1); oldImage = fractalImage; oldQImage = fractalQImage; fractalImage = newImage; fractalQImage = newQImage; FreeImage(oldImage); delete oldQImage; updateGeometry(); emit fractalChanged(fractal); refresh(); } void FractalExplorer::resizeEvent(QResizeEvent * event) { QSize size(event->size()); resizeImage(size.width(), size.height()); } void FractalExplorer::paintEvent(QPaintEvent *event) { UNUSED(event); setFocusPolicy(Qt::StrongFocus); if (fractalQImage != NULL) { QPainter painter(this); painter.setRenderHint(QPainter::SmoothPixmapTransform); if (!drawingPaused) { PauseTask(task); } painter.drawImage(fractalQImage->rect(), *fractalQImage, fractalQImage->rect()); if (!drawingPaused) { ResumeTask(task); } } } QSize FractalExplorer::sizeHint() const { if (fractalQImage == NULL) { return QSize(0, 0); } else { return fractalQImage->size(); } } void FractalExplorer::reInitFractal() { Fractal newFractal; InitFractal(&newFractal, fractal.fractalFormula, fractal.p, fractal.c, fractal.centerX, fractal.centerY, fractal.spanX, fractal.spanY, fractal.escapeRadius, fractal.maxIter); Fractal oldFractal = fractal; fractal = newFractal; FreeFractal(oldFractal); } void FractalExplorer::reInitRenderingParameters() { InitRenderingParameters(&render, render.bytesPerComponent, render.spaceColor, render.iterationCount, render.coloringMethod, render.addendFunction, render.stripeDensity, render.interpolationMethod, render.transferFunction, render.multiplier, render.offset, render.gradient); } /* Assumes that action is finished.*/ void FractalExplorer::launchFractalDrawing() { /* Free previous action. Safe even for first launching * because action has been initialized to doNothingAction(). */ FreeTask(task); redrawFractal = false; lastActionType = A_FractalDrawing; task = CreateDrawFractalTask(&fractalImage, &fractal, &render, solidGuessing ? quadInterpolationSize : 1, colorDissimilarityThreshold, floatPrecision, pCache, threads->N); LaunchTask(task, threads); if (drawingPaused) { PauseTask(task); } } /* Assumes that action is finished.*/ void FractalExplorer::launchFractalAntiAliasing() { FreeTask(task); lastActionType = A_FractalAntiAliasing; task = CreateAntiAliaseFractalTask(&fractalImage, &fractal, &render, currentAntiAliasingSize, adaptiveAAMThreshold, floatPrecision, NULL, threads->N); LaunchTask(task, threads); if (drawingPaused) { PauseTask(task); } } int FractalExplorer::cancelActionIfNotFinished() { int finished = TaskIsFinished(task); if (!finished) { CancelTask(task); if (drawingPaused) { ResumeTask(task); } int unused = GetTaskResult(task); UNUSED(unused); } return finished; } void FractalExplorer::onTimeout() { bool updateNeeded = true; if (redrawFractal) { cancelActionIfNotFinished(); launchFractalDrawing(); } else { if (TaskIsFinished(task) && GetTaskResult(task) == 0) { if (lastActionType == A_FractalDrawing) { currentAntiAliasingSize = minAntiAliasingSize; launchFractalAntiAliasing(); } else if (currentAntiAliasingSize < maxAntiAliasingSize) { currentAntiAliasingSize += antiAliasingSizeIteration; if (currentAntiAliasingSize > maxAntiAliasingSize) { currentAntiAliasingSize = maxAntiAliasingSize; } launchFractalAntiAliasing(); } else { updateNeeded = false; } } } if (updateNeeded) { update(); } } int FractalExplorer::stopDrawing() { return cancelActionIfNotFinished(); } void FractalExplorer::pauseDrawing() { drawingPaused = true; PauseTask(task); } void FractalExplorer::resumeDrawing() { drawingPaused = false; ResumeTask(task); } void FractalExplorer::refresh() { redrawFractal = true; update(); } void FractalExplorer::moveFractal(const mpfr_t dx, const mpfr_t dy, bool emitFractalChanged) { cancelActionIfNotFinished(); mpfr_t absdx, absdy; mpfr_init(absdx); mpfr_init(absdy); mpfr_abs(absdx, dx, MPFR_RNDN); mpfr_abs(absdy, dy, MPFR_RNDN); if (mpfr_cmp_ui(fractal.spanX, 0) == 0 || mpfr_cmp_ui(fractal.spanY, 0) == 0 || mpfr_cmp(absdx, fractal.spanX) >= 0 || mpfr_cmp(absdy, fractal.spanY) >= 0) { fractalQImage->fill(0); } else { QImage copiedImage(fractalQImage->copy()); fractalQImage->fill(0); QPainter painter(fractalQImage); painter.setRenderHint(QPainter::SmoothPixmapTransform); mpfr_t imgdx, imgdy; mpfr_init(imgdx); mpfr_init(imgdy); mpfr_div(imgdx, dx, fractal.spanX, MPFR_RNDN); mpfr_mul_ui(imgdx, imgdx, fractalQImage->width(), MPFR_RNDN); mpfr_div(imgdy, dy, fractal.spanY, MPFR_RNDN); mpfr_mul_ui(imgdy, imgdy, fractalQImage->height(), MPFR_RNDN); long double ddx = mpfr_get_ld(imgdx, MPFR_RNDN); long double ddy = mpfr_get_ld(imgdy, MPFR_RNDN); QRectF srcRect = QRectF(std::max((long double)0, ddx), std::max((long double)0, ddy), fractalImage.width-fabsl(ddx), fractalImage.height-fabsl(ddy)); QRectF dstRect = QRectF(std::max((long double)0, -ddx), std::max((long double)0, -ddy), fractalImage.width-fabsl(ddx), fractalImage.height-fabsl(ddy)); painter.drawImage(dstRect, copiedImage, srcRect); mpfr_clear(imgdx); mpfr_clear(imgdy); } mpfr_clear(absdx); mpfr_clear(absdy); mpfr_add(fractal.centerX, fractal.centerX, dx, MPFR_RNDN); mpfr_add(fractal.centerY, fractal.centerY, dy, MPFR_RNDN); //fractal.centerX += dx; //fractal.centerY += dy; reInitFractal(); if (emitFractalChanged) { emit fractalChanged(fractal); } refresh(); } void FractalExplorer::moveLeftFractal() { mpfr_t dx, tmp; mpfr_init(dx); mpfr_init(tmp); if (mpfr_cmp_ui(fractal.spanX, 0) == 0) { mpfr_set_ld(dx, -MIN_SINGLE_STEP, MPFR_RNDN); } else { /* We use modf to have a multiple of image width, * so that the temporary qimage matches the * fractal image that will be computed exactly. */ mpfr_set_ld(tmp, -0.2 * fractalImage.width, MPFR_RNDN); mpfr_modf(dx, tmp, tmp, MPFR_RNDN); mpfr_mul(dx, dx, fractal.spanX, MPFR_RNDN); mpfr_div_ui(dx, dx, fractalImage.width, MPFR_RNDN); } mpfr_set_ui(tmp, 0, MPFR_RNDN); moveFractal(dx, tmp, true); mpfr_clear(dx); mpfr_clear(tmp); } void FractalExplorer::moveRightFractal() { mpfr_t dx, tmp; mpfr_init(dx); mpfr_init(tmp); if (mpfr_cmp_ui(fractal.spanX, 0) == 0) { mpfr_set_ld(dx, MIN_SINGLE_STEP, MPFR_RNDN); } else { mpfr_set_ld(tmp, 0.2 * fractalImage.width, MPFR_RNDN); mpfr_modf(dx, tmp, tmp, MPFR_RNDN); mpfr_mul(dx, dx, fractal.spanX, MPFR_RNDN); mpfr_div_ui(dx, dx, fractalImage.width, MPFR_RNDN); } mpfr_set_ui(tmp, 0, MPFR_RNDN); moveFractal(dx, tmp, true); mpfr_clear(dx); mpfr_clear(tmp); } void FractalExplorer::moveUpFractal() { mpfr_t dy, tmp; mpfr_init(dy); mpfr_init(tmp); if (mpfr_cmp_ui(fractal.spanY,0) == 0) { mpfr_set_ld(dy, -MIN_SINGLE_STEP, MPFR_RNDN); } else { mpfr_set_ld(tmp, -0.2 * fractalImage.height, MPFR_RNDN); mpfr_modf(dy, tmp, tmp, MPFR_RNDN); mpfr_mul(dy, dy, fractal.spanY, MPFR_RNDN); mpfr_div_ui(dy, dy, fractalImage.height, MPFR_RNDN); } mpfr_set_ui(tmp, 0, MPFR_RNDN); moveFractal(tmp, dy, true); mpfr_clear(dy); mpfr_clear(tmp); } void FractalExplorer::moveDownFractal() { mpfr_t dy, tmp; mpfr_init(dy); mpfr_init(tmp); if (mpfr_cmp_ui(fractal.spanY,0) == 0) { mpfr_set_ld(dy, MIN_SINGLE_STEP, MPFR_RNDN); } else { mpfr_set_ld(tmp, 0.2 * fractalImage.height, MPFR_RNDN); mpfr_modf(dy, tmp, tmp, MPFR_RNDN); mpfr_mul(dy, dy, fractal.spanY, MPFR_RNDN); mpfr_div_ui(dy, dy, fractalImage.height, MPFR_RNDN); } mpfr_set_ui(tmp, 0, MPFR_RNDN); moveFractal(tmp, dy, true); mpfr_clear(dy); mpfr_clear(tmp); } void FractalExplorer::zoomInFractal(const mpfr_t newSpanX, const mpfr_t zoomCenterX, const mpfr_t zoomCenterY, bool emitFractalChanged) { cancelActionIfNotFinished(); if (mpfr_cmp_ui(newSpanX, 0) == 0) { fractalQImage->fill(0); mpfr_set_ui(fractal.spanX, 0, MPFR_RNDN); mpfr_set_ui(fractal.spanY, 0, MPFR_RNDN); } else { mpfr_t newSpanY, newCenterX, newCenterY, ratioSpanX; mpfr_init(newSpanY); mpfr_init(newCenterX); mpfr_init(newCenterY); mpfr_init(ratioSpanX); mpfr_div(ratioSpanX, newSpanX, fractal.spanX, MPFR_RNDN); mpfr_mul_ui(newSpanY, newSpanX, fractalImage.height, MPFR_RNDN); mpfr_div_ui(newSpanY, newSpanY, fractalImage.width, MPFR_RNDN); mpfr_sub(newCenterX, fractal.centerX, zoomCenterX, MPFR_RNDN); mpfr_mul(newCenterX, newCenterX, ratioSpanX, MPFR_RNDN); mpfr_add(newCenterX, newCenterX, zoomCenterX, MPFR_RNDN); mpfr_sub(newCenterY, fractal.centerY, zoomCenterY, MPFR_RNDN); mpfr_mul(newCenterY, newCenterY, newSpanY, MPFR_RNDN); mpfr_div(newCenterY, newCenterY, fractal.spanY, MPFR_RNDN); mpfr_add(newCenterY, newCenterY, zoomCenterY, MPFR_RNDN); QImage copiedImage(fractalQImage->copy()); fractalQImage->fill(0); QPainter painter(fractalQImage); painter.setRenderHint(QPainter::SmoothPixmapTransform); QRect dstRect(fractalQImage->rect()); QRectF srcRect(0, 0, dstRect.width() * mpfr_get_ld(ratioSpanX,MPFR_RNDN), dstRect.height() * mpfr_get_ld(ratioSpanX,MPFR_RNDN)); mpfr_t srcRectCenterX, srcRectCenterY; mpfr_init(srcRectCenterX); mpfr_init(srcRectCenterY); mpfr_sub(srcRectCenterX, newCenterX, fractal.x1, MPFR_RNDN); mpfr_div(srcRectCenterX, srcRectCenterX, fractal.spanX, MPFR_RNDN); mpfr_mul_ui(srcRectCenterX, srcRectCenterX, fractalQImage->width(), MPFR_RNDN); mpfr_sub(srcRectCenterY, newCenterY, fractal.y1, MPFR_RNDN); mpfr_div(srcRectCenterY, srcRectCenterY, fractal.spanY, MPFR_RNDN); mpfr_mul_ui(srcRectCenterY, srcRectCenterY, fractalQImage->height(), MPFR_RNDN); srcRect.moveCenter(QPointF(mpfr_get_ld(srcRectCenterX, MPFR_RNDN), mpfr_get_ld(srcRectCenterY, MPFR_RNDN))); painter.drawImage(dstRect, copiedImage, srcRect); mpfr_set(fractal.centerX, newCenterX, MPFR_RNDN); mpfr_set(fractal.centerY, newCenterY, MPFR_RNDN); mpfr_set(fractal.spanX, newSpanX, MPFR_RNDN); mpfr_set(fractal.spanY, newSpanY, MPFR_RNDN); mpfr_clear(newSpanY); mpfr_clear(newCenterX); mpfr_clear(newCenterY); mpfr_clear(ratioSpanX); mpfr_clear(srcRectCenterX); mpfr_clear(srcRectCenterY); } reInitFractal(); if (emitFractalChanged) { emit fractalChanged(fractal); } refresh(); } void FractalExplorer::zoomOutFractal(const mpfr_t newSpanX, const mpfr_t zoomCenterX, const mpfr_t zoomCenterY, bool emitFractalChanged) { cancelActionIfNotFinished(); if (mpfr_cmp_ui(newSpanX,0) == 0) { fractalQImage->fill(0); mpfr_set_ui(fractal.spanX, 0, MPFR_RNDN); mpfr_set_ui(fractal.spanY, 0, MPFR_RNDN); } else { mpfr_t newSpanY, newCenterX, newCenterY, ratioSpanX; mpfr_init(newSpanY); mpfr_init(newCenterX); mpfr_init(newCenterY); mpfr_init(ratioSpanX); mpfr_div(ratioSpanX, newSpanX, fractal.spanX, MPFR_RNDN); mpfr_mul_ui(newSpanY, newSpanX, fractalImage.height, MPFR_RNDN); mpfr_div_ui(newSpanY, newSpanY, fractalImage.width, MPFR_RNDN); if (mpfr_cmp_ui(fractal.spanX,0) == 0 || mpfr_cmp_ui(fractal.spanY,0) == 0) { mpfr_set(newCenterX, zoomCenterX, MPFR_RNDN); mpfr_set(newCenterY, zoomCenterY, MPFR_RNDN); } else { mpfr_sub(newCenterX, fractal.centerX, zoomCenterX, MPFR_RNDN); mpfr_mul(newCenterX, newCenterX, ratioSpanX, MPFR_RNDN); mpfr_add(newCenterX, newCenterX, zoomCenterX, MPFR_RNDN); mpfr_sub(newCenterY, fractal.centerY, zoomCenterY, MPFR_RNDN); mpfr_mul(newCenterY, newCenterY, newSpanY, MPFR_RNDN); mpfr_div(newCenterY, newCenterY, fractal.spanY, MPFR_RNDN); mpfr_add(newCenterY, newCenterY, zoomCenterY, MPFR_RNDN); } QImage copiedImage(fractalQImage->copy()); fractalQImage->fill(0); QPainter painter(fractalQImage); painter.setRenderHint(QPainter::SmoothPixmapTransform); QRect srcRect(fractalQImage->rect()); QRectF dstRect(0, 0, srcRect.width() / mpfr_get_ld(ratioSpanX, MPFR_RNDN), srcRect.height() / mpfr_get_ld(ratioSpanX, MPFR_RNDN)); mpfr_t dstRectCenterX, dstRectCenterY; mpfr_init(dstRectCenterX); mpfr_init(dstRectCenterY); mpfr_div_ui(dstRectCenterX, newSpanX, 2, MPFR_RNDN); mpfr_sub(dstRectCenterX, newCenterX, dstRectCenterX, MPFR_RNDN); mpfr_sub(dstRectCenterX, fractal.centerX, dstRectCenterX, MPFR_RNDN); mpfr_div(dstRectCenterX, dstRectCenterX, newSpanX, MPFR_RNDN); mpfr_mul_ui(dstRectCenterX, dstRectCenterX, srcRect.width(), MPFR_RNDN); mpfr_div_ui(dstRectCenterY, newSpanY, 2, MPFR_RNDN); mpfr_sub(dstRectCenterY, newCenterY, dstRectCenterY, MPFR_RNDN); mpfr_sub(dstRectCenterY, fractal.centerY, dstRectCenterY, MPFR_RNDN); mpfr_div(dstRectCenterY, dstRectCenterY, newSpanY, MPFR_RNDN); mpfr_mul_ui(dstRectCenterY, dstRectCenterY, srcRect.height(), MPFR_RNDN); dstRect.moveCenter(QPointF(mpfr_get_ld(dstRectCenterX, MPFR_RNDN), mpfr_get_ld(dstRectCenterY, MPFR_RNDN))); painter.drawImage(dstRect, copiedImage, srcRect); mpfr_set(fractal.centerX, newCenterX, MPFR_RNDN); mpfr_set(fractal.centerY, newCenterY, MPFR_RNDN); mpfr_set(fractal.spanX, newSpanX, MPFR_RNDN); mpfr_set(fractal.spanY, newSpanY, MPFR_RNDN); mpfr_clear(newSpanY); mpfr_clear(newCenterX); mpfr_clear(newCenterY); mpfr_clear(ratioSpanX); mpfr_clear(dstRectCenterX); mpfr_clear(dstRectCenterY); } reInitFractal(); if (emitFractalChanged) { emit fractalChanged(fractal); } refresh(); } void FractalExplorer::zoomInFractal() { mpfr_t newSpanX, tmp; mpfr_init(newSpanX); mpfr_init(tmp); if (mpfr_cmp_ui(fractal.spanX,0) == 0) { mpfr_set_ld(newSpanX, MIN_SINGLE_STEP, MPFR_RNDN); } else { mpfr_set_ld(tmp, (1 - 0.3) * fractalImage.width, MPFR_RNDN); mpfr_modf(newSpanX, tmp, tmp, MPFR_RNDN); mpfr_mul(newSpanX, newSpanX, fractal.spanX, MPFR_RNDN); mpfr_div_ui(newSpanX, newSpanX, fractalImage.width, MPFR_RNDN); } zoomInFractal(newSpanX, fractal.centerX, fractal.centerY, true); mpfr_clear(newSpanX); mpfr_clear(tmp); } void FractalExplorer::zoomOutFractal() { mpfr_t newSpanX, tmp; mpfr_init(newSpanX); mpfr_init(tmp); if (mpfr_cmp_ui(fractal.spanX,0) == 0) { mpfr_set_ld(newSpanX, MIN_SINGLE_STEP, MPFR_RNDN); } else { mpfr_set_ld(tmp, (1 + 0.3) * fractalImage.width, MPFR_RNDN); mpfr_modf(newSpanX, tmp, tmp, MPFR_RNDN); mpfr_mul(newSpanX, newSpanX, fractal.spanX, MPFR_RNDN); mpfr_div_ui(newSpanX, newSpanX, fractalImage.width, MPFR_RNDN); } zoomOutFractal(newSpanX, fractal.centerX, fractal.centerY, true); mpfr_clear(newSpanX); mpfr_clear(tmp); } void FractalExplorer::mousePressEvent(QMouseEvent *event) { if (fractalMoved) { emit fractalChanged(fractal); refresh(); } movingFractalDeferred = false; movingFractalRealTime = false; fractalMoved = false; QApplication::restoreOverrideCursor(); switch (event->button()) { case Qt::LeftButton: movingFractalDeferred = true; mpfr_set(fractalCenterXOnPress, fractal.centerX, MPFR_RNDN); mpfr_set(fractalCenterYOnPress, fractal.centerY, MPFR_RNDN); mousePosOnPress = event->posF(); QApplication::setOverrideCursor(Qt::ClosedHandCursor); break; case Qt::MidButton: movingFractalRealTime = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); break; default: QLabel::mousePressEvent(event); } prevMousePos = event->posF(); } void FractalExplorer::mouseReleaseEvent(QMouseEvent *event) { switch (event->button()) { case Qt::LeftButton: if (movingFractalDeferred) { if (fractalMoved) { emit fractalChanged(fractal); refresh(); } movingFractalDeferred = false; fractalMoved = false; QApplication::restoreOverrideCursor(); } break; case Qt::MidButton: if (movingFractalRealTime) { movingFractalRealTime = false; QApplication::restoreOverrideCursor(); } break; default: QLabel::mouseReleaseEvent(event); } } void FractalExplorer::mouseMoveEvent(QMouseEvent *event) { if (movingFractalDeferred) { if (!fractalMoved) { cancelActionIfNotFinished(); imageCopyOnPress = fractalQImage->copy(); } fractalMoved = true; QVector2D vect(event->posF()-mousePosOnPress); mpfr_t dx, dy; mpfr_init(dx); mpfr_init(dy); mpfr_mul_d(dx, fractal.spanX, vect.x(), MPFR_RNDN); mpfr_div_ui(dx, dx, fractalImage.width, MPFR_RNDN); mpfr_mul_d(dy, fractal.spanY, vect.y(), MPFR_RNDN); mpfr_div_ui(dy, dy, fractalImage.height, MPFR_RNDN); fractalQImage->fill(0); QPainter painter(fractalQImage); painter.setRenderHint(QPainter::SmoothPixmapTransform); double ddx = vect.x(); double ddy = vect.y(); QRectF srcRect = QRectF(std::max((double)0, -ddx), std::max((double)0, -ddy), fractalImage.width - fabs(ddx), fractalImage.height - fabs(ddy)); QRectF dstRect = QRectF(std::max((double)0, ddx), std::max((double)0, ddy), fractalImage.width - fabs(ddx), fractalImage.height - fabs(ddy)); painter.drawImage(dstRect, imageCopyOnPress, srcRect); mpfr_sub(fractal.centerX, fractalCenterXOnPress, dx, MPFR_RNDN); mpfr_sub(fractal.centerY, fractalCenterYOnPress, dy, MPFR_RNDN); mpfr_clear(dx); mpfr_clear(dy); reInitFractal(); emit fractalChanged(fractal); } else if (movingFractalRealTime) { QVector2D vect(event->posF()-prevMousePos); mpfr_t dx, dy; mpfr_init(dx); mpfr_init(dy); mpfr_mul_d(dx, fractal.spanX, -vect.x(), MPFR_RNDN); mpfr_div_ui(dx, dx, fractalImage.width, MPFR_RNDN); mpfr_mul_d(dy, fractal.spanY, -vect.y(), MPFR_RNDN); mpfr_div_ui(dy, dy, fractalImage.height, MPFR_RNDN); moveFractal(dx, dy, true); prevMousePos = event->posF(); mpfr_clear(dx); mpfr_clear(dy); } else { QLabel::mouseMoveEvent(event); } update(); } static inline double signl(double x) { return (x > 0) ? 1 : -1; } void FractalExplorer::wheelEvent(QWheelEvent *event) { if (movingFractalDeferred) { if (fractalMoved) { emit fractalChanged(fractal); refresh(); } movingFractalDeferred = false; fractalMoved = false; QApplication::restoreOverrideCursor(); } double numDegrees = event->delta() / 8.; double numSteps = numDegrees / 15; if (event->orientation() == Qt::Vertical) { mpfr_t newSpanX; mpfr_init(newSpanX); if (mpfr_cmp_ui(fractal.spanX, 0) == 0) { mpfr_set_ld(newSpanX, MIN_SINGLE_STEP, MPFR_RNDN); } else { mpfr_mul_d(newSpanX, fractal.spanX, powl(1 - signl(numSteps)*0.3, fabsl(numSteps)), MPFR_RNDN); } mpfr_t zoomCenterX, zoomCenterY; mpfr_init(zoomCenterX); mpfr_init(zoomCenterY); if (mpfr_cmp_ui(fractal.spanX,0) == 0 || mpfr_cmp_ui(fractal.spanY,0) == 0) { mpfr_set(zoomCenterX, fractal.centerX, MPFR_RNDN); mpfr_set(zoomCenterY, fractal.centerY, MPFR_RNDN); } else { mpfr_mul_d(zoomCenterX, fractal.spanX, (event->x() + 0.5) / fractalImage.width, MPFR_RNDN); mpfr_add(zoomCenterX, zoomCenterX, fractal.x1, MPFR_RNDN); mpfr_mul_d(zoomCenterY, fractal.spanY, (event->y() + 0.5) / fractalImage.height, MPFR_RNDN); mpfr_add(zoomCenterY, zoomCenterY, fractal.y1, MPFR_RNDN); } if (numSteps > 0) { zoomInFractal(newSpanX, zoomCenterX, zoomCenterY, true); } else { zoomOutFractal(newSpanX, zoomCenterX, zoomCenterY, true); } mpfr_clear(newSpanX); mpfr_clear(zoomCenterX); mpfr_clear(zoomCenterY); } event->accept(); update(); } void FractalExplorer::setFractalFormula(int index) { cancelActionIfNotFinished(); fractal.fractalFormula = (FractalFormula)index; reInitFractal(); emit fractalChanged(fractal); refresh(); } void FractalExplorer::setPParam(const mpc_t *value) { cancelActionIfNotFinished(); mpc_set(fractal.p, *value, MPC_RNDNN); reInitFractal(); refresh(); } void FractalExplorer::setPParamRe(const mpfr_t *value) { cancelActionIfNotFinished(); mpfr_t im; mpfr_init(im); mpfr_set(im, mpc_imagref(fractal.p), MPFR_RNDN); mpc_set_fr_fr(fractal.p, *value, im, MPC_RNDNN); mpfr_clear(im); reInitFractal(); refresh(); } void FractalExplorer::setPParamIm(const mpfr_t *value) { cancelActionIfNotFinished(); mpfr_t re; mpfr_init(re); mpfr_set(re, mpc_realref(fractal.p), MPFR_RNDN); mpc_set_fr_fr(fractal.p, re, *value, MPC_RNDNN); mpfr_clear(re); reInitFractal(); refresh(); } void FractalExplorer::setCParamRe(const mpfr_t *value) { cancelActionIfNotFinished(); mpfr_t im; mpfr_init(im); mpfr_set(im, mpc_imagref(fractal.c), MPFR_RNDN); mpc_set_fr_fr(fractal.c, *value, im, MPC_RNDNN); mpfr_clear(im); reInitFractal(); refresh(); } void FractalExplorer::setCParamIm(const mpfr_t *value) { cancelActionIfNotFinished(); mpfr_t re; mpfr_init(re); mpfr_set(re, mpc_realref(fractal.c), MPFR_RNDN); mpc_set_fr_fr(fractal.c, re, *value, MPC_RNDNN); mpfr_clear(re); reInitFractal(); refresh(); } void FractalExplorer::setCenterX(const mpfr_t *value) { mpfr_t dx, dy; mpfr_init(dx); mpfr_init(dy); mpfr_sub(dx, *value, fractal.centerX, MPFR_RNDN); mpfr_set_ui(dy, 0, MPFR_RNDN); moveFractal(dx, dy); mpfr_clear(dx); mpfr_clear(dy); } void FractalExplorer::setCenterY(const mpfr_t *value) { mpfr_t dx, dy; mpfr_init(dx); mpfr_init(dy); mpfr_set_ui(dx, 0, MPFR_RNDN); mpfr_sub(dy, *value, fractal.centerY, MPFR_RNDN); moveFractal(dx, dy); mpfr_clear(dx); mpfr_clear(dy); } void FractalExplorer::setSpanX(const mpfr_t *value) { if (mpfr_cmp(*value, fractal.spanX) > 0) { /* Zoom out */ zoomOutFractal(*value, fractal.centerX, fractal.centerY); } else { /* Zoom in */ zoomInFractal(*value, fractal.centerX, fractal.centerY); } } void FractalExplorer::setBailoutRadius(double value) { cancelActionIfNotFinished(); fractal.escapeRadius = value; reInitFractal(); refresh(); } void FractalExplorer::setMaxIterations(int value) { cancelActionIfNotFinished(); fractal.maxIter = value; reInitFractal(); refresh(); } void FractalExplorer::setAddendFunction(int index) { cancelActionIfNotFinished(); render.addendFunction = (AddendFunction)index; reInitRenderingParameters(); refresh(); } void FractalExplorer::setStripeDensity(int value) { cancelActionIfNotFinished(); render.stripeDensity = value; reInitRenderingParameters(); refresh(); } void FractalExplorer::setColoringMethod(int index) { cancelActionIfNotFinished(); render.coloringMethod = (ColoringMethod)index; reInitRenderingParameters(); refresh(); } void FractalExplorer::setIterationCount(int index) { cancelActionIfNotFinished(); render.iterationCount = (IterationCount)index; reInitRenderingParameters(); refresh(); } void FractalExplorer::setInterpolationMethod(int index) { cancelActionIfNotFinished(); render.interpolationMethod = (InterpolationMethod)index; reInitRenderingParameters(); refresh(); } void FractalExplorer::setTransferFunction(int index) { cancelActionIfNotFinished(); render.transferFunction = (TransferFunction)index; reInitRenderingParameters(); refresh(); } void FractalExplorer::setColorScaling(double value) { cancelActionIfNotFinished(); render.multiplier = value; reInitRenderingParameters(); refresh(); } void FractalExplorer::setColorOffset(double value) { cancelActionIfNotFinished(); render.offset = value; reInitRenderingParameters(); refresh(); } void FractalExplorer::setSpaceColor(const QColor &color) { cancelActionIfNotFinished(); render.spaceColor = ColorFromRGB(1, (uint16_t)color.red(), (uint16_t)color.green(), (uint16_t)color.blue()); reInitRenderingParameters(); refresh(); } inline static bool pos_less_than(const QGradientStop &s1, const QGradientStop &s2) { return s1.first < s2.first; } void FractalExplorer::setGradient(const QGradientStops &gradientStops) { if (gradientStops.size() < 2) { /* Emit signal to be sure that fractal explorer's gradient * matches rendering widget's gradient box. */ emit renderingParametersChanged(render); return; } cancelActionIfNotFinished(); /* First, sort gradient stops.*/ QGradientStops sortedGradientStops(gradientStops); qSort(sortedGradientStops.begin(), sortedGradientStops.end(), pos_less_than); /* Now create well formed gradient stops, i.e. first gradient * stop position must be 0, last must be 1, and positions * must be strictly increasing ("duplicates" are skipped). */ bool wellFormed = 1; QGradientStops wellFormedGradientStops; /* First position must be 0.*/ if (sortedGradientStops[0].first != 0) { wellFormed = 0; } wellFormedGradientStops << QPair(0, sortedGradientStops[0].second); for (int i = 1; i < sortedGradientStops.size(); ++i) { /* Positions should be strictly increasing.*/ if (sortedGradientStops[i].first <= wellFormedGradientStops[i-1].first) { wellFormed = 0; continue; } wellFormedGradientStops << sortedGradientStops[i]; } /* Last position must be 1.*/ if (wellFormedGradientStops.last().first != 1) { wellFormedGradientStops.last() = QPair(1, wellFormedGradientStops.last().second); wellFormed = 0; } /* Now gradient FractalNow gradient from well formed gradient.*/ double positionStop[wellFormedGradientStops.size()]; Color colorStop[wellFormedGradientStops.size()]; QGradientStop currentStop; for (int i = 0; i < wellFormedGradientStops.size(); ++i) { currentStop = wellFormedGradientStops[i]; positionStop[i] = currentStop.first; colorStop[i] = ColorFromUint32(currentStop.second.rgb()); } /* Replace old gradient.*/ Gradient oldGradient = render.gradient; GenerateGradient(&render.gradient, wellFormedGradientStops.size(), positionStop, colorStop, DEFAULT_GRADIENT_SIZE); FreeGradient(oldGradient); reInitRenderingParameters(); refresh(); if (!wellFormed) { emit renderingParametersChanged(render); } } void FractalExplorer::setFloatPrecision(int index) { cancelActionIfNotFinished(); floatPrecision = (FloatPrecision)index; refresh(); } void FractalExplorer::contextMenuEvent(QContextMenuEvent *event) { QMenu menu(this); menu.addAction(restoreInitialStateAction); menu.addSeparator(); menu.addAction(stopDrawingAction); menu.addAction(refreshAction); menu.addSeparator(); menu.addAction(zoomInAction); menu.addAction(zoomOutAction); menu.addSeparator(); menu.addAction(moveLeftAction); menu.addAction(moveRightAction); menu.addAction(moveUpAction); menu.addAction(moveDownAction); QAction *action = menu.exec(event->globalPos()); UNUSED(action); } fractalnow-0.8.1/gui/src/main.cpp0000664000175000017500000000240311754747533015346 0ustar mpegmpeg/* * main.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "main.h" #include "main_window.h" #include int main(int argc, char *argv[]) { QApplication::setGraphicsSystem(QString("raster")); QApplication::setApplicationName("QFractalNow"); QApplication::setOrganizationName("fractalnow"); QApplication::setApplicationVersion(QString(FractalNow_VersionNumber())); QApplication app(argc, argv); MainWindow mainWindow(argc, argv); mainWindow.show(); return app.exec(); } fractalnow-0.8.1/gui/src/gradient_dialog.cpp0000664000175000017500000000425211754747533017542 0ustar mpegmpeg/* * gradient_dialog.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gradient_dialog.h" GradientDialog::GradientDialog(const QGradientStops &gradientStops, QWidget *parent, Qt::WindowFlags f) : QDialog(parent,f) { setWindowTitle(tr("Edit gradient")); this->gradientStops = gradientStops; gradientEditor = new GradientEditor; gradientEditor->blockSignals(true); connect(gradientEditor, SIGNAL(gradientStopsChanged(const QGradientStops&)), this, SLOT(onGradientStopsChanged(const QGradientStops&))); QDialogButtonBox *dialogButtonBox = new QDialogButtonBox(this); QPushButton *cancelButton = dialogButtonBox->addButton(QDialogButtonBox::Cancel); connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); QPushButton *OkButton = dialogButtonBox->addButton(QDialogButtonBox::Ok); connect(OkButton, SIGNAL(clicked()), this, SLOT(accept())); QVBoxLayout *vBoxLayout = new QVBoxLayout; vBoxLayout->addWidget(gradientEditor); vBoxLayout->addWidget(dialogButtonBox); setLayout(vBoxLayout); QTimer::singleShot(5, this, SLOT(initGradientEditor())); } const QGradientStops &GradientDialog::currentGradientStops() const { return gradientStops; } void GradientDialog::onGradientStopsChanged(const QGradientStops &gradientStops) { this->gradientStops = gradientStops; } void GradientDialog::initGradientEditor() { gradientEditor->setGradientStops(gradientStops); gradientEditor->blockSignals(false); } fractalnow-0.8.1/gui/src/shade_widget.cpp0000664000175000017500000001014311777303657017051 0ustar mpegmpeg/**************************************************************************** ** ** This file is based on some files of the demonstration applications of the ** Qt Toolkit. ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Modified to be used as a part of FractalNow: ** Copyright (c) 2012 Marc Pegon ** ** This file can be distributed and/or modified under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation. ** You should have received a copy of the GNU General Public License ** along with this file; if not, write to the Free Software Foundation, Inc., ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ****************************************************************************/ #include "shade_widget.h" ShadeWidget::ShadeWidget(ShadeType type, QWidget *parent) : QWidget(parent), m_shade_type(type), m_alpha_gradient(QLinearGradient()) { // Checkers background if (m_shade_type == ARGBShade) { QPixmap pm(20, 20); QPainter pmp(&pm); pmp.fillRect(0, 0, 10, 10, Qt::lightGray); pmp.fillRect(10, 10, 10, 10, Qt::lightGray); pmp.fillRect(0, 10, 10, 10, Qt::darkGray); pmp.fillRect(10, 0, 10, 10, Qt::darkGray); pmp.end(); QPalette pal = palette(); pal.setBrush(backgroundRole(), QBrush(pm)); setAutoFillBackground(true); setPalette(pal); } else { setAttribute(Qt::WA_NoBackground); } QPolygonF points; points << QPointF(0, sizeHint().height()) << QPointF(sizeHint().width(), 0); m_hoverPoints = new HoverPoints(this, HoverPoints::CircleShape); // m_hoverPoints->setConnectionType(HoverPoints::LineConnection); m_hoverPoints->setPoints(points); m_hoverPoints->setPointLock(0, HoverPoints::LockToLeft); m_hoverPoints->setPointLock(1, HoverPoints::LockToRight); m_hoverPoints->setSortType(HoverPoints::XSort); m_hoverPoints->setConnectionType(HoverPoints::LineConnection); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); connect(m_hoverPoints, SIGNAL(pointsChanged(QPolygonF)), this, SIGNAL(colorsChanged())); } QPolygonF ShadeWidget::points() const { return m_hoverPoints->points(); } unsigned int ShadeWidget::colorAt(int x) { generateShade(); QPolygonF pts = m_hoverPoints->points(); for (int i=1; i < pts.size(); ++i) { if (pts.at(i-1).x() <= x && pts.at(i).x() >= x) { QLineF l(pts.at(i-1), pts.at(i)); l.setLength(l.length() * ((x - l.x1()) / l.dx())); return m_shade.pixel(qRound(qMin(l.x2(), (qreal(m_shade.width() - 1)))), qRound(qMin(l.y2(), qreal(m_shade.height() - 1)))); } } return 0; } void ShadeWidget::setGradientStops(const QGradientStops &stops) { if (m_shade_type == ARGBShade) { m_alpha_gradient = QLinearGradient(0, 0, width(), 0); for (int i=0; i * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gradient_box.h" #include "gradient_dialog.h" #include "gradient_label.h" #include #include static QGradientStops getGradientStops(const Gradient &gradient) { uint_fast32_t nbStops = gradient.nbStops; Color c; QGradientStops gradientStops; for (uint_fast32_t i = 0; i < nbStops; ++i) { c = gradient.colorStop[i]; gradientStops << QGradientStop(gradient.positionStop[i], QColor(c.r, c.g, c.b)); } return gradientStops; } void GradientBox::initGradientBox(const QGradientStops &gradientStops) { this->gradientStops = gradientStops; QHBoxLayout *hBoxLayout = new QHBoxLayout; QToolButton *editGradientButton = new QToolButton(); editGradientButton->setText(tr("...")); connect(editGradientButton, SIGNAL(clicked()), this, SLOT(openGradientDialog())); gradientLabel = new GradientLabel(this); gradientLabel->setGradientStops(gradientStops); hBoxLayout->addWidget(gradientLabel); hBoxLayout->addWidget(editGradientButton); hBoxLayout->setSizeConstraint(QLayout::SetNoConstraint); hBoxLayout->setStretch(0, 1); this->setLayout(hBoxLayout); } GradientBox::GradientBox(const QGradientStops &gradientStops, QWidget *parent) : QWidget(parent) { initGradientBox(gradientStops); } GradientBox::GradientBox(const Gradient &gradient, QWidget *parent) : QWidget(parent) { QGradientStops gradientStops = getGradientStops(gradient); initGradientBox(gradientStops); } void GradientBox::setGradientStops(const QGradientStops &gradientStops) { this->gradientStops = gradientStops; gradientLabel->setGradientStops(gradientStops); } void GradientBox::setGradient(const Gradient &gradient) { QGradientStops gradientStops(getGradientStops(gradient)); setGradientStops(gradientStops); } void GradientBox::openGradientDialog() { GradientDialog dialog(gradientStops, this); if (dialog.exec() == QDialog::Accepted) { QGradientStops newGradientStops(dialog.currentGradientStops()); if (newGradientStops != gradientStops) { gradientStops = newGradientStops; gradientLabel->setGradientStops(gradientStops); emit gradientStopsChanged(gradientStops); } } } fractalnow-0.8.1/gui/src/gradient_label.cpp0000664000175000017500000000273411754747533017365 0ustar mpegmpeg/* * gradient_label.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gradient_label.h" #include GradientLabel::GradientLabel(QWidget *parent) : QLabel(parent) { gradientStops << QGradientStop(0, QColor::fromRgb(0x0)); gradientStops << QGradientStop(1, QColor::fromRgb(0xFFFFFF)); } void GradientLabel::setGradientStops(const QGradientStops &gradientStops) { this->gradientStops = gradientStops; update(); } void GradientLabel::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); QLinearGradient qGradient(rect().topLeft(), rect().topRight()); qGradient.setStops(gradientStops); painter.setBrush(qGradient); painter.setPen(Qt::NoPen); painter.drawRect(rect()); } fractalnow-0.8.1/gui/src/gradient_editor.cpp0000664000175000017500000000701711777303657017573 0ustar mpegmpeg/**************************************************************************** ** ** This file is based on some files of the demonstration applications of the ** Qt Toolkit. ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Modified to be used as a part of FractalNow: ** Copyright (c) 2012 Marc Pegon ** ** This file can be distributed and/or modified under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation. ** You should have received a copy of the GNU General Public License ** along with this file; if not, write to the Free Software Foundation, Inc., ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ****************************************************************************/ #include "gradient_editor.h" GradientEditor::GradientEditor(QWidget *parent) : QWidget(parent) { QVBoxLayout *vbox = new QVBoxLayout; vbox->setSpacing(1); vbox->setMargin(1); m_gradient_label = new GradientLabel; m_red_shade = new ShadeWidget(ShadeWidget::RedShade); m_green_shade = new ShadeWidget(ShadeWidget::GreenShade); m_blue_shade = new ShadeWidget(ShadeWidget::BlueShade); vbox->addWidget(m_gradient_label); vbox->addWidget(m_red_shade); vbox->addWidget(m_green_shade); vbox->addWidget(m_blue_shade); setLayout(vbox); connect(m_red_shade, SIGNAL(colorsChanged()), this, SLOT(pointsUpdated())); connect(m_green_shade, SIGNAL(colorsChanged()), this, SLOT(pointsUpdated())); connect(m_blue_shade, SIGNAL(colorsChanged()), this, SLOT(pointsUpdated())); } inline static bool x_less_than(const QPointF &p1, const QPointF &p2) { return p1.x() < p2.x(); } void GradientEditor::pointsUpdated() { qreal w = m_red_shade->width(); QGradientStops stops; QPolygonF points; points += m_red_shade->points(); points += m_green_shade->points(); points += m_blue_shade->points(); qSort(points.begin(), points.end(), x_less_than); for (int i=0; i0 && int(x) == int(points.at(i-1).x())) { continue; } QColor color((0x00ff0000 & m_red_shade->colorAt(int(x))) >> 16, (0x0000ff00 & m_green_shade->colorAt(int(x))) >> 8, (0x000000ff & m_blue_shade->colorAt(int(x)))); if (x / w > 1) { return; } stops << QGradientStop(x / w, color); } m_gradient_label->setGradientStops(stops); emit gradientStopsChanged(stops); } static void set_shade_points(const QPolygonF &points, ShadeWidget *shade) { shade->hoverPoints()->setPoints(points); shade->hoverPoints()->setPointLock(0, HoverPoints::LockToLeft); shade->hoverPoints()->setPointLock(points.size() - 1, HoverPoints::LockToRight); shade->update(); } void GradientEditor::setGradientStops(const QGradientStops &stops) { QPolygonF pts_red, pts_green, pts_blue; m_gradient_label->setGradientStops(stops); qreal h_red = m_red_shade->height(); qreal h_green = m_green_shade->height(); qreal h_blue = m_blue_shade->height(); for (int i=0; iwidth(), h_red - qRed(color) * h_red / 255); pts_green << QPointF(pos * m_green_shade->width(), h_green - qGreen(color) * h_green / 255); pts_blue << QPointF(pos * m_blue_shade->width(), h_blue - qBlue(color) * h_blue / 255); } set_shade_points(pts_red, m_red_shade); set_shade_points(pts_green, m_green_shade); set_shade_points(pts_blue, m_blue_shade); } fractalnow-0.8.1/gui/src/fractal_config_widget.cpp0000664000175000017500000001700011754747533020725 0ustar mpegmpeg/* * fractal_config_widget.cpp -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "main.h" #include "fractal_config_widget.h" #include #include #include FractalConfigWidget::FractalConfigWidget(const Fractal &fractal) : QWidget() { fractalFormulaComboBox = new QComboBox; for (uint_fast32_t i = 0; i < nbFractalFormulas; ++i) { fractalFormulaComboBox->addItem(fractalFormulaDescStr[i]); } pParamReSpinBox = new MPFRSpinBox; pParamReSpinBox->setDecimals(DEFAULT_DECIMALS_NUMBER); pParamReSpinBox->setRange(0, 100); pParamReSpinBox->setAccelerated(true); pParamImSpinBox = new MPFRSpinBox; pParamImSpinBox->setDecimals(DEFAULT_DECIMALS_NUMBER); pParamImSpinBox->setRange(0, 100); pParamImSpinBox->setAccelerated(true); cParamReSpinBox = new MPFRSpinBox; cParamReSpinBox->setDecimals(DEFAULT_DECIMALS_NUMBER); cParamReSpinBox->setRange(-100, 100); cParamReSpinBox->setAccelerated(true); cParamImSpinBox = new MPFRSpinBox; cParamImSpinBox->setDecimals(DEFAULT_DECIMALS_NUMBER); cParamImSpinBox->setRange(-100, 100); cParamImSpinBox->setAccelerated(true); centerXSpinBox = new MPFRSpinBox; centerXSpinBox->setRange(-100, 100); centerXSpinBox->setAccelerated(true); centerXSpinBox->setNotation(MPFRSpinBox::ScientificNotation); centerYSpinBox = new MPFRSpinBox; centerYSpinBox->setRange(-100, 100); centerYSpinBox->setAccelerated(true); centerYSpinBox->setNotation(MPFRSpinBox::ScientificNotation); spanXSpinBox = new MPFRSpinBox; spanXSpinBox->setRange(0, std::numeric_limits::max()); spanXSpinBox->setAccelerated(true); spanXSpinBox->setNotation(MPFRSpinBox::ScientificNotation); bailoutRadiusSpinBox = new QDoubleSpinBox; bailoutRadiusSpinBox->setDecimals(0); bailoutRadiusSpinBox->setRange(1, std::numeric_limits::max()); bailoutRadiusSpinBox->setAccelerated(true); maxIterationsSpinBox = new QSpinBox; maxIterationsSpinBox->setRange(1, std::numeric_limits::max()); maxIterationsSpinBox->setAccelerated(true); QFormLayout *formLayout = new QFormLayout; formLayout->addRow(tr("Fractal formula:"), fractalFormulaComboBox); formLayout->addRow(tr("p (Re):"), pParamReSpinBox); formLayout->addRow(tr("p (Im):"), pParamImSpinBox); formLayout->addRow(tr("c (Re):"), cParamReSpinBox); formLayout->addRow(tr("c (Im):"), cParamImSpinBox); formLayout->addRow(tr("Center X:"), centerXSpinBox); formLayout->addRow(tr("Center Y:"), centerYSpinBox); formLayout->addRow(tr("Span X:"), spanXSpinBox); formLayout->addRow(tr("Bailout radius:"), bailoutRadiusSpinBox); formLayout->addRow(tr("Max iterations:"), maxIterationsSpinBox); this->setLayout(formLayout); updateBoxesValues(fractal); updateSpaceBoxesSingleSteps(); updateCParamReSingleStep(); updateCParamImSingleStep(); updateBoxesEnabledValue(); connect(spanXSpinBox, SIGNAL(valueChanged(const mpfr_t *)), this, SLOT(updateSpaceBoxesSingleSteps())); connect(cParamReSpinBox, SIGNAL(valueChanged(const mpfr_t *)), this, SLOT(updateCParamReSingleStep())); connect(cParamImSpinBox, SIGNAL(valueChanged(const mpfr_t *)), this, SLOT(updateCParamImSingleStep())); connect(fractalFormulaComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateBoxesEnabledValue())); } void FractalConfigWidget::blockBoxesSignals(bool block) { fractalFormulaComboBox->blockSignals(block); pParamReSpinBox->blockSignals(block); pParamImSpinBox->blockSignals(block); cParamReSpinBox->blockSignals(block); cParamImSpinBox->blockSignals(block); centerXSpinBox->blockSignals(block); centerYSpinBox->blockSignals(block); spanXSpinBox->blockSignals(block); bailoutRadiusSpinBox->blockSignals(block); maxIterationsSpinBox->blockSignals(block); } void FractalConfigWidget::updateBoxesValues(const Fractal &fractal) { blockBoxesSignals(true); fractalFormulaComboBox->setCurrentIndex((int)fractal.fractalFormula); pParamReSpinBox->setValue(&mpc_realref(fractal.p)); pParamImSpinBox->setValue(&mpc_imagref(fractal.p)); cParamReSpinBox->setValue(&mpc_realref(fractal.c)); cParamImSpinBox->setValue(&mpc_imagref(fractal.c)); centerXSpinBox->setValue(&fractal.centerX); centerYSpinBox->setValue(&fractal.centerY); spanXSpinBox->setValue(&fractal.spanX); bailoutRadiusSpinBox->setValue(fractal.escapeRadius); maxIterationsSpinBox->setValue(fractal.maxIter); updateBoxesEnabledValue(); updateSpaceBoxesSingleSteps(); updateCParamReSingleStep(); updateCParamImSingleStep(); blockBoxesSignals(false); } void FractalConfigWidget::updateSpaceBoxesSingleSteps() { const mpfr_t * spanX = spanXSpinBox->value(); if (mpfr_cmp_ui(*spanX, 0) <= 0) { centerXSpinBox->setSingleStep(MIN_SINGLE_STEP); centerYSpinBox->setSingleStep(MIN_SINGLE_STEP); spanXSpinBox->setSingleStep(MIN_SINGLE_STEP); } else { mpfr_t step; mpfr_init(step); mpfr_div_ui(step, *spanX, 5, MPFR_RNDN); centerXSpinBox->setSingleStep(&step); centerYSpinBox->setSingleStep(&step); mpfr_mul_d(step, *spanX, 0.3, MPFR_RNDN); spanXSpinBox->setSingleStep(&step); mpfr_clear(step); } } void FractalConfigWidget::updateCParamReSingleStep() { const mpfr_t *cParamRe = cParamReSpinBox->value(); if (mpfr_cmp_ui(*cParamRe, 0) <= 0) { cParamReSpinBox->setSingleStep(MIN_SINGLE_STEP); } else { mpfr_t step; mpfr_init(step); mpfr_div_ui(step, *cParamRe, 5, MPFR_RNDN); cParamReSpinBox->setSingleStep(&step); mpfr_clear(step); } } void FractalConfigWidget::updateCParamImSingleStep() { const mpfr_t *cParamIm = cParamImSpinBox->value(); if (mpfr_cmp_ui(*cParamIm, 0) <= 0) { cParamImSpinBox->setSingleStep(MIN_SINGLE_STEP); } else { mpfr_t step; mpfr_init(step); mpfr_div_ui(step, *cParamIm, 5, MPFR_RNDN); cParamImSpinBox->setSingleStep(&step); mpfr_clear(step); } } void FractalConfigWidget::updateBoxesEnabledValue() { FractalFormula formula = (FractalFormula)fractalFormulaComboBox->currentIndex(); switch (formula) { case FRAC_MANDELBROT: pParamReSpinBox->setEnabled(false); pParamImSpinBox->setEnabled(false); cParamReSpinBox->setEnabled(false); cParamImSpinBox->setEnabled(false); break; case FRAC_MULTIBROT: case FRAC_BURNINGSHIP: case FRAC_MANDELBAR: pParamReSpinBox->setEnabled(true); pParamImSpinBox->setEnabled(true); cParamReSpinBox->setEnabled(false); cParamImSpinBox->setEnabled(false); break; case FRAC_JULIA: pParamReSpinBox->setEnabled(false); pParamImSpinBox->setEnabled(false); cParamReSpinBox->setEnabled(true); cParamImSpinBox->setEnabled(true); break; case FRAC_MULTIJULIA: case FRAC_JULIABURNINGSHIP: case FRAC_JULIABAR: case FRAC_RUDY: pParamReSpinBox->setEnabled(true); pParamImSpinBox->setEnabled(true); cParamReSpinBox->setEnabled(true); cParamImSpinBox->setEnabled(true); break; default: pParamReSpinBox->setEnabled(true); pParamImSpinBox->setEnabled(true); cParamReSpinBox->setEnabled(true); cParamImSpinBox->setEnabled(true); break; } } fractalnow-0.8.1/gui/icons/0000775000175000017500000000000011764667445014247 5ustar mpegmpegfractalnow-0.8.1/gui/icons/icon32x32.png0000664000175000017500000000453011764667445016411 0ustar mpegmpeg‰PNG  IHDR szzôgAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAg ‡úœ8IDATX×mŒ$U†Ÿ[u»ªë£¿§‡Ýe'°Y@A1 dÄ!1üü"„@ŒF&&þ@Ù¿c&†¨A0ŠF‘„L4F”¸Èº–E,»awzfz¦»º««ºªëúãLu£(k%®ª{ëÜ÷œ÷=çž«î¿ß|6Ë8”çì‹"0”ËÛ† €0„é&( ×<ÚmÃh¤äýl&ÿŽa:UlmAšŠíJ² cÛ¼V«ñ-­µ9†ìëõZ/Œ— l[ CÃd¢˜N˜ãÈœ°ë Àj’d~2‘9¶-öÂ&T¥Â…žg¾­ãXo 42±(FŠB å9ı" iªÈs1e ”Â÷ ³™ÂuÅŽçAQˆ'Õª€ÒéŒÁ@]hEj0ÁFC>ô<ñZk`Œ(=(½÷}™[©È·Í&Ôë†FZ- çÉ;Ç‘ï‚ÀÐíŒQƒ­‹B< Û5´Z°½­°íE¨•y®CƒR cÀ÷ ¾¯PJ¼ìv3ŠÂf4R¤©ÐR­Š>GæT«°¹iÍǵRåDñ*$¬Y&xž€()ñ2Ï&IKÐA /¦SE½n¨×%µÂ:am„Oøùw~Æ‘W¤S›ƒw\@fú<{¼ÏÙ®4/8½c{uôXjëB’(² ´T4á;%Cà‚  ðOa'Oqì™?ñýGOrìŒxûÇV¹rÅc<ÍÎ `iyJ/“çRMã˜{о/áØ³gÊÊÊšã¸NB¥’oáüŽŸ<ö&¯¬Fsƒ§ÖVûƒ9ëâ—¾¯Égîºc/¡š¥0I¬SŽlÂ"ãÿñøŽ×ÿ×eXlÙÿí²o¸á¾ûl²Ìf<1ÖyäÅ~Œunc—øðûþüôÛô¢€}]_äs|-9+€ÞfBÞðÑë®gkXg8Tlm)¢Hö­ıä¾ãVÏ€ï+êu›Nç|̓\|픯Ývš#ÿ(Ex!Ób“'ï|‘Q¹Ñ¿ÇµÑ[Ãäëh½­¥žd™4@z<:Ža2‘,Ë2ä¹…m‡„x|úws{‘`THuy…·^–—¼É^xë=wµÅʲÏ,’ç’mïlÏ´ïK“0I!*·Û )D•Š›±½¶eÐÚPK»¾pÇßÙxà™÷¬—œWãŽ/Þ‚Uû ùº,<›IùOSÐÕªìíe)ö|_§’> 1†8^è&MEdµš´vI²81—‚®T ^7¯Zy®îÛÚR'”of³ÅIA–IM&‹ñRÍ%Èwž+’„ù\Ï[,,v I0ã1ÿœLÔ½ÿèÌL‘ÉB¢%tEXtdate:create2012-05-27T10:48:29+02:00Ó+b%tEXtdate:modify2012-05-27T10:48:29+02:00qŽ“ÞIEND®B`‚fractalnow-0.8.1/gui/icons/icon16x16.png0000664000175000017500000000167711764667445016426 0ustar mpegmpeg‰PNG  IHDRóÿagAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAg\ƭßIDAT8Ë“ÏKTQÇ?÷ýgœy½™ÉGê'4jök# -”6µèhQ´Ú A´‰´¨E-Z„ #©h"Ò±MjY8*3óôÍû1ó^‹«•­:p¸œsî=?îù~Ž{ñL¹ÌÏEtLGÚ¦ Q¾‰Ôj°±šºÎ´V«ÑÉ@2 A ƒ™ èºô§R†ÐhHc0ÍÏ5×EXär1kk]—IZZb@`šP°«èªËü·](Š  ž‡¢(Šl+ŠÙ,Æmm…®=KNRû~›}{+ضŒmu£55ÉYëuYUÓÄfA›µLcã-Ïž=flì=7ouÒÙÞGïÇue«Z.'¤Ó‚‚í’ÏGd ÁÒìs.œ¿ÊÄÌ2®ßàóéË\¹8Èñ¡û”Ë&¾ZC>Ù,ØhÍN2ñâ #Í«×SŒO.±%sKŒŽäØ@ E54Àb±F‡ýƒ´>Çè£;\º6N؈hÒþ•öŽôÔN4U®uû Bÿ-šãÀÂBŠjµ »ÐÅ©s yË¢)“æåë)nÜÜö`iq‘°¶J½‘#@ÖÖ$PÂêv‡Oô1öî§|x·ðû‹»š:y¡[D›€RûûGFêuièzL¥¢ã8 'AÞ*08ÐMÑòˆÜu<¼Î¡ž³,þl§TRå|TU·\( ¸.x^ŒëZ´µ3|&ÍÑÞ7dí3|ϲº*ùP­‚EëŠòÊa(±á8¥»—¤}ˆÙ/&¥’䌪nnn&„ëJŒ$ÐÊŠLæûà8;Ã4P©HŸiÆ$“"ÖR)>•Ëü›Îõ:¬¯KäH[ti@×™þ Vƒfen(%tEXtdate:create2012-05-27T10:48:29+02:00Ó+b%tEXtdate:modify2012-05-27T10:48:29+02:00qŽ“ÞIEND®B`‚fractalnow-0.8.1/gui/icons/icon256x256.png0000664000175000017500000020273511764667445016600 0ustar mpegmpeg‰PNG  IHDR\r¨fsRGB®ÎébKGDùC» pHYs  šœtIMEÜ0Tƒ"ˆ IDATxÚÔ½y°déUø;wÍíeæ[꽪®Þ»µu‹F,B2’Œ¤1„A˜Í0`f†1CLLx‚ñÌ£öŒÇƒcL„±Ç<8l!Iˆ¤1 ‰–„¤V«wU×ÒÕµ½ýå¾Üí›?Î=ß½yóÞÌ›¯JØ“õ*_¾Ì»|ßY~çw~‡~é—|_! 0$D Ôì3çñ8€@„{lk­*Ó©2Z-DGGp&BÎNÁg}]Dü”ŸÓ¯g†1ÿÿôߦŸ†ÁOËêu…V 8:âÿG0$ç,?çÓ^—ìyäcÑ¿ésÌž›eµš‚a• ¿nšüs­¬¯‡¨VC¼òŠƒé øø ˜Lø½ƒ!øz¤×Sö|Ó罫^“ì9ÊùÉý’s«V67ù8×Ö¦SÂî.0|sëß¶&“ä\‚€æÖsÞ¹-»ç§xO À`˜8!Â+þ”ÿ7€½¢õŸ¾Çò¯iÖÚšBÝîü‰D¿9~ýq¿ ‘ýßW8{–¸BÑÜI¤>ëëºñ‹}™´Ê#Û¶¶€Ñè÷I_\¹†yŸO¸®ÂtÊFwÕE¿è˜ËœOÑ1YÐh(4€ãðý÷}Àó€é”Ïq<6Q¯›è÷ù~û~bðÂ0Ù(˾_®œsvm¤qÙuYd ³›Êó€“`{¸ç»»ÖÖŽ£Ðë%ï³m>÷zÏÝóøüÓÆ}ѱ”yO™k”öK6Rÿ¯hx€ïð¿Å¯’?NÄÆ k䳯Yí6Ðé†A0ÍÄZFŸ´Rø(€ïŠ¿0עȂŸL€Fƒ‚ü‹òõ4Ë6ÿi7GÞ{j5…z„ëÇÇÉù}†¾è–Bµ íqÒ׿v#ÓBÙÀÃ!—iQD3Ç­wµªP­ÒŒgL?Óž0»‘³›?»6ò¼à*÷­(òKÞGˆ"…ѸpÁtÄã8ü½–ů¼®G#öþÙû›wN§qvéÏ=íþˆÿþ?!Â.€ˆðóDøHö;ø\9ʳöö€µ5 Ýf H4›Àá!`t¢Úyd|± ƒ­äh ‡ú…a¾5Ì»Pwr㯺ùmÖeÏc#gšÔëüI'2Ñ“¥]—šçic{»QÀ²4§¬‡ NŰË52M¾¯£Ðí>ß²©NÞýÏó²ˆ1ï;ŠÎ;oX–B»Í¯µÛõöz¤S`1xb$¢ã¸(Ä/cЖÝÞS ž—˪PjM?B„áßá'óÒ½õuÀ Ã!P­­oþá+ehgÿ0íõØÜTp]%\t£òB’;•ç—õv·ptDð?Ùã'éOѹ-ºö«!’gÄ#(¥à8l)]wþB- ÷²VrÕ\¯Ìâ^ŽŸ&—Ìâ$Ó){”ÍMÅò®ƒPl,{½ä&…½ÿ¡¢€,¨5{LJß·j R@+ò„E¡ò²c³í$ÒÊFSeR€,è•^{¶ ìï³á¶¬Yƒ—5‚‹ì¢Ð•ˆ(½>$•N§á§qˆ²?yê_ïá,öx_+‰”å¯_'T«øÄtÊ9’ïS èJÑLøïºN ÐVu•‹”·ùoÀ:M~|;œ‹i2hæûù>ã)ÙEà8ÐáçpÈDöß©Èe™W*ûHß7Éÿkµ0ôýy¬§lˆ¼è< ƒ ŒçaT]ed=({X>ÇaÌf:¥`oÑsH·Ä,ú'U Ž>dm¬b²çßlòÞ5 ¿KrÝ$Õ·l›/# t† ëëÉ­TTn a°'#’\˜f @_´Ólþ;áÝaË~—·±‚€sIÇΜáë$eÕ4êïº ,)EKA²ÛÊà!e®yú˜Äpù> ¾Ÿ±¼(/΋t²žPR%ÏccZv¤ï“ãðfçJFR±mÞh¦IsiN6 *ƒÐŸÆûg£9gù×49Zd, K§‹¢yo«Åëq:%16ÿ¦RQ?Ùlòy[ã±€ôQÃ@{8ä?ÜÜz½­6Í$÷3M^ð''¼ Êä~‹.Òíb«†Û­ÌþŽâüè÷ÙxN§l|?©%¯¯sµe<& ’žÖKÞ'àôÑé°8’jÿL…rQ:ݸ¶ÍÑ(ÀU`‰—2 |ç\€7þý÷+ܸA0 ‚mó·Zœ;Ï’"Êlü¼M;Õ€ÓD ˪«9ò°möþkk‰Á4 ¥=ÎÉ ‡œ”.CÆWÉ!ïäÏeŒK¥J³—N~'uQd³(Ââ2£l `:U h)V”½‡J6Põ:¦iòg‡wÎù¬ä{òut]~2™Š#ÈU+ ék©§8ï[ÏSX[ˆð“ûûøH‚A@"<®*Q”ä!ò8TP°,è‹9™¬Æî[Tþ»SÞÕM² °˜(eZßç›ÆúzÕjÀþ>Ö"É"0iUö PZöÚÌ.*Þ@µZXqT¨4 æûÀdB¥½¶äÁ²`+öØ‚ÈgÃÚ2ÇÊQa:åõ[«÷ÜÁ²Ç„ër@¢´tÙí4¡ÿiòÿô5N J)ôû˜KOcÒá›ÜwŸ‚çñ}A€Ï£=+~Ïï¥OFØ_£× ÏžM0NG¬Sùƒ:­‡»S‘ÁiÈ2Y ‰óG7åR+¶àçÎ…ˆ"àÚ5‡‡É"+{N[û]¥Š±¬D˜ÏøZ«‡£ àT Vã×G£$l-ƒóäw®ËkL0†2àå¢{©Á4‚€°·g`:M¢5¥8: T)#p;èÿ2@–±!5çhVM²OÛfü)ŠHGQD¿àGÅ4f­Á²’¿³¡R^~Ù@Ñ\»¨ô³Œ$±j¨{§R„2‘ŠË]Âþ“‹§P©‰xÔë¼xÅû$ôX*œ–ýÆ$#ƒµ´²×È[˜ŒÆ+T*âíy=8…ÍMË20óué÷ÅØQésÉÁš˜(U¾zQÌPºŠÐï3{qnmÉ›ƒW=~Yð²ø-‹IYîBŽók¾¶Í÷HÈEy½ § ýO›ÿ§Ž"èÞ Ç)î=(âM8—fû}Ò×OJüRÆçåû„£#…vÃR ÷d/ši*Ýþyt”,`ËâZw·Ë”Í÷–±ËN‹tËû¥)9õª\ñÓü?¡ÁJÇ$HéP7{ C ^Ðëèt¤º²|ƒ¯Ê!Ï‚Iµš Ê\RPZS˜øï…YF$Ý ²ÝnI6¹Çœ« »PhÇeŒ¢DZ¶œÆ²ØQ%¼¬lOÛÄ´ ØE§=J¯#"5C·Î36é{oÛŸ T«ì厃—®@…!pp€s–a`M8Ñ®›ä £ßd®—’¶2Ã!pþ¼ÂåËW(——œwWm–È.!wôzT¶­²—EéHCÈN|,4ãÒ7Á49”ó<àúuC¦²ùn¶YîyvM&|㥑…QðÕ J‘aJSreQYƒ€Ò+püBms¤Á9¹@…F©D\[ã‡C~“e1ã­ÓÁÊk¦,¥=ï˜N›r ç¡Õšm­.j/OÖ—=[-îT¾ÃtJ3 Yo„ À½V­†Š„®Ò󂟵® 8sãiªfº®(ÄO·½žÖË¥jò¨¡·Ã&\fW÷ˆ"Æ6¦• [æ(R3¡r–Ý•­ª”ñxɵQšôÂQšÂþ>¡Óac•68yçQÔ¨StŽâ,,‹ NÃ!¡Û]Þ+¿,pÆZF£dm-+@ÛfçÕlòúâO™ð~€}ZgV¶d'©\¥Â×3½Ö—UQØ`*<ð@„k× ŒÇóÂ,ÖãYË0”³½Í©Óá‹Î5ÉÙ/0M^`"ÒnóÍ ÎG#J],öÔ¶Í­£‹nâ"^@–+Ö+“)󙧉VæÄrKéJªÃ!§M Î6Ö0šÎ7|2¡•ŒYÑï}Ÿ]$]]F¤cï-<îÍÏWÓ‘à²2 8©&L§å[»Ó› Ý.{À3g€f3Âá¡¡ ¥xË2,¿2éÙí”nó~ös†s~i&ª×ÙQª£—º†u| +Íz¨ä ¥å5ÝT!}ԞǑ ´õj·ùàz½Ó7ÿ¤#jUÍl ËR1…’´(k‰OÓR\ö¸³¿CÎË.DZ¾œm³¥îvŒeYyiù¢OžžÇ^v’{;çGe””ò ‚ƒ¬•4œˆ‡’–Þá°ø{³†c2ÉW“Z LL6Åɉ££ÙT5½Î—•§•/³!õªåÛE à~œ0T::>‰DÁõ:ßS×eܩӘbÍŠ„T”‡5)X‚N¡¹i.ÔO9ÀNg¶ ®ßgÏ6ŠZÎX”ûK‡rä˜NN”®­½°€e2µ|©G7› R ‡ÜKÁ‚"·WÍû>ÞŒbtxQ0PN¯0ŸP3ÿ¾qO"E!߈VâÁÁ¬®Dö\Ó¼ yåÇËpiù•¨Q˜˜ÂSÈÓ,,K3N·F#a+®ºöÊDZÒtµ¹É›_î?G8­Ÿ¯è +üh!ϬE”Þ¼“IÚ?âÇpÈ!g»ÍÍCbT²uÞUÃsyïhDžÄ“ÉM-º·#$¹ªÁ*ênK㦩pß}.\°u7‹³œf!å1ßÄX2XG88Hª5«.μ¾zÙГ a4R:5SŠCMË66ú}šòòèÖiŒ)-†‘‡]$Ÿ“äóÙk!¤¢´—^¦v]6"ã–n€*›&–Õ¬cY¼§nÞ$Xͤ–‚‡=ôP„Ý]C÷Á)+h’5ÀÚœV”"+Å!w Jî’â-j¹\D‘$b„s:M¬ù¢¼ìNE«~Ža0‡‚{Ú¡»(;BÙ:Ï•÷²ïYÐL‡¬LDØØH •Ìo¨Eì<韷m•z/͈›:°±!Œø³UŒÿ¦%gK¥ék%=û‚M§IÏA^(žÞ·ú¦Ë†ÁÎ`(ŠUy›¿¬Ñ>}µ Yu»Éµ¸uVTB—J@X_ŽŽ”®”L&Ç‘ã0ôµ ‚$½)’.Ïþl¥Ê–ŸÒÄ ·vwÙ‚s'a nP6§^¦—ÎÜ©ƒÛ‰äoj5õ ƒ-²°ÿÄ0JØ\F±Lÿ÷|èHZŸ_ &·íJ÷Û|/Ç2>@¥Â`ŸK¢ ¹iš¾kYl|$Ê™­Uχþ–ÅiÑdÂ×Î÷9§­×9U’ŠTöoñ¶mÞèò{×å5) hö|óxE† »….eÛ<£¶Êþ)NµžÉhÄç#åLÖKàð_hØ“ ¿Þj%Õ¦²k•&ˆäÄ”æ,†€}îM&\¹å,‘! Ú-B†ÓHWöäîDPvó—)ŽÇIô“ö~J)sN—V šLève sS‰Ê¤ )z9-qI/nÏãM-ó¦SîÓí)67vw+º„—nH*y9—•ÏÞÜ  ”ÛæcÌ)M@šM yÑ{žÒÆÆ0¸÷]šhʨR-R*N?=ç t»¼!{=…É„NÕÛ²LØ3’ùž=›”F¥ÀךfÞôþ(³®¬¢ ´¨ÑÁ4ù$ÃhF bm Ú‚§†¤g\þ¦lÚhÌ E© ïàt@Ù( ¬t–Ðfódµ¥¯`4RØÞV89aòÌ"°«lªTôw’W1«Nš“Êç»ÒßO1à¥tYi§’rC“É,Ÿ¡LC¼ï+ŒF&ƒD^>‘ ›÷ÌŒA%*:“I’~)Eèõæ“VQ\ʶ{s>ÎV>{Q¯B™òmºt>o F©º½ñ} ‡ut»ú}ÒtaÉû³D¬"y¹ôëV²½HÀCJ?GG ʘþPÃà‹T­òë÷ÅJrØ2ÍßÔEy(Ûâ'‚Ù W–Èq§*E†!ådÃ_×e8&c¨ŠXzYЪ¬FÚJÿÂdBšÇm°‹Å:òu¸Lºƒ›jT€-M,JŸ{¢ÈiÄÖ“J…ñ(qFL,RzÔ—\ÿ²êÄaÈ!÷ÚZ¢™=‡ÓjJçßúºHì¥Ï›âèJékxñbµZE§7ÜçQÜ1X†ÍX:Hß¼tKké—ây|RçÎI¾” §ÙºpQ]WDŠ:­·*çi ÁâêD9¾€4¥=g«Å×(²ol$ÌÀE´Ó²ü}‰:þ¾¬æü2f1@™Ì”Ð_X¥ÒƒþL×å‚uêH×´}_iÄ;ûg£ªlÙ4­Ì<>8…eñ°R5Ã.,3¾-»þä{ CÁqµšÌ¤Ò<‚E.ÏKºl“´ET˜\WÖ w^Öj<ÜD€Ù~Ÿ»'-‹i÷é´)/ÊËÒŠ­UÐçU&ÝŠ¼‘ç[[œ³çM:YDI›cZ hã~=#€Ó‚ƒÙcÚí²W©Tx¡Ê¸* ëV‘øZvŒâ%¥Édƒé”P«IgœÂp8 àeK{y=''Ë…&EeÚ5O3rû4±¥té†uà¥cuAÈ2‘‰ðã·¶øû†ÃÙÅ^$]Vt DáHðÓd*¸´KÉ1Y «3Íø“z~«¥æ¦ ᇑ~ÖíKä3×Ö€µµQDèõH Š +YžZQq‰›ïëòµbŠröØÊ;Ï¢õ#‘á`À÷€'M³ÁÛÞfÇ™Èï+=¼UƘU*‰!°,Žä^Š8Tí£™ôÈZ¥|± ä߉¼1÷`³å Cf îí%,&€ë½Å*fÊ1b+aIÚêËìr±þý~¹ÿvye& —1Ù…& ²µµ„¬1r£ÊhdáÌõÒ³ð²¥ÄUR˜EVô66x8Ž€³óÀWš›.eµ¼ÏRW5L4BÄQƒH3ÿ˜¶šà¬4¬`ÛËRñ¢&;ãЛæ ÊÚšŠûÞùؘRn mQ“ßÃÁÆZ:ëÒžó4ѽIOAæ–^…n×Àþ~ESÊÓÓ·²ÿlä†ÒÁÝ4¡?‡#¾[es˜²'›EmÓ,.©Kïì÷ÜÃdñÙG«ÅVJYʰo§ ù½h!ý’ö$D¤5ìŽiF19ZZÒYÆòBE_ùŽ0î¾ÛÃñ±ƒšÙ ÙÚ¶xl.!ΊM“yÄCM§µU*‰d˜T5j5 ÕŠ ”s:Ó©ÂÆ†B³éa:uÑï'šR+—08½NÄlm©ÝÂ"éî<Ï/×GX›bìDsBr–•J±Z9 &j%€œ§S,ŠB:jô}53…«¨Ñ'ý (uÿ”&i)Ýv=— Ÿ62È3‚øŠÅw]ŠQpè‹¢¤¡HRJ/˜Eá×i‡kβU¬ J¥AÄe)CZS0=H„uܘ3!rl‚ò é)oQÛ¶Š¥ž(—É´j5‘Ü–ªÊ``ˆôx¯L¤°³£p|L3¢¬Ùóf#@ØØ`BN¿ŸÖoHÈA¼É’ÍdâΏ¤k÷Âþä!bDƒA"QW¡Ýé)€Ñq˜LttD…Fe–å³8Nb¤²<‰‚D; vBb¶c«ÅûC6õ"=É<#$!i²Ñt¿:ù &A7ɈfÞtjh”Uèœ"]¼¶Æ d?.•[V¯·XX“Ž”’ÊFË"´åžU1¥T@RÒSq% ˜íPºº’güæ…uòŽŽ’ÜÛ4¹§ÙdÌA^/¢“Êñ†!Å£áÔLË·PUe0Še›cœtªz4µÜg¥8¿6 ŠK’IÇž¿Jßh(¸®ÂxlèHÑ4•6Z¢€ÌS‹ó®UÒ‡‘§ˆ”nCf†7›Ì(³†u,¦+YkkÜ;0Û¹=h¥Vã¶ßì9‰¢êuvÜøDK;þfÚyC6Æ)À_ÅpNi’91a  ¤ÙGÀ—zZÅe•ÒËie™Ò†Àó†‚RJ7êˆ÷ZE_¿ÈdÕYDs0 xCÎNÛ {˜ªÕ¤!'ŸŽ:¢f©ÇJ7pÉìǤÜE¹À˜ˆ;;œºåƒhÆÝÑq­V„ñØÔ‘UR¬U¯`šÛf>Ïdï[¯óçõšB·gh„[€¿f“1“Fƒ=5_šÃ1d4ÍYƒ9›ÆcƒÓ|?d0g©/;ê,¯œ-36Æc“á”.GÏÞ`LLÍLß CfFг Š#€E­¿óÿÒ<à4›½Ü†K,ªXe©…‡Ì´m…n—{þü…X–ps¯Ê°KzÀyœÔéÓ"#0r Ž9P\®Qšj›í)’Ö(ƒx§£ Y`ܹɯW†»ä P¦¯Ëñ1¡ÝV©–IIN†[0€@d`s3B·k€ˆ°¹ T*‡7çõºÉÄ…m+Mu]2ŒˆG1†A¸ë®ã±©qÜ’® ¨X˜D&ìPaŠ$@âÎŽ‡kל\1’Uc³ß†ldšMIƒ¤žˆÁ`Ïc›V-J¢ÂɉÒMI’ê‰}”ùw®¨ìæ.b¨-“Ê^$ñôr³|ð×®mâúu#{òó¦U*§I¤íSrfé+Ÿ¼¼½š|µoÕïsD$ºþY±Pוy÷ó’Ù«°ø$Ô–ÞA¼%$.* £p2!4¼écKsÓ)öövß7Q¯pœ> ¢Vk!Š(eB)&ò˜f„ãc+‘•´ô ¯¤ßWz^¡msý¿Ñàk%½ÒSašÜz-méÙÞiB2Œ$ò8>¶õ8­0dÜ)r­Ÿåråb“Bñ– IDATªFÒè&e`!.å{xÒ)cžá*›~¡¸ÝM_FèBñd¤!*X[ ±¶fè\Tr»4B:’•|Z¥=VËR‰27oÒ¿°Ê¸ëe³àŠTœ#'Ûô“’N´;-=Yæú ‡„õu…V‹¾430“E„áPiöÙtÊx:¿ Ã8s&@§ci*+QB_][S¨VCD‘ ÀPÑy õý0ýÏ"ºö«€]qîg@Ã0žGØß·±±ÁuHäζpµZÇ™èÊá.Àþ& väVAd€è@†a Ñð0Û°¬žgj•ãfs‚(ªÂ² `5!n”á~€½=k,+0‚‚`ÊCtpaoTû#Wý¯@dñûÔVœÓP©TŒˆ"ív5v–ëõëÊ„"!( qHX†=L§¤;ç²ôæ²ÃYYÖKJ‘i‡¨ô=ˆ"¥ç8IǧPªƒ€¥´+/ çW5Ë~o-ûc¶˜0°l:×J¾H+œ„a¢Rš–u–¿I÷f!^lIÚ ›Ã0[[I½{Ÿ?/=æx9h*pÖ3Š7ö<ЉJ³ªòhºË €p°EèTƱ3XÆÄ¨ZA4Ë"ŒFUضšÁÌ ¤’º¼ôÒû>ã éë’×ÄÀÉ c­öJv–"œw‘qd'' …ÍM/Ž@ܸtèÀ0B˜¦Ï›&@k0ïýfüÅÿüñ—oá|  7åtWœTã#Ü0†RcÁ—á:ß Ï?‡jU¡Ù †„nל‘ÈJ{~™Æl|[­{{ÆŒ0IöÞeÐfÃÿ´nŸ•ÒQ(ù(%Rb˜ÎMPšI;ÿªÖ2ï(M<³çf&Y¿Ÿ{ß{0 &‰8diO«©æ5jÈ@‡JxÃÆØÝuñê«F®…Ìë”; #pögÒ†L”WE“Ýó”îÐZ$«ULâêÆáaâ!DéE$¸£ˆâN4[{Ž”ö6''J…ò§irع¾®ô´à<}ýY£Iˆ"æœonF0 .ëǤ©ÉòŽMGe åÖ„ãLÑhL oxÃc.@©ÁågðÀÝÇxݵ*‚‹7aÚ¹ó½ ƒ´Æ#àê¢ÎÇ`l¿¶ÝF³éĈ­u¸Ç$M'çÈjÁ<-øèȈ''Î$¯B)¥‰G‹´Çã4))×:_Ëìh²<•ž²#èïôÃüŽïx≢ü¿ˆÜ"¼ýôL¦¤<–/:Á<„¹Ziq ahht^ÊbegÝŸ†<þü}ëëÐòUÒ¢¹ q/O•sÆ#¾–¼X„¶+“u67#r e7 €æ¥éÍ)^\úíçÉ¤Ê )^¥loØhf*ü~c#ŠRé!Å2áˆLضÓìƒè8F#‚øÙÕzh½mßø}„7šÀܹ‡†œØ‚/!:zFónq”jb8tô¤_VñI€A6`|^[[ ÆDݧH‰ŠS0¥{ Ò†$ àŠŽòŒû 6ùߣ#Ò¥Ý4Q©ï?Š`Q.Áì¥ù®¼(¢…S]yæì¸(é æµ5ÆnÜ 9IñÛ‘æZd0f‘vö*’£÷z‹…—Q“jÃ|cHºõÙ0”ÆQΞâÚ5WKB¥JO¸«Lag‡½ž–¼P–‰=‰ c9³xŽd¤7Â÷ ív„ÁÀˆiºI/:s) FŽÄáˆ+PUßàÈlú·ƒñ—ú06?ëœB€àúŸÁܨ#ìtݸ ëþ‡¡ü=éÁ0|ض Ç1P­FÂpHq<éP¼ZUh4& XË`–´þ`:MÜK´,³#ß³sëí0­ËºÅ)ã*›~•.ײ²R<€ERT’+•˜VÕÎKÿ­m«8NäÄ„,ttĺ‚̃f”Y¦ëÞnîT†º;ów‹urЪôà¼Þ1¬iPOt«U ß7`v\JM®4¿¿èþ±©¡9iÂJºÝW˜|Ž#“— ŒFkØÞž°q|lÌ ÜRïç²Z„ÉÄÐ-ÎܽÆá;h°¯!Åœ€iüúGvŸÿÀ9|sç¶~º elÁ1‚ƒqô[>¾ðÌY<þÓ>Œ·ƒÌw¨Ä†9„ãð}''V,Už€p¶ ´Û>ºÝ*Òà.ƒ…³×]Œ®à3''Å£ÍÒm¾r/Ο²\ºÔš©re×úª¹hçßË$Ëæ@þÛ)'”‘ +ù©z±7\ïàcZÉD"y= _F\%eÉ8ÒŸ0ñqÌ7Ëp€eÜüÙãUšÅÔ€ï¨×•ž7(Æ'ï¾ÌÊN³ÝÙQñy¨™*Y”‰ò¡êu…NÇA½ÅÒxD’šmnúð}Ó©¡™ž®;N5áõ Ô4FZ,€ŒúÞõ Ïàê¿<‹µ _†Õ&\ù'k¨ÖLÜõs5¼g· çÁŒ×¨ðAÔ…alb4ruÏ»’J¾oÀñ±£5 ™µ¨4‹0kÀYFKiV`Þ{¤Ä×l&½ûÜw_…RJåI‚š)/Ÿvó/ªt6B¸-p'±¦ÿ»·—€Žâidct» ÷ÞËœuÑÓÏöH ܶ“ÖÖ<²DYênÖ[KƒK"l:ßåw^Bú¦ )Í¿¥»ìOÌ_–3ó¾7x:q½®t‰,ï½ic)5vþ.­‡ØÙ‘ß"Eêu–å øYmƒ0¨Â›]Õbcफ़&Ì×ÀXŸbç{/âÚ/n"2mÜõ¾]¸í€êo†ûðÃî‹£ Pˆ"GžB®‘kY©(ŒF†nJðªyÏ.=|¤}xQÌhÄF ÝæïßÝ5´C— ö½Ip…e2ce~ÎsES·²¯—jZæñóšpŠ:æšCünWˆ”KÔxoSî`KJb “Ž?Oøü«äèEä tÎÎ4×Dª)éÒ*Ç=Xv}eÊb#3™GG†}åy*žÄ<ÛÀ’w^B÷uŠ=“J'i¡’0$˜f«Y Rz5«çF#D„ju ¥(eÀ0 Þ°@pAÇ›X,h¼©Žµo÷qå·xÝO¼÷íÆcÎXà¨ÅOæ ØöDuø¾­©¶®;Ådâ Ó1Sš ó¸U–¸ÃÍX¤+yF"  r'c€^ÏJi4!‚œ0aØâMY´oŠá.sÒ‹†¤žJtYè_fºP:GÍë×Î[”ÝnR6té”÷˨¥££åƒ7WUNfä‰B ´”u:úBS‰íEÑÇl©ˆ¹ö<ç½”È<T³Xõu…N‡ô¤å"­¬ÌW§c¡Ý±¶a<6Ðhø‡Ôl?–U…ëL¬Å›>ˆ7o—Ó‚ªËå=ôtÿ{¬ãú•{qÏsWá¼ÙU™š ²åˆÊÑ&”j#Ь8áº#¥½¼l~áí'›9é|CP«%:€i>H:ÂcR¯WzUØÝµ†É‘kcÞ‡šÁ„Ç’·¥‡yQBÑÐEû0»þ­UÁiõÑzSd´ã+:A¡  ‚ À‚aL@ä`:µ4]¹Ùœ`:µb¶ œ+odŽàOá±ó4“’ AJ4,¸ãÁ½ƒC—ÿ„ýzÚ¾ý¼5—LÇ’Þ~­Õâc’&;0Í3|&® M…Ý{¢À:yL‘ÝØˆÐï3úwJQ…OŒëxòøó8î| “éQ ¹|úÙ?ÃÖýxò«ï…c ðþO^…ºç"ÔHáòg¿oú›OÁ^?Ð ý¸ƒp -µZ>ÅhähT× P¯q|ÜÖbž"R«%Úûr(• ë ML&†nóe^Fv¦$ÿ½H~s?K> ËãÙgYœÂ3¨×¡7ûñq2“B<~o(.E׿»ÞõÄ‹.Šn , JXÊ ¹|ANÕ Óè÷ç«é\¾^ç°Žûîók¿Y² “¿m·yã‰vvºÌ¼6 i• ™v“U¦ÉÜ&­â4ˆ§êø¾Ó´¡Å¥BÒ½‚"7›’:ÐÌp"‘ì¦L2fÚ\ Àëz0M€ƒ‚LsÃÄF`×úG±'ö@d½·†êCPÝÀø…>>õÂëñáîCøÃÎe\¨?>qùw±»~@enèÔópÒÛÇ 0©¯ám—ªøÒ“ß„s×w±wauŒ°ûÕ*ªµ—áÞý(@ç@äÆåÁ #„eùCA`h-ËJeÏk@)C ÞÈ´*¾†Ž-KiñÎш0Ppã/põú¼PûF£éÒ{?õ<<ÿÊ—ðOÞú_c÷êÓøô¶ðöÿæó” »õ`˜ óPY @4F¤¶ ”OFŽ`Ûø~“‰¥eç`ýIÒ³ødža«b84tD6¤O âHIñ䄱˜<*qú︚“h`G¹¢2$›]RÃ<>Á²h}©ÈZ|•Ý´e BÙÏXÆ!Ȧ"šÉ”’nl@Ï{{ù Ûæ .„e ÈEeJÑ{W 8<4´HƒE\AÔ§Söþ››ö÷‹•Ò5çÔUˆ§ä*¨×#÷ú>‹Q¶Û\7^eE°¬5T*8NE‡§µšÉĉl –u ÛJ¯£þMûLåWQ|N@5@MÁâŸ&@îû¡xì³Ïà­ÇoB·}ˆN§_: ô}}òŸ! #Xoªà•*ÂÚݨ?ômÞÈÄ#Pü|Œt ¶­`Û^ž‡˜N ]Ó‡#ƒý¾© ¤•˜ÉV” eœ7Å©? öÔB Ê~Y ( yÝÈ`ÐÁ€µ…*\ê—Ùü«ÌÊ´–‘Ê…eààŠŠiIeá¸ooóÄU©¤o Í{Ù2ŠE³˜@B©µmßgB45É‚É sfs5ž o ^g, «»¨W€Ùm|,ëë ív„É„ôd^ù»é”ÐlFð}ŠÛvUbšp•Š{nnþáÎ:‚iŽb{ ¢s1â>ˆ AP»`Éï7ø(/îA…\ý`88‹‡›¯Àª¾¾bÕGFø†×+¾Ï4ð?óIÔî n rr/‚Ø(5â×&0 ;.IÂ#î 1™z ©ë˜NM݆¾¶ÅFÒˆû-#©T˜2,mÓõ:áN‡ôxól”š¦ðŠÓ©×»îòprbcŸS A÷—)•ÉûË’ó¬U<ñ*éÀ2bP²PÙÔ Û Áóæ9åžm¥s)Ť++o®À²è%{Œ’†H ­‘2–¥§‹{öe„– ÅšäfÓ‚<. Hr—_£áÃ÷]Ýü"¿·mÄÓ—ÜXG_iQ –5A¥b!Š °í1XxážðòaÅ܈AÅF| PÊb¢Nâðk6þýŸüÞ|ø쵎0Lkœ¯ðèõ†¸»}„à9Ï¿lãÁ﹌êÇÇQ B5>Æ!ˆÖã¤`†áÁ4+qσ ¨Ä¸Jˆ(²ôôb¹®ÍµFÓ© ¥T¬$,Òi\ij·Cœœ¹ˆÿ|izøi£¡pp`#’Ôb‘h¸ì,Œ\°,OX…:»l"΢t`Œ¡(2O'SX77YNL(³î%¢ybËHAÅ™ÃkÏc@=m~„‘Q°€îØ“«öõ`ÛQÜhãÅ^Þˆs{#nìép® +.ûU˜ŸO¨*€“|0Ô×ï¸Bhn]Á/Ð|î™ß=uEhìwðÌèÍ8øÀcxô[.ã5?fņƋ½¼ ‚à;HšˆlÀˆ«DÂÐÕx‡ãŒ07`Û¬d4š\ PUxž©Bß–Lj4"›ç±)qD¶­tǦeg΄8:2±·—è*´Z¬ krÕpYÞ¿ˆ d…狈 eŒ@Þ Á2Õˆ¤XÓOi0§Ñ!–Œžçyãe¹ÿ"c 1.–¥pæÌ7nTfêÌy–zösØ€ˆ@ФYb©xÌV"]Æñ˜+³ý|Ã^†ÃȾȌ«[ œávcìh‚0‰kƇ<›"ÇÕ(?®,ËÐ#&ÀÝâÒ&G­¶¥€^Ï…Rœ 4JË’K‡¡ÖÔjì8M­-)Þ~@H> ·JyoQ ›ž¦8&Àü®ïzâ ˜˜l~*AE]LâêiÖס9äÒ2[¤i_†D”&¸ÔëÌŽMœ!dŸ­-¦êN&„¡¥5Ð#ºÒ#¿²ÜyÓTqÿ·Šg&!w–”Ö‹—’4Œ0²®4Y(̓Å%/™ `hš°Hœ¥»ö¸öL±‡JÊ}-&ýY¨TƱ>?@Ôë÷½8L—Æ €=DÞ³{Oƒªv|-Ä“F ÆÂB(˜€ÐÂ8~_7~MTºàÜk^À7V®àÒþOãk{_…ï{+m~Ó´ð×úQüÃ÷~¯ýÉC˜m |ÆãÆ| 4X©Ôa|Žò)Cjqà 8wÖ@äÇÏ ˆõù|ƒÏÁ¿ôÂhnÁ°PÊŠ×?c6)Åcß67}º]&‰¢´¬…E³–åþeö^Þ^LûŠ IL@zï{Ÿx¢Ñ`òŒX…loñ¢0?ï}ÙÚzðÆßØàh ;co™@Æ¢“’<‹yõIm5AÆŠ-¬[ÇrZ2d£RÉ×È›¿Çußô £C1û7¤É6ëëQ¬ÜBº±ƒËs”ó]¤™…BnÚØð1˜3C=Ä`HõAú¤¼i¤Ylܯ`À4OÀÒ[·€à+PÁ‹ûOƒ*V¼i\Çè…?Ƶ>»u îvDvüw D²É=(Ü¢qËï‹Ð0Žº\2D=­ê€ì.hêaó/oaoó1\¼vy¥(à±×þ‹{vñí?yîk-À¨K<¤ÓŠ{8ú8Âtÿ³xõ#Ï£ýh dX\Á Æ-&ñ¹9 øñßNâ´I— ÆW@êÕGaš.L“GÚO§¤£·ZM¡Õ áû„~ߌ×:b¤¿x0È*CsŠ~'ŒR‰óÛØIÓ›¥´iÉ„S M„š˜í’[¥æŸ÷à/Th48¤eÚ«Òtȼ®¼¢ŠB:D Â` ô€K1bæË,>n—åðûüy7nØèõ’ó- ¹¸žGƒmm)MÄ)BôÓ†I”b8L„¦é¦CŠR*™>4™XñlIÒsHƒŒív€0Z¦km̓Rv¼è×@8€ò_Äø«¿„“OޱýwÆzGð®í£öHFôºÏ߃{~øk½Pv¼Ñ¢øxƈ¦_Ãñ2z÷>©ÂÑn üp D ¨¨ƒ(`ý?ÃQ˜ŒáÖB¼ýáÿWvîÅs·®–Úüg[øoþöÛ/é‡À0„r®îÀ>žŽPÝ^Gã®{@Ô‚‚‡pzŒŸÆµÏ=€óÿ ¬Ú7Â\ûf(rµ€Ì˜58hsâÈ)Ž 8ŠÀ9ï¢÷›ŸCý=£} Ó\PÑX ¯-îª<:²0%ÃY%Ú\,Uâ’õ1 ,­i”KÛM;d1Ògà8 æw÷ûŸpYÆT 4(㡳!´ Ú,uMqØž Tl·17W½Lù-ýÔ82š3³4D|Ÿ´rN– P$bÛ”Ru¥¹÷H#GZ/€g¨˜ŽÊ¤4Y$ï¥J1yDzHŸëìõ¥ø{ªÕq¼¸¡9ûŽãÁ4„ ŒAf€È{PWñü]4Ö/ÀTÏãÅ_'T‚ðÑôV¸g=<øƒÃÚ„„ó`LcïØ—0yöEü‹þf|æÓçq×Ñel¿ù*ìµ#ô^z¿ús;¸øIo|Íó¸ðq㯬W#Ð%àÞ}œ¿üF<ÓüN„Õ˜N‡¹¿Ñ¨c§õ>ülÿAügµ§®)Ü|u n×ÃïþÚƒ¨†{X£øµÿù1|âÞôØK¨nOuOÿrŸú•ûpõênþ¡f\Æúwât  "‰.cÂgð†1èyÌÓ‰‚çqð+_@óñ*ìsï̇ã^ƒ*ˆ ÔëSñ`Ôш´×g"VÒ<–—©žG¾eÛ\Y’t2oJ‰Q„BÒŠTüII¹Ùä¨tk+‚ï&9ë2mü2¥À,XÁH<‡ ½‡J2õw4*¦L.«ÇgÛ*gKeÉÿMSé!GGœ´Z Í& D XÔž)=§S¥ëûÙ÷&Õè¼\€¼ÍÍkètîÆá¡9c8’óLÚu³×OjÕ†éÔÑôS9®¤³ÐQ ÆžWEšñ5uâ:x'w 8÷¿ν.î3¾€çÿé=¨T¼òµûñ¥§Á[ïù Þð3/Ãp€Â :Œ3 UÁ0…R7pùÏoáéOoã‚]ÁDE¸÷É»ð-O¾„àþÅûÿ>v¥‡óÖý{;øÙ‹M¼6ÜÄ.öpÞ<ƒýþûNÏ5ñø;¿ò'ÄÑ‘—iîÞñŽGpé‚‹_^ć»ç}<€iïà õ.Œ÷ð;Ÿ¿øðÓøìµ&n7PûûÛøû¿ñeîm(~í|ì®7bçØÃ[œ—L^†U­1W@U‘(P0¸¼©ÂØãž@áý'ÿÿî·ñÝ.ü©-¦PÃ4»¨Têè÷«ZŒs¾ÕwvŠ“8"I[¥J%]…yÈ¿ëŠøììš.J¿¥/%-¤S©ð“»B^g%–L€•¡ËÂýeByF#m}ŸC”zå«&ÒýÚËšVéÈR(e£Kû*+Ú öÌ\ëe‹]LÁL€Z-éÝ϶y±V€ï'd‘ÉÄ@¯w·îHãVÒY«/à¥Ì©Ÿ× °ÐnZŠ[xFA4ü§SD5T«](UQ"‹Ùpˆbßfª¬±í÷ÔÐ2>‹Oý¯ïÀŸ¬¿?xá·ðÈ[_йŒ›_ pðÜ:ùϯÀnß ÂZœ#_ÇèjÖ^g_íá·z€àžÇñò?=üö+xÓSûøg½!^œ\DÐ|7^ ŸÂ‹ÓCL¦#DÑ«ŸK££ÏáòoçßÏ(þø¿à‹€K#¹&×ðBµ ÏáÁÈÁßÛ{>~øûh5Úxg…à|€?ûÔÃøÕ—F—†Ø»ú‡ø~ó.|æwÆ÷|ë5´î;ŸñÑ¢0¬Èâr!&PØGã-SüÈ_×9“ vcშ§Ìø~+ídd¦‚4U‰&G¡ŒÙpË:Í9´lû7w–"7UMG"[&ÇQ¯ FÄNæø˜t_Œ¨G™ï{ßOˆÅ­ù2m…eþŸ÷ºiòÌzÏãzùÆF2kÐqòËc§yΖSæÓßçÜÜ4I#•êD¶˜5Å$*2é÷&|2q†;õ”²R2R4S1ØÜŒô1ÎV’F”F#„R¦´œ²¸D4 –5Ñ®øÓ¸Mw… vÑ{ê“ð^yþ?¾'Q÷ߺ€=t†Ÿ»Ÿ~áQþÁ7ãã7ƒõâ6ï¿ŠÊæPG°}î":B|𨉗¯¾ˆË{/"œÞ‡§¿ú~3¬£‡#œtpiü2zý&Ó‚ÀG†·5]J)ÏŸ Cövqi|¾ïammÏv_‡Ï?i¿PÁ¿¾ôe\Þ»Ǯ⑻ÏáïüïŸFãu[Ü2Lv\ÚìÑ\ýПaróEôŸ{îÆu˜µ W°G¸ö‡ Tïö°ö 7_C4¸ £ú rbÞa<6RÒܤŒoëë*VæÈS0¢"´ O§Œ¥£#I¤¡Éq”²m¨õu„®‹°VCP«!Æ CCr„~Ül–ëróŠôŸvân™& Ó»ÝÙÉ,í¶xºùq[«tæEyƒ„ï00A¨Ó1q|LsŒ½ù´†™z,Í‘D:ÇË”’w…!Áó=ž*«ØCÄ©V%™t™QÅ‘Kp±!11ذ,Òµçj5D˜3âŸDMyq½›¥´£ñM\þ‰ÃKß‚ûο€oÿ¶/áÂÂÇoÃ?ôŸÅC·¾ áo¿ã~Ïžëà=G#Ô~ø"î!EØÿJû ­£Ý›·b¢p\ëâC{—1wSàoˆ¯ç#ˆ§xìî_Ã]ÇSµºë;0™>Ëš'·ð\x7Èö üW„&¬ê„£ D€qëo¸…—aŸ9|;Þð{ð7þ¯OÁ¨®ƒÌ)àßDcÒÄè•_ø Ÿ|MPËw-k6Yq5)qÌáà}Ÿ×ÚÉ Å Ày)þK½^@ú,À,i¯…zÔh€ÎŸŸ7n¸ètx|^@SÒÓS‰¤ƒÖªT’id:oèå²é£eŒ(©ÈwM§|DÓ_&Ö”Iqò°‹Ä#3bê8,Ž):ëÂØ“¼<]î”|¶0ñ¤3,o¸ À)‡‡<¡—£ 5G&âÉ4&3—õÇÀ¢‚mí#R[p]3f¨Q¼ÐB¸n3ý ‡ÿvŒÜï3èÔðºŸ1ñhóÌÊèV„Ïüé7âÚ+×qáÒK¸µö*¾äò™>ïá÷_óàâ;ëWpýÉ6~ðmâÞæy¼õæÖ+ß‚«8>îâÊ+—ñò¡”BoØÁÓ_3ó^{æø©áELÿHác¿Ò€_âGÞÿìÚG|®µæÔbyÔ4—›Í»»‰.~ÌK§"à9r?>``<&]ª‘´A€ J…§Í¤ÏÅó¸g= xþÝpœ#¸.áŒ"Ë{;¨T&p]/Á:Ô„sv2jÇ%0†µêkÞ `ˆž‡Úëáõ/áéèðµÖçÐíÐï'{½ùÇxôÓ÷á]¯`øšºôâçñùö9ì]ÿ×:øå‘81…ËG_ÄOŒšøáþV|¶ÔÝÞý¾WqîÛàíOð;?ÿ\zùmxéè&>¹ûôÆãµï÷P }<ïnáõñô›ø±>†ã½ œ7+ ç<€xÕ$i`:µ57àä$2’ÍËÝg§'¬Ïj5™T,MEI r!t:ÉðÑ(B\‰Rº%=ÏHó˜ùþ÷ÿO ‡&Ä’Z³L½t8"áì*úúˤ¿DæH…¤ auRîJˆ-˾»ˆ¡—f(J¹Prçj5ÑúsÄ=ý˜ÉÉh ÃDzK½t)F6`BÐàëZ«M1Zš”Çœtœ,¾@1é‡t}Ÿ¨ÓœÀ4M)ù.¦Ù‹Ù~fò™ªKS ^% 4cŒ÷öðÿÃc¨=7À‡(Ä×^}a¾ o<Äft_6ñ·.]“ptr ƒaç¶òù¿Š‡xèOúxºxuï"~À>‹×­bóüèæ_ýh¿øâ‹øÊ­gÑíwðÌá³xvzŒÏoá3/ÿ9ܳ÷âzý¿ÇýÿË« Ð{9D¥y kýmRµxãÛñØ1Ã!éf¦ÿRaJ›]Íf’³XiÖ*ËÁ1ˆØëqEM”‡X¦,‘ Éù´†ež¾€õÒK ž= ]"]JX_g™L[-1 óÊwÝ.a2‘V*žWO:l¯×“1\‹zŠõûæ½DF#®4›Jƒ7”i­4)(©¯ª™ª÷ðÈ(é}H pš¦«ùý¢›ŽzÖÖÂxÆ^òÙ³•V´©Õ¶ÝÑúLúÁƒ2&1³¯ tTc¾þQª™‡‡iDcÏywãCÕ·àêÞ¯Ïióñ5ŠpÁ}7þnïq0~ ÓÎ.þÿöèõ:0 žNðÑÕÀ'CÔ…ߨ%ÜÜ¿¢I£Haïð&`íÿcïÍ£,»êûÞÏ>ÓoÍÝÕó$µ$Z#a’0„ãØx Ï1vlç½xxñÊ[±²b;‰Ÿ¼$ÏÓ³±ÕüŒN´(²ñäºÙÃ|mô¡77'w¶"4Ç:A­6ýòŇt—Â+_j8hË]ÏÓlØ {B•T Ôׂ+Vk ²À ëðº´&×¼+€› ä?dqÑÉ…ô2QB»í$œÛÓK9'Û…f3û¼M¨(•âdë:ÉàÖã^øC:/³GÖËøòFÍãºC|¿cÞPV¦ËU6C¿YÐYx裘Zhݧq:`§3‹œáy&Pêøÿ¯žçЮ~ŒÃ'žçå+ŽcŽÍd´:Éÿö±üb‡z‡—©g¯×íz¿°õ1®þåEœòëQÜDášÝÀU4#$â$-¢h j\W–›ÍT&Þ~¿ÓIãbdÄjSh£L6„„¡C¿¯XZ¡ßW,.ªÄtÖÎ,©,[æÛ9ÛÒRŠ-¹Xpï½÷¾ûì©Y«¥h!ÛO8ލÜF«JV_ŒÌs¹íÀÊ5›Í„ããiu`у«wV®ì …TS}¥EVö~%%¾òRªOLÔh6‹IÙdc­¾ ý\ú³ˆ8v–U "=-ÁnFh´R”J<)‰•¶!öuÄAÈ`à'i-"“dìã*\×G©E3é7l=µ$ ?evÜÔÍÓFÑ@ÑMÊ¥Z”·×Ù´ã9n®á©Ú­œY8M¿ß_8šÙÙy¾Y®^¿Ã±^“ƒÁ{8a0h­N@ò]¾çšˆòTUqqŠ×á8ÛQL ÒcA2ç ‚ˆB!4°k‰¡ÜªeÃ\‰!•¨ iu;:*¾(rh4„LÔn»I…a•¦³"¡Ùþ~ù–KeÔ†ÖVrï½WØ€v×h2¶ç°ee¶——›—Oâ¹Ü™=E­¢Êؘ…áJæ¼NÀr²EÈaù)¼Ä7$ðìªm8,0:*Ú a³Š0©„´ã(ŠM·ç$¯5‘ùÎi†a6ˆºl.§Éç–Èå × L‰ŸÎ!lÀçó=Ç5'‹2ÒÔãx£ÌkŠqœ&J…@ÝpÝ]S–6 ÄcÕuÖ°÷ê@ð—ó®Z”6ÏR[`×îâ΄T7h6|³^q³Àó”+íöêêÄ~ÞgOó5¼tð&Ë Fo¸ åìj± CR¡µÏ`àÑíút:Š^Ï1ó!•`_¬Ÿã`@‡/•D¿Q(ÝÂl6Uâîd…ní¦Ç®‘í©ÿÕÜV«º¼ÔM&Å /. ¶|r¶l‰8sÆMÀ/vоÒúz5·“¯Æ9h5€^O0 »w÷9~<·Ì4û|+ŒÕ˜˜´á‚Øp­ÔÜð‰Hƒµët\#)î;¶*…Ädg$¨TH 5$ƒûFAàÓlz‰[O±(vZŽ“§ÙT˘‰±Öhíá8ä,¸gÄ`à$üààû `„ÁÀM¶àû}Óï«t ¤ò Cáçë¥r†#?ƒÒBà‰‡/òòÿx¿Úgç;/€è<'ZäãtoWG¹ï‘€#ìå™öcPò­t)žëÅ£#ãì›ÚËÕ;§øþÿôT^M~ê*yóã8]òyÇq=c&*ý>/+½|>6I!¢×óYZRÉinov-gõšNvø€Ç©ñH·+›€µx:—ÃåÑ:“²&ÙÅ™3*áØ[#Kû‚íékûè~_'Œ¥µV—ÚÝÛòÈ" ,þ^Xu’„r9ùž´«?‡:ıflL³Õ²U@:Ô[ ܱ=o«åR*I°[#ŽJeˆÖ]8I¿gÕaìó 7 ðìF% =òù>¾õ]q²¿=ÛI)o«’ôoæ¢Ô¬y–2å¾''¿våsÝ’Þ_Ÿ&Ï€š£?óžþÈ6öí=s÷yp*Äí:ú/¯â÷Ÿ<Ƨ‚WÓtGyêØG_q{ý¿Ëó\nÝ÷ãÜuä wÞvœ¿ç#o>I~ç v›½¿µ_nK¢¥ªJ CeeJEärZkÚm‡zÝÅq4ý¾—¼ÂÄÊ~0Ð(­,ómè÷SÍ‹|^Ój-W^Y \ò÷Î"ÿ,ôÔî­­g¿/ƒ¬©)É>²_ÔFUD'(¾,°ábjÃ×õz:õv][‰ÙÇÔ”N€4Yg–µZÁ@œZD¢IþØvÍ—µ¶t]{Ú Z1fllH£‘Kúô|^ãy1á)µqM.ȯ,ŠË÷åï)ÞzAR-ÁÏ+eЖÚì÷õ2€ìúCâ¸bîbµúågpŒ¨…ʾôð('?ü)œð ¡ãðÌ_n噥)Þ¸õ1Îü…CqÇ"£Å6×éy&ò;øü±ûñ<ï[2øå}ñijÀÄØ¾o²ÉæÛ–PÛÇQ*@ã.EÓüý§¤P%Ð9F%(ý«UmJ«ô÷] …ˆJ%Æ÷£DAWl¦5b´*(Ù}ÿº>r IDATj0`YÅi†CgÙ^^^³”÷÷0>>$”©††8Î<ôþ˜-:ep”oL5Z¸nÏ Qj¥z¸nÞLû›(ÕÁqdo¬QhQçU¢´£QÊG©AEÖÏèï[¥Gr¡™êK뀲Ž=Ó,¡Ü:›ö=Ãñ/•¹ëØ~žpž;zV«A§Û¡½±ÌÑÆQz½özäg“ÀpÀ–üfúÏò¹Ï߯Á¹¯{}âä´©Àº‚¸TSq¹æt“A`Xga™‰ ìêÖ_+Y«K+z«é ®&ª³Öçî=÷Üwߥ ½+7b­$Ôl:ŒŒèä.•¬ZºZ´°D‘ÿº>{é›ÅÎ+R+,ŦMbö¸’»EÎe“€UÜÕZ12PÍj¼ê }\·+ÁG·¿(Q'= ªh 5º¢–£bS¨÷ ?0¡h›€ošàîŠÐ:”“eZ¼%À“D@ݸîbJÎŽéA‡f5/Kåd£ÐÛÅñøã6o=ˆï×yüäݼ|~?ZËë¬/ÍÒïwÖ#~•«6xh¾Æ‘þ,×nÞÎÛÞ³HndÊü_æ¤X=x‘¸{lD©B"ƪµC«%¼€T1(•ª_©;áº:ƒ&T—T ^íãå˜ê\à¼ZöY+L¥«U j;h·U‚¼³F™+¹ÍÙ çJÓÄÕfk•FJ÷ûŽ‘f¶ØzùX,.ç,¤ûu[MˆCËȈfj*¤^÷•[MÈÄÖÁuò»ø{PÞ³ ^üîÄNi7ªú^S~M(Õ’=½˜]㮣Ûf_oQg SÊ—€:š3☊`hÊý®I,&ià øó<0iZ ʈÐ,˜û NÝqKlºÓ¥¿Ø¢üðvlØÌ©¹³ Ãá7ýžÿëkúäóEî(ñóïzˆÊæ-À) DÓG£ÕA–zž±{¦e³OÑízfµœ‚n]‡•’”m‹í{z0Ê¡ÑHw—[Ö¯ev©Ÿußö6iV ­Ì‚ˆ³b)“ÏnJ%¬³¬’­¬ ÷jª—ËêËÎú})«¬ž•g)nm0«)ö¤í‰ •JŒëŠ ‡¬ô4•ÊPV:N„¢R*(âŒÔ<€·ç (gÊôæÎ©)ʱ;z:¦O_ÀÊNkfÑýýàÅ&èC /k%:Ƨƒæ"òé™û,’jþ÷ÌP4s¦]ˆÌýê(æÑÌB| ôyFsó¼õìY6}y7§ö¼•s Ï®JüY¿²­nÄæâr•·Þ3G¸4Ëé'ºT¦8^ôº/?Oãþ&…kÇpËûPª@»„¡Å¨DÔ³TÒ”J:‘‹ó}Ù*Y@˜µZ©»ôÅLB/ÜkÍØ–ÅÓj àb°Þ~_1¨@ I†J¸lHqîù|ŠÒ[Í$kÄ‘Ê[]øýt‘JeY8o© ¥Y­ òêÂk¿–*¨*ÆÆºAˆãx&A8ø~„ã´@-M45‡áÀ_Älz}lU Í)m|ñðÍ¿k†¯M7ôžü#œ‘*WFQ07æÔWvà×7“ýX`§–Ê«”ìù!3C¨™ç·¦³,¼xˆ/üç€-½£„§b~ñÿÛÂýúj¾tä#DQ´á—Îh· îΕ¹n¤ÎÙÇŸþkX<µÄUo|žþË/óá_ÜÂ-?SÜóV”³ (à(—|>$ø¾K.™ÃPÖb)¯Ì&Í~´‡8 ¯ø—¸Ë¶ËéýR){—ÿÇHKê3îî IŽÎ° S€ƒd¦+¶•Pb[ªçrVH_`}áŠDðVÅqtb°r Hpª+ ^zƒAŽ\nH±hNVåd†q.ÖqÆ…kß^Géõ¬Lƒõ"0ad¥{XfžFTE¤¨Ëi>‡»©Áì>ÀôO—Pyl0í¤Yó Ðd€ÖM“ìÀ13†CáE43@—xp˜°y?<àþÏnàºçr¸ÚãðùIšûa®G÷e^Ý~‹C/oçßÿë|†*½ÁKüÚƒc,Ý~Š<=vU®¦ôªIP⎤TL¬z=ÁT,-9 N‚žå½h©îý— ‡¬m#Ÿ…¿¯Å_£MËœ¾–ïã)µ\žêRI`µáCV>¬ßMj6o• üì¬ZÖÿ¯ö‹ÊvÁú\(ƒ¼xh0b"4\×´ z™4s¡ M’"™þËzP”v—|^“Ë pœñÏC£uúOÕ óØiÜ1Àé!t~æ‰êÎETôâQ¿´‰šOrîƒÓ>šcÛOöQ9k§eÈÆx#õÜ LyZ·22È¿¦™7 ÍÏùÀYŽþ}pœÍð¸Ž=dÌöøYQ„0Ô«2]×”0^Ö˜#Âs#<¯Hµ*öýnwýãã1##VîK%ë?[­„¡ÂugÔÀ0ç4¸yœB‰Âëª<ÿkpÝ®ƒx;G$è)ÊÄô"á¹—ñ6݆Ò¦´Èàˆó8¹&õ3v¾ã…붃γ&èÇ$˜µõ·3-DâÎ+€ÖeĹ&ݿʛŸ[ºlº­Oïw ”Jøòñqúì)”‚b1¿Þ÷ ×áÓE:i ž8öðFömÙG9ö»q†Êíß ªŒÖaè&­±¥ ¦„‹¶+OïÕ*åB…_Ý¥J~N›y[:³jU6n¤ÚÖéðRÒÞ«ÍVJmeÝj簾BFFz4ARþ Ã(cµD²^\¾âc™ÔV¡ 1t»ÊñÒízFPq¹c°•ó²Ð_I ‚¬T,ÒOáºJuQª#†‘n•Å)…s‡p¼6þ¶z0GÜxô9”ßdpæËôŸ‰`׸œtA Qª&ÉDŸbñ‰ÑAÅü±…êYT±!AîÊ@QCǧѽð\ƒ7˜ñ_ÇœôKBE¥ ÔPÉ– _\bïmûÙz¨Æ±¹Í«ÍE1ƒÁzéÿµÍ–~ÓÖøwøÜóÞýŒï2~ã«¦Þ jÚLú]|_σnKvv¦3¨ZcP·\cR«©(N–Ëb5©TRWërãT-úÁ@¶u½žºp°KïbYË*ñX{äÕ*œ;ç>Å¢NtÿÕWÙçí÷!—SFœsy`×z25µëe<ô0~zVp#Y´ZްùªÕ!½žŸ(¯F‘G>?Àu¦ìžÖ%Ó{£»¥×•™ý°¦ôòqÏÓX*±í®£TîV8§>·‡kn§XGG9pÇL;Ñ/âêŸ:N÷“CžÿËͼðø7îxž ?yžÜÖP"\š¡¶ÿ<ý[þIŒvv€öÌ nNþ–©¼wŒk~ö<…k#Ưً[º ¯´؈°Áq8§¬Ùtåy2ܶUpvµmOïfS'-„-÷mlŒÄ¸®“ðX|_'"¤q,ƒv‰ùšõÝ´¥¿Ý|Ù„w¹–Ük!‰€Ä×¾è¬R®ëZ Å‚o¬¬…[ÇË¥ÆW>—øXkv¨U«›a-Sqt´O½ž3jÂY7+oP©„‹]âØ'Ž=aë)TÑnSr7ÐzQl½͈_ ·u–·åžáñ¯¼žÆöòž™Ðù Ì,qÝ/¾Qbp©‡7Ú!<Ú!|´@®µHÔj²ß?Ï›Ÿ¨Ð}ú0Åëúè3WqêôF—šŒ÷Žà\Sú€"Ð5|et'{¦³¬Óž;ɧþíŸ<¤ù·™h$¦»ðÒzWgØäƒ½1þtoƒÜmWá»ÍÌfÄü¿¸@(Ê1¸ÉÐYü&H¦ð¹œT…‚¦VS M0Ëû»\¶÷‚Èçe~–Ïk …^O”‡„t¤õßìv¬ßÏrä9Eƒ@-å¹ï|§hZúêÊÝüåÂtÓu†º \·ûý¾D¨D)ÅŠm¬fÃ%ÔÜT­×ª¬¬”ê^©õgí’ÂÐ¥Z ‰céɬôwögµvð}çupÝDZºúMSfGfÐ×7«@m{=Üéáo<Ëæ«Ž±ýÀ)>1ØÎ§sÐßÿZ>ïÞB~]7¤ýÜ€#ÿï4£Þ Ã/»üõïßÿWUþöÄg9}îeZSûx‡~·5d²7Kðt?9t•3ól~ãiâaÞÜ^Eøþ‡É P±€£ÎðèÇ&9t®ÏþÃOpúüËkŠ^®__Ý èoåàWöò†·) £;LUVAt¬%Ôr1Éç»hí‘ËiŠE[±¨©”[¸žŸwŠ·€6I@%¹Z‹X»-‡V«åÒí*Ob3fcÎ~´|«7`?·ó‡ì³'²ªµZj͵ÂÅ ºv"™^ÚÉg­&Aïº"Ï51¡' ”)YÁŒÕž§ßóqN'û²ß×én•¼–œw»2Œ"—áP%Ê=ù|ºþ}\·€£NI&WcæÔ̪¯mÊï¾ >« £”‹·Ác8ôxfæNWOòÅÇ?ÆéiœzÀÄä¼îƒû)”:<ñàV~ë¡*ÿÔoàÎô9Y©±° b›ÇÏ4øìïÝ»ý4%]åáÙOVÀ{r 7ïÿ÷ÿÑÛ(¸mÞøFy[Ík+’X\SÚ¸ù?ô£r翘äç6ÝÃ#3ŸZ/ÿ¯L à|¿Î¦©ˆÒx€¦&í€3Æ«ãDQŽ~ß5p.ý¾“ c¥êtH‰¥%éËm{Ǥ«×Ó ­Tìé­L¥-ÞšÙ^>{¢_ê¶ò~žõæËå¤o÷}¸¹®Npñ—ƒ6ZmU˜M Ù€Cņ !çÏ{+<–ë¨ HG^[©Ñë‰6ºP,U²ãœœ×Ü0ÔË~VH Ï Éçët:IÛ²ïs™aä”ô×ú¼ˆ=‰me†x]´ÔTôÑz¸yµÔàÑÝÎ'*wðâñ? ŽcÎ̈¶üGý Þùá«y¢0ÁSÁõ|äÌïqüšïà\é#S!7‚¤“=~½ásþHÛ·|?t~›Æ£²ïÚ7ý޿ē\ÿ=30˜‘y %D™Ö0i£õQc‰¿øó½|æüœsž^þ+xùNÄßzœÚÓÓlxÃa”;Osÿ,å~lB´.†BÒZ‚ßëp(I !—sÍÀšŒalªñoåîêuØ~Ù¸j6%1ôzú1‘¯VнçžûîÁË´‰cy‚µVu+KîËeõÙv Šd*92¢“ÒÄuEc ;?XŽ6tŒ¸¢JæéþßR}Õ²•I¡ (?­=Ã^Ôı—¬*}?Æó"\WD:ͨ!ÕÌšM@l„5#SrǦÜ^"j¿Ì¡_ ¨ÿm•Ç^¾…GZ‡9pôÉeèÊø4ÏO¾·æ+‹°´ÔàÄÙç˜_:ÃÌÌÙä~gfNrná8­n“#µGh·xžËÈÖï£õ¥aO¶G¸}â(aØÄ+µpüTQ«i€^ä¥Oäù¥ßÕ¾’Ë…€o~ÖÁqj8ŽŒT5óB#s². þ>ÁñwPªnÀAMTÐ`ê5‡›:Í-g8púž­gföíj‰Îþ-s çéöº—õF³âQsìü£ ¸¿ù K­Eî~ªÂÇøn~Íc bPõ ^€¸ÁX‘éÇvp8¼•ÓK/¬3þ®àÕ y®vžù~[Ï3óð&öý¬¦´ãn”šòh¹8• á²eº=íeS–"SƒuÙÇÊ^$ëÔ2QÜ,*pµ¯u¹÷Þ{ß}ƒJžØN,Ùã§ØüTw?{ú¯ ö”Ô“"¡V÷êSI¥!ØT‹o9x'ý( ©´Vª9 Œ]–N4Ô³¯Õ²­|_áº]<ÏÁóB“<4ŠšLû•Ù4¯X @u@ø-5`Q†n¹Ž_§óB‰}ŽNº|’z½ifá×e‘Çšz}žn¯ËÆÍÛ¨·ÞÊ 9x]ù0Õ ¸•.J·dŸÔáð§Çøß¿XåTç8f}=j¯àåy.q¤ ü€š¾?¿‹};ÏS¾öM(g+Ck× ‘LÞ×ù¼NvmO{[\®Îÿj¥þÊ`_-à/Öx+]C­§@yŧT’ m40H•ÈÛUDvx'H$ 𲀡¬Å±Uú™žÐéÌÏ«äD—•¢Î ÷TRÎŽG,,¸Ë6 ²êPŒ‰­R§#Û–n) Ï+ Ôi3ÁõPj(öYzÈK ëXN}Õ’a›®µãUí®ó<ºwÕŸgáccÄG5sð"רú^ùëÐ ÏrvìNÍçÏþð]Ürð$ïþ¥ÐãÆÿc¼3šbg's Ÿ^Ø+|m-ìæ»öŶ\Å{ï:†3Öcê-÷¢¼ €gŒBƒ €$>²}ü¥Nå‹ï¥ ?¾ê¤¶ò‰,qÁU½.Z.KE ¨&L(›M.ÐÛ·AY­ ŠÏ²ì÷]×ZcÊv×Õ”J*úTj9È>n·ëªeš dh)m@ Q*0ëBÌú¯¿bØWEuE„žsÀ¨Ù Ô@瀾Øè Ü&ç?ô"Å]mÆÞª‰ç¼üÛSìÚ±ð‰ ?öòîô=ó¿®ÿRW­Ö¤XÌóW:bé¹&oüL…ñ×5Ñ>pΜñ8œø†¾†oÕËqú|ï=^ý¯fðНu#p-Š14y 6•¥—œîYP­ ª»ìþr®KñzVÓôÖÊ6VÉÔW½.Á4>žJƒÛßNñ³Á/ç¨×Óµœ•Cj4¤,ò}1¶ i·•iÒ_¾RÑÆ`Q™¾X‚å²Pu­>0\7O¥ÒFë’é‘´-~ÑÕwD`C+`FÖ{Jƒî™ €íÿk&?jÁ¸>oƒCÿÏféòÒ 7ð@{Û?ºÈx#"Ü0àѧþúï”ÒéñìóJùÕ?Ãg¿PæÜQ“’ÂÑÑhýÌzÄ^á«è)â=¼bÙ"“¨Ä,Ä'Š|ú}/™iy^œød¬”Ì;s[ε.QYί–°·Z ¯U!¸÷Þ›Š‚®…LËô4Þ¸QS(¤Z€vå–öí*™èÛB¶·OM.-PHvxbû÷J%îû>T«±6ÌÀÅIü,Èuòù.JùÉó¸n¥–L;Ñ”µç¡÷x¡œòÈGúÉä_±(Š@4ñ&C6}ûóT:3üÕ^ÇÛÏñW'ÿަK:üÈßû©;3ûáøÜzv‰‰¸…žØÈGN½L¯×_Ø+z)öU¯bs¾Äõ¯;ÌÂã!¥Ý·£Ô&ÔÁqÜP—ËE„¡X¹‹tÊ\õ¼hLKN+•L²)¦q˜ùz†º«!z½µúŽ•Þ{ÙÊÄBK0÷Ö.ûÂ’ÆúûÙv`0H±V¸S´ú´@†„¡g¶v'*àÙñ‹#Oh”r ‚ÏÒãĦYk¥br9»¶Ë¡T^pózm€&ÑÒSÄÇ?‹·ýZTñf\ƒù~ݬþÎK¥€ùj²Å{Jð¥Ænš­Ï|ôä-E>ÿE>zõµüüÒ,Nsf!¢·.ôù ¸4_<ÿeÔƒ71ò£7rýM1eN~M­+„¡ˆ€8N„çu)Êär ¥"º]Çóߌô¼k€pÚHæËj:C©—aö ¾Ü–`­ `忽ËyÀìÚLU¯cNh˜˜Ðæ4×fgŸ-kĘ3Ÿ1ÑÅE鋬%ò` Øc§ãQ,J«a¹Ì"'ÑhxÉÔºøŠA‡UŠqœØÈ2ËÚO©™L_ß‘¶ôEŒ;±‰¥Oïgl[Œ¦‚b£)û)é¦'Û]ƒn\µÃ¶Mg¹ýÐ[˜Ùw3ÏxúìmY«5øÐ¹ÓÜ]ÛÊ«˜å„S¥ß?±¯Wøš(NrÇævoÚÀÙ‘*oý‘ƒÃê8 ®Ùé{x^@·+Àßw ¯Å1Ì=‘ÑÇ« /ty‡n7Zfàåœèk©eÅBW&‘‹²WK½žuÓðÎ`çÎ)ªUi êu9½m¿#ÜzùEJ%M¹,²aVDÔ÷•èjÃwîÒíæ3DEÄÆf+UQÕÚÁóšär¾é³\|¿R®iC,þ½) AwE=G¹ ÅÔzè^ÂcáCg˜ü‰çÁéêmH<˜§‹òr@ Ý;ÍÁ_߆s¾Ê}ñzŽmŠyîéø^û…3gù¹·ð#«x!×ÿ–µ÷úF^›*yþÓo.°ù® hu3Aõõ(U–F‹Ux.×g8ôévã€QÒËðªÛA¡ \Í].v±€Ï²r-fGàÅ—W*xS^î«2YF8ùž§Ív@äÁëu¿@kcÔïkCÒ æ ß—¿ÓI«±ÉÂ(©jô1¹œ6œç~ß7÷u ‚Ïà…¢ƒïG¦'sQjÄ”ïŽ9Ñ›†Ñv]ŒS¾šÒOÐúýÓ„gámiSAÑ~ö(Ãs}ÆÞ™—ŸQ‹\wÇYú­xlᇎêA´‰"Íg†§ñÔ¿àœû?×£õÐÿœ2á™6í—Ç}Í>ã Ë ´.0zôz*ÏÉ€ ¸'uŽc0ø²`ŸÕpý«ÿʯÉJãÐMÒ6\¬’Oö—R¾Te`_h»-ßí† Ú”òRÎÛà Q,Ê׬:éØXlè0äóC )ýEà`˜€)|?JÖ}ÐÆqæD Ì AÅÆ€£‡R5éÿuô9ëT.Bì±J½€ÊáŒíaúgsÌüqž³ÿy=ÿzð þðÃÎ'|áÌtˆÎ9lè,²wú®„|ôJ¸šñqžÞuªªÖãõJ—ÿ… †Þ€?ûØ›Q£»ÎÈn Ô<ž +ÊaÍ^Ó[É—uߺ\w-¤­¥Ûçóâºåyd HXSy; Öó²Äš ﬓ‰þ…%ˆ^&µeÉ<²M)"̧ÑÑt[Ðë‰XÇ`àv”¢X¢”O±(î·®Û X¬C|?‡R‹Æn9@©%‚ÀöõßìI¯®A|ŽéÛCùO¢gÚzË›·bšâú£p!WbtÇQ>ó‡ïæ;Ý?§×ÍÓ=Wá¯÷¿‹÷Îÿ)'íäÚ»á¼óÈÌU<Úý‹WÔ®=Šº|û;å‘Gœ=·´WììWŠï¹z‚_ûÏ5âMeFö¼(£qQj ­ ¦:’Ë 9á]7oŒAu‚ý·nÛ—»Æ[íÐ]i"ŠØòùü<É–n5AÑìcûWãYüüÊò@)£êYàÏò}¦¨“X€ƒNNÃ~ÅÀ³Rµ’8V‰%²0ûz@ÑL?ýW.ÍêoX@±ˆ¦,|4š¡ öQªc¦ò® b?ó±);~e5ù}Ð9!÷hϸ÷D2Уm†ƒmˆ;8nLOûüÆG5ì³ól¿Ý]á™Ï¿—JÐåmÿ¥ÄmîAžoo¤Ñzì÷f=~ü· ùõ¨½‚×te’Sá§O\Åw݆bMÁ¸@ž0Ú¯µûvœ˜NÇYf*bË;‹ X»·¿0ð³É¡P$P«‘Hß­•8²ÿö]QñÑ3Û´¸þ¨†XsQ7€ŸAùG÷¡‚p)íiòöÉó/Ïüùâ³wÏu¼üäGÿø|qâFÞrð?^qoÖO}êàzÄ^ÁËw}þé5“üÄñÙxËmÀF4cF¦m†Å]´®˜*ÌöƒþK!À©:u–å*t÷,RÖjsØ8Êêf*¥“™HùŸË¥Û„¬‡Æj‰#ßÖ¼Ôùm˜i,OŠVKj5½ó/ƒ½ZM*…ñqm‚[’BÙþ?2=±à ‚Pøþ¾?‚Rõd=§8jI8÷ƒC7§tÙLí=£?àb IDAT³–S‚×§k„†¸Ó2ßAUWÃ$…3D§?‰»y/Ê5-ÂYZ>3hPÚÕàÜná‘o¥»Í¡Ûí²ÿ™/'“vž¬?LãjŸ7Üþ>ôåMÚ×…®Üå:.?|õîúg˜~õí8þ6#RÉ?E´qrÝ¡¡ûôûΚ®>+ƒ¿TJù2YY|‹‘" ~Ö[š¾ÌÙ‚@@öä¿ÐwS' <[yXg,Ï"“äÅê„egHØK¹´üû¶÷CM·«“5Ÿ¬óÄþºPP(88NŒãôÌÏ;¦d·Î¸Úœì5㺻€î„ü$è­(µ»ÌÞU*Ít‚üvpv“âš¹ÙåwÓ Efq&®2±Hå¶:'ï›âü‘)¢Š/oácÿZBÉ]y½|ä‹TF^ZçÙ_žãñ®ëvó3ÿq‚ëï¾ålF›Ê-Úå®Çyƒ”û/¨SˆuZ|LÖF/ŽSÝZM%HV{j[e_«žmƒVB—Oþ³¬×Õœ‚•’˜l6Y±#à ‚ôìúÎíÞ}dD2M±(­‡ŸëJ '¢ZŒhÇ QÊBcsêj”—›H°ÏÚ:ÛÔÑÃ/¢[ÏòüŸÌ2~ÕŸ1}ïàÝŠ•àÒD&i„ÀÃÓâm>Ž*åûQœœqÏÑñ<8mÐçðwö.¼vþˆÜÞ.ý‡bJóu~kî§8R펥ÿôà"§¬æË_>½%ߤ×H±ÈO}Ïf~áWGß²Ô40fZP×Lÿ‹XĨR'Hð.7Ú¬úãûéJ¼TÒt:‚‰i6U² ³•AI<õû©¡H¶¬<ŒLý ©¬Þe§CbJjݯì,Ïâ ‚@’Q©d´>ÆÆ4Å¢b8°‚mèa'N$šÑÑØ¦/XðÿrÚÛA_µ2‡çŸ‘aôðÊ«˜Œ)ÖJ:î¡ÇäßÞ¨€t€^¤wèIþä_+~ý&7Mû|ìÕ_Â_@w4ª<†6‰ÏŸÆG»f>ߦ²õãwÕÑ­ˆá|g4rÊ8%áÑÓ ôkjOçùÛ‡nâ;Þô §^ÜÃÔÆE޼¸›g7røO>óÐ+jµ·~ý=¾;Âíð_qØýÎ'ØfJý‚ña´¼%ÓbFfåàûc†øà8CÚ2•ŠçD¸®k‚1"—s)—[8NÙáHLsÂJ¥˜VKQ(¤jÙ®«)—cz=‡~_Öé[¶Ì1;;‰ë:Æ—CŽÞ[bQ¹¬ÍÊ15‰Å`å.Ò–Ëÿ­.)1”|Ä1¥¸kn~æß®)Ï=IJ™¯Ù¡‡ò¯q•l$5ºàhó3ž¡!z \\_£|Žk^¡\å¸à¸(WR« 4Žã»1Nã¹®â9!^e†Œë×·âë˜~$¨TVíîTæcövá÷5ê‚8ZKP·šÅÞÚq¸’±ë\¶@ÈÊÏ-ØH}ò“±÷• :•´Ön[ƒm  26Þé*bt¦¦"‚@Z×.h$+Ù Èî²àèà¥Í0¶Çaê-w¢2-@²×'D3ÏðÅÿ‰·e Nùv @ÇMPAÚèyésD'ž :Ó&xM…þÁÜU]F´þ¢Èzé§8ê è.ðÑO|p="¾E¯J¡ÀO~×6~éW«Lî¸Ôn`Š1SLJù¯ŠhGk‡á0`0P™5 Fkq–aøÚ-@§“Â~m P,¦VáÙ R!¹©”"ÿZ-‰Óv[p¶â‹Ò°º pß÷¾_¹O&‹Êˆ¦H¥TùGžd0°½„Jœtl&“ý¾6E{ ‡9\7 ŽKh]D©œéFÌ©?Žìù«æëÊݹã×.RÚ÷npö¡ÔvÄ„aÒü¬½pK  7¡ÔUÀ$Jm2úlUéÝTÅ((—ÁÓ‡ñ¯ßˆªÜˆ·irÜéEæÿnœ[¢¼iö_iÜÉÁúãk‚|\Wñmß¶ƒÓ§—Ö£å›ð„!O¬óܧ‹\·³ÍôU#(U4ï§œ™=)sà—Ð:—À~ÃPR+òiS¡OÂY™ïBA›ÏSÁP»is]Ñ ”¸TÆÄrqä9ìÜj©Ì}­òp ?#œTK0ëàþঠ@@ jÒ(‹1¶Zf¶lqp›+È!|,„¢Ûjy œC„'2ªÍšÏxÞ+â å½¥¶I¢P#¾Rž‘ì.‰ƒ¿Ôv“¡sæ?«`à¾eó5…Ê-âNÞ‚R[LÒqi>*ÚÃÝü(z™„KùŽ}ŠN2ýgxÃ|—¿9{=ÅB‰k¯¾ž<—®¿™{f_ÅÓŸ1+ÐWÖ*Ð*3­ã®ÌLà¿>ʶ?P\{Ý#l~M7g€}`Å(š"Q$-@ÊÝ×É<`%-7%ûˆ*–ëªe4^û½ AŠz]g‚Ê pe‹7j²D½,“0‹K°¯ÃRòÝ{ïý•û²%ûžö}É8YáO›¬ß¸•·¾|Bؑ̀XIbCE¯§Èå4¥R—v;g²œ‹ïGÆó>gÔy'PjÚX/Étžî1JU°0L3Õ¤ …µeCüqLRð‘½ÿ˜ÌT¢P^¥\.Ñz`ÈÇù^‚`È“×qïl‘áõoæ þÞ¸aˆNñžÑÏðt}ŒúÃá+ËnûÝï¾σÙÙöz_¡$ð|SóÌÃcÜPYdãÍ›QäÍûrÄÌ™ÊF~^%¢º"N“ªÿX% T8µÑ[^)°ª¸ýhÛîTÄWb®\N«†•Écí¡½xnzòCb-÷ß~²ÒÞvm!–_V@¾žËÁÄD„ã(j5Ç 5Òg¿ív>qI)¬Y¨gÈ@cø~ŒN\or2ÄÃCëJuѺˆ8ã4Å’I•ä¤'*>Ü”™î#úþ„4¤óExÜl(ÚòX^­eÕåç¿ÿÏéõòtÏæh>ù¼÷]ÆÉ#»Ø{÷!Â\ö~l޲ªÒît_QoØ­[ÿ'Nü7óû­_Wâšk-²Ù­³eÇ1fM²áº’ñÌÔÅó"'O>oV€PzÚ*%Ãõ•'ñZ’ÞSζèÝ®´é• ¦Ô×˳WÛØ®×&àÊ“ùjC­AVÉÍqt¢É'´^E¿ï˜ÞÓYBL£!_‚3Є¡C·ë†®áøôzà)o—Á@D>G†‹JÅfÃà˜²,/[P“ ò$¼%Cp” @ AõÑÌ¡ÛG™ûlÀîסú¿3Ài³+’‘_bìŽ:ÎÕqè2òò€£cßÏKgŸ|ňo¸n‘æùû˜«=D«}d=r¯àu¼©ùËO•èïŸä†okP˜ØaæC1Ž¢¨B¿Ðéøæ&ƒ¹nWæaâi©¾*÷žKQ…íçƒTÝv{`€k™ƒ¤³%HÀUC_­žV»ŸRÒXÿ€¹9E±˜ÊYR.§étlðK;0ÊÉ–K¾? ×mu×u`¢ŸX;Žk¶ >ù|‘8.Ež´%®ƒV#é퉠êÓf·»`Ž93+P@Ÿxñ0ç~oȦàmÚaAB†Á¼}}Ø´ —ús¨É§sS<ò¹WÔ `ÄÛÅkO<Îç ëå+}-tÙ;º‘÷}ßý8­×#òe`¨ :®E.Q$Ûký2h³ó3HEuVÓÝX-ÐW× PÉêÑBˆA_ "ºV {Ù·²<É&‚ôû:Qõumüúää÷<‘ë÷%Ùi£çÉ‹âBêrZ­ ^z8´ûI¹Yï3PÆ?ÍI០(µŽ <#¦¨qÝ"ÃAÎT#=´®e”*™R¿j Ç ™  ˆ›/Òzð$¹©oÓ>”³ÛÌ"J7–L €ZǼøØÛ¯žãMõÙ:úF¾ðìüƒ«y®â^w3ïÓγñ€³ë1{…/M}X‡ Ma×"ýÚsäÆªfUF©.¾æ«Ïpèày©¨­ÀͶЅ‚´ÐaxáseûûËK) •Ì»¸MXÂMxÇ;¤Xëd_©DR(ÈÐÁ®% Qêõõz*d˜ÅXyo€FC%ÌCQ ^®•>Xi%Él¹œü\·›ò­Et$DkŸ^Ï3íEDK!%qltªI°+fà¢éázàž¦ý䋌ÿàvTp ŠMfu8ŠrË(gEIKžbÃíÇ™ØyŽ;ŽœáÜ›YØq~ö.䔂ë·oá? æ¹9÷»ežçÖ=¯ðÅÏýÝ$O||#'êqÃmu¼‘Ý&œCë"½^`ÚT’Ù–Ö$‡d¡`…8ÒÙ€ÝÞXÍË|>¥Ûr©6Á­ÝØZ?³Zð.Gj8û}„cc$2^† š¬ê=ùå—Óf©ŒµXº¦Œ%§whŠÅzÝ£ÛMÁá¢Õò’AŠLU5¾ße8,f’‚“È‚‹cЭ7™Œ˜ß¡f^Ýf Æ!šŸ¡òÆÝÀ5(v#€$m3C8L½8W¥WëqüÌ6?ƳÏ=ýúÆåýS›¸a×~Ü8f÷‹-rCŸNw°µWðªõøÔÑEÞ—xëx“À5Û›àl JE2<™¥:x^…RI¡TLÈ|+D\*Z7!ýØ÷zĉ­]³)«fA^¤_­ðj‰À»XÀ¯¥+B0p˜UL;Ó› ÁØUb*šj¢+­–Ç` [r. ºPL?5ž'“VAPaz/'“Ic´vè÷S©h|¿g{ ¥fNPÁû6Üé­æOQ6ÃCÇT #fn°Á$‚ÝéÏi>Þ}=‹…ƒŒTGÙ¹íF^8üwô²ØÍ¿Òßó¸sïü£é'ð^£0u‚^a=\ñJKñÖé×òþ»»¼óWR;`dçôET ß# ó ‡q\¡Óq %Ø¥kF¢äáyV5È€s9‘e„B.o0x)ÏÀµ6 Þå”þÖÌZƒ¹®¾…&fq6I¸®6킵Ëê êeÎÁ…‚ft4d~ÞK4ÑEsP'ÐI[ê4›##1KKUóKèeöKÂÅîÑé”C+_™2­d@qý™‚ü[äsÝ&áè–¬ñLGvˆé<Á¡ßÞCq¬ÅÍOS[º…÷nÜÊØ|Äo_ýžxîoþÞJo¥à¶?À÷n8Àî·žƒIP³pÛ.{‚×ðTý ëQ{%§Zs.žg×m-Ü©W1ùæ×ÊÉÌ–`‚0,Ðíº‰â/èd?oU¬üž`cÒ‰½mú}m¬Ã1jBkû\jUx±D°j°Ü¾ÛZÉ=+ùZ»ŠXÊpVë,«U&ƒµŒÔ`§ýÕª5ÕT«C:Ïô0)1"ŽÓ™MDrÊÇÔë^ò¼é\ ¦PèÓíŒà¨€2 ¤×Ë›l`Ê{-ý>M£.$ÈBThC+ˆHI(£Ã!‹_P\õ§ùvÅ5 '¹öw°s÷IŽþùò‡Ç¹ëÕßÍ#Ï|ü.Z*¸fçr{þqÞþ¶P·"†2ÄÛ†´NÖ_‘HÅÿÕ¯v?$ÜeØjà—jÀ,ZMׄ®ë’Ï{„¡g.ç¿Í¬<¸MËA?j”w­íÛÅ“ÕÅ+€eUäÊÀõ})Û­ÁáØ˜W¿oíÁÓ“¼Ù´öàËO”µËN~{‹")|_ËȈüâYL4(––X!•…‚.ZS…켡ßWø~1dŽ ˆ¢¼ùÝ,…³Œ¡ñ@û(–L™Ÿ3¥ÿ˜ñŒPL‚ŽÑz”éznpÎôy®ú哨¾Ç†^¶åDËä^pþ|@[èqª=hM\—d­P«¹ û*kYæûšzÝMþpŽ£Œ5“9óO­·$ù/¡+«qã]Â}ã |N¼‚}8Á¤/©*  .ä"ÆÞuš¥Ù2eÑsZ ºß„à ×ÝÌ]7qv“âÿñ‡Ùþ °¹„rQJr:8;4ýâ §¶qzæèzÐ^Áëdë0¿s dâDÃgïäÖ‰iÞ?ö6½çf”·¥ZärE<Ï1B¹®ÑL:YI¯ËmõVóö[- ¿Za0š€ÕªN‚É–îžssVçìÂ^d-Ó•% ü•F×Õ†>œjŸŒè„)eïkO~y1a˜rì}ÄM¨:ì¸m‰ÿc"â7z70ã[· û\… Äì>BÔ«‘ßã œ®9<*ıK¯çÛzy¯fç)¬^'U¥ê®W٘ɪg~eRXK xµ¤á‰1'LM¥J¡óó’lÖZ+Ó¬T ]™.Ô&v¡% åó°´d„²öÈβ¢$RR)šÍTj9úé¤"±UƒH.ËMð âØ£ÓÉgD‡h=ŠÖ²¢‘DГA ¡l”kÖ‡£€kúêE‹¨ÕáÐÿµ‹|§Å'Ÿ¾“gz3ôúËm¹G*WsÇÖ÷ó\ý©·Ï±°0Ér-Ÿ †xžÇ=7ÿKÞ}ú¹ëùÊ51Ûþùø±½Iaû8SæuPN ÃKGFù7§«ÝoL(£õˆ½B×öòµÜ1áàOìàúŸ~†|¾Ã¹PÝsÌvÔâì;¦Ãk‹ÊËÎׄģYZR˾n¶Ö’(²2áöfÅx,Ì~åÁ¼š ðZï7÷»¿ûWî«VåIÚí”ú+=vZö¯…+¾˜ØjvFJ 0bz:dqÑMt¬rV¾„\T(ÀøxÈ` h4T1¶†ü!eýU–¯P*õpœÝn5á%AŒëFɪÐuEËM¼ú(5&À!ÐVŸmn"Jªü>^œñ×cøx@½ûNë#4KÉßd×Ä6~«ñ»ü *å{9<8Ànø~Š~•Ý×läÌ™”‚Û_ÿf6”÷â9CîÞþ/˜‹Ÿ§ßïò®Éÿü_äàü­¼ûϱ÷ý]ò›váúS$ê4Íê2fbÛå3£¸GßM8¢˜[:³¹Wèª\þÛOŸážt˜~ÃnJ;vR’Ûòf”»(ÇáCª¤µ¶ÌÀ¬¯àöÕ²¿ãÈi×àV¿ßJôÛ¯XLÕ²,ݯi•¬TjõϧÚÖâ{µ2b­l³Úýl©c¥‹í/µ°à&ÎNC³Æ+ÐïË Þj¹ l2k¯¤ÌÏ;É®6+¾´ãhÂЧߟHD@›-—ÑiWÆÛµ‘ÄlÄ8‰Î[eÈÉ"o6†*oEçêÜþþÇéÿŸ_Ù~+3gO³eóV>ßUÚËž÷|”ë‹Ïã}$»ç&~Üy’Símüòl?M¨gá_ "‚=eòúãÜ\¾™GnØBµ<ûÓŠ=ÅsôgÇÁ/ Øj4鋦¥*Q§Òà{¿ï0¯þ»:?7w/ƒA¸½Wàê…ðÇO]Ã/ÿŒB¹{€”oÞj«YÃ88N„ç)ƒ“‰h6½D=»Ó±üÙN-,¸fàžú ¤>uû­Tdþ–)—aq1­ìÐýkÙxívŠºËNôWžîkõYýqËÈžøÖ‚¨×“D0>®ÍI.¿¬ôòÇ_égšZM%™4;#°{ÔìS)Ë=Ðäó!õºRÒ*ØìªµE ‚ïQªƒfÚ`|”ZBÀ?–iØ"4Ãë}´ ÏqUÈMÓØÞÿAÞ~ûðNoæõPþÑ>™"·ÕNóÞw½Äð%—~o/;J‹í DaÈÖ©*wÇg)ÜØÇ=¡Ùýß·:yûm§ðnÚËÝ¿YgPPÞU•Y™Sß¶(MÔóùàÞÉ_FM¾tî³ëÁåVl/NQ_œ ]«Ž!èÐM¤uu\·D.W ŽÐC|ßͼ'Äê>—ëP©”(Ò™—çiƒ]‘¨ d ßï«D}Ënälð¯ÆòËŠŒ®L öÐM€Eï­æ x)˜p|“ˆ º© ‰=]Å 4Å t:V×L/k/V2¡¬þy¯'6äËËû‹Ûfl¬G­–§ÛµNFÊôÿ)9#Ÿâ8!aX&Ž]ƒL´2ešfæ9†‚ iª‚èÍû=ÿÉkyªûÆG·ñ“g¿Ä ?ð,‡\͵¿xuÕvJ»=öÞØÀ«Ž v´ønÿ³Üü?6ó»ÿ1G'gùI} ïíÞ51/ý׫x9·‹ùÀ#l~Ǹ7รä7x²ÏréZÇ(UéwFØ2YCQáú­o"ößÏp¸Ž üz.ÇqØ\mòï~õr›_m‡kR‹*€KÀ@¤ƒØCv0€ p¡X,S«¥(ZyϦ>‚–\W(¤üþBAS( ˜› ’Ç @+r1Qɹœ´+eÆ–O+u²Ž\ZRË̳-‚åØÀÃMX¨ÑPËXWÿ?{o%Éuwþ^DdDîY{ïºÑØ H!R2IË–dŠeI¦myÍHã3cÍ í±ŽYcËöx[öØÇ¶|dY%›%q3 ’"$b_»»ªkɪ¬Ü3"Þüqß‹ˆÌŠÌªjŽf$‹yNŸjÍ̈÷Þ½ßý–´ßOIÝnªàò<ç AÐ8(æ èëh=B·cô§YûŠÚM-vž:F»]âƒù£Ô¾Õ%n¾Î ÿújáv–> qñ.HË B¢×è<:G4*ñÎó_âÖ³_gåƒu”ÿ Â™w_aîÌ/-‚>!ÑhÊ3NHv"±k~ Ø@2ëeƒrJ'øÑ¿ýñoì¢ö(w¶¾—Ï ~ŽÁà›Ä k},Yáƒ/6©þÔ·¹}ËUÞö7?IÔYÇ? ç`9õ½dÒ%qÝ©þß¶¬a˜VÍV gy[vòf×”hat2ânµRQžçÉâ·žïËB/—µ™°ÉZó<Ù\W%!£J©½Z€<„?PÁº‹LšR¶ZšsçFT*^|±jB ÓD¡Éþ$[ø¾,RÙEÇA?k€`7‰Ty(U€ïGìîú‰[úZd‡ÅÖ–Ÿ€¾¯q݈ÑÈ'Š| IVjdtm›PÒùR—¥wG”ÞtžFX#îPþqœò2áðŽ¿mUúà„”¨¢Tz=ºÄ³ÿä õîGþøw¼u ÿÄ ¨ÂIà$PÁ«fá-ô=#pÎb3 ÑTÌk²Æ&> –ÓH»t×|>û‰‹üŸƒ>óò¿ ¿‰|#W^{€µî:7 ß¬°ý+ϱ¾Ýää·®R½ùO‚³€ãÄ”ËuSꋃÈâk6Óì1Ò%{§îÁé©mÍEì(Qsš:þÚ5;¦‡a½.ms±(@âü|ÌÖ–$i-m¸ï ë&zX†ÒttQ›H1èv]z½JB„Èú•OVRÖËÎ躘Ò/0i++šp]a/./𼈵µr.¦§¿,þZ-6´c•)6’©Ýöð}«˜RÉ•…>M¼û)âÎs\z|žRàÜŠò—qý P@QÀ?q ·ð<¨ (¥4ÔEãq¨ä”èo1÷¶-*—ÁyŠÓæTŸGèÈ!ÊñQÅPgôEMŒÐ˜KÒèP6Õ0Ì.àÐ[ïñï~ìn>×x¢ù(qá8•J‘ÝÝî7Wó!"5Oo§.?Åÿüèmü©×¡æ8¼û–'¨„Ï üsh½Ì`PLÊò^„µjût$´x¹ IDATËù·'ÿÞÄŸüD®8–Ö X”É@VK`MCí½Þn vÖéHe;ŠEŸ]+ö£§[‚táObVÞ+¾ãšÕU9ž xò„öd·vŽ^R’φí€íƒJ%CÏ8¥ *Y|£R‚†µ$³è¬m d3ˆñ¼Jí´ßȃcaõksÝwðN¿Å4ÇQTÌ⮀:‰{äFùœ*W¢†™"#î¿È܉—þóYNïS¾}Ôq³ø•|T=Ð6}ÞlFUSâWPª “ }U¸zhzÐ`—+_(Ò¨jFkÛÜqô¹nî“ v ôCx²ýñoŠ„ù¸xê[yñÒçŒ:8ŽÃ}àÎã§øV÷‹¼Z<ÍÎ× Þ‡©ß?J ðð/óƒ«þó/<@ùí-jž£ÿÂ.¯tweÚ½U§L¬=”Š)C´Ž¨×e#ïv]ãî“e½ê ¦•.Д˜6]!˜×:d¿|#Pcí‡Å$à€@ZÞÃü¼õèKGk–¯¿¼¬i·Yécj~`U†y`:P{܇²/̈ØçS.Ëïì¨Ä‘HÀ¿I‚Ñ$ËPZ‚bQôÍf‰ ÐF=¨)—GæoMìØŠÿÌ 7¿ó%TùŒQz çÌ&04'vh¼]¸1Y2‹Ø£x×¢üã(VLo¿`žaß,òžù=•ØœGæki 4h{š/ @¨c`€bž…ë/òοú,è¼Üão<¸Æ/ÿë+tnþ¾øÔÿM~3BhöéïòÀüm”n¼Lå]e‚nï¼c‡ã÷,¡¼‹”.vùÞŸyš­_ìP:ÿ …# ­]†C—v»€ãHÛë8N‚Ä‹c•¦^Ç€„:Aý-H.Ê[+žæî“÷õY›BI%áåõöÓI–ÄS¯ ±§ÓIçîYÂŽíQ²£= ‚dƒL&Ÿ›ÝĆ\½­­TšVK±'Sã|˜fÓK&¶]ét|Êåß×@ˆÖk°ûIF¯z3¿ë¿Ä¥¯>A}sñï÷ð >ž³Å7ôÀ;MaáNÞw̶E9éÏ*Êwm3Èûo/oáÏÚF#É4+—aq1=I××¥¬±ýwö„·ø€õþ›6Ìã!ä‘‘ÁleÍAl³»«s¤”iœy¡ËË!½žËúº—lH–³P*i‚ ÂuGrÈ*F/¢ã!þM?Þy7vÄ,j%Ü|]\=™hËÜP°"¸€ŽMñU4­E¥<ó½‘YðƺLÄŸù|1ßÝæïô~~ê½Wiœ=e*µ3ÚuQºÌ܃oçz ‚ãŒ(•4J‰Cµ½ÿ¬½—¤¥iÜvÌ×íZ°0V:µÍ»~YüIàè~à^Þ& J%¡)6¯¾ê™ AE¿¯“Ò;[I’Tz¸IC:Yp]ëY ¹|Ù%R}@¶çɾË„j44J)ªÕ˜vÛ5j¬T aŽŠÅˆÁÀa8,R­º¸nâmTõðî6 ®d^cÃ,⎉@pH.q\ÀqúhJ %aVÑ4 ¹j¬»”QÉbWh xH`6 []øiU¡ÌóðÌÆQRˆ‰ú[tž}™þýÛYþú›¥/˜ß+ëÎÝÁÆævv®~sÅO£N‡Gæ «Wò_ÎÜMûê‡9öz:Ý>áhÀƒíyž ø¬»I}Ó7À>j•ý ÇûþûUœÓM^ûüu4ÎÞ%×\U æãL']Aë:៲•q­Ö{˜¬y‹w°ÞÏÐ#[!ï·!äU c-@¶\v)í-ÝÐ~¾TJÕH†Œ1šÆf_´É{C ³KÊ{Q³ôít8YY‰ØØ¬þ2~)o©V5ͦK¡’’,&P.Ki¶½-ýuh”ÒxÞˆ^oÏ«ãºCâ8Àq"F£¾¿H ‡ŠbÑ1(®“È‘mš‘ïGÉfP()æÐºH9ı‹çÕPJ†ž©B¬)‰‡ÖŽÙ ˆ oÚES†FB¢kx=PWÑ:$ÞÞàØù â—o¢8•‡_x;ï(}˜yú^<Äÿ¾ò;|ìÙ24þ¾ôŸ~ÏÍLÿ <?àGÎrß1Õûª4Î]àè[Π¼Ó(æ #0xŒ,¢é£T¥<¢ÈM˜®ÃaÚÏg×—¥âf‘þ¼q{žî&«æ;l —ë 8YÞG‘,îÅEh6uû­”|.Žas31(%x€p§ø&Õ†³xV­g=ì?߇VËÉ8«î]üY>máÇÖV€'JÃÙ—{2¤ÊÞÚ·¾›\Ìyx\rj{B N™€×n âMöþrrivwmä°ÌÚ%¶KNÎl€RŠnWô÷ÙÌëCš>T(hææì8OÞ¼JEúþÑH±ï§ºèIšð¸œXž÷‚Œ÷,j4Ò{’ŽG£¤ûpÙÌšÍ Ù4*;Ç•*BJô˜ÑÈ¡ßw2 ‘fIü‡ˆ"…ç„¡Š°Ø‹GÄq‘0t’¬P3TÐZNç 0Ø:(ЍÂuœþ¾÷ ÃKÀG|œÎ_¨°ãÏq뽊*-ï6yrXe«÷*œyˆ·Áç^ú¥?”>‚¾ïr÷-š‹Ï}…ç/‡Ô?í0Œ¨ŸˆU<.šª±÷̤§¸DQÉØ€» 1JET*å2t:®+¡6¢ëYˆ?ž˜g–ÅÂÊå”×bG‡×úpßõ®}(K…•ÿV‰Aè‘#šRI%%:ÖHÁ ËÚ³þd)Kf™ÚEíûbK^©ˆ¼q{[@»Á }yÏ*ûlbq*Ó2¨ Çz¯ £ø>ÌÍEt»NâS(ÏËIÈM¥RŒïˆc‡ÑÈI¼‚@S,oxkwf埥RhOüQJ1:Iµåû!Ž32)3޹1¤‘þ^€?¹NÆ ‘+PªŠõ§sœ%”ÓÀ)U(.Sº©ÄÜõ'PîTÁçâ¹M޶ŽðçÏ>ÅS¯­Tïb£wå&Çš+ëóèà>ºéð©¯Ü@ós·pÏ›¿D8 (T— hƹjM­-Œ&É×ý¾¤TµZNÂ~­ÕbÊå˜z½O·ëu_zß•Ëi Xy):—í‹R…Frøu:jævè à;¾C6€,Ê.£0Þ ÑãKù¬ Ø7ÎCŽã4Ì3i<ÈéŸí÷åSI°âòòˆÕUÏ+ÒE•‡|Ú7K„?²ˆ KíAW'ÙVN\©ÈÅìtRUhcõì$aŒžçÐn»fº¡’Ï»®C§ãf¸ ¶ª€ ¢µË`à%ïåp¨’‹/چМ*®ù¼6ÆF#ã6ƒ•BGµbÕ´EEݼ©Ê-±pËQæ.,¡œ%#"*R?5âîo{‰…›vx¸Ôå¡'Z¼½Ÿá±ˆíÕ?d›€œ<ýAæ`›wžÏ­ÐyLsä– ó§ì·(lÊh]¤ß/ÐïË8Z@RQözr`űC¯§ð<…Ö¥’µ±W }^œäUBª››“E.6w²øëuÁæÚmùÝ“÷ó~AިݓD4ʸPÐÌÏ[~xþy'ñ-³ ¦,Ð÷Љ¦+l® Rðâ‹~Ò—O* ³;©ýÿbQ²õ°ÜéÉ…Ú˜Ž¤iÇv Øé2ÖKRt»i™îyrð©$Ó^¬p¤Æ¬žƒ@S©DòwU—8.%~²‘©L)¨Íéï&ÔPÏÇ2–ki‘+wMÙ¿)ÊCU1Ó€.¨e3Mè¢8¦ 4LJA0µ‹*¯²Ë—¾vŽïù|ôqt¿ýßü‚/—+ÔëVW·÷|­Ýió±«Ïr?÷ðJ޳¿óç>°idÛ:™º8N‘ ¨¡µ—¤óÚ“ßÞw;;Ç‘èð¬÷ŸæèÑ8©¬vßZáK;)•,Hnº„3àÙ¸­ZMœDªUYüâJbOY„„ä,fÍ+§y—OÙElu¥’X”F⹉/ÓŒý¤ìÏÚ&On¶Ý°oz¥¢YZÚduu‘~?%4 sK¥üi“P¬Ñ‰å™åF8Ž&šw†!ìì¸fׯÑéð}QÚJÆÚ˜ qìÒízc¿c0(0¹‰ñ©ë:†KÐ @YAß“BÃìŠon£ x%¹Š]t<`õ3á­ó³«÷𱫿Nk·qBûošåwgðý<ÙúÕé„[ãî7|• ïÛ$¸ë<Êm èJ tÝ`1>Qäà81•Jl‚?Eqš¶ÊÊhÚ轞l Ë=µ¸(†¡ž§i·3†ºûö¶Úã˜=y Mú扉&§n^±˜ óóò‡®^µÀ”9?º6"L'c³zýi+*šflùü{cÊ÷A–Ë:É“Ú&¶¤½Y64µR‰é÷1Ù±µ(k·± 8)4#ãg9 ésû&!)¹É"øJ~·­rg€Ö1aXN8æÂ!ˆÍÉË`1…‘)ÇÆœdÊgîü€Wõ"/'‰ _˽®aSÜx„‹ó.¯öž¦ßü\ø®ërvéV”Þäg¾kr¨¸í3·ð©§¾ôÿÙÇç_ú~ºü]|ßßÜàÛöeT1¦÷ìïâ¹oé=@¥ŠfA:I`=²²]+¾™ôÃh6Ó Aî ÍÕ«B®«Õ Vk† u‚IYwkë,356-¨Vå~ÝÜÔ ¨Ÿ;¼ñÆ/¼°¶&OªTJ£‰SåØeçç‡9ý'Ëþ¼…o©ºÅ¢äXPÑ>¬ºoòôŸ|ay“æ¡“œƒJÅr TåT¯ËŘ\ÜV†Šv{ܯPkh6Ó*es ¡Z)—ììÇ8 ÙßíºÂ3°ØC^W,Æ  ç’žÓ‚Œ¢"İÔ"#ê ó%ÃÜ0ø@ˆò}î(½Ê{GŸäÇ7ñ¼zqaˆç9Üœ©nñµ€³r”_}üÔâoÔhwvxOàñÁiqæ}]âMżòòÖõll¿N»#†G–Nà\®¬½ÎŽnq“ûUÔÚe®|ªMäU9òÀ“°ô"Ê’Ql±h*¼‘“xúOJz³‹?ÕŸ¨±vTÌ?Óªòµ×hµÒpÑ¥%¹W67¶£ëlv@HEoU¹ÓÈqJûÞ÷þõµÛ¶_&AÚ'} jLJ÷Cö§•ùöŸodV«òºÝq°1õD;ؘq–k‘Z L ÛÝUJs꿞%`4²˜ …˜Ý]glú‘?*׿¼PpÆÿìk‘ P¡áÐÉX¥Ë– c4Ñ$ŠªôznRI¸.øãlN¥LÕ†1˜¦)6«À å+ÜpççØþzg×îãÙî“cæ¡JÁ‰ã§øžã ¼çOñ.×åÓë§Xë_åÈò:Ýß×C¥ ÎÑÆ (] ïÿK]ê·/ú>ϵ/êŸÇOÎ~./.̦ŸT*²cYËð¼…ž÷;óü,ü!¹1J©“õ´%š”czx8Ù%E§ãš^/»àÕX ª÷„¦éõZ­½.Ç6ßP‚"ÕDû@’}躿ð:q¼L¿ï&²üü(öƒj”cU…» ›‰3qq,m¤Rš¹¹ˆáÐ! 5ŽißÔž©×$ž–eÞŠÎE%jWùtÆ4Šz$s3m;ÔØ›üg]‹½~_æŠyåɬExÐÒÝ2)UåÔYoZöØVá~'ÿ4q–h´»+›ÎâbÄÎŽ—”åi9¿×‘HxÝz Йe]Ò^HªN`“«[èv±ÍÁŠœ,ûÑó4£ð(qì˜>3ÝÝÏ Ñ6¢ÖæÄW#31ðÑtÑáçþ¥fýùðªKÜïxàò|¬üínãlãéµÙÝ®òÛç ¼ÓyŠ7ÿñ+pa…Ç#~íâ:Þ˯qù7êüÜ'¾,þ³g.°¹¹E»³õÿ‹ÌØqõò×{ÇŸÿeâXóbósüܹ{¹÷ë¼ç†>q|78…¦ D8Å ƒAŸãaŸs§‚7ðПãîc”» Ãë_(rÛ»çè·µXû ‡ù³¿JùžîÑ[ ÓS&DVÿE ÇqP¸VÓ&˜F'D:KòÉ›ªMâÙö!Kûõ<8 [ÒÛùó}._Ò5e)æã÷ªàžŒÉtBF˜¶3tñïö‰š/}¡í·Þæûa Ù ò*ƒ<Ì¡ZÕ¬­Éâ—°Æñ CV[`´ç‘1Q{.šáÚÿïïðýÀ(ÅôÔBA'-Eö¹ À¤MfAÌöv€çéÌÁÊLÁö'øcð½Ï}‚wþ‰ßâžþŇ]Ž\?äbuƒ»~TQ>vÅ1Ã4Œyòʼø›+ì^9Í‹ÎËÅÙg|><ˆð‡Gæf»Ü§àù „¿ u|M‚p \jÕy æâñ;¹¯x/‡—<Ÿtý?üW^§ã6ØRwq¢~Š¡òŽA¯?‘³÷*Šs7UùP5GãÖ T®»‰êõ7áV®7.OU¡e ^!|q¨U§þÆûPέbå^¼›8^f0ðÙÞÚ·½^6ËÂŽÃ0eZªy¹L"£Ï«º'+᥌¯%‘Y6® ÿhµR ßJé%”T%!=âàž Ý©[iši>Ûd ï„–l™t®«Œ±Q¤& ßèÉ¿_Ly½žÆ&‹iÛa}–`”}YOb‘ÄÃmRM(ß'%µ¢‰Í…ñ}M­z‰(:I» h˜eRZ=…ר©…­Têõ¥bÚm/‰lô¹dxALté÷ıcJPëP8F+0L ÚdõÃ=^øp쎫¼í‰ßàåó§XzåVn*<‹_?Ç‘Ïpäyp–1IÑLêûŽ+6оE¿‡^{ùÉ×)Ü}ŽS/–9åßÊO”¿ôõ9.†Ç¸ª®r\-³Ñî²Öªsµöî}¨ÏG?úoØØìÑs|çw~ Ï}ý&ô¥gX(®ù!Ž·ÂmõOu7Xž/ówoø úk„ÕÂe>wÜçÍïèòðÃk¼ùW¯ð»?}+ÿìä;ù¼7äzßǨ}+š%#ë-¢peRbÆx¨ŠØ¬4ˆÎ‹üÒ¼À#ß³#„+ŽÇ†휤÷ T"{·ÀuÚZ+C× %~~²9ôzš……”è“7‚O tŒ2rd+*“çR­ÊÂïõdZ[3Ù€½Î‚oû‘}¦ryã¾ZÍŠDÓRöG‘|m¶°óžKÖÁ(3ÿ¿µ “ž_›Ø$Ç„+¨= {[œèÙt—ÉLÇ!éí ØÜ:E¿/VÑý~j‘žVT{Œìïµ£Ï^OD?Q䌟ìx¨XŒ‚ív%éù„â=Dò }u4 _þÇ~—KŸŸçö¿²†ßhþs—s=ίÿý7±ñOyÛßkã–Îc‹U` K¶Aœ}K›ðË_áÆÿÔg¤î¾ÿ5Ü·¬à­ðêó?}ž¹ò·ýåuþÕc#JÝטöñžy ýiům¼…Ÿìoóë¿þŸÙÙär:~ë·ž`®¸ÈŸáÏ{ çÁÍã[,ßÚáß¹‘7>ò5N^ðàO´Ør‹üð_»Œ·p7è>/ï†lÝÔàÛׯpte—a÷(np^Z"QÊ1†,#ÑJ „=©b#¬rP¨¾ù^¾û;þ s÷;èÑš\PŠDQ~ߣ\ ”G¯çEÖÙ…'¯E¥ÿ¤ÎXzϽ7yõû°¾¾×N?à–õÞÌV¥ý~:á¤ò.cñ¢HJôL“Áƒ}&8û¯×“…¾²"(©ô%ÒÛnm{”A˜}á’äc£ÁƼì&EÚ,ʈ(rÆžç4rSöô}q=ž46ÍŽzlúŠÌÿSÇânWQ,Ú*kÜñ5/œÕ¢jµ˜nסݞ–s¨€²Ó)›‘vY[Ê IDAT"b …¡™ ,áº=Á†«D/ЩÄ?VÀ;ú¢ÝMnü“ë”.^à­<Ê×þÎI†¯µ)^?g¬ÆÝ0…Ð# Ùéóc?ýU¾fóÊ"å£g@U¨ß°ÃþÓmi;¼ë8ÝtðBDÔQ|tx–-¿Ì³—?=óÞêv{t»¿ÎÏÖçX*žæÏ=Ï©wµà¼Çw¿{ ü£@Àûÿú*Åå*Gï‘%5äÎ?³Á-ïyœÏý­ßò×Üò½ N.„uXò°Y R)Ð d©È×½ëYúàË´þÝ©<üÞ ¨1zF˜ôëˆÝ]ÇЀÓëcAºÉ‘zª™~èÚêx4J³ó°ûÑâãeX¬$ëÜ÷««BM÷,È`y$¼Ÿ<ñ§¾oÉ3Ù9¿šª)È%æ-~+û•ò\N]­uâ­fõ¶är )ci šM«œ$ÿ °µ%×bZy‡,%Sæ²Â ”ù¿fnn<³ @´Ä'ß—œÃ˜²Ð.|+ä*mE¶íRìî†R;b\êßJé ?NñŽMâ^¸ ·Sºa4Ñ^‹ù;¯†7'@-›Xôš™&T@wq7þÄQaÒcE‡ ÄµÕGZ(ºh6€5ºôÛ>óñóüãú)¾þÕß:pïµµÍ?Äýìݼï/S*—Á=#¨,±x[,¢L¶‚b„ëŸdT„3Ž(,¼åžæQªaLSD5©‚.šŸUˆËrÕ´; Âðµ.å‡ïÇ©^‰ÂJED‘G»­ âîâûšÅÅZ 67=ôí½GjØ™eâÎÚ$ìÇV+ßu;{ŸZN!)¼("‰ ²4ài¶^ûÞò¾µëõ…¬ÕdÊR|gM¦a ¶?—%ÍH·cëgP­jj5E±(&W¯:ÉxĪÿòÞØìëf•N¸“þ^¶¡6§½N˜–É(-À48”õþi66 Éî}n–DU*Ù ¬v\›ÊhÄbLë†ñpQî<ÊÝÅñílº-:½CéœýàNãVs –ínNIè£8ƒV’M Øçdb`Ë(KhZ¦¬ní(úOüûö{ùÄcÿèЦ#O?ÿ4¿èÿIîûØ%Î]?Ä?ZV|„yó\fáŠ-{°|„³ßS4æ©6§±d^“U6~Š%PŽ!KiSô…J=zGñVÞ‹*ÜC/Ñt:V%ªÌý§L°K­&ÎÀ–Ó!†¯$žƒªûUy˜\vMåƒä:Y/'ðìB·ˆå4“ƒ,üÉ'åº:EÈ /3êIÛðY憳*kôéy:12ÉN¢HN÷…8z´ÉpÐlVÔÝ.Ì ÞêQ4oy½ž| 牶­$Ûm1­V¥¹/‰”<§2ËÑw?¿ÿ¼EŸ7ʶ­£ ,M6 ÂÐcàÁ¬Å8­ôÏ+u¶·ÇÉ »»*,œå!8­Ht5ƾ³ÚlÌòÖVcŒbkyþÓˆOÙçh‰CÙ“?o ó~ |Š—`–de7žÉ÷Ò>o;,—I\—'½³»y§#7bV¬”ò4åÒ&aT§ÛõÌD"¤×«P,öqœô‚Y¤&‘X™D#­°ŽBb]9D³cNxÏüܦ9]#P#AÉõ†9E(vÐŒh,´)®ÝÂñÅ‹¼¾öúµIx½÷m~ŽóÇžø”D,à#.HKÒªhebÚ´IYRªjNú¨¶¹ç3•Mh®MÏ›3.Ï}”ªÇG h«éõ|ÂPQ,h·ƒ$h6K`³ ­Û•±n¹¬YZŠX[sFg±˜uÚû+oí̪ òÚ‡Y-ú¸þ ­@½¨SS5ûûÑló~ÎŽ1¦-–Y¬½YtâiŸË{s|_úüz]sé’ðæEa•ú ÌÊX³è~§£rGy›‘M!ž›péR1AñóâÐÇOSï… Ð¬¯{‰Q^J²ÝHSþ}¾R©”Jš^ž8vè÷íMà'ãÂáp ­|?|aꫤn·Êxá cNJì¾ùX4'{Kúeå0mŸÍ™v!"¬·_§ØóX/¾ÂêúK×Lúy}õUþ¶_¢÷oïã-_Üâ¶ÿ¥…Wvgžl j)a>Š‘§¤)iÐÐ%ŽFE¹ˆãt}s¿z¦œ«÷^Ï7±Ý®œúív@¹Ó빉A‡mñl…˜eàu»’_±¸¨ÖC6{+ä)´a‚¦×yòtÏ;á÷k öVÌ2 KU®™ `?ß,ÊmÞÇìÎ6í{’4‹|4í¹[ÒHêd±ØñÜh$¬¨<ð.¯ËãdKªì{!=ž&W¯ ·bwWçÚ—ï½`ìIi7±qokÜšÕØç$š9u”Ò4›årœ±O×ø~l G\Ó:ÃA0Äq”œœº‚R]ÐERÿAmhÅ5sºÛ'5oþ»ºc\‹¦’pyí—ú¬þêmçñÂÍ­+×¼,/ãûëo¤ð²O{¾GÔéâ• É).㼚‘=ÏÉsÕm4¡1ó,š{20nÎÊ(ù ðÛK¸¶&Ÿ›Tia¨ \êõ˜0tˆcm*€q»<ËÖ³ÑÜ¥’be%bsS6„0ÔËWó˜V̪¬ÉOÒNî—%¶Ÿ`Ö?r9ëg÷M#€cÕªìÊiêp·+“O虀K^…0Ë÷К0ø¾Œþ¤ý™ärO_d ETSlþÖþêæ%î=ÿG¯]ÙçÏs{ýE¾÷‘•75ÑÝ(™×+ꦟ/!é&bM-‰.‚Z]ƒÇ&šúѨŒãÄÆuÚ¾_ਾE$".ו S»-ïíÂB”„Õfï[ XV ø>Â¥K.QGjåÝÙa¬•ÛÏ»bÚ:Üo¢`ŸWVóãÍ¿ÍâúçõèÓÊôYDžƒöü³X“”Ý(’“wnNsù²J ;³=´†bT‡s3ž|ŽöÖžNXarRè=îÉü›]P.“P…-¢;Izš69ÈV(»»¾9•RÒ¸9A·ëóJ•LB‚” CŸÁÀ1eiÌhT¾ßÕ1‹Í†åd" ¾„mËB<Ò›r3£ÐÞK7¾Æ÷-ý"µç69ùèýT«ÚíÎá7€Rçzs¼í"Üðpî9ƒM`ª±éÆT)B\*˜MKZ +Æ ÃBÒ»+åR.÷q]7‰Š+5­VƒÁP%”Ýácëe7eÖn)—UüåqKl5 UžâøñÛÛb!6ê1BجµsÐDàƒ<¼ƒo¦-Îýê~}ûµüÎi*?w¥\߇«WU&Da\ÝgóìXî°„ÄRÉ“  *a9N˜ÌÚ(Å!æêUgZpZ{d_K¥"ˆ˜·Jõawû,¥X‰ŽÙŒ´‰ª†ÀPj@¿_7T2ZÿÁ2ž×Ï,*4u×ÌÍËæÞï‹HF—¥pœþsèí¯óù¿t‘ÝÎ ¦Õ8ÜÃóž~þ >|û gÿÙ·ñ®‹OS¾Ð1Ïä^× ™§mLQ‹Ä±kÚ”Çi£T•(ré÷S/kÓn«.kì’j0Üå·º¥o[˺j#Óc—lÅfïÁ(Júk¯Œ.F& NªíŸô¯Ì;l§U‡Ù¼ýH=]¤ûõøû©*4š&ü)—SE_½.Fû½y„ÂÎKfmÓ*¢,a§Ý¶öå±YøÎýsVHŠ”å²ˆ76œÜpÈñ÷]'³~»°G# <­V¬­•r*! ÙSÌzAlb©w·]jˆ†¾9ý5ŽÓEëaXÊl(#ƒL|“w¸c`—ÄqÈ ì/ýü)¾úÚí<¶ûIZ­6•J‘N§ Åï~ã_`mçËÜãÞÂ¥Á&nçuÚ_Òæv Î7ï“o‹Z·ÐºÀhä†>®S(hïº}⸂R5G£ul(¶m` “€èZŸú4Ã΋w_a´Ý`¹ñC'>ÊvÞÀÝ£EûØý<ê‰Íæúƒq%¯sn®ÁJý:ÞV»ƒÀëpú|’»øitG3|²BãÞóïÃ;òÀ‚Èœ5”´=¾Âó$Ëo4rLF_Ïë06`ξWí¶ø)t:Ö™GHfq¬(c*×8óJu)Ñujl¾>È&ÎäU˜–&œ^oÙ˜wv$«Âºtmn¦ãB×ÕÆÆ^ån‡Yø{*€ýNôodá#û7mvA½.ýS6 ¡TÒÉ×›M¹ÑØÊWŠQ‡H-íøf hoÏŸâ rƒXŸ@ÍêjÖ ^O-ß,˜W*‰/A§#žŒÙç‘W5E‘lnVl$‹QÓë—éõ|_'~ÙMOÔ`*“)`JÅE¸Õ™±`*Á$J¥ˆh·ƒ„ÅV.‡fqybQæKà‰Lz¶‹czO|†îc›tK/ýüP-¸XXçÔŸy3ç^'üŠÃ÷Ë÷Î_Çgç߯¥òõ|aóò Bºùâý|ðõï¸ç7XU§Þá¡N]ý!¾õy®|åå7ðVÊf4¹dF çÐzÁL}üì‹"qNêt q’êdUzí¶lˆYçœ~_0•ãÇ[ ‡uZ­4hÒßÏnöÛÛz qÏÛ¦ÅèÙj$ …EÛhÈTKƈ֒.ÿ°ÞoáçƒÌêã÷[ø™íÿ¿õí¶Œ`ªUycÄs=-ýEug{:ÆÌ:óN÷Ý]5sþ?IÑô§‘‹lÛbËõìÍ2 Cÿ}:1wØÚréõRÁÓ¤³‘µ ÏN-ä¤×‰µy¶ª\Á*ÉRLÁq4NÁ|µ‹54ŽˆsÔ.8!¥»~ÿìE•{èè¼À£½ÆðØ<å uFñ€·ÿÈÓ,s™‡>þ(õÉàå—SŽÀc_þmž½áýü‘»#î|ß3¨ÆÍ(uJÇÞùÒ¼IéìnC¸ Úäöi …¶i*ƒú§íß` ¨×µZ„R.»»:‰›ËÞ7iµ¤¸tiŽR) ‚Éb,{M>ó¦Ù{mîdÛƒõu©d«U8yR³¾®Æ¦A6f{bÝ<óLÑx¨ ¢?Ȱߛ³Ÿ!ûù¬pCæî*Iw©ÕäâØÈYÀbž°húû§“±_6ÈEÚÅE¡n%Ýc;½7Ú Än×MÌMÒ‰N¼è[-'q¯µ> årŒëÊh°XÜa8¬3º ÂuC´‰#Sj´ 'Qç(¿ñƒ†¬]4[„ëÏðì?¸…í+|ëÒïòÎíÿìÂûx±ÿ*oׯòî?óyò·ïeñn…òŒ3 æcM€GÀF¦Fâ8Æq"F#×p–pa†f-³G#ÁPú}'YÈv ’Eî»Ýôz)%Ñyóóš#G"¶·]Z­ük7ÙB΢ôNÝÙŸÏæd„¡\Ÿ¥%¹×„½¨Ç j§-ö¼¯í©®¥8lu°Ÿß´YzÊÍ\­Jo Ä:›=ÀÞ~'þ,†bÞóµœ{ë¯fMMG#Ù,_ü óÚýFŸv±7€JO¨ƒ±–RIïiÁ)ëœíë­GÁâbŸÏØ«1[s4aOÄq¢hÞ«•+„Qƒ~ßc8tÌf8Bk—8®â8FLÛ”æ5Cª¢TÉø*œr•¥·u)ù/qäí¯³ôÐ:·=ý*ƒÎ|Ï{ÿ Å÷Xù6Ç[ÁmÜŠâ˜aùÍâQU6Ý6H‰~ßIÚA+q ”q‚ÒFš›n|¶¬/•bF#g̃ßnÙ÷W6;e¦L*Ù„³Š×ƒrõò}vѧãF‹óH[$ÉÙ٪ï÷òÄŸVþvñg7;™ŸO]PììzwW³¸hX§[.DØ4­*²?S.Ëbl6Ss¡–½`ÓPÓN‡¼÷TÜ‹EÅU­ÂÒRŸõõ4blœj¼7:ZƇÂ4“ÜÅbb7> f5›*Se±‹«x^D§{Ô¬ªdœ9¹D‘k&=椮£T1ïèšÐR_\y•—¥w—PÞ%¢ËÏÒ×E®†C^þò-ÜìláÎß;¡ Ú5ª¿P2îÇecƒÖ&ŠªÆ %›3¡ØÙ‘ PÊi´q évG'~Yß$…Û.¾vÛ¡ÑÐÔëò»­GC¿Ÿâ ¶ZœLîýFè¼<¶›„‡è± Ðƒˆ„ýÉ,&àµl­$Ò“%5ó˜%fX­åä¡EºóÙ›|sSÊ# iœÝFr<¹ ìŒvÜ!X™½ø³€½iïóô1¬Œ66Š ÊD¶çsò\»y6›*Ãz˾ÖTehíÓl[àyP¯IÚM¯çP­ÆÉF'§¤kNÙ±Úª!RâІanË¨Ž£ˆsPW¬Æ 1PÀ]é1ÿð*üÛ8ñÀ àœ ‘«*hkÕÕ7ÿ"àÃ…ãÄ”J ‡N§˜ø?ØÒ"ü“ä°Ô‡A¸{mÛìuéõ¤-°#àZM‡² Çïoë褦²Ú_Ä3«œßë%¨åâ5s pØ“V_?K´“]Üâ ¬ƒ©Úc¶içž–s_.§óþÉ´àÁ@æ,ÿµV6V¸S,Ú CrÜÔ¾¿û b«½ï“NÊX«¬T,•of2>úÓ‰«±œ{Gž“1R)~ss!(‰D—1˜3– àû1ž×'ŠJh]ÅuŽc[Y°uÄr»büF†Ã߀Â"Ëßý'?ó*¥z(?D|¬q`NíPu´Ðz€ãH$Úhä0•ñý åH71›à3©ªÌ¦+i­©×µaü1¶‘gGªö½Ò—ˆzvv<66T&ÍG'|ЬÝþÎNJ4ÚOãжá dÞ¦â] ÿ Èþ~›…¥ÒöûšååÔ[2:[>/ÄÓ§õä;{ÚZUÛMq³”гü í"´¬Øœ©\§Ök>ǼNÐz¥TÒ¿/-Å´ZNÑlή6RGc j3S¹Tãñê(}®+väç°sõ[Дˑq*™ˆ2Ù¬§-§¿Z@PwД€JG†G ÍFЦõ©€¢ÛáåŸ?Ïñæ*Å;¿LáL`NëÒFÐ €9Â00`úںݢa†t»®ikôX‹”e]f¯]©dÁµTÔ“§ÍÈVT;;^B+÷}L’Sz@u:ÒH°×oÚi¿ß(q ¸Þ”ÛôôÏÆNVv–].Ñ#6*LNºNPÚ¹9X_—›°RÙËÆJ߀½£ Õ¯ÛÖòkzˆê7>!±ñi–ÎlçÑ©Echõ~ü 9ÁµÑGì­&ÍM,ÞR«™r)f{Ç{¿Ó±¢6Õ†¦Ûñ eñW*®;Dëª)ßû‚¨žñ0>H¼V¸ñÑågXÿÈQNÿx wÎå•ÿc‘à±Çü³ ®qì3:Æ:Í1&/:QåÙl¾(“O»P%_QMµz‹cyíA—7Ò<,\—ŒœlY^FžÓÏAOìk[߯ ðöSåÍâ£H€°t¶™ZZYDZ„"㢉ÀìLöÔ©>««aèìëšzX;¤ƒ”ÿVÿ^«¥:€YmÇA6Qñ¤ FkÍe£Ë,ÿ¼V“¿½³#öâ£QšàdG yà¦}`©¹zU%Ó•É>ÖÞ°¶?µãÀêj%Y4“ùÑ67¤M³+ž§©Õ"‚`8D‘OMAOÌF‚­~Ë¿ôù¯e¾ÿÇ*¸GÎC|œc@¥\¹EµL´ç¡Ê¯‚{Z/ ã˜Ri@èõÄ˯ßWcݬ66d$X¯k#J¹üy›@ èœgí5îF-÷þÖV ô‰+3,/ë$zÒ’nZÅý´×òðf-Œ´ÆH?ÓÀËFÃÊQÓÓaØXbe&#´å&·%Z^œwµjOxñÅáUÿsè8詜þ·œdAæéžx IDAT³{{Úƒ–ÿãÏMn˜ÅÅ”bkuúöoY’ÑÜÜÏ‹¹t)HøÖcp²™¼v’x¬ÙÜ·›=åÑI…×n‹DÙó”¡3f«&qØ6Î,¥*ËõŒC~ß'ŽÅ¢-Ý$¥RŒïkm B+gålqæFs8‰Öuà ôˆ¢Š±èòq—0tPJ L„h£û2 FLÊýgíÔ­ð'û> Hé$÷·Ý|÷›±çUÉb¤B3—eë9ŽuJ%Íü<\¾¬Æ˜¯¶rªVíf6}R0‹:~؃nê ¯ɪֲU@¯GrSØd<E%ýlB YY±‰¶âÀbçÒbÐ)¥w½.»§½™ì÷k+µLêvåæ¼V¤5I?ê¤ØØÀÄ<å» „\d¿o4ç†OÊ-.°° c¿^üët¦ß˜{‡¦« ³Ÿ·ï¯p0FlmyoH7w»‘Œ ”Ò±a¹,›d«•ê„T£M>aH¡00€ž©†è^§~ XAqT ­K&µGÓï»x^™áPÓïK8I£!¥­–2ÏA<3rXZ Y[óÆþÉEEÂ'©×å}m6u"åž Øœ¶ ØûÀp“„,û¹BAk½žÜ³­VŠo¥‚6YOÙk–[÷µ²w÷uÚd°% ˜WN¾{=Í' »µ¥h4¤Ì C˜)‹r#^¹‚Q¹¥ÿÒ¤émçç¥ô’puh pZÿŸÝèêõT*.Cz»ðZÇ:<ËæÉÙ©ßO íÊ ¬ ’eJN«&¯Át€L8J%)§íu”BU“taß׬¬„lmyI¦Râ ½¯Æq4½žX‰ÕBëK0ü"ôÖÑ£º¢T­—Œ1GL§ã›{Ì%"z=×Uìì ÓH?Ji®\ñÌßÍ÷çcAëE{"á R™F³¨¦UY“¤ìýe¯Ÿ±$dcC6/K[ÏÚÛí··_6çaƒv½Y¥pÞ/ʉDÉgËßáÐÚXÉÉ1?++šF#¢\òÜså¤'Î#ûØÏml¤ˆú$þ -Àä‰m)³–Ïíû$áž“6Ðû)¶¦!»“аô}OE7’/¯I«ÖRŠÛ£Ù¼¶¶'ïd±€ HCß'7Ì$»ø­,ucÃ3ærÍd¬3'ŸK©¥RtÐúuôÎ/££ Ω…Ñô¿Œ.=Hûôûecäi]žaè2ÙªSQ¯Çì•™EÙí¡äyrºooëda¥÷Oj«eåÂA†Øæi"¦]siÆ+ÙɉKAØ­ƒâú뇼úªŸÈÈóª‹ÃdstÌ÷5ï ‹dZ5pPÕ`V×lçÞ  'ŽËË=Úí"Å¢­D4±³“×óª}K´ÃFŠ¥Ø„,€FC£ÕöÌækbѬ‘c©$U‡p,˜°OÄåe©’¬åôa²Û2øÄèÓ¦¥ã¯l?kLv’S, Þ3dÎÛG»ÕÍkŠÅ¥b´î FŸCùÇP¥ï–ÀA·‰ãz½Ý®¢P(P(ŒÐ:H¸ói¿¯ð<‡jUðÑH'ó~»A‡¡6A+RÉXnÊ8™ÇŽï”1–‘¿a @´N«P{¿M#šÙמ×þeÛãnWžÓÖVRI6žÉ6ú ±`­öS¼H 4;Ðòà´×ìÏÜÈ¢–Òx^ŸÝÝ »»RVMj³g‘j‡´ßkLY•ŠôÜBúѹ§ÿaˆE³X†ösV¡×륛Oö¦µfžåÙaõß(—¥^]u’ñÙ¤É䤰¨Zµ¾÷65‰­ìVø ÚØj ¯^?ïÿET¡ƒŽk¢æ‹b-ÑÛ®+¥~·ëP,ÐZ'¹z¾Ÿ’‘„$2I¬V¿¯ÙÙ§9ïìÀ‚Ü_2Ï×Mˆˆ‡Ä¡V³¹Žj¬íœ&)ßÏy'oüòž5›Ê¼÷vƒ—bÛ¶p2üÖò&¯Ï¬ä­Y©BJ²Ø=Ÿ€Mm½ž„,4R&=÷Ü;;*IJzÿ°ÑÃæ¢Í*¡ìïû²[·Z²¤^‡ÓÄ_ÁuuÂö³nB¢4ŽX Õž"ý~*1=Þ1ùßáЮ%*]%N^Œ¹½-Ä÷|Mé¶“XÚdŠmùúºgxJÍQ,Ö \´©¨V‡ì€Öbj:ɽ`Ob!>Ù/•°P-AjÜËOî­õuá[ä17³§ºug^YÑnØÞo-kÞ‘½lùo•‚ÍfŠé,.¦QõÂúÔ¦Qc"¶=µï±âWL»Lž•°™«zhêM/7S¥««R.ZÏûZMæávD³ßâ?,xZ?œrl"%®-á«+˜Æ¬Ìþ·zØ8êÔÆ:ïæ³“–ÔŒcö5šfb ,ý¾¤Oæ(ä½O®+hbËq{ÊØR^ŒEcƒ¬e¹IFÙñ¯ëêÄz=û·¤\µÉ¹Rþon–ðTBG¥ÄµÈ¸]váÛþØz€6m23r2th ÁH6%;BÞÞg¥f{¦¸Q”vh-Þ‹ ×U3Ú~®;YW¦(’ƒ.Û»g‘¹ËhÜfZò™5ÙÙ‘ qò09¯Åól¥”þP©d¾ö{Á=ž†d UÖßÿSܵ+7’\Ù›@áM6›l6›ÓÓ£‡!ElÄ:Ò_¬µŠXw#äÊØ±ç Ö^_Ö|€Üµô2¦½ÙŒQ·FR7ƒ&H @ rS'3+‘Y•Uà®Áˆnê•7ï½çÜsT1¼aq\÷ï9 ³\–eÂRoB›aŠ<·ì¦d¢XãÏ%Îp¶€d™nÑ}8D³×">?ŽšXEœ~6@.†„ÏÎ6²Zõ¢ÌÂòñãúø1*óª¡ÌÐ…Q‡å ä¹Èp¸–áp Ṵ́Ä ã–a.9Â5'«JF,>Ò¥ù \]©BpF^DJºv„¿ã“¦\ð˜€Ñ ­É§˜ÍÂRy©P iùÜùX–Ë@P—Z¤,ˆ{/SC4ý€sstÔ§Qò¤ïïÝ «õ_Û ¡›™z®)â÷Ð>$þ¬ ÿþø©8GWS†ÒœA#NãÅ}Y,¬ü•‹G‡JŠ»;;{áß_m¢ƒÝ¥ÝÝX))†‹:…RFJ»+Õ—»;)Yos6‚Æ«¡þêJÉñ±-?B:Õe£òî§2ŒÔçϹs§g±ßû –™Á|nG‡×k-GGÈ>¸a\]íÎù\…P¹É’Ȇ•n#ÇãèW–ú°W-vÿàºÝ²Ò/jNmh“wwd^áX,Ê^v‹…mòâøâ M~(°®Ž¯‚\bå;жÛ+æ;>ÞÈõufcu;Vj9»FìÎ_^¢Ñ8™°æg.<´ë‹  ¼ÛÊÅE×LNººÝ®…ññicv ý1ŒBk¢)¢[¯Ë6Ù¤Ó‘¶eº U;èÆº÷>;r0ÐÎkU´Ñ—RvºÏŠ õ1@bþCÉ~”ËÉÉZþøÇ¡á@p-ùúŽ.ùp2òÙ3{¿ùù··=bé“5…ê^b v¼ù\öNµÿÅ…ï:¦¥þ$•;§¾X ÊIªØ h‚¤¤Î~œºøcH ÓpÎþŸœˆaúYNW£ر׿†"yަ"Pµ'ó!­ÝsE_°\ÇÙÑÂ%š½ßdÚrâÜ–v.‘Çbànb>yý:7_ úVSz«x(›Ð©?=E6zsÏ÷)?Ý¿çLÆr©äòr ƒ²ÆùÜ:ù žù›Ev¸a’=É×YIdV†Ð$¨²°âÏlº¿Z•á¾rÃI9**áÏ``èõôŽ(Ej°N©·ª‹ M¿[c»‡¹‡¬¨÷8‡_-7V¥&Søùx`¬GÞtªwäÍë˜g!E@]ʤë.§€óü¹kG½-ƒ•,we¹‰¸ïG6i¯‡ÏåÈ8iÒŽ®Ý±cYaÍ,3z^÷ìתg‹}ŠÁ\^b·??ׯ¶›(²6[”ON,Óh†-¡pXzºrèYæe¡FEìÄc¼¦Jù<=…2ʇªH?vÍ;c7àñ'9›íNÿUá¯M2€*jeɢͭÅÖkì,ä<Ž@™ç:*øQGhŠ$BŸ>Y†!|H£>ÔÌõ»ÛtÃa/#ËtÁaP;Y žnÃŽúúdA– Jnn´9ñœ¨]°Zuäô›Ô‰¤ØF(3ŽºúÝú,bAž‘¥© ‰'I§<{¡û%ÔêP",~y 2¦µQâbæ|p€_Ç £×sVEl×ëH P¯[_ýÍÈNVÝl¦v4×R\¼HëµµB®ÚeÛ¤aU»j“]>ÕKQ› Gäßk-òØL ¤„{WÕ«)ÇÈ…:aˆÊõ3hÒ[}öd"Å{»¤]-åk¡¯Pîî“°³ÝZ2’σ`lw'&íPçÑуœžnäýû3:M wpðÃÍÎŒjƒ¢–Û[ð4˜Ý² /WýŽ´sgŽÑÏçVâä5=ç.F#¬Bæ$Ð…ˆýo7æ¹RÍ?ýÎ~¨ëÏnðÉ dN²é¨ÔRèŠ9ˆÙŒ5xš¢)@•iHÊâw¡@ve ?¹òUÛ-(¥¹«¦ÐRS6am3²)Âo6¢öá;ðð€)¼ùÜ+¹eÇwCiå4àܯ®Ê¢«ìu¬V@¯_³G åð¥3²9ešz¡‘ºM7«Óð÷çª3}´tPü^~Ö¿˜?šy˜€J›ds~µ²Ã„OêJ‰}2€ØxtS´ìo(†¸rsc(ìy(£PµH«jq¿ÔàÈTÛ‡›,~Öñüf@£iɧOÊÔïuÆ]ÀD@:°ã\«ë:-}f7´ƒ;=•¡<Æíj94¡óBÕA=-îÒMÑ?pSùÉÏÊ*ÛV@YÑÏ~ö ãñB..äæf°³–Ꚍ¡ß%gî÷f#òò%v±ùÜvfÙä¡àåå¥Jq'-»RKzÂ×^Ììu¨aµÏ8p]ÍŸú²[~¶´ZÁ4Uê”ûQ]]Y5îéî\GGàáßß+£‹—ríýë€rN¦"Ë‘—/e»íH·Û5Òé¡'(í.=àºí©RãaSŒTË%ˆU?ü äàÀ–¡VPÉUU%–+qG©:Ò„-„§Ý/÷Ëõ/ðŸÒ¦¹^0²‘e6SŸx3ìÐ}Ȫvû˜šÌv‹Ôþð©%Ó½~_]¹ù¼Üõåâ°W4mÃ8"‹ºY%±±öÝý›4üÜ4¿×㹫7‚ÒéWWª$ëÝÆÈ4Vž¸P|ò´L&ÊØš…Æ[«¾¨9ÛñmjàÝ݉éàgÙ£ŒF]ÙlìD[Ý"&‰ˆYÄx¼•ƒƒLº]-Ë%¹ï»c¼ø·6³ 4i¥dÜá!Òd*ÅØ{u¥€}g3‘7o¬ÇŸÿÞM{~¤Lð±Ôjhd*ùöÛÃ’EˆSªÄ HÙƒ%@Š—óŠ¢žÄÁYÆj±²¤W[§^ª¼0à vî6aö±GªÛý›4û, ^´ÄˆùÃÙÊWÇš5)Ý䨨1¤,ÓFùî.N1®ëcÀ5ÈÎÿSúëñ‘B}3–K’8íªr÷¡TöÁüõufÈ*dö…ô™ŒÇœQ% ÿæÆŽW¿R{ldÇy9·ÐVŠÎÿXÁÌ÷ú×øÙ3)ú-^ããtª öŸBóÏÜ£.øÊAnWËù9îò’î>ñÅßd¡ºãÛQïÛ„IÙý›fÄù€²|ap¸¿“IR¦ªQfbÅàNàž ÆTÁú?,OVþZ,lNqPW6­ÓÁ`à<ïî,œéóôùY0Á¿ÙÙ¦Òoh‚ç¾ÙàZrPˆï‰ìoCëµ.à,½ã} XÈH|ž¼6ô×ÃClH¡g¸‰  0sІjùô‰êû ÒÆ ÝñX <1Iƒæ%‡ˆ>ûL;2îá »ªW”u»²‘~Ý‚Ùuð±QŠ4û;ec|1ÔNièk<Ö…)ˆ5׎…<ÞSwþ§Úýc‰ëö²Ý*y÷®g NÜæi›ò(ÎsWÅn:øá÷‡ÚyM4X†¹2æå £‹s)7´g*9=µý‚Ø ‘ûž„‹cXvùaV¥crŸQf/^”ƒV,íNÉ"]%¡<×%Ž}ÓÀ]U†r¹¿×³Q•\Š}VåŸÿÜ‘ñY¼2ì£{ß"ó*²Á@çœ{†?Ò¿çϱ™"®×h:1EšÍtÖÚ$äèp¿o­Ã]BËÿÅî_÷UÔP?¸°i¶\âZ¿xÕZJ]5)eR$×,LŽšúJ·¡L"¶3Å2w6ƒ÷ŠˆOžk¹¸°ikUßAi³S¾¤6ëv»çªxNŸœ ~ö%µ8RÚ (Ÿ§2ý¦}›X¦‚\¡«àNHÚlx2Á³„Ý%ÉB„@IƃqJ*ü!;>–u×\ˆÎÜÙ)Ùí*ÓÙ¾¹qtÚ¨TEj©ûÚn ñØùhW/ð½ûWÎûSÊ›j7Ô/VhaÞzªŒŸÞöûxïëkë\34­rœ c³>eŠÊϨKÝîØÎÊàäJйJ»)eKh!¯V"Ÿ}¶‘®éÍp¨Ì…«²€ªl`7ªºçŒëj½V;:.½™è‡h÷Ó©õì<8Àk)¡ ³½Îî亮Ô7É ÁGG„ ç¯5:þŒÞn³Ž'ÒXOI‹B³ÎôU«"™<åî_e£@ûn?l2óÚðßî¸s8©ÜHÔ¦aÄú‘*7Ì’ªlĪvÿÐuëõ´‘µvK°=´PB;!iĶ?¡]o蘣@¬Øµwõë`²¹¹6ÈSUýuƒ MжCÇŠMÖ-gV+¬Å—/D9î 7kµcØSo–å¹Z_]I&:¹Ü¾â+k4îZpÑÕJ•˜_xceº–mvÿ ³X3«­`“Ý?Å…Y Ë*×Z¬¼@ÂÍÒ¦FþîÕïcøêòRy)¤¢º ˆï5™è¢Ù¦d6Ó;°XçÞ¿/td¦pJÈ -–ÅñçY†ìÊ>"ɲp€ª#’¥êM6Ežª®s¿j5ƒaLÊ‹´¬ 3-?ýi.ßß1ðh ÉSJÖÙb!÷ŽŒ;<¨œØnu¡»†ˆÃ&Ê`€Áˆï¾SFºÉ=HÚªtw(Ýåg„°ó¦»Sêoªû¿¡í&æÁc'½‰¿A]ÓÈ× „á%Ê}"ÀN¡*G}›Œ“§¾^c“`_ÃÏ`šœ“K÷¦“¯+{–µ‘w >^½²ÔôºkÐDo²-ó´Î8†—)ZeCoŸQ¼à»ï:k±Œ¦øJB"r—å¹\j-gáÅÊl`2á–qÉ¿þÉÑHŒsÕÎÜVº;ÅøÞïMLÊîï«ßᇭÌõð!(ItpŸ=yó&—¿ÿ½c°ÝØujëkÂ]ùi·£ÞUˆ-|—ÖL:0î‡Ú‘'o²pÙ©ÆðؤäT-D¿T¤ÚEJ‰VÝÞ–áË&‘&A ö³:Ÿ?ÿÿzF®—A•'hÃT×¢œ=šñ›mºŠJÅ€Ô»L)ù­åŸÝ:î.Úðú7Ô]{ÅŒo‡»QªîÁnÂ_vo¶;ÍÕ¶éW·û‡ê~âÔÏŸÃeF)1Rfîqâëïï;²ÝZg_ˆOƯÑ>¾<îùÜ:Íúž‰©¨‚Ÿýd™v2e¦=ÇcÌ›®ã5ÔS›µ‘æ~xÃ5lÊ5b r326AÏÎðþ³™*ÊR†ÑRžá}¨Hà ÄÐÈÉq©š§pwuöæse ÄíV(v:-À^OäøX~—å¹ü§Ròo¾:.İë}ñ…–ׯ7òí·=3±Æ [ÇökbÛÕ42·ýÛ*Ë$ßÐ$Ë䳌F8çÑÈNjÑò›4e 5L§vÒ+ærÊ’Ra@ÿÜ(ž2œlš’òg½vRa·[4ØuÑ4V%ͺÔ ´ö³)iÕBaü½ž#'YÆg¿ºXyꆻOMÅ@xNŽÝPI½Þnun†Ê•¡ÈãÏbv†½fÝ®.fxäëLDÞÆØihY.»Eým<ëFKSRÿ6®¶m ¹ºFLìßÐïCmJ 2ÖÊ JÃ,áóÏ7²ÙÀãŽ_¡Ñå¶ðhL¿|ü§4wŸ¾§+×=™à÷¸FºH?Óy îÏ6¤½\°”-« ’)JWw„(êý1[céÒd¬/»ö»o6࡟Òéh™Níó– ƒº÷n³Á&4¸»Œ_¨n¯—KuËqà yň‰æ¦4Ž´i 6pDÕ”Õ¾IÛ]¿ b©ëƺ?ÏsKUEZ¦ žÂ$L‹éò*«;×ÍëU-$Ñôúøç¸Ý¢œëT]Þ9Ç_™þC˜RÉtªÌpÌxŒà·XØÆcìŠ|øÐ5ºø§§à£W i´!HÕ©W¥Ú©Yë³ç~˜eh¸!­FÓɵ ñêv06,™¶öûÚ—îC“fo!Ë´¼y“ËßþÖ5Þ, |ÇÝ}KÔÌ×m¤gašR| 0¸6ã $xÐ_‰(3 øV)¹QJžsê ÃD Ë5a–…qÅ&ì)jú¦ê©J?1·ÁäïL„OOOirA~;²UË,k)Õ-øªÔ3 õÀɤl&JÕWÊ«)T›çØ©Hf¢™ÅSSx » AS4°;ÆsÒE”êÔë2´¶Y€{¬ƒ6 “íê6ÙÜ&n¯‡ îý{Å>Ö ¹UJKFé!¥Ô׎üG¿(©ÛÅŒF¨ûé+6ÂŒvC»ÖI)éíSeuŒµTFÕ¢H hlŠÞÞÚEAwá,ƒäl¦Í¼ûdH1À˜/•úxdgÁÇNš@œà·£œÀ‘Úøªº.¢À‘àåÒ jrŒ7¥4Ù'(¤Ü3þŸŽrpÛ-õþÓš€±ŒR)m2yØåÐýIDATÌÏ(Y¯u>ËoÎÎ g ŠxÌçúKõ¯“‰üøðpê]òe£ÈG–Y©îÐQj h[ã§\Ü&A åÁÿÎÚbâBó&ÚkíýãcDã›´o“Ä@ó†gÍqØŽ²“š×ÁÀ)pweŽ·0åf,¨Ü£Šl½…ãcl^®¶_¬w”"<Ûtsóß—5¯ø“/•ñÛ¸¸¶!=ÏIMõë^O¿e@ÌÀº"ÅWÿd8=Zýö°ej Bð¹SIóæûf)\õª@PÕüKÉüŸg™±SîŽîÍãÉÑÆg¯í”d]¯£ÎÅ(uñûàœS§•:~ªC 8¿é„Û60˜ø“¬ðeÜsNÍþöE´ª‚­Ó\%­W• 6$s~¯µ|½X€çs|,’Q§o8ÔòÅZ¾ÿ^ýr¹TßÐHÀõìs?pµÂ@ÂÙ™õ.ù÷=UäLImSvñ}&þü…±Ý‚ùˆILwhð@’99AJ¶ZY ¶QVc*R·øaÿM'_1Æ“Yž¬k›Ýp¡SÖ*Æ‚«Û¸p\ò ¬°qQaúà0áã£ÚÇõÙU÷hŸg™Áh³±NÎus )ïé™èüI)ùßãú…$…þò%"ò6Ëô/×kùÆ7wØ}0°«Ž»³6IŸžj×K u¯­ÓÊ#<ˆ,pRlþÝtÊ£Cþúi2€6©}ݹ…Í^”QfKOí AUp“ @RKª‚qUsÑŠfZZìçŸÃ…w6‹7vÝTU<¼íf"m½|XØZÑËï•’_)%·®©ŠÖZ²ÑÈrˆÉ™~öLÞ.—¢ò\Þå¹ü8v૚‚GGPb1Оb µ Ö6ÕmòZJd³ö§¨¥‹Ý†4ðèg°ÙpN^µÖIhºû§™Ä$ÍéÖL‡g4æÊx½¶‡cÊóÛBÏí´Pª)ãOÙíj)+4!“³ ’ÿN5£©:—ª ‰¤¥T ½*D)É•’_‹È×®b4ÎQv~Žk6³"Nw÷'ZËi-ÿ."ÏݤÏ[·‹ÝìÅ 1ÀXUcÑħ ©A ®iXõ'K ¾¾C`þCH{l0éÒ Rþ¿vêé±[îš\%ÞgÏtÉ‘&‰Øw¨¦É½Ý×ÍF~Ú4m•I†Â,ƒM‘—K;öN½Ãº—òœÇ [’¹öå„(%¹Öòù8L_ß¡ùÓ'‘l:c½ìKlß_j-_ŠÈ/Dä¿EäUŒy4÷Ç.÷uîi²(ömz¥¾f±À°Åd‚ݵ¾[èF:ÕµsúM€}ÌL¹À'ì’˜$Ô†,C‚†rÉP~:Ût0,uÁÔí€ÕÜm,ìþó•|øÐ—‹ œáMf¤“G¿\ZÄ«‰^@“E¼½Ö²‘ߊÈWJÉm¬\FF–`ǵsrÞä­ˆœÿþ…Öò•RòOÝ®œõzêàãGÝ?:’¼ ÐfZ[¥á4 °m-\÷ÅØtJJmœêΙ]î§À¢Û°P6´Ù¨ÂY×*0sÊq8Äb89ÙÊh´•Õª_ŒíZeª!ßß§é<O$5Г`D;í÷ï†Ñ¸XX]Êm!Ö;b.m:ò-^s-"¹ˆ E¤ïV ÅÏDä“RòND~'"_‹Èm¬4ö׿ÿ¸²ÒIrIEND®B`‚fractalnow-0.8.1/gui/icons/icon.svg0000664000175000017500000756242011754747533015734 0ustar mpegmpeg fractalnow-0.8.1/gui/icons/icon24x24.png0000664000175000017500000000313311764667445016411 0ustar mpegmpeg‰PNG  IHDRàw=øgAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAgxL¥¦;IDATHÇ•–]ˆUÇwf2™Ììd3I¶ÕluA«"ÒB­¶ˆZQ‘ªÅ"¢ `‹‚"¾ùâ‹`Q¬TñE­àü@¤Hñ û`±Zµ`éV+»[ºn’M²“™d2™ëÃIZÄúà…p“ýçãÿç¢^zI¿–$ìl·qÒ”À\Êeù½²¦ ¾ž§i6i ““ÐïC«áÜMS"ßç-K)v8N‹ÃC–%ß M¿¯0M¹²»®œ —Ó„¡Â²Ä溠®Rì´šM ¾/Y¤)h q,™÷zày’ušÂÄ„÷<Èç!Ë@kM’(\W' ”JÓ„ÅEå[i*§¦4® õºÂ¶ÅÀp¨(•4Q¤p±»®bÕª.Z›´ÚºdÞéHö†í¶B)° C.¥©Â²4¾axŒ  (‚@S 3Ób%‡h–·‘³Î£^¨†CI2Ф Š,㌥ZC±¨Y&UärP «WuiÏ}ÅáïsÃ=Ujµí†" aiIȲÑ[Ú¶àˉa0PLMiâXá8 ÇÑØ6‹0Ué09±ˆã,ðÁDZë¹ïxoí6m½‚¢07çÒO ¤©°ÊóÀ yƒBA>J 4ժƶ¾/–Ë—Ã|òê üxb‰/ž  xâéÙ~ä$W­_ÃŤ5±‰~OcY#ˆl[‡à8ÂqÇQÔj=‚ ÆÎç±s;WçûûyöõCü0Ûb¼¾8|š¯¿û”»o¹˜½oÝÇdQ®@*VVÀŠ"(• R?"ÔÎk@ëD˜ŽO°&Ï‹{÷ÿÃùx¥Yàço¿dzÝõ€…iJâV¡ MU((*(Õê ^ág>|ã3v=ÿ=–mqï¾92Ï­N7¡ŸM`&†!ý4€•ÏCµšqÉ%ŠÞ \·Ñ/¼¿÷]žyå~]˜}¥K8üÏW_5Ão L¦©ñýÁ…Øþe\¹e†ªñ¿ýÚ 6åñÈý5fOvYÓsú¯/u¸éšµLM_K£¡h·¥/¬8Ʊf~^Q©h’ÄgMm=·Ý} ›®»Ëñ)Mç9:û2¿ï?~ÎEÏ&o„dÙ,³Îô–åºBÑ¿þÎ//K“F… x˜Ò¥yl[húè#'9zìí1ÉR°eã4ë7ßÌ|ÃDâ¬$‘Fó<‘Œ$Q†æÔ©<õºƒïëQ£]ÀºÍÛxü¡cü4»ÄçOptv…k6TÙ~û6®[CÒwiw$Á\NtMíÞ­µR#ÎZ"ÛA Rẜ‘ŠÉI¨VBJ§q ¼±ç)ví9Ä{û`ÓÖÇ£€¹¹ó šMQÖ,UË góy‰¼´$bgšnWˆ&Ž}VJ>«W׸ýλ˜r‡\¾a+§/âôiEj:£ ´†nw¤¦Ž#ò\.‹Ã±\w:BUß×´F°§©&M=f.¸‘[w84û›95§¨×%IÓ”Ç#5Í2‰89©IS™¿Irö'&d>D‘T’ej$ï3h}­–C£!w:›¾¯ÑZƬ%2q,⤵NSÌ45­–"MeRu»×ñãZŸ™a(„!T*’ðâ¢Â*—‰”Â]^–’ÆCß¶º,“ªLSöq±m0™Eê ö­–ŒKÛ&4´f_¯Gœ$U¯'ÒTœG‘bLånW` Š$ˆd®ÆUH9×jÑyóoÓ¦ué¦mz%tEXtdate:create2012-05-27T10:48:29+02:00Ó+b%tEXtdate:modify2012-05-27T10:48:29+02:00qŽ“ÞIEND®B`‚fractalnow-0.8.1/gui/icons/icon36x36.png0000664000175000017500000000543711764667445016430 0ustar mpegmpeg‰PNG  IHDR$$ᘘgAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAg$$x ÿIDATXØ[¬\UÇk_gÏì¹k)-¨-HAJZµ1"RH|ñACLŒÑ5A´‰!>(‰Bˆ j¼Dã ð (¡­4@Q¡H9¥==í¹ÌmÏeϾ,¾Y3§lw2™™½ÖÞ뿾ËÿûþK=þx~{¿¯²m®o·±Ò´¥äcY`ÛàûP«i†CEšÂ`pîxÀÔ”Œ7›eòí80=­Ih6½ä¹<§¤)©ãp( Ùo)¥šÕ»´ÆRJ&9Ž|Û¶,hYສ^×(%sšMÅ`°ŽÊås£Þó`8œ€4i,d©Fl-Öð<¨T5eû Ýcž¤Æ‰ãÇ9µx eåh`iõ$ï|Š‹.ßÃl}–P­€þiê³²"íûÂ]ž§QO=•ëNG‘e’-Õª Í2™X­J~ C*c9¥p€êüžÇö=ÆÒ âïG[Œh÷22­©6óÕßøÊ6Jn‘[wmbþæ‡yïý ¬®‚RšÁ@â¸ÛU8&6ú}5ÂÌŒqŠg`¥’áùŽÍ¨<ä 1$G9ñî!ÞZ\áéçO£±éèZëf¬u‡øÙë\6Wä¦Ûo$Êe¡—^O2µÕ’úè´ZŠrY gž«Q€)êuãLOçÌV_ÄñK`Ï ²5”;ôi-½ÄOô¿ýóÒGÀ¬¿YÎr4ä­7ßæÒm/áûw‘eQ$@LÙq”’¾¯˜Ÿ²s]S¡M•OqÔ‡¬y–D4W˜Ùz%ó;.æC¯ðìÁ%â,å|×JgÈOâ¶=ŸÇ›–ú†’Lâ!cQ€IfÙö„Ö§¦b‚`+yá¹wyô‰ý!êùþ9úö2'[ýó‚1×0׸¥i†ÚB)ñJ’' ‡ 'Ž'mE¹¬¨×¥‚AN$øî»d?ðáÑÃüüW ¼º°À;gÛœÞßfÎ÷ü‚mÙrÅúvzí š–D)p*©UÕjÎW´(—–HûoQ*(Ú$§ó›ÇÿÆÏœâðBûœ—[ð¾u~W™ë[J|ë»_Ä ·7õ¨Ub"…õ¿iÓo¬¿¨]æãGÎw™ °þ²ï¸ãÁ¥3TDQ‘$™A9Ÿ$c+ÊÙŽW½„»2n¿QñÚË+,¬öÆo› Ø^+p¢3¸ kÍ„xm…½w}†þpžVK*‚´µRhß?6ÂC–%µ¬T²)—m¦¦®¤X»KoÚÌ·¿|†äŒ‚ºÈläèÑe^z´}Áq´pâ4½Æ;Øþ5ã6Ùq$¨µ'ŠäFµ*þ4ýÊp–•“¦óósÊçÓ{·qó×Ñ\\föŠ«˜Ûq1á_`Ó“kœlv/«Iw«“ç Ë’X ‚Q?®µÔß׬­ 1šº²º*í©ï;¸ÕK˜¾î~°gؘ5Pnèó©]1{w¿Á/ÿ²À ýÿ>Söøú×vS›ßÄÙCGt»ŒºO…S­ ÂfSÀ˜*ФtdضE’ÜŠçY8¸Þ¥¸£ÒQš¾?>ÎðÁ?ñôs‹ËÖÛb¶ä±ãš«±k·7¶-ĘçÒw% RËÖÖ&ÅÕó Ó…`A§Qd¯+® ß·¨V-Já6oÛ͵_aß=^9Òà½SZëŠëS\½"vë$ý¨O§SmZ㺚ZmT\[-5n?|_bg8”ßBðŽ#€•Ù#ÅÑb* (ÛÛ¹÷þ/QÜ\cñƒãüû/òýoÒè¦<òÃk¸å³{¸è²=”jsô›+,µëıf0PD‘Åë¨hw:“æ¬×›È­åÓn‹EMh qA–I¬9$Á T·îÄñ\¾sÎé%t~…bÃÔ&¶îþ*ýÁVÎ6<ºœ^²èvÁq¤ÙK£Ž¡mÓ)†š4ë˜À×Zä’d¡Âu%ð}_ÑíúT*õúf¶^}=8ÁÿiqË7Òënby¥@£!Öïv…ZŒ÷}Iû$É ÓhÛö¨ ¬hò\b)Žd¡À8 =Oj_¿/½q±¨Çn׺ÆÌ¦{¸ûÞ.ñ©Ã6ÜÂÙµkkÒØ÷zjÔ‡‹ '5-ËF€DW ¨rYS,JÖu»Œ­ÂYæ…I"ýÓÊŠü/>Sǽ|kÍ­,Qôºš^OÑn3@\e|2R' XK±3J$ËÄÄFæ9¬®ª±Pô<¡ ­GÙêÃ/œ#»]IóáPÑ騱P CŠ0:À0uTÜ¢9sFnˆB•±n÷Üc×똸P£SÍ Ûž?GJw»B|–Å8ˆ³L,k¨f8É iî¥[Œ¢6˜³9B‘Ý®wg¯§Æy.±b’D¤×“wgÙD:nk6Å+N¥BÚÉ2c|ê8ò “`÷}±T§3‘JY&ÁX´Ý–±h¯7‘ã¦34''JIµoµ¤t:ŽÃëžÇ ««2Yž&ZÍ|@ÊóIŠ*%4`ürߤ³ç™ø”à ËRc)n@Ʊ¸3Õª~ÍÒZX^V‡”"3lÊ2hvÇ^2òפ­e Ñ­?ò“Ãùe"£M(˜9Q„NÒ^;µÿ¿Mydr’¸aÇ%tEXtdate:create2012-05-27T10:48:29+02:00Ó+b%tEXtdate:modify2012-05-27T10:48:29+02:00qŽ“ÞIEND®B`‚fractalnow-0.8.1/gui/icons/icon.ico0000664000175000017500000026173611764667445015712 0ustar mpegmpeg è–(~00¨¦ ¨Nhö È^!00 ¨%&)  ¨ÎN hv_( @€€€€€€€€€€€€€ÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿ‡ŒˆÈxˆwˆˆŒˆˆŒ‡€ˆÈwwxˆŒ‡‡Œˆx|‡ˆx‡wwxÈȈxx‡‡‡ˆŒwˆ‡ˆxxxˆŒˆxˆˆˆxȈxxȈȌ‡‡ˆˆˆ‡ˆxˆˆ‡ˆˆÈx‡ˆˆˆÿøˆxŒŒŒwxˆÈxˆˆˆø¸øˆ‡ˆˆˆˆˆ‡ˆˆˆˆøûxøˆxÈÈÈȈˆˆˆÿÿó¿ÿˆˆˆˆˆxxˆˆÿø‹sˆøøˆÈŒ‡ˆˆÿø18ˆˆˆˆ‡ˆˆÿÿ‹øˆ‡wˆˆÿøˆø‡ˆˆˆˆÿûs70øˆˆˆˆÿÿˆ0ø‡ˆˆ‹1øˆˆˆøø1øˆˆˆˆÿˆPøˆˆŒˆˆû30ˆˆˆˆˆxˆøøˆÈˆˆˆˆˆÿÿó0øˆˆˆÏˆˆˆˆÿøqøˆxˆÈȈˆˆˆøˆsxøˆˆˆ‡ˆˆxxˆˆÿƒøˆŒˆŒŒˆˆxˆˆˆˆ8øˆˆˆx‡‡ˆÈ‡‡ˆˆˆÿˆøˆ‡Œˆwwˆˆxw‡ˆˆˆøˆˆ‡‡x‡ˆ‡Œˆˆ‡ˆxˆˆˆxxˆxŒ‡wŒwxxxˆˆ‡ˆˆwxˆˆwˆx‡ˆxˆˆ‡ˆˆŒˆˆŒ‡ŒŒŒŒˆÈÈȇxÈŒŒwˆˆx‡ˆˆˆˆˆˆˆˆˆˆˆ€€€( À€€€€€€€€€€€€ÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿ‡Œˆˆxxˆˆˆ‡xȈˆŒˆŒ‡xˆˆ‡ˆˆˆˆˆø¸ˆ‡Œˆˆ‡8øˆˆˆøxˆˆø÷·XˆˆøqxˆˆøqxˆˆˆwxˆŒˆˆø0xˆ‡ˆˆˆ‡ˆˆ‡xxˆˆˆ‡ˆ‡‡ˆˆˆˆˆˆ‡xÈwˆxŒˆˆ‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ(0`€        &#$&+,+++.#2$3#<$=$?*A+L.M4L"4U$6VA^MkNl(Ci(Dj*Jn(Qo-[zÿ}}_`ž/b‹/cŒ$nˆ'k5n‡5bŒ6n‰7nŒ8oˆ8p‰#b’,z–4{“5}•={›>|œ/r¢4r =z¦4wª4x«7€˜6ˆ¦;£½J‚™BŒ¬Iˆ«Q–¡I¢¾=±Õ;°Û<³Ø;±ÜM•ÏK¢ËL£ËC©ÓDªÓ@±ÕG°ßT¿Þm¿ÚM½âK½ä/ÏàTÀß[ÂÝ\ÃÞ`Ìß\ÜìQÕòTÖô\Üõ`ÌàfÎédÐíoÔëqÞôlàïnïõlçúrâøvéúyôüÿÿ……þ‰‰þþ‘‘þ••þ™™þþ¡¡þ¥¥þ©©þ­­þ±±þµµþººþ½½ŠÁÏŠÁЇÙò‡Ýô¡Ûï¡Üðåïåïéó“ãöŸí÷íø—ìú˜ìúîø‰òýøû‰ùý•õý’úþ®çõ í÷¯èõºêô¥õù¡øü¦ùý¨ùý®øý±òúµòù²õû±öü¸öû²ûþ²üþ¸ûý¾ùýþÁÁþÅÅþÉÉýÍÍýÑÑýÕÕýÙÙýÝÝÃìôÉõúÌõûÇùýÂüþÄþÿËøúÉþÿÎþÿÛòöÛ÷÷Ü÷÷×öøØôøÚøúÞûýØýýßýýíçèáëìîèéëìíúààýááúååüåå÷êêðííøééüééùííâô÷çõöèõöàûüåûüáüýåþþíúúìüüòòòñööõööùññøôôñøø÷øø÷‘ÿù±ÿûÑÿÿÿÿ/-P?pRc°vψð™ÿ¦1ÿ´QÿÂqÿÏ‘ÿܱÿëÑÿÿÿÿ/Pp!°&Ï,ð>ÿX1ÿqQÿŒqÿ¦‘ÿ¿±ÿÚÑÿÿÿÿwvsqqqqrrrrtuxvvttttuuwy}yvvuuuuv{zwussssssvutqo,,,,,,,oprwvtrqqqrrsuywtstursuytrppoprqpptxwwqpoo,oooopquwztrqrststvzyutvwttwxtrqqpqttqrv{vsvtrpoqrpoppqrtxwtssuwutvyywvxwuvzwsrrrqqtutvuusprvtrpstqpppqrsxyustuyvvw{~yx{xxyzvttvsrrtxzwrtropsvurttqqqqqrsuyxuuuxywxz¥{{}{z~{wuxvsstw{|wsur,pqtxvwsrqrrrssuy{wvvx|{y{¥¦§§¥~~zxxyuttvyzvtuxr,pqsx~xtsrrtvttuw{zzxx|~|¥¦¬ÀÁ«©¥}{}yvvwzxvtrqurostuxz{xtsstywuux{¦|yz{¥¦¦«Éž‰ÎÁª¥¥|yxzzzvssqqsrorsssw{xutttwyvvx{¥~{~}¦«ªÄÛ¤clʪ§}|z¥|wutrrqtropqrruvyyvuuvzzxxz|¦~~§§«ÆØÑšYZ£×Ĩ§~~~{wuuusqtrppqqrsux|xwwwz~z{||¦©§ª¬ÆØÐ‚T(0f¯ØÄª¨§|zxwxwtrusppqrrstvy{{yxz~}|¥~§««ÆØÛÔµg# AŸÔØÆÄ©¥||zwusrvuqqqtuttvy~¥z{|}§¥¦©©«ËÌ®°²˜`!E ÑÔºÁ©¦|yvutuyxrrrtxwvvy{¦}|¥¥©©¨«ÄÊÚˆP^d>1 &1 %;I‡”h•æ}yywyx|uqqqtuttvy~¥z{{}§¥¦©¨¬Ë̯°²˜`!E ÑÔºÁ©¦|yvuttysppqqrstvy|{yxz~}|¥~¦««ÆØÙÔµg# AŸÓÙÆÄ¨¦||zwttrvsopqqrsty|xwwwz~z{|}¦©§ª¬ÆØÐ‚S'0f¯ØÄª¨§|yxwxwtquropqqsuvyyvuuvzzxxz|§~~¨§ªÆØÑšYZ£×Ĩ§}~~{wuuusqtrorsstv{yutttwywvx{¥~{~}¦«©ÄפclžÆª§}|{~|wussqqtrostuw{zxtsstywuux{¦{yz{¦¦¦«ËžÎÁª¦¥}yxzzzvtrrqsr,pqsx~xtsrrtvttuv{zzxx|~|¥¦¬ÀÁ«©¥}z}yvvwzxvtrqtr,pqtxvwsrqrrsrtuy{wvvx}{y|~¦¦§¥}~zxxyutuuyzvtuxroqrwtrutqqqqqrsuyyutuxywxz¥{{}{z~{wvxvsstw{|wsusprvtqqrtppppqrsxyustuywvw{~zx{xxyzvtuvsrstx{wrtvsvtrpoqrpoppqrtxwtrsvwttvyywvxwuvzwsrrqqqtutvuuxwwqpo,ooooooquwztrrrststvzyutwvttwxtrqpqqtsqsu{utqo,,,,,,ooprwvtqqqqrrsuyvtstursuxtrppoprqpptwvrqqqqqrrrsvxuvtttttuwy}yvvuuuuv{zwtsrssssvÀwv€wvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwvwv€wvÀwv( @€      -',$3'4-@,E2F2W3XASBTG_Le&Hf#Nm-Uf)Ql,Vu2a}5gEiyÿ~~3e‚2i3j3r›3sœ6|£6}¤5¢µLªG ·O¡µR ³Q¡´J³Ðr»ÜmÂÛnÃÜ|ÂÜpÆàzÒâ}Ùåc×ó}æøÿÿ……þ‰‰þþ‘‘þ••þ™™þþ¡¡þ¥¥þ©©þ¬¬þ±±þµµþ¹¹þ½½—ÉЉÒß‘ÕãŒåöŒîù™çõ–è÷™èõìö’ïú•îû’ðú®ãñ¨éô£íø¿ëö¬öû¯øý¶ôúºóù¹õù²ûýþÂÂþÅÅþÈÈúÎÎýÍÍùÐÐþÑÑú××ýÕÕøÚÛüÚÚýÞßÂßëÐèîÁîòÅîóÀëöÇøûÑðóßòõ×õùÙùûïäåäëîæìîéììììîöããýààùåå÷êêõîîúêêúííîóóîööåúûìùúëüüòññ÷ððòõõðøøÏ©ðÃÿÒÿØ1ÿÝQÿäqÿê‘ÿð±ÿöÑÿÿÿ/P"p0>°MÏ[ðiÿyÿŠ1ÿQÿ¯qÿÁ‘ÿÒ±ÿåÑÿÿÿ/Pp ° Ï ðÿ ÿ>1ÿ\Qÿzqÿ—‘ÿ¶±ÿÔÑÿÿÿ/Pp!+°6Ï@ðIÿZÿ1pÿQ†ÿqœÿ‘²ÿ±ÈÿÑßÿÿÿ/ P6pLb°xÏŽð¤ÿ³ÿ1¾ÿQÇÿqÑÿ‘Üÿ±åÿÑðÿÿÿ,/KPip‡¥°ÄÏáððÿò1ÿôQÿöqÿ÷‘ÿù±ÿûÑÿÿÿÿ/-P?pRc°vψð™ÿ¦1ÿ´QÿÂqÿÏ‘ÿܱÿëÑÿÿÿÿ/Pp!°&Ï,ð>ÿX1ÿqQÿŒqÿ¦‘ÿ¿±ÿÚÑÿÿÿÿ?:877889;><;:;;=A?<<;<@>;99:9>@<7555569>;8799:?=:<::>9777979A;::6686568;>:9<<;>@=><>>9978:<<;87::9:7678:>=:<>=@DAB@B>;=99=A<;858=>:8899:=@==AAB[a^[D?@<;<@<:<87:>@<97:8699=?<:;?=>B[B[]e{l3Sx_DBD>;98:9678:>@=<@B@A[]_e|o0 .nwa\B>==9;:6799<@B?@DC[]ex„UY…yd[B?;9<<88<<<@DCC\__f{k,1**GRQeC?==A@;:;??@C]a®ww|€M /v\CB?>>>>=?CC\es‚„…X& Fu_C?;=<;@BAD_czOLHLZ2gaC@=@><@D[_e|I"'%hcDB=>>?C]exƒpO+raC?=>AA`tiYV4$  Eza[CAAAA`uiYV4#  EƒaDCAA>?B]exƒpO+raC?=>?<@D[_e|I!'%hc[A>><<@BAD_cƒOKHLZ2gaC@=@>>>=?CC]es‚„…X& Fu_C?;=@;9;??@C]acfw|€S /v\CB>>=79<<<@DBD[_ae{k,1*)GRQeC?==A:6799<@B?@DC[]ex„UW~yd[B?;9<9678:=@=<@B@A[]_e{o0.nwa\B>==9:8789=?<:;?=>A[BD_e{l3Sx_DBD>;98:879=A=:9;=;=BB?A[[emjq_DA>>@<97:858=;;=99=A;;;::7686668;>:9<<;>@=><>=:988:<<<@<755569>;8899:?=:<::>9766:79A>;877889;><;::;=A><<;<@>;99:9=€€( @  $:I!=M)@J8kyD[aY…—SŠšQ’¨e¤ºm®½y¼Ñÿ‡‡ÿ‹‹þþ‘‘þ••þ™™þþ¡¡þ¥¥þ©©þ¬¬þ±±þ´´þ¹¹ý¼¼—ÄϘÅÏžÍØ¬Ôß»Ýæ¼èð¼ìôÛÑÖúÂÂþÁÁþÄÄöÍÍþÎÎîÔ×çÖØìÙÛñÔÕõÖÖûÚÚÍÛâìÞàÝçéèáäñååïððqÿÓ‘ÿܱÿåÑÿðÿÿÿ/Pp",°6Ï@ðJÿ[1ÿqQÿ‡qÿ‘ÿ²±ÿÉÑÿßÿÿÿ/Pp ° Ïð ÿ=ÿ1[ÿQyÿq˜ÿ‘µÿ±ÔÿÑÿÿÿ/"P0p=L°YÏgðxÿŠÿ1œÿQ®ÿqÀÿ‘Òÿ±äÿÑÿÿÿ&/@PZptް©ÏÂðÑÿØÿ1ÞÿQãÿqéÿ‘ïÿ±öÿÑÿÿÿ/&PAp[t°ŽÏ©ðÃÿÒÿØ1ÿÝQÿäqÿê‘ÿð±ÿöÑÿÿÿ/P"p0>°MÏ[ðiÿyÿŠ1ÿQÿ¯qÿÁ‘ÿÒ±ÿåÑÿÿÿ/Pp ° Ï ðÿ ÿ>1ÿ\Qÿzqÿ—‘ÿ¶±ÿÔÑÿÿÿ/Pp!+°6Ï@ðIÿZÿ1pÿQ†ÿqœÿ‘²ÿ±ÈÿÑßÿÿÿ/ P6pLb°xÏŽð¤ÿ³ÿ1¾ÿQÇÿqÑÿ‘Üÿ±åÿÑðÿÿÿ,/KPip‡¥°ÄÏáððÿò1ÿôQÿöqÿ÷‘ÿù±ÿûÑÿÿÿÿ/-P?pRc°vψð™ÿ¦1ÿ´QÿÂqÿÏ‘ÿܱÿëÑÿÿÿÿ/Pp!°&Ï,ð>ÿX1ÿqQÿŒqÿ¦‘ÿ¿±ÿÚÑÿÿÿÿ! !20! ,4&6,+.8% #5*!39:$ /+4'  )-7( 1 -7( 1 +4'  )!39:$ /+.8% "5* ,4&6,!20!  ‰PNG  IHDR\r¨fÿÿIDATxÚì}œegY÷sn™>³S¶÷’¶é…„P!H †*¨ˆ"@DåûøPùˆ ‘* Ũ„ÐLh „ôlH/›mÙ:;»;;»;õ–ó½ÿ÷9ÿ{ÞûÎ9÷ž;D?9¿ß¹å”·<½2‡ãŠ+ªAõ½a(+ÚÛ¥·¯O:ffÂ\OTÌ·MMR©ˆ˜ßg½þ³Ž Ðß»ßûG.7û³{­ûÂox "Ýݡ̛'²¿~®VEŽ‰çŽ£Ùœçº.þ<’æ˜öߣ?7Ì£«+´ï;:ôû|^ßwu‰ T¤³³"[·¶Éô4æ«ãÇùSSz.Ö \ÖõÀË£ÿÞ]]æ²üÏùq¿8·ÎÎP††tœ½½¡™C {öˆLLR*Õ¯b1´óâ\Êå`<'Í­Ùž·zN¥R1O—ƒæÕf^f&2eæ0ÁV3ÓµµÉß½ó¹á–á(ë‰@ú\®ú5³t=\hfáB  å/æ\6¶å 5ú´ÏþwY @{{(‹‹ö‰ ‘Ç™™™ ôIcĵX§J%hym’ˆX#b—ô?i^Å¢HOOh^ÊÚt@ ¼@ôô52¢û]*Åÿ‰(î+ Yü9§Í¿ÙºøsNÚ/¼«…Bh‰àõ„¦ ò·Éðp`÷âСøy˜+æ¹â7ì+öxr2h:§Vö²Ñ1xÃêÛÚ‚Wg%M ÀûÞWù†¹íEfù:’™TulL¿;|X)*Š“ùEV‘ßKÒÜüÏ(r‡‘€,²ìÞ ‰9_à=„à¦8—£Íœ›­A#$q÷cÃ|ð¾Z êÎokS‰gáÂЀ@FGÅrPñ1ŸøÏaZY¿pøRæÄW7R«%tŠÔú;sÇsAàù=àç‘©5bls%î¸çŠ'õ{]y8—Ë]~ùå¹oxM£¯¾º<†ùþ¤`a°Xø?o^håàAEþgÝü£=q½¤s’Ýÿ®çûùóXÆÆêE_wžD0ŒŽŽÐrˆÊ.@µ².YT€´õ Ê“47ŸkºÄˆî90 rà€Î™HA) h¶ÿ;Kú=m®Isžaìø<8¨ˆ}èDÿ0"bAí9 pp.>»j@šZ{4ÈÏ}‘U)2»d˜DÜãï«_¾üòüï¥^›ôå§>U½ÐP¼ žºÀé>ƒò8öîUñ—ÜÀ·¤-ÐÑ‚f@ŸvnÒbñp‘Ã=Ç(ÌÙ›±àˆø ˆáŠö¼€ ë.ªzg²NùT¯C#IS’Æ…ø ä ¾+àÈÊ%›Yצ™z㎜éÒШ«•Â\îî>Ï%fÿhE—ȆŽZ…‹´ùó»j5\œ¤ÌB‹/~±z¡ád7Ð ’F0X¨#D~,f ¤-R«†ŸfˆñÝ…Jû. Q’œeÑ"•z`ƒ 䀨ÀZÎB©€êÐs5”¶*øsñ?7"T Á@â|`ßAì°÷Ü÷$±¿UõÏaÅA›J³k›ìXÐ=À½°þØ?À-ö!ÌE¢ii9>0ª†ÍlII÷s‰ ^îµ_¿õ­õD`z\w]5iýÅt?ûb1×ê^{÷ª-À'œø­¿?´×A|Æ9äœO…}¤ä÷× ÈçUo†¤ÓÙ©û N"À¹dÕý›ÍÏ„}ð„û·"ø\¿ÞávH`Øz«\ &¤Íçh¸¿+úSšœ??´†tÂPÎ2J›¸†KÞãmo«‡úºŸøDy´·7×ßÛ«V^ úªZAõ&º˜º4dAôÅþ$0m‘æºpsù=+òû š&V1°q@ð t=´ T± î' pLØJ\b9WOI‡ÿý\‰ö@U,Öý©žu%¹üÒ ÀI{žÄ ) »Ä´ÂLBFæ1¼ þ«¤Vüͤ˜,FíVÕ•X )Àº†šÁFÒ>â~}}:_¨k0ÖâÈåª_þÓ?m5Ðøð‡+ßÈår/ÆÂ±¡'˜±ˆØ•(Zè9X@Rÿ£€§êÈJšÙš‰È¾XIë2ƒRâ=ÄNxI YSonä&;šyg±d™çlbûÒ1Oå¢ÉÖñFóJóŽ`@HqàþûöµÆ ë9 Žp ¢‹=Q)LEÆ*¸Ä+Iàx³ ÿ\¬þxÁ° ;žõ øF樂,ODU¢P{^€=Hé‘êe¯yzj`ñ”'óù|u{,¨ÑÎAÃãæ4úaóéj&þµjùme[=7 òûÔÌZ®®P¥¸°6 žô'i Ra½ˆü¾‘i.À”Uìoô¾Ub‡ù@•5R"ÉÕWÓ©Ñœ\ަ[ƒºcoI3.8[¤V¯¤jˆÿÃó‘dÀl•$' ¢ò½ „9#®„ëJx™+àœ›`N:!Ý›;}ãå/ϿԞ?W_ȾàºöÈØ,œº÷t (hðdŸÜEùEpþFGV#aBøzdºLÅNP[™rF]|Ø`(óEå§"P*iüY× Uƒ' „Ша¿ƒLÒM’ ñß«èšM HÚ³X:S‰uÅŠªå€»vå#lüJópÜO%÷w×Ù][2ÞññXBIò¦µ>ÅéeËB»–¬ CZ|Ùe¹a{ÙUW•A¾ÇõS“{Òcñ0 X ˆ(šbï1.ÌÿÕZB06–³RCe•£Ö3†Fóò­ôj ­ôY‘ „µf­5œ7¬í3Bné€ÿŽ“ÆêZŒ*6Þþ†¹CÊÎ2÷¤{2X Ò<97ž)ã oÈÁ•W"Æ?¸!‰àÐÉV¬eÉ’²<òHÑlL`/fœ@šå.ØÑøJÝ{ªŽ,†1z; à!ÚƒrÞXTÖ ßQ—Ãwг€4à„X+Kúš“¢ÿZQ•’ˆÆ10FȘ=¼¸ QJC…½Æš Ï®]¹Z ÍÁüç©´F‘¥Ê¥°–êQinK#?ßç¬iy s•d›Ïß7ŽãÜ®ð*6ˆ@RîAÒ}¨~ñ;MæR[ öK= ºG Š€esÿÅÁÕW—o Ãü¹>%ÂðàhÿTïÓï@Q ª%ùQçÜYõhõå´÷ÄH;ÝxôSðñE„!0è°‘ ø„€"m3ý¿UÄu‘\”ž¡¤YÝgî½pÔgÑ…5æ5€"5¤D€2:)' +àcÍèaÀºe%Iž ŒH…€5 ÆŠ=Ìš»EôŸ«þï®3ƒ¬€¬@ZØhlFˆì€I8œ‡=Âwû±žd@8"xþÝÀèÿ;Œþ¿Œ€Îxd\`Â…®µ’ÆÜ bEã$‰£±¸‹E†ÙiYî×L/nä#wõlRÙÀŠüeÔ]çs 9-[V•Ý»s–øj@3.Ó ¹„ýQ÷¬SRXrÚ½ü{&Ý”a*8 EõF*Ž¿?I÷…‡ÿ¡«Óž”[‘4~Šû®{¢‚ï4î¿qÜB« ,«g«™àÂöv 7×"m ùÂuØÚ›¨÷kP‘®#ñ4ºÖùíÁûß_Ëåò}wIð‹„ɱ˜.a€‘fóf ¤UñÔ]¸4CÐ\¸ƒ;°‘IT1«ø•ô}#‹¸ßÈ=HK. Àˆµt=&iu²®Qš!‰Ä,E&²€øÐ¸•e½Ó ïñp‰F&‡Óf!n‚'î¥:p²-! (Úâ~pža°Ä:$I*iÀÖSaËòçíÎßUY?8”4W\âɘ·ª qÐÙlØ«^üÍß”§óù|¸ãÔ‹ì>„ÖD¨,BÒ¨4'éZhe±Ü æâ`bØÈ£ ¡m¤4s‹5"@ iÒ®' ÐZO’­kƒÿË—«hNk|³{73ú’÷î:€­4*ÓŒ @07´‘;Ñ'Ä^œ ‚‚{3¨¨‘¤ÒÈïÏã©R’ÆÎñƒÉA½ã l¦úÐF#âš5UÙ¾=g¥(õÖIšíéºàškª!($T_¹•‹Ä*b¨‹”¿a‘ÉaðßÍÿ1Á$0 k£"iÀè¾÷‡ ë=ýû6{^ÈòrEeê´Í@Í9îh”µ¼{jÖˆ¯¤±ºŸø¢.Èl)Lj€O°P¼ á¹Òršéî¼/8#áhüËâŸíNSí뫚ñå¢hV‰@siÌ]§§Š¤ÁZÅ:PrLŠ‚ÄžGw°×bOÀxpCÑWL8K&z•jð…/TC| $%Åý0%XX,b¨!V[,4"—(ªà ¬Æ‡dCFkN7ÑL  lþ„²Ü3ˆøÏnö9 Q(’à¥i§$ap¥Ü®Qúg3éë,ТŽ}Áýcê?;®¼™'$MW¥‹R#žã…EO°ýxvÿy¼/îÖjCé†å4Xq34«‡/®šõUW%À" Öøp™Å ëïÍ\¥Ú¤uv×°®RÌl s£}G‰¾ªd Üs0 ЮzæîQðѪCT+ ‰›”à´Šƒ€(à¡à­åL³L¢´YÉU=p ˆÎÆD‰Ù@×øþI’@V) r¤!#Œ‡t!bÜ ÎZC ޤsƒ„æB ݵr#¿ðßâtõI÷IÜß}FZ}=pX×™Mn…Š)½iŒÅ; & b¸IÒ¥]c¥ãZš0;ƒ‘k’U¢ôm­À^#5€ö¨; áÚ‚yè\‚š ‘¶xtš—Ê'à+xÿûuÈÍ>{aT`A=¸@€Ï0À¸¾áFUTš=“†-¦¡â;<ÿY’ê)$½×M¨¼¤MtÕp6HDÖ¯4Ï@–y¤Ö‹uïW®n4©y"²pÓ¤ûúóc!6<ƒaª€ èQ)d¶!+ qAè?ZW"Ý^ÒÈ¢N·î÷cJßM™F`š­=<©žC+0×H…Ü@uÄ~©™ÌCØ£„ƒßX·jŽ»vÍb‚¿ú«ôa7Uâ¸pEPˆœ Hb°EãC¦Er¹):î©™véFµV(és't¿óËj%eºúèâÅY¼XËl”ˆ’f€8 !¬S»³$–$qÿ4Çx »J¸o> -IU–â>ÈÏp='eÖ_F‘‰/Šœ,ýºŸ±˜µ`iòZ‡5ïŽ_Ó±|g•´ˆÜØC¬É®]A-·‚×0q ®æ={r©„ΕR’$à}ï«nÐdÐÄÀ†g°P+uÔÒô[æ( ðÄO”8Z;@ÚœÝ1$mZ d„S=Nׇç`Ã0~ýë ÀSá t_4þœÁõÖd±ÌǪž[|nPûÅP«2<œ«¹Þ0Ohf´ñ¹îóh¼dÎ>­¸™zþÞrŒDô8©^•<âù¸‡[ñ§YÄ_Òš)ý ⢅BÓ¥”¬p–Ì\UÒ¢±+™ÆxÌ֙궛qšÕͼç=Ѷfà€>‡Ã¢È1( „ñð¤ºXœ4ßp3àN#t¥!O#Äi´!YÖÀýŸDèÊà3-±#‘ç¸F³fAÍÆž¦€ ,UæïG£{óEû`íq­F>ÖrË-²1<@‹g¥©€î3XX†ú+ ïqÜ“)ÿZÀÕ*F¿á{ÆŠÐÆ8•,5+ü5w×s22ЈU{æb»Ií$ v¨2ÌWP 5ñëŒÏ,Ð;:Z騔\qEc `ºñØ8|ÖÜ÷ *‹Ö¬Û‘Õ}p£óŸGDC$“êdÙ€f“e-p¤ILhQ#Qœ5HªÎtOÈ4ßy«ÀäÕ€ ØÜÌž\BŽ Ä~3ÎÀˆ ŸW®œ¶¢ñž=Vpƒxü½w7Ü|ùò²e QAæQuÒƒ»žZ”6VphJmøá׬hö›‹îó0ßåËc"¥ÕŸŽ®v_Ž¹Þ Ip{¬9ÏÁq~.sßÓåܼûÝõ …rE,R º"èËÅoxÏúxyMÚ¢»‹ƒ. @ š®>78j ÀGöFÈïÿæ__öuçzu)´”:-x†ãϪ*¹ë…ƒ*EtH% Ä j…ÐKË4í>ZrJÏ_° dæ3{“·Ü8ö·7ï‘àfž"ÂL¬6œïÂ!+0a!QhuÆÆ¿4ñ߆«—ƒP±*‹ß2%>KTj’ÚÆÜ‘¤gÒÐ"‡Ï€™u뛵鶘;vhRžëÑHjÌ’$¸ðU#Y‰ýÌzƒ˜:sàðG2«¡¢êµÖ:éuÏ}€ö-¢eÝöSsõÇ&~3$ó×Ãÿܨh½Íç 'µËêÿNBXט¤Yõ 6iåÞýû&¹ÿêí?*íhÐMh.ˆî#_Úâ±ê=ØoÀ5X&¹xÝkYæ’(χš"PŸNÖb!²FáxæZ~aO!óiÕÃåïko؉¸¶ ]à^ Ž«WO™ñL"Ù#7¶×ܯnqÓ,Ùu^€w½+›à"e£XêŸÔ]4ÀH¹~÷¹¿>ð¹åÇ1Y¿ïÜÑJ>²7Cþf ÝH7f‚º³äUœ¬»VÁI“Ägß –4ޤ€$JlYjÎ7ò$Ù€¼K—V- ¸ÉP^ÿ¾¾!k¡‡U2¢Ë2‰¸»ðá–Ów“ÁXöì©÷>`]Ùê ÜÒLmD¸gÌìÄÚ1£Óe>sß`òàAÕ%>óÃïèc€ù`0¬/‰“¦²ÔçðÃk höªO)VÝnÉý vÝ_YrœÝ¸s·RqÒâ?Õ@3äO{߈¸ÄnS¦iRÕ‡¡ÀÛ,ß¡¡ö‘•qdM£ ³´}O’(™`aN8Ø Æu»ñ^T!˜`Ʊ2V÷q‰bÚÞú†W^¿ví”™kY¶oï©ÙY4.B¯ÃZS½h6ÞkâDQ&qK*!ÖŠ{Û•¦)b|TY… ÜŸF@¼XŒ·#jÔ§5tŽngª4[Gªp´€ždÁdL3Ä24`d™ç$·PÒB¹‡šSंš¿H  Òe!~”‰ J8ód2–ãeüžËˆÄØ3QÏû¾g· jÍA˜¶fëÞ 1€ ÀÕ¦±$:?z”çàú8Ð(–˜ÿÀ†%42¼Dˆ©µI o’+íUxAúddœË<…¬Òg ùð€½ÁP­!ÕPÀsXœe¾ñ’ím®Ñ4Ìr«º i°iÀ•p®Ø‚I±3õ^ Ü Åu¾žçÞéµ´¸ú˜T¶)éH3¢µJš©HYÝ;°ì²CÃu!˜¥^²ò}’ÈN‚ìfÚØÝÞxIkàßÓU÷xoH´àãÞDXÜÔךˆ=6´“á7˜2Ù* õ%fz«“È‘P`-”hÚQÙyè¾èžð¹–¸ºÕÑJ¸)¬Î”Râ –Ü=T Æ:/Σ1Ì=ÜÌ(tC¿óP£ÅŸ«U ÈJ|äwuglöÊ•eÃ] )Ü^{ÍÒ`›%I*Wq‘I÷&¬s¥5óÊ$K±„.Bû»¹%¸†éäx–Ûy˜Y€^'¨'N¬gGvÇCõ6èÇ®w¥YÙ¯¤õ$qÌb\¸Ÿk—È͈@Ò2º’¸?æC÷­Ní2LŒ‘6 U/ãðaÍÿÐsgšC£{BÂÜÐukùˆè¿O“ÜÉø.0P5ØÄ–KJ >ðÅ&Ž) ¿5ûÿ"âZ•ÒtgJE Â+Õ½ ΧÀm²Ñ, Î7úÀ›´'®» .%tõaÙrœçêI÷ldÛ ·P V ‘Ï×UÙåžÒbǵ+ ã7¿(¯Ó¤õ0øÉjlR÷¬Pì–%oTúˇw~X'ì¤%J®Ç¦YQ#Kcì °reÕÌiF¼ÃIcN– !éw±J¥!Ú1CƪW8@€‡ ¶GE’$Éb[£•ºá3£Cnž¼ŠÇqZd}:cÖ’Ss‰ðç•åü¤õ rÚiIŸÁ*þ„„$-d5ë|Òoµ‡¡‘‘vØp8׿ÀçÅs£= ïjATµ°”<ÅQƸ³îíx®Á{J'DDUê U Œ÷ÐÐ\E2?!&kà³í@œ(y¶Rî,ëÞ9r´±Œæo0Њ©ö ™$= Äã¦T€ÿ¸ö ×sfÈýï³¾ÒtE·“.D,.ÝR.ç¡uTŠÙdÍ\G#øcovŸV ƒ¾[ŃZ<;6ˆ1뜧þo\Ê«Qp ̬Oé HºjÕŒá¸E+ ¸ñúIÇWvª'¼/¹X¶Mc7âœõùó«FÈY$‡'@»õ‚0̘±´×¬Ú$@lê3 fâZœ‹yøT΃rÈz£$%U¿˜FçoFPÒö‡^Ü“]‹(¾ÃB#+ÖÊ/‘ÞL=tŸ‹ugÔ)æK•ë\~¹ÚžJЈûØaÔC AsäãèYàPõ vJ©7ê$‰_­$‘ œšõí² [3"àKB³]t LÚÁg²_Ù×}†¢˜g?È‹ÍÆzjöûVÍsQ£—dñÒ_€A×Oq÷Ü@‡óX ”â(8ž‡9¶p_ŒÉ%FPÃÞ .qµkÖbC(ÉdýyÐvA£Uq¶Ò¬êipç® î‰ßhøäï$˜ Ȭ€¹ª£çÒCæÀ}j%–Me*ñóñ\»¿­€,*@2ÐI0èža73ã(²`⌘ƒkƒA*†5O,Ê¢¤sK\›'Íd%¾Dä»ç@¿ €*@QÖçÈäèXKµöÖGS&Yš]¡§ä69t,âŠÍI€Šk€hl îÂ¥–]ºdBFvÚF2ØCJ?lY DǼÁ…\¥ø°Î?ÆÅ¹°Ï ö½’êÀÝŠH>rÐË„ë8Gºb›Åœ4²Ïp¯Y°ƒÁQîo4€‚ íׯÄýfÊ5ó,²¨4>.ÔÏ=RëÞùNýz. »û+¬5ÉTÑ7nÜÈ´Mr>FÊÁ*àðóæÓš-@3„u92ÄJ·NÎiT˜±àº%I 8$Œ@H»ü`4âVàIK’†Èªy q ¨ÏÌF^Ëx}¨nPË\IU¥™ ‰aÞ¼ª!âyKðÀ¯E?àÞÊY’¡nŒx6UCÜsþùþP®Õ‡C+ÿª{ ÄD9u½î¯‰Îãq f},AlgÀÁ&~ºö\36)©0ÀKK“5&­öÖÏ­…àî;«ý2 1«œö[m²€FŸF|Ñ×­+Ï8n­Û¦@€s4¨avRI³È¦,ˆŸ†°®­ˆˆtÂp·æa«ê€»†>À¼i˜Žƒ%Ï\@ ’Ë‚@ú%£Ó€ÿ̸R‘r¦%KÂ(Á%¨¹àüû¹¡Ì,RÎÎT]—H0@H›Ë†ö…äÍm¯Zàïè¨ ÎÛù˜{zf `·×âõ±÷Lëe/?rp¦ •Íüó–`ªÕ¿>ÄY¢°j  ãu‰¸»6j‡@¼ýŒlßÞV WOJHjEüwí#tk”ÔÆ†sèçǘ)Ÿûʽç˜é̪ §!¿½w#0¤ÏBÜúõ.ÊÚµûÌâÙ~z¬øÃØíF›0O@š àµ0T@ÃæF–×4ä÷×+=®>–ˆÌj¨çlsEÒ›Ff»í”ëÑb=@ü¼‚ëßË5fBbÑÐSHƒ:"  >¡%¦Ýݳ~yó¼’!"‡%ŒPŸgžÓf®Ï[}b¢h®«Z—¨ÎµùôuÝ1F ²&å`ʆh¬Ô€õ` ‘c€huÊ AwºþAš­*(݇špKŒnÍÖß­ Ik<Þ+±‹cI¹1â†âw}ÊŠü™@r´‚ôˆ ‚ µ<þøÃfÁ; (:ƒ±º‘ß®UüqÒOÍŠ½ç®]³+Þ¶¢Z4󒸶&à3ó\‘ÕäóuÁFãðŸIžÏ†‡VpVN¤†¸z=ßôÄg ;þã|Ú4p *ÒÏ›W1§bÎ{R‚ÒWÌæ6Øù*s†™Œ€º’ªœ`¯ÏrÜ¿­ RAGäª #÷`P“Ð0¿p›ÓèZ…5?8›ºáç$8‡-îhpÁàšÓÿϰ鴽ŸíY¨_{×@ XïìT,8¿_ý(-Á( ãËŠüîw @’ÎïSV‚'Ô‹ Bˆ½)!vuÍÈOtÖB(øSo½¿[ä¢UÀÿÔYP’"¹K¡é]i®Á4DœMè ŠÔ<žPX¼¸ñIsn䑨o«È ® 1÷cLºìK,´–ãÀX˜àC÷À2ø Oí톪ɃŽ}Aª¥6É>Ãà¿ù®bÛÎ?1Ï[d®é2°1c%‚Çs9À¡±ÇjL ­Í`d$Ÿ€üaDx”±¸¾ ‡Æ9Ø{°æ0¾&ùÛ›•Q#¬hWæúõ¯W3TêÅRÕ >ï×ÏÌJüßÒ¿°^`!¶ ´I“mt ëúc²X¶ c`#Ó4\x¶ÖE~v1r›¶b H³Ö»z,žà` ’oMNrÑ5CÀ4¯€[fM‹Z† ¡ªõ;îpËÈ0_*ÊJÒBP¡§2ÕTõîzàŽH©ÅMÊfŒ…Á†*ÀB¨ºßsŸ|åvÄü¾ÃŒõ!3‰[¤ºë§æá’[òFóýӌܱÔüV5{Þkö¿ÍÜO'›Áþý…HrÔ´cÁ˜˜Ü„ÆÿÀ“lÔ¹¨AD *æÍp_¿zP£¢&,‹F†ocÀX¸`(X3Ø-0—¸nb½³UŽŸ”Ô•U"hJ’€•ˆk<›Žß0ß𥠥×AÂÆ‹ã|¦s‚‹¸ÝQiä¢ ÀÅ‚ã36>©KÐ\%A„Ázwö—OªS—…À¤­§/š#²m` jg6X#PIëtZ/Æ´g':7¥„s[¸°dupH±2Œ®÷š@›ÅhL$ ‰8ØA˜D¢««lÎ2׎@(v¿Q*#ÿ"A{§äú^f>kn>`æÑož;h ÁädѦ÷Â`85•‹"ô& rwÚ}ÇØÕFÇ·Ã88<\¨¥ìú™§tI³®Ö’DVEþ ‘'I|´G`ýXçÑÿ!ð Æb\ÆF¿_Ø#MÒ<îŸFRÓÝx|õu@£E"ã ÓB %å&q€ ï19ÜW«Ù§ÚsµEVÌ=«Ìê?x9¾cpˆï"ô‘! ð_®! ccL·ßA–$bÊzn?÷¤[í%Ö\>ìÄìê³IsŽŸFD8H ‰9˜†6è× ì4~á>ØÎ jãum9Šä¡}ǧóŒ­ùÐ{-¨{ YÙ$ᑯIõàn),¹ù¼Ú|¿Æ¼ÐÓ`…ÌüºÍ=Æ õ™g–Í}ÍC¥jÆ4zR ¢רּIåÈI€t”v|8jT;Ðß[®»ðúJtˆñÀÚjyï8[ÆJŒGã ’]|þhÄÿ¦€®êž®þÈ׸†  0Æú+ÆêµÈ&ruy$êBŒEÒƒÀ:Íj¨ø ÷g:¤ßh.*€O·@$ÔVª©oY݈à$q^·½¨à{BW ¤ 5k™ïª²eK­Ï_³ãñ<ÂÚ~qýß}Õ#îF£{A·™Š®è±ÔW‡†=§œ%àÚS2ðQ±È,V0:Uø T¶~R*‡†¥°â8 f:%X|™9D hÆ0ßþ×óÑâF†œ™wÎìAgÄ Qº«F6"²”•„¹N"qàŽ6HX8Ÿå´“ú$­¯O0ox´v¼Î”ˆiTf¥^•®\øÑ b”láOCæ4ñ¿â· Än*Š| fЉìl»ÄvW˜>3âËõÎ8ß{¶ b ¾ã&³"°›ì1×äŒ$$ _Üü’F1¿\–„ á\@£Ä/.4AˆF#"Ð¥diçζšêQ©„ÑÜ“íîz‚˱83×Å'J®AP½VÆ•úÀuaÒ€©@3Vr˜šjB»UÏçAÆ”Èf3‰ä'ÿçùÞ=%yïWú¥måïòa@°4BþÎhVp Nš±£Ú=æ§ÈLi‰_ÞŒ¯bÇ56–¯qP"? {§Å2Ø0FÄ\-ÉÇoâîkš”»Tã”aWóÂsñY áè5iní¬q.ÿ) ‘ËÊmÁo¸ÝX´$pø†¤$¤ðïO@’¬_?i¤€vyòÉœ¥Ô®a0)F;+ò7›³Ëá(æÅE)êEµ´g&‰ÝT-0Gr̃D‘“¬þ¢qÿAÍøG]ÒO¢ò“)ºàÞ(’ávNŠKð; Um´ăþqÌØÔD²8ºÄ»§§bö¥Âs?¿¹³ùÀ¤y° 7Kyã_ËîëwÊoë”W¾yFÚ×+ùE¿!Aî8sÚOëµÖU(% «›¤:òuÉ-ü sýÉfþmùÇÇ‹VBa½Ì‹µ‡àø„xZìödL¯¿Çð§I̵Àï¬ìÄ <C¨¯ôÚ¤U'öß»ÈûŸF’DbI™}ÐÉÝy>]hI F›?N ¶„KdÙ "+ÎÐz*2>ëõò¸ð¤6A­¯Ù—•$¹þh_qÕ7{ȸh‘v¸%p³©hZ×]7Ü—!¤ .¢_?ߨPÅZP{Ç ruÙöÚ¬°Ãë âCç>r$W+ Ï@Þ£££jöoÊÜâû8bœR@h$€pò»´’°´E¦nß*ùùó¤íäß4çk @h‘€rPÿ{¤²ãɯüC3Á°ÔÀC1ûu0.5ª¢}ÂHb­Ú÷pâw¿ò° G4jcýX¡ÉW³âuŽã3hLáíT2«Fb#I#Íè—†ÔY­ýGMêÅžÙ€î^ã߯ò'¹ßÔÅN6Ê%ÁYÐwuÏåFÏU à_êaÈ2£ðÜì´47\Ò½Ó’‚¹µÉ'b$J²}{{Íž’VÞß'ˆï šPSŸ«lc®ÄÄäÞÞq[‡Hdaü?‘Œ„¿k˜n}¹p Eô_‰Àêñc–E¶›×“2³ùÇ2y÷aé:o½–<Çœ;Ï€’”wüXòƒÝR98&ÕÛ¤°ú zŸ%AÇ+Í3—™1uD’JÕ® ˜Ôéq¨ÄlÒÍ6ë!`€‰èì" oXHOn…"wÝù²l½z#4¬ÝoL’æ^ÄÑŒ¤!|«F@ÿûº¾<%ùÁ'Yþ§¦° Ë1öˆÇs5N[?ûÙZs!ÍÆFÀl:¿ãl#;@Ú½ý` $ÕÏ„Ä>@HH,78*)Èu½ø±¦Lˆ!7ó÷”õ X¾ý.œ¶A9äê¬Üqxk¹us¢éÆA4vyòÑ\À}áD˜ˆJÓÀu^ÍRÚþ=ùÑÈ™/Ú*ó_†”Yèò™zà^ûaI\øúÒñ¬ËŒfpž¹fµTÃA«@TGdÝèh¡V;ßÑë2þŒ•0†ùùáÃ1òÇYšoQŽKÌi¼f¿U«Æ­ÛrÓ¦yµêÆIM`“j 4">7{ßè¿…V @3äo•Ј¤g÷Šû"*ÂQ4òiW`½†)zÒ&ÞŒ4ŸÏ•©W³PI–Öä$Ÿ4"Àçx¨8h‡s»Ò¦%(¹\ƺkßl)À•:ê¹ZÔÇ «*Çò5[ž‘phù¬²÷ŸžÎEÖqˆÿÓ5õÆìZ¤ÿ‘?„X•„1;¤ràÇRÙs¿lûÛŲâǤÐÈ–ôJg×”,ýóv)í”¶µÏ5=Ë\·ZTEè0ã2sjcÖ'ï@ßÇXQÈØ~EHÖÑ›íÎÅ|à *뙹½#øëøE±$A\âi¡c·Jvã6J5nEø…€VÞ'!€ûÞ6¶c&\}õט›­\©.)×;ÛFȓ޺9I]ñǘD„zÂB&Y+³4"~º0ur7þBÝMU Ì,ºÒŠyúá¾@T×çŸë§ SêÑL65FjìzÜóPíUsNÕš’AÂ6Û&ŒîÜbñ€AXø;¡ÿ—­F@LðÚfæð þþ2|ÝTóEYzéi?u‘—mžuŒ9g•hþÀBs¿ùWa©Ô^c Ž˜+95lPXÖËu'õ-Ô¾ {Á„´$"Áõr‹Ÿ@b@mÂ"ÓÛIh T"4›€§å¹´Bš1Á$"0‹øº¼Ÿ#á³ ¿k­f­ƒëwvÂ]±D/p~¸N êÃh0EFõ}`¾Av°Ñ,êÝrÿŸ#ÇÿþÃÒþì5f0§™ßÖšQÂ5ˆx€Eè³ÏAl@¹Üm=/¢’ÇÔÒzóµù2Ô6©¶-Ñ¥—D$|I {°dIÉ'±5šJXadLT]Ù¸·oXl!V)€ïçD²‚¤óýÏ쀋ŠÉ’ï1ZêÆÚ}8®NƒßÙGjDZ'ÜfR€ÿl_Ggþ83R ÑëôMR=¿,ê@’qF`bŽT?¨Ç&©|U@ÃŒ5é‡}ܵK’HP5Ò®bç…@p|ÿØDCûVmÌ¿áyæÕk=J‘î¿W  (Ñ:Ä·ÈC`XzD†¿0"÷üóÓ坸©ôÿÁb :Ïpþ Xaî±Ø¼GGÒ¢Þ;„ÏÌtXQ=—«˜gO˜y¬ZÀP긚oX«HE÷4=1êA`ùïäÊBdXº^ATè5¬•êÂz¹‰ZzáA÷Åhd¿jÄT’>kµ¬TÀGþf ò'q×Fö„f/$EKä`äÚêÊÞÕn&Ý1~—”¬"º?~ßèéZ}ÁÙYD9ˆº~’ëù5#i^M‘eíI#nvD6Ù©®þ~ºI?ÔëÀÌ“çAסÎ%¨Í—uÿ!æRÀz9’·ªZ±Xµ¡¾ÕUcâ¸äpü6}àø‘+/Ä{¼*–„²]™wIe÷ã²õÿ ÉŸ¼T~{íM²þ3£t.±î??zÁ2ÜižßcÇ¢*cÅ ~Õßµ–„›ÔF8§,yÜú saô½Lþþ1¸ žö!` ‹\â‘dükµÈˆ{€˜(Œêž2H-Ëýf©I{4 À·J\ñ”‰(n:l(x½±'{’PVät… 06a¦”>üÀ™´g53 RâÁ¡(©eµTçtõI¡èîµgP_Õ Ä°·LÂÕùðcîFX×4‘˜°~ƒ5øõí–reȺÕffrQ|})ò¢°ß‰šØoÀSTç‡õúÇAóY¤Èÿ°ìûÖFéèß'm¹)Ùý™¥òáß”Ë.ù¤t¿ÙŒej‰TŽ,‘öÕ¿®Æ¿áu(Ô®ï‘7j‘©©;îØ÷‹ðÐÓÁáÍp 6æãÄè¨FRºrõrîK›Cb(1% 7@-ÉÝ—öŸÏÈb°VÛFX³1áø½3Òî9‹^qE½ôÀV»Ñ9>Ai…ÌÖM•#Ñ‚¥ÄX=˜"X#j˜„æåÚè^b&Ä><‹Q}n“:ŸkÊ\›æ&ÄnI©•Ãf-=}ŽJ 7“D„¢< jÀFÂ*@8Ì…8y鉡ԅö[ˆúÓį1x}Öò¯®0ÜJõ}é4ÿÑ¥\~ØŒ b>|þ°þC\ƒz°_Ê#?•Ç?8!£›{¤­4.ÝÈß¶ýº×.—þÑurÿΑþטtŸöB3£XIžˆàXlÆÐgÆS4ó®FIBùš] ë‡ï`À$²bÌš\¦Ä<7,çàZŒ*T)(´ó…ŠÁ–uI…Íþ7ãÔ„ÀaÙ <ÂXµªsã†2 %€$äŸëÿV@3„pEp7q…éÅàÂÇ3)[¶tDF˜Ùé²­€¤¹¸cñ“gà^1 Õ­%Ÿ&uè½”ûDߤ>×7ÌQ‚$€šyjÔSˆ%­ýª½®G@ûÍ— ×ÈGÄ*¨§FY—ÊÕ¼1q³Î[ fGÌïEs}{4C ¬«oÂ# ôƒs6Ëø_–Žãú$?x‚ý AAaø˜T÷Ü)¥ëgäoÿñuò“|IîÚò=92~D~ëÄ7Éñ¹19­m«¬yåNYõ‡gI®p¢¹Öl¸µÌ‹"—˜{Í7ïûE3Ѹ…McŒSfŽQA‘Ø3‘ª%„T§êóTâÁ¹@²\T= ÿÙÄ{î–UoêÛJQ[WÕ‚ª*Ñ0¹çÖ’:n§IIð¼ç=³A´ÿ¢ @⹜WÝca”¤"‘h¬®,ˆÛYw.5<“E<)À(·zõ„ìØÑUWá¥Q ŠÛÐ=™ÄŒ@ÿ<_ú`Ü%ÎÒÔÞ°öÙ÷õÁµ«¬úï\ä6ëþ…uê«9ǹíšç_,ŽG#΋ª °øƒŒ©îî3Èù„ŒÞøM9p§Èª7vHqÁ2ó¶(Þ$›>´L>÷£‹å“÷Þ¨øÐÛÛ#Wó2yÓe×IÇ+{%7øls÷•æºÚ:•·ß+ùÅ¿!¹"ìCæ·!›)Hƒ`¡0m#a’»Dë„2eðj¸Ñ•¾=ëÄB,Xk¬1¤FúQ~D— ¸È™Æ$¸oÌEÁÁn7!ѹµ#Ór Ò¿!È‚ôO5HC~7:"tYfÑÑøN nÆŠ®nI§4 Ëd–¤ÅI’DðlXÑÙ’÷V÷— mÞPßÀ$é¹DfÖÚwíiªB’{6Œ‡U‹]}0)ØÇ­¤-Ââ@™ú¼‰š³h¦‚{🥿õ5þut ØgvÖü‡Aî°y.\{KeßO$èž’é-}c«Ü~ÕÓäÜ÷Ý%]§ôÊ‘Gfdäæ.Y˜Û!•Ÿäåüž|æ±Ï¤*Gˆ×!o;öÕò¿/ûºô¿ÊLª½AôÕÖž0qÿF»(ËÔý‡eॿ#ù¾K.ÂÐJAMjA3Ö…DY$¬yPúú*Q"QΠ؉=¼“ܰ–0t"/‚Õªü¬Ô$%Ñ' ÿ@œénÕJÐZI¨¾}\Üð#‹já5Øp @#oD²þ? Õeâš®îŠß´ ’,Ú$ÕrKé 3­´èHˆ¨> þí&ñ@Ô# ýýØ;ž+H.b‘Áe!RÂz›T·>éù® ¶ZˆxC(.€¢¬ËÅh%¦>O⣱üBK?µ>3ˆˆSÙçv±ô©È­Á2ÙÓµVîÞÿiÙ´i‡Ãsžy©üþÖ>yÁó¾/ÃÁ Y÷ú]Ò^Ÿ„“ÓòÄÇ{ez8/kßP”®_cžª@PÛÀ´ºKƒµâ$äîZR¼ÍE~ éV7žæ €‘°7¡ÚP–-“ú,‘e|߭ж?\<ɇï#?ÝÞ€uüΖëtSúEj0i*¼÷½éíÁ›…ÿ €ƒÀΣn‹#—«±8[*»j}äf‚¦Õfk³•¤Ó#qž‘Œ<×O¾ñš†9Ö®§õ=í|7ÛŽs‡xºt)’mª²k×¼ºb)¼^˨…Q ·°µüZÕŽ@…5á9Ì ˜7oÚá@>ý!¦ãs.2’MZ"k<\|¡$®Þ%‡n¹QÊÓ{eàÔaÙó¯óä_¯½T^4ÿF¹óðò´é ò®‰säÖ‘ÛåÀÁ½25=m x<ú ô/˜·ZÎï?KÚrGäŠß, ^kî=Ê÷ßþ"9ý’ 2øÒeR\úbsö)fĨ$´H´¬X—Aú‚Ý{UÚ¬£ÞŠóݸAæ~»ÖLX¤e¬‰¦´ëúiáZ-t›ˆÂŠö>äµnq\Ï’ßnKqÝv].ÌÅQ›ú"^㞌cÈV» ò׀ح¾Ÿ«0+ð#ã’’yìð `óPXÔ¥”îÁðV b•‹¨IÑ ®7¬)  ï6uœ*\·èžZ.Žë÷îÍÍêW¾r:íòªz¿F'j`ž¥íx£XýÈMã C}A€ÐŠƒõ‚$ÁùêšV­!MCnóµï …Cf\êAÙ.p4`é"û‡Íà7›ï6ËÞ/î–k¾üÙlÔÆ#ÈÉ¿&ß~ä3²oÿ°4:ÚÍ ×¯zšümç„ì^±LÎ?á¹ç–§ËšS·ÉDÿ€¬º4'½Ïx“ðIfð t˜çÖ²Tj³ D°¦Xë®®13Ïn3Ï‚£?«…éÍ<Ô<$’X;HÌ7HÊ%`d –+óa€Ù†x>K豄ۀѳ„½wýûÍâ’$‹†FÀ÷½/ÝØ ò7Bt÷÷FˆŸF\CXR&š:08;Œ]XÔ%ÀbÁ[i iãª×§•‹ãÙ Ví}öìÉÍŠøòïéêÚ¸Ö˜†Ù-¬\)€yq½yÒžžiCø:ki®î|Ye‰yòj„Tkw×!©†í`i@£‡B¥‚îîñHìï¬p>?* ¢ÕzìbpH õÿÈȿmF%xP¶þý“òïœ#µõg²mdzöHà™–,G±Ø&—žûfÙ3úsyZû™²nþˆ\ö¡oJ9\.Åy'JÛª— ²ƒ`y6"AÄ&ÍœæÛ(Aµ_TÍ}¦Ìû6óܸŠ1mXW –ª˜6b©X;¾gH1-ò.2=ÄpÇn¾IÞ U¥ÂšÛ{˘õ"ÅR®ó ßd­”„ð³àÛ%iâ+„`.Ü?í÷F.AŸ(`T,j½Ø´V}\ãž?ª[\´Q‘Ï4»-´4á3ì*¶Íæ¾dáºæÀ9ì)ÀWÜóëv¤†È0ÊAŠ0ƒ‹1óŒ§aÄšCν½³fG  ÷ÙµP½·dãé9ÇB–}ˆýíÒ— ˜²HyÊ£¹°È§ˆØjÞß+áÁ;äî?['Û°NnØõ#¥΄ü<òyŒ»*Ï=ýbù“UrñG“®uç˜_N­#¸Ä<§7:–ÊV@IrŒUÅó’Ùpÿ¼-9NﺡdJŒQܦ—kƒœ?“Ñ…<° nÙö¤B#ÜÀ(sV´ˆ‰F!&}M«t´ÈoáêÊ+ëOkD²‚V<­¨~ÒŒÿŸˆA· Ä^­Ä#" lÌÙN*­ÕŒÔ#pl§`³ ¸âT¿‹­Ê¾}Á­ Dï>khi:7,šqø— ’{Á#fßò`ÛnMÛ kyÿ½=S†cæ,Ò«zÒŒ¿C4¿D|ÃõÛ°G"B0eÎAÏ![ÄC¬-È|ÿ=R­<.Ûþé>‘‘Q™·yDþôŽ×Ê7ù{'uná8å„§ÉëºÊ뮼Ez_`>ÿ,óí æ¹Èè‰^ ¤’Ð,¼P„ˆ5ߪ8Zͽ"É´AÞöZ©{=a Éi‘î%W ¦µ4v|Ç ¢¤JÕ8 M1g¢þÒ¥3‹¶èˆ_î®Õ²aîç¬Èoáê¯þª± ö}+®À£!îw>p‘È}¢‚³A,BáÀ&âZR_ße˜¶p¤¿¨¦fì1)$î%à§ìÎíÙõ&ãñ³ž=ÛÉŒI­4:Ú^ë¶LŽäïÅ:A z¿Àúôóù)3Î.kôCM?×ï0çT4¥"}W[!Bª\46„ý‚£ï·U|û݈y¿[ªÓwȆ+÷Ê÷ðl9{ßOåCóÖÉîýj6èôŽUK×ËGVöÉ/{\vµ¯“µ/š/k.´ñZN¼7zuìÁ@´†PIl´àô4<÷§m+:Í.-GQ•…Z±ZlÕwPŽ©ˆY…  øÏ2õØk$H!–B34ë3][ŽÃÈ¡ï)%²r[q:+×'Œd5úÍ‚í«®ª÷øÈxQF I”÷ªÑµþwÀldd™kå~jÀQjË0”¦–øFA·ÿ›ó §½îÆ$I ÅE$8Šê¡Rk»å^—”º' …V¬…H #tXprU5`Ô+™ïÚ#‚U²†2¤ÐærÐéÁE»©-—Í8â}9B²² ò±®7dû!Î߯äG×B Ø.O^ûSÙûŠÜ1¶Tþ}ÿ´Üvÿð³éþþ±pÁyã’a¿]N:k³<ýCÒ6t¾hx0ÌæóÍ*aìPMàh‹ÆÔe¾G‘öÈà7cö½½&ut6cê±ÜšÓÓšÔÔÙ9mö¡Ãî!ë а§ë\µ¹ÚJ~vD-êJÆ„F3èr”¯y}TڢѰÞåÖ h†ü.l5SeëÑÕW'Û’|â­—K¦Óʽˆt.ðÿ×#„êÕਖÑè8³±ðl÷åç ¤qé4bà"0û̃Ӣ”ÖÎuA&>pçâ{˜°Õ¶Ss¾Šîñ‚Y„!®fdèÁ; ÀÈþ “Ö†œý¶6 k›µBÖh‡d¬Q!h0î)b…Ò(ðRD¢Y/@!¤pÝ]Îlêøý²ç|öÓ'ÉWön‘­Û7͉@RY½ì8ù󳑧¯ß/'½c¥º. µdH4RÍ|KÂP£ ›EXB RÍ„ ¡–œ+ Š–¢ùö MPƒÔ¦4c»Ý" Ê#¿LD㪑™Žîö!ÀA‚X`iyVXƹn92æ°×aà{ÂQ⧇Ÿ+Œ²•šýþ0¼!PÀcLyÚM|dMB^÷@Ä7̵™t‘„hI÷NC~×:Ï0Ò!ö-¦@Á5˜"½¼;ŠÎn¹?_—€3à@€£Ùà3‰Àð´¼ãz­¬±ú~`õyXõ™*R_¢ €mÍÝ{@*Õ^CÚísáG =$íär@XˆóG¢Ñ Í·¬²÷h$F£G›=Gõ}ÃQíÒÚby«&HäP‘ȇ Àí‚^€}yB¾þ¡çÊ7d£ÜõðZB|+–¬’÷ö —^u§ ¾ØˆýyWÚyÖèWŠÞ« ¥ÇúÍç¨n·M BnÜ…ÝÑ]÷Gó²R¼•J§U‡ÐȤZí±„b2²± FFÚký øÄö„ÔÆØj çk!ÇÚkv¥à´B·­pIŒŒý.!mÐÐ|ðƒfz9Õ=“*Ü4CRÿ!|ÏTˆÃ N Bb´\D’\qÌqw¿g0‹& šMj“;ºëªµ&htÇAª‰ûhÿx‡?ïúD¥°V#Ž)£nÆ>/𞣮I­F‹be[Z ‘g1w¡UŸÒMÕ—0DXcÔ‡_© ZNÑVË)`ÈË™³ '`ѯDD¹¼eEzûœvEü ?â¤*%–.*@R˜Œ~;bï)!K~ç"Ä‚:·à&¹ë‘¾¾@>óÐÙ}`gfÕ=à…'\&oþ­ä¬7Áõx¼é2QB†cù®;š“h;6H0…èUç@Z()°Ëv›L¤ó†„3/ú}4²mB,3ë8©Šü`"@x¬¿ö‹Pa p£0C®__Š<)m¸‘îï"}³H¿$FƨUí®Hýð‡ÃPóÀãÆ…IÜ* !HBPmð¡z ÖO6µðÝŒøú·r˰&Ú²EMm k‚„R\jÅ/Üή¾Ž®ÜV= È¿w[m%¹ôÜ„èòn´ˆþ~vêqŸE©E zR«»ß˜+àž«õèô7u7®ïFUÇ£çÀ8v rßVD±â>~GYœƒRy܈ì{%?€ðÚ^sM—hU›vÑÀœ§R€Ööƒê0fÿ*‚ê³PüÓþ®±ÕÊ¡o†ò¶¯¾EþåöO™58"­ù|A.>ùuò×/ù–¬ü£’´-<Ñ,ã=ûzûX‚›À¨4FB¥=$Í&d cÚ, {¶3}²‘ÓÈÅèÞ›!½ªcÅ H)š‘sƒ0“6œÏ 4 €slö î©ÓÉ}¢G£ DG­öÖ,ÆþšÖ÷蹈½ß»·­.Çß÷µ×`h }< +³6¿í,›ÿËÁá W.?*aõ€T'H¾ÿäqK–8Œ?ð=Ùýíý²è’Ò{ʆ>,‹Dë^ëGW=B zTÍ+n‹ÀRd ˆ>[· ÎCJ0ž¹M¦ïš–Û?¸Z>6¶F¾sË÷mHmÖã´õ§É[WçåUïxP:ža)¿ÆÜ5‘ Œç™Ï]R3PšùL ß+;o,Ëšß>O‚ÂÚÑ!TE%‚QÉ!’­"Ä?Ä1˜qoºVrm}’ï]'¹þ78X`kÀkXRÇ¥Ü+–Ñ¡o!Û¬ûݬš€F\¿‘±Ïg„b2ˆ ÃÏmuç< $èGäo”Κ„øÍ”î- ÏÑB–j#`[Ѩƒ5‚1?©Á†Ÿ¬né@€ù‚«ã a0IOsë÷il€¶Þ¦ëÉ îq]Xr"ÐGuQ4ö˜äëë='lgÞ°t‹LÞ÷72úÃIYøû=RX|¾”í—™í{¥ëÄN™¼ÿyøÃ+ää÷”öu/ޏ,Žy‘yëˆE’êôcr×G7˺ öJeڬ˞yrâ+a0:sÕHå1{n®‹“yoˆlªHåÇüøK«äï åÁÝÛ2!ÿâyƒrõò!ùßÙ,m›y®ËKØftûö…QG~nT…Ò³t… ØÞfL#RÞýs¹ýCkäÜ+ Rè:Í ð™¢åÄŠj'#w¦ d­Â@‰ìÖ­¹Íh7Ê¡¯n)…eÿ×ü¶Îz â=‘È뢠`d‚iꦛ©Ú¼vElXLÃIöÔ¤xïGºj9;\ÙŸøD5§€»L;¥ÖW³iE H³lc`80ark†éB%Gä3Óˆ@š1Ð Šñs|ë:ÛBCGŽS‡gwdõ Ýs˜häçÛ»úwìRÉ „€Uc zÕô³‹w .+¸ªxKáîè˜4cëŽÂyuaÕVƒ_Ίê"[dzëçeâ;eãMrÜ«JÒ14*}n‰¬9—|ûšgÈò5ûå¹|ÇY¢uøº¬½ ´£R}PžøÛäþí<)¹dõÝrΕ¤{i§zä|áÇÉ`÷´üÎ[Ísîì—îÉi¬LIñ±ª„?ËÉwî{†\Þsœ ß2û°7Îzzºe óby³‘ØÞ¸â»’{NIö/î’E§‘oÜr¢œsÑnYuüaùäŸ_ #F=yÛU;e褥V÷ßpMYúñ|9¸H–,—3_<*kë…f‹íœëƒ£¬¶küÆûŠ ˆÁaUcÊdï§ÿC.ÉKqÅË ý†ùm¹•O€x‚ÉÉ¢a …Z–*¹0¢ý¨@wßã~A*Ãeí•>Óá N3Kãó¦&1.lÔˆSÀä†È]sM5%@‘M-/”Næ"¦ôPÓÛ!`q0`¿XC3"“$ $¹]QT÷†(­žÕŵAú¸Bn!ÖÃà‹ðœ'œÖŸÓßQ¶`Ávóœå²o_¾fªOø‰ÓuëU‰0j‹V¶Õvöïo«éz5ªŽ9iâ΄[§uÿÅY”àþ@\èã(Äù˜À²÷{wÈ_]!£²õ±µ²¯³KÎ]q¯¬ëF)ž²ÆÜÞpÿª¡z9ˆÈЛ0H·Ý)›o~B6|:'×ù“'úä¸Êì1"õ²üÙ{øˆìë‘}½§ÈÙçÏÈ~ðOfn3³Öý¢‹Î–M+•ÝOÈ`ç~©Í:Éúîy|rXΗósyûÆ‹eWn§\²$'ù…û,½>” 9QþnéseQnFþâ7Ê’>[ §™ßa3À|¢Æ£¶‰)6AL«¨-cDÿä[òWä…¯“µ¯ýCsê™æWÄÌ3kÜm¸¾ÚØŸ= üœ7cç¹½.“BÆUŠÔâ³xNºªªîn­QO€k8FÔ<Ä=ƒO}* ©£ã‹$ßx¨6°¤Å$£BbÀÕõãæ[%…HŠE^DÅ.B‹@lDÂîIúS½^j­ºýH/¿:³íP‚â™ "ñköáœGW’+Qà{­Ÿ/?7¿Y¦o|DnzßyòÍ—É+ÿgyÎoÿL‚K Ñ8¾(»î^)#ȉH±¥¹ú5bvȃ_‘'>ß!ßr½üó¡oÉÓV\(Çuÿ\>øì-ró¿­“×—É©Ãr~ßrWeƒLNOÈÔ4üïe³¥–ôwa¬ëêì“™Ò„¬]t’_Y"ÿ±ïG2¯§_þí„@ÎzÓ^ùñMÇÈg=FÆFÇexfDÞ•7{F§¼è%™·êÜÈS0¹¼'DÓ˜ñFÑȪÎSvK8ýÙ÷/»dæàbYö–—p¢ù^{T«+ÍtØN@Ú­J]€PýVî$òšÎ­ICPÜvó.~Ñþ©ïݨÕ$Õ‘Þ*üg•)ØÜðÕµ)ŒÔâl‹½Ï|& ÉAüôÅ,á…iîÀ4.ÍšúÔÓá–`U|N3È5">Ò'WU`.Tl–žÚXꥦ’j‘À3ô…µ¬=øý;:`ØË[BÀ´a [­˜ûæE«ö‚À7¯®,ë¾³ˆ[± :ñS¹ÿݷ˾MÝÒ>o¯<óœ»åñ¯¬“wž%ì¾MÖ œ!ÏŸš‘ÉÃ=rÓ’@ÞžHÎÿøýÒvz¯T&ª²÷Þª·NÉÈ =òÛ?^*÷ï¹ßŽwÍêµ2<¼_&&Ç~aßè€4ÔÛ5OÖ±ÿçO\oÌmmEyÕgËgÿîi?n±YÛuF @ua„ù¨ä:$ÈC¦ß%;®î“iƒ]‹žwHöÝÚ/ƒë¦¤ûé/”üâ·›=Xl»iõ)V ª—èØWö)`=·”¸/þ“1€Y"j5)c•L؛ҲeS²sg»S·Pj6¡8ž$Ž% ®½¶ ªaâŠ#þ šfö€$dtÅjpVÕ¤b®ö€4¢ %¼ê]‡@*Ô@½5–xŠf*LÄqEr–äf|73ÃÜó y*Âëd(eùùúÚe¦j 3¤Ò|¦‰­Á×ÝµÓæ¹CôTƒ cü5^‘~Ø\O.‡H8 Ô±®8ëâ2ºtùa™Úr³úž”|Lj»Gåï.…|~ëA¹sÃ÷Í8º¤£]dzzF^}ì+å%Ïý¡¼à²-²Í À+®’•}ËäÜ]#òÝŽså#_7ãþå }|hˆm '.yžüÍÀræï€»‹é¬@JmÛœlô%€´ç¥U " nÏBãPo„êk H0ì¸MJA, 6!ÂnŸ={ 57"×ÈHŒ xjLRtAäèªqíCCZ|ç¸ÄcÕœ|6EÙoÆ9` [(P‘þ?´èwD-º‚ªE~ zA ÐNÛ‘m¹¥úÑ”W­?ð2¹vËgÍú×é,Y¼LÞ¹t•¼á¥·ÉãwôË[:UnÛu» ö/‘á‘msÒçÿ³Ž®Ž^éïì“WUæ×lŸúÔ6YòÌN™Ù;%×]þtÙ´q‘<º—üpϹdé ä¸ö骔ä¡öùrBX‘Ã=Cò; ¯—±¡~9å/:¤m œ-CFg¢R ¹eCжúSˆ•(HTø#¹M¸ã€F}BíñGº°â¥ÂSww » 6€[Á=ñ;k ¸EI]í[¶L†›7·[ © trßOMQ4)HÈ=ÒT~NOÞQË<€Í}K¹R¾ •(4³¸nCþ§{Ö}êç*²ÇëÀû“›k? óuÚ5I¤Þ˜çàìíkÔ'Õ‚Ãy¸?¼".á!d6$MÝíŒs‘Zƒ=ÒÆ›Í‹$EUz‚jÐN­‰:p Nî¹[¾÷Ö²ú‘-òöܹéþïJèm.Šq¼zÁÙòÚÜù½ £PvÏ—m;üeãvKG__¿Y×ÃòÖ¥§Ëk_»INxõ!£ òÕ+Îw=8*ûî’É©I+5,\"…b^öìÝ%/:óRùÄi÷Èò¿Ü-{~¶TJå^YôœÕÒ¾ö/Íškà±7êXBˆÔ`¿!©ß”´Qþ p×j(Uá)¬2x=<‡’­VzÒûh•ê Ÿi-ò‚ï}OÉ7kŒã"VÜ] êcr¸a³iG3]½‘J µíãv_n =¾gHlÒ3}nßì™n-Ë}CD§Ç€‹¼?uróׂPH$€  (a`: CŸa ˆ :õ‰<ðççk’ןZû»ºÓ?m%5)Àº° þ#^¿¬1úÁh$À8—bÞ7Ëø–ŸÈGßöty`×2¹wøó²yÛÖÄ==wÕ;dß¡ïÈö‰G­Zðßñ@·âUó×K.“^6&ÝåP^uÛz¹åá{ê ’òèí™'/]ÿùíSFäß.Aûj™ÚlÔ‡çHaðE‚x€juÀÆÀ˜e_Èr9¬+í¥ûçðqØS–¬s+1l~Íš}Ùìý¡¢CR§4 cÚbÆLý÷ƒZíÇÔ/}© ‹¡õ5HÁ}ÉâÆ‘LêÁÍÈ™[•Ü÷iî;·ýö‚|ž½ÒL*I:q ¬´•—·`’ŽNÉgÑ¢jÍX‚<ï8 /¬EÒ€‰5ä‡ÏÞzlC%Bâ[ò»££úýÃZN! ¨uërѼÂhÌSG°bÞ£p1z,ýê×jUy´Ž*ÅHÓ… à ù±üÌÚl—Ý·Ü+ßÿ›e²esI®Ý-µß¶ÑÄó~í”ËÇŽyXŽýÐi_÷ ³n§›5DHñ*ó~¹u–Ë=Ve£Ám:*u€ý„$—{kaêôç“ãÃø­Æ\•À.,[Ïp Q«È ݽ[Ë‘û¶„¤n@8Xdç²kU"øÜç4€õöÙt:u` $ޤ*§­&óøê€.V=b‚ RüAÂ0.mü9Û>àÞ›Á38ßí àŸ§ÎÆyôæÏ?`tûÁZNVŒ×ÇæÒè†S˾Z€éŽÓšZ—ÄËöÙýý3¶—=ŒDpÅí¹Y¨µøKQN½¯‡Š÷i_À=µ&?‚{P«É. ‡D  v@ü7‹icðÛDô?®Ü»÷ŽMRúɸ¼õÆ_“Ü}ƒŒ"ÿ??Š…¢œ5ïuòÐôõrøÈîÄsŽ]v¢üë3²ú£ÒqÖ*i[t©äò§˜_¸Ð6$5Øc³LÕRµÞ ŽË|Ñx5£î¹2À*à[s6ÂZº0à×kËu½ŽAC~CŸ¸Hž”gàž|úÓa€eL~܃^/b "ÏlT@Ã?ZQpø•u ‡ã……Àwìƒæ–ðrŸE)Ü‹ ĵ~.¿ãOƒ XÔß¾o_±–â Äfúwmé¯ÁŠŒF墢;Ûq÷=ýÐá\홬.kƒ5:G¥všÍìŠ C±®Ïº}½½Gl4zÜÅVþ)s¿b @…–æVË~€l7àñ<âüö=&ÏCs´ŸKF£ÏÛ¬!°üȹçC«äÚ[{äë{ „Í;";wnÏ þßõèìì2{]áád‚·hÁR¹bÑ3 â÷Êó~w£¬~õK%W8MlÍAä<„HB¡î±jµ5"P¥BfÒ8¬!èzoà—2«ª…¨Œ"dR%\§ªc}‹F6…,/Á'?©Aê­äj¸BtÝ;ó5ÜûP÷ ëÅçÌiÿÓT7›ˆU`É’iÙºµ½®ó¯û,÷¾®ë j š謷è»*‡[ÔS ‘ÚGo£¥ âÐ -#¥.˜ŠýŒßYLR{ö©5_õ² &mt¢ÑÓ „ÍÙ’\ zbKoÆïww£IFÁV¯Õª5܃>|¥Rotnµáž‰rÖYH}…QeD4÷},ÿUì×óf¢t](”Û¤zd“ä¶ŒÉøõyÙþùyÇØKä罷ɶ'úeãè/íèíé•ß\}Žœ·¦*«—åì·I×ê £Å1Dö|貪š¶g‹KzÓ£|Ñ&šÙ99Y°Dç‚¡â:õÂÅmË™6ÏêÃŒã‡À*D~ñѬƒëpôŸPàëÆÔûÁùÀq0P$œç éªRëuë<~ Ä†ÑBô¦ wˆz!ê³£ü{™ÁݹøZ½e¶àJ¬¹ç/XP¶Æ8ˆbô™B:Àµ®{ÕreÛ8|¸PËïW bÒŸ<InürÅs9Ôä몉‚ïá3F1Nµ”ÌùGl”ªéõp=Òø}?ˆB}YïHÄÑa@â¸Ú°9KuTJÉÆyTŠ}Ó²ú…†ˆÌW†eÛOÈ7?¿@.6Ë{ni“MrœÜ·ëvóÜ’üO:¬ú˜/J¥Z‘þyƒrÒ‚ãä…Ç­”?ûø­óΔŽ¨>t¬YOäÎô ÊŽ#( ’™†zkQQêÿ`$ø â­vœ’ŒŒtX77†˜²®M?ÝÊO¡d§¥CªqUò¬Ž:æ‰t`_`—öšÇ{–ºesCfÉ1 íÒ }øú¿û¯ÿ#ï)Bq,8@„˜ãOcŠÿ ©µµ“†üR¤wz³Ãwé‰Ð—6PãÛà úäµÕ’"¼Ñw‡kÞm9]²¢:sôq-]8OGǸ¹o—5V{ÆÌ§EòiAO¸ó`a†1ˆ±_u~è,÷A€èZ§?´]yG VQ¨Ú<ôI Ë;ÍÅ#2µóçòÍ·®“Ž{DNy÷°H¯áüåý¿¢|ö®-rbÛ)r8ß/wlùúi¿þ/ê(órÖIoçnzHžóÌ­rê+ɼ z¤gõ©fýÐÒ|y­ˆZaýÛíroöº¿–ä¥RYÅöN£Ò¸•âƒTeëK‚Å9úüѰǶa€g·-ÏKÓ÷ À_ÿu½@Î Ý›™rø Ü â8öÓcÇhV_½dàŠç:Ùÿ}"@NÌ€"&–XX‘T“TޤJ½Ÿ¨cy]•€ <|&nŽßÞ^¶% ´–{Éêz…BÕ"¸ÖØ+X5€‘_JK6Öal>£?‹­ûŽ@¤ìBäPi~þƒ •­¯YçnyYÂ**Ìi‹b@îT_µôý›œY–®UÓÒß5.ÿþur僃rÿ–»m\}©ô?‹ó»G.W_X'ï»x¯œþç%8qѨN5H~¼ ò°VºPZg ’Š‘-G6hÒÆUbf‡*2 ÞI®ЈàP{]èd@E Wtfú!Œç"B±ë{;P_ñõswÀî÷ûf±n1H°I°¬²[™'M !`Ó-ÝT_ª[#â@'Æ#ôõ¡„tÁrß|¾d«é¢ÍT¹\”¶â„”ÊVLGŒþÔTÑ•îî ›^Šp]*œ²-ª0V w±xÈfëá¾è\S(”¢0ÎbäË’Š E/"ñÇ–´Òb›ªïƒ U£l¶¨¢¯­ã‡üú-2µízÙü•aùÚÈcF¥Y|WŸüZ×w䫃'KLɇæÿH¾ýx‡|©|žÜ¹õ¿Ð¤ÿ.G›á/\º^ž~l(oüôé_{ŒTË+%WÚ| ¸òˆ¹~ATMvÚ"¹ŠêàÔ­·BP,j-=èøù<:éÂ@䲿kתh ~rˆóðó£€…VäÖÝ 1–Q=ßêĵpó0ñ¼]2µï&ùñÿ:(?l•ÜÓ½JùºÙ§C219%ÕÊ´\œ"[ÌúܾÿfÛvëW‡=ݽ²¢¡Üxån —÷ÉŽ;×ÊÙo;]òíhC¶T´ª0ª `?ú¥ÚP`mÔˆ¹4­÷® Ïåþn¸n#Ã^£nAÍ€û¾Æ0]F›d ¤orñb\Û¶­Psø­°x½F¯Å:‹¤Åî»q1Ò SØ8£Q[mÚhÐD0(3Dpï(%hž’hO¹ÀŠïù¼Ñ£§>g¾Ê¼ÎÊ”P1­&‹sÇÍóç‹–ÖŽ,ðFd„hŸËaA4æ‰rñƒöJ¸’p^h98ÆÆðÝ â*FŸ·l ¢|8@8ˆ{Âú2\Ñﶪoäû—a©L? ›~*ÿú—'ËÒGwËUfn{ô®šŽ¿nÍɲwßCL÷ý²qî¿ÜqÚ‚“äå¾÷"™[8#ïúDI†N8ÏV!í~ ª3öY=PÕàÝÑx‘°¦"6á‰r‹‚úÀGþfê@+½I–àC£L:ßEG#!›bˆ*9Z&9n·ÍCõgõ*ŒŒ$Åù7w ú‘{°Q,\ˆ¶Lù:{€Þ+Œ$‹8Ì–®A&S ñF8¦@ÓHGk?jìµµÍXÎnƒff¾.áÄ­t?ÝœtŒ¹©TkU·Ï튊Sæ£PÜ‚ ÑÃèì@V‹àÑLI\f ±ûE رœ\ oHˆ’-P jÎèµVÁF¾=æwëìÖë,!©DÞ€sÏ' §@†oy\ö¯,ïüÁKä;÷}ÖÌ·\[óÿŸýüGs´µµÛ}íï”WœõL¹úïöJßJô"DñÑ…‘ú•—pf·Tä—ë~Žù¼8*Á®.\7/€¹4ø¹ wºaMÂeŠ$IÀGx÷³½K×_ ð‘ÄŽ4)€¨‰-ú\Ÿ–sqCX8Y,ÕpÓŽ]du,D€ÕvÄBp”_Žƒ}âh$B>š£þzœ‹î¯…Z"«©ø_5z>‚mö™çÜg&üï2³õ^É ™ 7Èß÷jÑm’ͱ1¼–;·G=©ïmT›™vÐñÑÀÈ Ž=O% {>®½ƒúÞ[‡s´|•F÷í×ï,6Š Z²*/~ž0ßß/[¿1&ïüÈIrûÖ­²}d·”Êÿs}YŽŽ.¹dájùÐÛFdõ-“ p’h"H}ÖÛR-?$¿ÿˆ \t¹Ù–³ l#=¸P+æªìш­R“{¤V ’2T¨Õnqœ¬í²ˆýu* €ý4–´½"–Š“]Ø‚ ®9&³hrB\®B7ð,WÛ`Ç…±ˆlý…saìƒzàúýëÓsãbÚ+°j¥¼‡å^%ŒRTËÉ5à¨;Ìëa©Nß 3wß!íÏx¶3 ÊLG†:Kú¢8ü®è5¡lkéƒ ”lN8ýùz…å&Zƒn(ʘvãAí=µÓ  9ýxÉHÚ2_¡U9 ¢%©Ô ØÒ_†TT’­{åð§‹òÍ/ž*Ÿ\~ŠÜóð?þJïor yè‚ÅO——_¼KÞpÍa)÷É®×Èòs‡$ßêH2ñØ#ràk‡eÑë_)ÅE¿gàz±Á[º ðd¦K[Û©!šå¡"ND¼ÈïÝ%éüYýýüŸôŽLÀ÷­3t—߃j#Cl’ǹ±±ß»1É:{죯ÿ>9p‡•~±80 ÒHÈ–Z±Fcj*+í`lƒƒ“ö¼©©ÎÈZ{ÀLTQwØFÖ…²I¦ý¢<ðÅrÖå§K®çæÆËEˆóíç—€è>‰þSÑ÷36ò¶ÏJÛIgK¾I&K¢{ôe|©a@j?…¬ɪ¶YÔý¬ÿ•`íì>¹õËmò¼sïÜä´¼íýËeãèiò“ß•r¤üêh|twöÉÏš/¯ùã=2²§GþãkÏ–5ç’‹ß5,Ó›Ë?½ýXyÅå£ÒwÖ›„ðl©fP. ‘~]±ž Ð¼‡wâ¿"¶Ö¢d’ÝõзŸÅÐÁ]sÏc4kfdœs ÿ™´+s-«E 5¸”Í?46¬uù‰¬uc›ÍÉ•@ú ¥ß1 ‹ëù¹©—TªQF`)ªãB’³î>µÐ±%Üa÷a©ì¹N&Ý,=ç]h$€§Ù®4ÖlûÐ ép-w§Î™ßAÖ»4fß ­åÖåefÇ ²ÿëyYüæK$×Å—[ña¦åÈÈ8…œjj¯º!QÀø¢¥«UºÐï-ÇGÍþ™Ç¥|ø!¹ûš¹î;«å—Ý$yŒo¸ûX¹yä>[CïWG¶RÀ›œ(óú*òFº›š—«VÈùïxÀü)¹íKçÉs>›—|×… ž/šžîµž$ <’€ènqÀ'ÝÐI‚eú¹ÈŸ–ã?Û §*/“Ùèõ‚Á;øèGa®G²fD ‘‘Ža»ÜÚy¬lB½&­º)Kxãwט˜äÃüxˆóCCe;A”Õbƒ}´/šJAK „”à-@Èm>Ê93ÖÍf9ñô¤2z“LÜú°äf¤ëüç˜1gnYÔ’GL9¢å¥»#N {$ü—Êá[eÏ?Ü&ã›s²âÓÒyâEæ>4A6Æ ×ˆì†ðØ–üé‰Ä{Ø$@aóQ¼»¨ÛðH”îû¤lþÎrë?tÈWöÎHaúérhò'2q°`ÎÊɃ»,~Á_ãW/[vÞ)3å +™>ã˜óäÔÅ+äõÅûdgÇrYÿ‚=²ðôAé{ÎÍ~­3ßc³DݶáLªçòÉ®@×%˜ XeQ£¤¹ë#ò×?[(7<~»”~%ö?eÇ+O“«ŸÓ&g_²EFö¯’å/ÝǽÆ"ráÙkúµ¥[ÁÂÄoäôÇá¿¡£÷’ìóW¬v4T]ÖêðC€i?Ód5ExíC fQäF=tqsYÀ}ñ¡€+úÓJÏŒ: 1Äm”¡Ñ{8WËÏ.íåúì5 WÏsY'»AÝ”ðhëq¨,¬ˆ2J©Db½¿#Å7¾«9þLÔøýz:2D€ˆÛ;%<ò})m»Eö^kƸö°zdPuËŠçî’Þç©âÀÙøÅurü{Ú AXcŽ®¥ªNØfÛ¥2²A&¿S’GþíÙ;8ON]õˆ,|c´/G£În©Œí’Ñ Ã2½­ Ë~ï\3YHQCáAõC‹v¾ …Á?Q¼OJyß}RýÎa¹ëšEò®C/–Û¶ÿ½Â_¹þæz¬^y‚””¾Á!9qÁÉrÙ¹#òü¥:y’ç?ÓÀŠa!Z†i±V¦ó¿¾âŠ×,)7öŠÕ—÷bIíAFµ.➸øIƒ©äl’ XfÖ!ó_´Ge,eØd8<:+òãð£ô`‰‡®„@'gÖÜ|èàeyòÉ¢üÊB|ž+M°\|®À1øž Ú4m²j)+žCqß%0”Ø3=ÝnÏ­•kòÃÀvX´Å48«úÖEP\c“Tn°é´29,ßï‘/Ýp‘¼ð¤{äÈî~9”ë–|ò&Ùwßré¤ïY(#Õ®÷€;°ºMäáQ¹ûò³åËû.’Þ®qyåé7É)WN^ì‘'¾lÆüm‘e8*ó/<ËŒ’Á`tJÔ¥ ö€Ž-úß%•‰‡ä“oY*§ß¼_n1?x|‡:ü_§l÷Ç£§}ž\{Ü€ÿ'G¤ó„ù2xüqÒ¹jÞjA‰0 –˜=€ºÖm®Ýv ª¯(5Θb³†[S’Ò1ŠëøLÜB]I¸)Ð^ßjà“È“¥çjvÂV‚ƒÂ>nö`]6`£”]÷}½k0ŒÊŃf±K·ˆ&^Zl“ÕwƒÚbøaÃnü>¤ü61áD/Á¬s]Ïãúûû§ØÕ%øè9$8fPKÔ\C¬>rº¶«(1/ì <²Ùcf¶ÏþD ÕGåÀ÷ʶ¯,—»Žœ-'/ßõ59íå÷Ê/ëßþ¸´Ÿ«fAÊcSRèŸòfóúQN6^·T>»ïE²y`XþO¸KÎýнҵ~Z6~êyì[ëä”·>&+~£GrÇ™gÂF ]ˆbH«€1ŽÈøÈ£òÝ+sò¹;ÿ{W&WU¥ÿWU]½ïk’ξCaÙwÁ]FFwQGAgÔqFQEPPv;I€ìûJ–NwÒÞ×ZÞÜÿžw꽪Tu: ƒ¹ßWéTÕ«·ÞsîYþóŸ"³º JbÕægþ¡«üÆ`6àÂÉãpÇÍMÈ?aÂQc™a*H . 0ÖuT[¦f¡÷‹~”SB‘²Âø«©j¤|ðÿ €Y5éø¬TyäÈKÕPÖ(ðéý<h›2?åîzx„tw#E¢äsÜçVÙkü<{:pG€ºÖÝS pP;iד\®€Æ¸¢K7a'MaºJçbÊùÏßÇíá #âÂBmªVаì!ä°YFØCâI3 ‹Ç·h»AfŸEà ?'RoÜØJÄþÔ_?דå©ï膳¿(.«9_8ónâ×÷g.|<¯ ;¶ŽÅ×J÷býÖEöÜOœpþm Œð¸(vËðls1O‹“JÚñ•¯?‚'ÿ÷†{qÒúŠ4zuœpqïÕa¸ÉMxa¶|±Ÿk;Ï5=rØ÷?HcLE#>~Z)®¼-Šh)ƒŒ¨s„Ç\m+CÃÞbÅ~áTCÎ].J|OÒ–µkGa…£SàUH•L»QÓ* »ÍØA°•ßHQ‚ûÐéýò—IW ±é7 «ö.ŽLk ›Ȧ”×^ºå õqKK$U¨²oŸçž®…ïÄ­e$SÁ<>nÀ÷‹T (Ͷp÷õ¥Ðc@µ×NKpþþÄbùVNTn®ü¬©gnŸ‚óŠl˜ hó"í©ç®C²{)œÎmxúK'àMgà¾×nÆŽ;R÷k΄cp‹ÀE…Õx%:wï¼ ÇLšwoAi} ‹¿j¯ãØcN±TZÚÖãÄ1ŸÀ‚7Ëe/.Ÿq¾;ïIܾèÌzïrœpeœ¢ F â   Rë±Ê*ѹw|­>x2V„–`Õk‹µÜ¼iÆ„ªQxú ˆžÜ€º·Ž‡®@÷+»Q2ûr„¢…Õ˜9XjMvmÑÍ9©7eü ÖoÈœ¥Àû0z%þðùù[nǺ`ÏÀ×ó²íÁ•Týw&(x ÈVߟidC îkž‹O/‚+) F*y³´ˆG ‰T(Wº(Éí»ëJŽSVz2«ú|òWz‰QôYŸ8m^£d*†¼ëˆêÏ‹Ô[ßúùa¯Ô¶Ý+øéò} íB¼gVgÑ®^<¶ìD<ÐÛ‚«îO£Ôš2éhQþOXÙö¿èènÁÞö½û­ÂcCKúìü{ÖÜ+qþŽ—ÐªÇŠ©CøÁåO¡`JJ&"R\kn&gN·úïÁÚ{\ò•(6µíF¯¹™‡ñþoL¬œ…ù ×NÀ·®ZnÌø|´þ¹Ó¿|1ò*ßnæFƒynÂöL>H- ’‚¤|oGæ'}ùà"¤ËDýqèoµEfŸŽ©°û"+0K it…¦ài— a«É^oŸ+& )¨æ¹0üˆpR p[¾—æé¹{e)®®NÚs  ðat”Â/ÊÄw“ )¾/# ;´ÂáVHs¨”ñÚÿ¤ðõŽ´'<ÔtØL?­ H¶~y;â„ðÕgÞŽ›Wÿ }ý>ئªªÐœ»½¾n:‘Hc§™{´µ%帽6ŠgËÏÆ'þûVÏ-Ï9IØd7Kûðàæâ¿wNÄKÛîû‡ä÷û[ mE>¦z,n|kœX5Nºj•s? 'ttÀˆ¤ƒi@¥ÑÕ?R ZP؇ãÈÜn8Rý¿kpà ®Œ¤S(ËÏYO^qý~ä9{æ (칃AÚïš7­µa¼ YGÒjW¥TJøHóM½8í¤Ce&VãÖß™w‚tÑ´YĘÓÝ` øäf/ÕÆ a‹­“3ÛÍÉn‚Û´]¿*Áò_ÌÀ·ËOÁ¦þßaË–}1cN<-õI|ïýwcÂ…mȱu .€vôaýo+ñÏ?‹¦îN45¿v(ååM7¬e6GuY N"Ž­K?¶ £Þ}Bv *µ4ášf#'€°=K×`±v÷¥Ë…ÌV œ‹d¸Õ>M_J³ºšj]¼tΕ¿Buäƒj´Æ?ØtÃÇóKÍ>‡ìÒIE\$Û54 YÒLiÑN7.¿uR|…„ò ׿ßF[}~–“ȃLºôÃ8øÍLH)1süNæÕ#ðyõäãjj|}RlY®~* ÆZZ†DïFDÊàùJ-p¶Áܶ; ‘|ÅÅs™›KNÀÚÁßaëÖm“IXYYŠ›‡ËG_€£ß² ^±À^ŠeÛ l¾½ÿzÇ)xq÷Ÿ§þò˜T>ïš”Dá˜)¸äÔUŽÂ„wž„¼ª3-_`Ò­¶BœSó?Xñ'ÅpÁ^ûW¹VùáÈA^—È•Rã*Í¡ÍÕ"ài)h»"º"Kë,¤ˆÎècò}„ sñ„N2§Í?µ•’RøÌÄbÄ-‰‡¦O4h)\ýƒ–‹¹XÉ&­¯/Á>Ø`ŸùØ9Eì#œzŒêWx•xôÿ ºéó6褽Š?}E{Qy¶ñÓZ»°áÆZLœô¶Þ= —m¨D¸z<^Xöðßœ\“˜þ)ã߃3ÊÖâkÿ´UÇwKå±1Vžým >öÂlغ–¡oL©œ€ß|bóþ³‘¢ãÌ\™c>áejA¢W²±£cU™E@à ÷ ý §ögpìÃT¹yA÷@-j3馛Þ#€#â¡"ðû¡¥›ôbšË6ê¶¶HªROúñ‰5"­ý4¢tÙ•À!- ¡ãvS\…¥¥½f?ň/MFôÃÞu ._Êmí~$ÒÏØ…—+?ßpã™þØ‚uO`õO*_ÜõkGcAïXŒÛ¾U] ü¢n —?ôw'λŸi\žó´Õîþ±Ÿï˜ƒEKþüw7ÿ˜S;7}·'ü+«7O0sg¾‡eËÂIsô–Y¨$9ÁÞ¾p»iU~+€àgö,†! ÙGdKíýw%ÿ !(£ô»wK´“C}ò ÓràöÌ÷)º2;ó2"J–<¿=5{,úüÝ¥’ô\‡.sKmƒMé]àƒ{èëç告»8¥8ò,µË9™>ë²f¿Eò ¼`4™`íKÅEMF 3Ó~\Vù—1€æ›õæ¿KÑÿH~ð?ÀÃCk°~ÃZŒ; ë7½lü þž#l.øÇ_€kjbê‘ÍÖ“¹ñ‰Éø¯]­hï8 ý=¸ÃÁ óñÏoÂ?_½ íËg£öìÏÙ’p¦c]Õ9Ï·½"è÷³H‚ÒÊ å#ö$øí¿§Lh— *Îcuø7$|½)?ŽÌÿgU¹”€_H£-»ü¼¦²Û[•¡LTÎ3Åÿ½„dŸ´.Ä´2õòsÅRk–BVy¶Î*´m¹xShê'!oæø¥XF=ù^i/#øü\ºèºØŒDË­H¶·"2nBEGAøõànP éG“Ϋ×òÀ]‡gZ°éêQøò®IøóšÇi¤½²² WL/¾Œ¹ÿ¹n®ïÞiîáaÿÿ`ZgLœ‹OO+Ǭ©ÅÔ÷Ä|6É€X ‚ÏÎ@¡P¿y%ž5›°–SÍ´VÙc‚x… +XNzV$m7!.hš"Ô¸ÁÿH¨Áí51 7²šáÉ—“¶_Aöi;cõÙƒV£ýTšæÓ­dâwôù©i2i-3Í}Þö]ãEI ‘CÜÞPù9Í|‰QD¼ #S~4ÝCßgoªðõ5{Ô¬šñDZ÷7£ò}–ñ×A½Q£Fš‚ `c1ô¯7: Ý?*ÂõO|÷T/ÄòKéÄ´Á6>‹÷埅ô%peþ –>HÏçÍ8fÕ7âÁŸ÷`ô©3ÍÚp2¢ärtè:6€íÁ’É|O¨óì îGþ…L$ØÄ“ƒ–¬òc€23û~ZüC¢„£#RÚ\v²¯àçâÿËÆ°«n/,ˆêó» ûA=~NÅ@¡§Ÿ¤M+*è»G½î.HÍsÜv`‘‚Ÿn³ŸÂTH¸]ˆ3lŸ]ré»{LºvE'x'&ßYå@ÿ~+íAËÏw ö’!DÆŒ3Wj¾O ûå͈5¢òíÒ£ƒ­H<=ˆg®›ÛâbõÖo¤]EÞL\ÿ"þRx7šûîppì¨éøí×ZP}ì[P1ÿ©à9Ù„Í])ì>¸þËÌÉ@”Ôc¤iÀlô_š’—Ý>¼8W í·„Wî› ïŸÉΫ•ut Õç…IàOê¿×Ö&­ nëö¹xø{6Ï$Fp0j}%ñô¤zùùƒ6¥Ç~z¡Wq^•×µÔ˜ìäj‡å×gª/ê­öFÐ-3oÌ+é¥;@Áeºo—ùl­1^ÂöëbÈ+£áCf?e ¾Ò‹Îg*PwI âÝÆµÈÂгyØpó(|Óy'î_x㦟^8\ˆã_ÂÞ¾+°«ù±C}:oªQ]Xƒ±5ex׌£ñ¹G¡|Êù^›pYl̲fæi­-Ò¦4㥈ÿ Ò´áך6å‰õþÚ5;9¬œßt“pf+òñ)†üè}&€ïf€¥¿ìºÃïZ[¥J{eŒö“‡ÁjLi4³þzh²çåQH‰Ì‹Ax$»¨3A7€B«q»Í¿dÉåû!ï*;¼÷¢Ï.>ù x9ÿÙÞ¦û j‚_Š®;6ãÑ_^ˆ‹ÞwŒÒßœ^½—w¶m™€g®Fb}·Ü*¾Õ¿Í-Íx#Ë/ÿ)ž{î×XºôÅC}*ošÁÀßÇgOÃÕ?nGrÔÛP3õt°#,´äþ¥ƒsAÀgL¬Àƒýº6æEÿ^Ücg¿ `8”GÊ|÷j^˜šç tßï@”[q¨ $gË5Å é¥pjPN•„~§ÝzÕ´áR¸.Wzú÷üœ«½ÖæÓß§É_YÙg>/²ßSyÐÇ—Çë£×jYð]›–Ë—BxWifr…§`ÓôgP«;Kw™¶Û#ïÍççY%à7ÏàgCا)ª¯¡eèù}þxÓûðZ¤Nlv àIµ¨míFi´çt¯ÃqáUøÚž‹ðËž{m“Í7Ò¸à‚#±uë¬\¹ûPŸÊ›fŒ*«ÅÑ“ñÝ+ª1çÒó-«k9ªì¥zÎj=++jððö¯òà_æP®Æ7Øiý¿yá<üǼ)øØõ5¨?ú,„£Ò̽ÚE§Ü¶v‹ÅJ­|(˜˜û¾°ë"™Ùï1Ä œ}Lþ})óüÆ»Jǧ\Aå’MqøûQX½ùÿC%]ú Š«× ÔÇ“]4L&îbú¹Âkç]^8•O¤¦&a÷CíȨ=O<Zî¼¼vH?õ ¼õÄƯn¿ ‡ùõß¼# ã_§MÅÅ_©Ç)ŸˆPé¿ìKèÙØ Örܹ(¶¦> fID«mÀ³ÁƒÂϬ‡r^úŠÛ'ÕÏï[Z>ÏÅ–òŒ/}Ý_°O-xʵóÈ#I×oוÞUW<4õ•¹$ó{¥à¢&¢PÚ"¦ï"Çü Yå¼ß+o`¿5öee¦6ât»ž4‹ÿ©æ}£ùM£gÞB‚~É·8ý¾gŒHßéþ#.¶a`Á½ˆÎ.A¨zŠ÷½¹sÝk°í›µˆo !ñšƒëB—à¶ÕW›ëÍ^¾K7eÞ¼1xùå8<Þœ#Šà‚™“ð­ÿ©Å¬35sk2àõnp,¸¬Ôƾ?WoeßU¿Ÿñ3 vK º«2B^ÀÌnYNaÏö÷¬½Q…@y²¯Á!¼ÔØø€¥õøá¤« |R'”Ö[J&¦=]iœ ¯JO¶£¢¨­Mxæû¸àîå²!€î—Ñxie-àélc9ïcOÁíYŽ5·îF•‘Ó†·'r ´ÿžëÑ_;žˆ­¿‘Ñc*y‹|Ÿ0Š%ÄÀ¡ Ý¤q BÄþ7_ŒÄ¶>D-Æà sžÓú1øŒñ×þP„ë6~ ›"}ˆW´áÞo;Ôsðð8D£ÜLðO½w4þýªJT9Ú ø5ZFq5YtQd3M®ËÀ_ÈŸ žÅ'ì ÐÓ P*HZäIÚ›…×' ¡¼q{Úéù6÷àöL¹3ÞF‹€ÂMùS7€qŸXGp¡¼ Ï‘¿·çú —H ¸SÅ" ÂN£ûIÛr‹Â­@”;!‚;çßúºDòY§ÏmLïØ&#ÀÔ˜kŠÓM`g[wh‹ôD*¼ºû!‹¿Xµ·~ÃÁw4anCî{² ᪩æ§Fq”Tšýu#Ù²áê*¸á>l»}'Jã¨:u´Q ÄZ;ª(0ZÛ¬ôÅÄ6ï°°ÞÁ­FÛ.)À_ž™Žwœ¶ Û×MDmý^lZ7 ˺æàÎøB,^öŒ=§Ã(º¼Q.ÇeGá“ÿƤ·× g>¥¥8ÆëÃ@7”J€–(3T\–œÕu+måe<5r³ÌR½}%6Ó%àœ„Ô°·ò&Ìça³¨ö¡,IÕ ( P„;iÙ`‘øûI‹¡¼r3fvï®1V„t´&߇â4¨¯ÌC ’Å:i÷ã<ÿ|ÒUóžWRKŸ~}"§F!Çþ­«Ûc~Ë´óïTFÐ#Åó@˜.©êD ®{ wü—‹ïü¥sFåáO–#\9Í裊«DìÙn”B5\³²ïüík(nL¢ò¤F¸½FìÙk¶/4  Ô(éâ[¶ÛŠ¿Á×’èx5ЧLÇùg.ÃÎÕP3ª ›W°w.~“\ŠEËž²7í°øÇ¥f¾\:3O=ŒéU#2SPèµu[P8ž Ú/ÏZ½œË¬Feì‹òA< ëT¨X±ÚÞ^lçÝÊ“X>Vf80ztö쩱àÐÔ=‹êhµüÕ.€¤ e§ þÑÀà€ù,± `M~¨ @Nš °ÀœÀ ¬ÿM*'‡P{Vº åºTqËÛ[g\€1tN´ÇM²¡GÔw˜pÔX„ÄÎ^Dç—bpUùSú1ô|=¿/Â× ›#ÆR0.À¼åPÏÇÃãR3™?ñ®±¸âª2ÔŒW€Tì~ÿ†w$ èZ…ÀÎÀûs´‰íH]Ýž&|ùG9åÿ¹« Àÿ+‹pN`$A@ ¶úÙû×Ï2ƒ€R®« 3È‘ì~NÙi à˜@ŠDƒ€{ÍÏŸ5& ƒ€±ß àS÷":·!l¶€AÀÕØþÍÛ¬'±ø.Åmk¾—³´—¸…㎇_¿ž9Xš"d‡³e’øKŽQC©†¡”ê ˜ œ÷Ý#€çOÅ@PêAgȳAF Ü+¿MAùw‡QËÐ}×.ÜsóÐl.:„¦Ü;¥u-í(/Â9=«0/¼_k¹¿ì}½}ýx#‹.šƒM›Z°reË¡>•7ͨ+­Æqã¦âª/Ua·ϷU€#ƒ;) %¿£fkç• œÔCÿfB鯫ß?(0庶ÖY1 g¶¦ ÙŠè µU‚ t”àcäÅ@Úõ†9}ÝÔ˜ ɦ(湞հ¿b ˜·W ”b Çn~.ºø.snèß•_„KN¼Û6MÄ´3W#¾6Œ_Þw*¾Ý· -»ßX‚ö™ÏüÏ?–.}áPŸÊ›fpîlöt\ýÃv$êÏEÝL-ªòŠ$0­HMxÊWiåÆü{eë ¿Kìr`ú)\å/ ë ]x´÷`]]ÂJ˵qâðåÀ%ö"”ôCÊYÏÏ+cd–Ñ‘£¸ÝãýKVÀf#¨låÀÝ/bÇbˆVÅP÷Á)~¹]Ï•£ö’$è¾D†{>‚M¿…o$ß‹û]ÿ*.Âô±/boÿhn9\|0GuQ5ÊKñ#Ág~Ò€Êi´høåÀñxz9pÐÈt v9°pdŠŒµµ¥÷ ÌåÈoÿ„ <òd#Q¨0Í#%¡EÀÎ$aì@S™„ CCyö˜JÂX‚Kä$)=a A¤ßŸ´ø¦Ù‚ÄÞÇÑ|Sêþe‘Qã=B8º_Ù„XË *ß&%Ÿ܃ø‚!,¸n>¿ië·¯yÂTÿôCŸÅŸ ÿˆ]‡ Aòpð–Ñ3qÇ7w¡rÞ[P>ïýæfHRiæ`™%¡ð«à BÅè A2ùöùíë¡“ÝIU#qPð$FÐvb™”`ÚÛ/%•@~%XQQÌX#£#YˆX&ZêËVߥ%XÌãû P‚uÿ Ýy±Öª/;Ò«)àAŒYÛ%J$"ÅJ¤[ý½Jäµ¶ãÇ‹ç`c¢O,¿ù#Æû@þYøp_ W aÉÀaà`™µ£ñðM}}Ú ³ˆœ„üÊÍܘŸ,j…y8J0u8+cf-h®ËËï 8%X6K€ŸiûðS‚ý5¤ ÑRP5hS6RP®þÌ{*)¨¶ ’‚r{~faŠ<ðdŠý×'ÙETzIA™Y`<€+x¿:RRPj¨]>)èûÇϤ µž’P¬cÌŸÐdNl=°® ]?,Âõ¹¨^„e+^=d“×<{üüÊÜ×鯽ù¦â÷½+í¤;<Þ¨,¨Æ‰cª0¡n¦7–ã²kÇ¢pü;í|RÐ Ëü«¤ \(J ÊEOùú8‡¹’‚jPï¯! ¾? RÐ×K NÁ§Ð*›)/VS…*üƒ\oB:-x·íĺZp^i4@ NK€ÂíÑ‚7ÿ ÉžNDFOG¨ˆ^Š<À$_J NRÖ¬ÁÀÓ»±þê±øJËx<¶êχP]]¯Lš‚Ï—¼Š°¹ßX7?ì܉¾þ×׌ôðÈ=,-ø„¹øì¥˜þÁzLÿ§ÛJAViÁC¡„íA10Pêõ¬HZ pÎyf ÛâœîëZp.X²ð NFÚÚÉ¢J%¡}-øAn bÖÅÝ‚‚óæõ5¡P9\cmð¡AJJºÍ)¶1Èà`‰Wá7!¨Èqºl+Ѓ‹ŒIÑ¿1H2Є¦?]¿1ˆÛËÆ ݸîÇÀñUX¿~&Œƒµšóùû2±[í;Ž=×6,Âä#š­gsÃãñÍæ½æžn r0…ÿì†cñ¡·÷ãƒWíDûŠÙ¨9ã³^cR37(Ql R`©é©ˆÿ'¦Ÿò  £s5Q°6á⪼‚ׯ ûk Fð€‚2[ƒÉò·ÍÝÌo ¦­Á¸ú·¶Ž¼5˜¢š‚9|k0¦Ãaÿ"v;«l‹ï¤·ÓZZ}Ö`üœÄÍè_õVßX…¢Êl\[§:'aâŽ=¨ìJàÆÚ­|/c€÷ñ-G_ŽËÇ®ÀÎõZƒç¥{ðÙ½Gâ•åO:iy“Ž9õ“ðÓïôàÄË(ôl vL 5X•×,üºZƒù‚}[ƒ^ ´9¨… :~ÇSŽ‘6•…Ñ_ý3›ƒÀ(*Úœ‚Jó_¢©£9h5Á¤9(ƒ€½Yšƒš ²ÍA<Ôæ ´ºáÆ_AÓOŸEÉô^”ŸnJ['6ýÌø„“¶aó]cðÉUp*'â¹e÷ÿÍSƒÅÅ…˜>ábœQ¾ ÿqÉZTÌïM5}áÎj\öü¬ßòêa¨òA“+ÆáwŸŽaö•µÈ+>¶9¨3ÓÌ£±©æ tØì@›ƒfë ðwmlΕ'K +>Ír ;MûC'{{p…SxyàÊŸYC íÁëë”Ù<D ¶çïYšœ­=8K&yŽ¹ÛƒSüÃê."cBEæ1go¾ÉØr$û6!L8Y’]mÞ‚ö»òá¾ââ…Çfá¦âS±>q6nÜò7™„ôùdŸ}.fŸ¸ ~yè-WôÖÆ[+ñ±ß½/ìzìp{ðƒ<&WÎÀ¹q”5NÇNÞ §¢“Þw"¢ÕçxíÁkìôÑ%õž¯ 9ʲX'E6-õ1á'ŸÕ}ÊÚ“«ûÏ s}~@ €@ æçµÔ—BÏœ>tÏQ’^Û·`(Wö`¸8‚‡…VÜ/{”>€nªw CWòšš¤=‡½{CiÛ(c‘¬üüÜñŽ%˜Aº–£€ß x”Ço5û ýÌŠÂ!.a¡MY‘ºëá·™¡.w±‰ÖW\ÖøC¾þÒ…¸iùƒitáÕÕ$}`sÈ× ä¤×8]Í(ãÎÆ|<[r6>vÝí(™S"À'ž?yÌ+±´}a®Ý9 ·=p˜Üä U5ãðóS*¨Â‰ßBÕ¼Ï%<Ϧc±/(ÁqáÚºÚ Lž ÿHÌ ½™G.¿?Sð³}Ç4û³A‚S €P` Gm­ß¢˜«0ÿf >GæŠ?\16,ˆA5Ç)ð‰Ðº):2%/¤ ÀíäwÄ 0¨¢7LŠt#0$ƒþV?§r~‚>óƒŒzl)B"ðGÜA¨ÓóýIãä¹R;àZˆñ^£v!Þ³«¿3€‚¾<¼ä<ÜÛ„§V¤ ݤ GaNù‡°²ãWèèmF[[kêä$˜ˆÙ(ÿ¹G}îx]hÀÒéI\ûù'P8-‚âqű#£M…Ò;!¹kîvpÉWò°¥½½f¹y£@•ß crå,œ\B^õx|íêeö9íùS9¦}ñäU¾ÝÌ›šfîŸVªr|T`0(d2ÿ•ÈCë”ku—¢P¨h43À‘Ú×/™t)”švðá»n*gÙŠ††[ù3Íxëëãhi‰Ø Ÿ^¬‡×µB© €¦««ã¶^€«°:Q2ÒˆA”h¹2ÅWEE¿5ýûújìÃá±IÈàc¾—]2®=…ŸÙKø6,šü{=þN7p]I ¢ó5<ûÅãqÿŽ3qÏö[°}ǶÔ=:zÒ±øå@^ίƢ¼ùøý®_`þ´w¡eÏ”Ôbá¢ÅÑ?á ¶ça÷Þ58¡þãxºùF39ÚðùYçà[G=†[_úŽ~ÿ«8öË-p 'ئ iw&¸†nk¥$»¶ã·_…Çî= KïbÕ¶E‡ZnÞ4c|å(<ý¥vžÞ€šã& W¢gÉùi„¢ÇØ@ X!»¨qžIE¬2•V×rQ£[ °] h»û,¼*‡>=˜?¯ÅB?p¦LX¬í‰…öË hšôÍßÏ&ìÙZˆ)t˜Nä ˜/|6¢ôãcT\ýµ¼88R…üÎIs3´ãpQQÂúe¼‰ôÉx£ièö_ˆ@ÁxÕ…B8 ã®‘½HcüœÔàŒq°ñÇÚñÔ×NÅ÷KJñÌÂû1f4™dóðÑÊð¹óþˆÂ¢Aüægaa¤ÍkÃöÍcñÕ’¬ÛºØžû‰ÎÀ¿…ß„· [jðÜÄ1xkI+®øÆ#XpëYÈOà¤õ³Ñã¤g,#î½:<+`3_h¦/Õàs{ŽÃsM˜I?Ô²ó¦õ¥£ðɳêðÕ_9ˆ–Í7ŸL0ó£ÎË4ÚT`"‘oæXÄ+ NX ç-ç#ç.ç³Smm~ÊPeŽ 1ñj)0ûF… Át.Š\@I"0ãÜÈ¿ý„RA@îX}ô ¬=(ìú7—ϯmÃ5â`–óBù=…Ÿ‚Hü/–fRP å"Ó‘„,"Ò '~Ì,d*¥(£&¥`—•Åͱò<œ€kÓƒz½R?@ cÈüNòþb…äyLETTÍCæS¦ùêð: “øt§¹‰›ß¾áØsC®¼­Æg[«Fã‚ê8ý;/¡¯©¯Ý?S/XØúî¿éÜV<ˆ%›– afÀYSNÁÍïx …s~ÍÅk·7âוgâí§­À¼+Íi”a¨#Šüº±–¢ÚµiU*3åDà'͈÷­ÅÏ?=÷¬ìÆK«—ç¤6;<t88¶~6NœQƒoÜjüþñ¤¡Êp3«!ä ´‹Í6TLÆûvÝÙï_Ž+¦bÆ—7"žñÕ“f%è@¤¬ñ­=H,6ÿn4~Ör6×ìÆ—Üí8áKQ8}ëo˜‚ LÄÜ/®ÅèóË*˜æÑPz¯<y¦cÀc:ÚÞÖuxüû.®_PŠî.3󬨸¤™,‡¡ÁÍ…ÂxÇäq¸ów"ÿ¸yå`>e· ñ°ƒœj V0Í{ÎuaëñAk\p(¸Ê¨(Z~§}f/q¦´¹ cuLcïÙµs…Ö­ÅÑp¨ëÀBÏ Âpþç²eû̯ðK>à¸Ê‹Ù-;g<Ûpï|®üqlßžgoˆò—ÙSsÓ÷­0ašý4á‰rêvÁmÕ”Wt!³ª]y<hv€ûfSR ûÀ@4U¶Lå‘4Ûv[°{qëÿså߈ÄÞWÍ]o1ºÍ·”áÎ'Ìj}Ôbtí¬B»[Žsn| {WA´4„²ÙYÆã3t›aH×ìÅËÿ9¿Þ{.*ò{ñ¾ù pä·Íqóбù·ItÜFã‡ÛQw>™iÇBVB“`².IDHN¨\žWÌž_²~ú¹Ì]Њçz“¸¶o7:»Úµ ý¿%Ñ üvZ¦|ªEÓ«QsÄ5ç•%à°*°Ì¼Šm¹zgg^*@¡óéÀ\O˜EhIË¡Y+šü¨–÷*[œ·Ò3@¶áœçüVE¢°cnK%DëZc Ü]‡`]U™«êþ”€6¡ ®¼<1ùeæíÇÕ<uânœþ½0½G Z²™+“Ìói4sºÒr_ ÏŸ2SŠy˘%Áº*k\cb´„ú[»¥8N”†ÒQ(üãà++73 FÒJDÚ»)¿}Çpü™ h ø Ar"\½'NŒ™ ÄæÍ%Vð9TË…Z«JåAÿGSƒÛh”Ÿ7ƒŠ&x>l–·\9Òü}»)-*Z¥Bs¼€¡P’‰"KZ³ß6/µ¦?ƒ~›/þ"Úo{ 3(<~2Üx)’}f厖"TT‹¡ë0¸Æ(ƒ³Î3»#dm‚^‹HÆV`íÕ{PÖ׊،"4œbüÂ1få7¯ýÉb«,Üd/Ü¡˜ù)#þ…²—ðä±×œ[>„á¨Wàe(Œ{â®F÷Úxá¿«qã¢:<ºîys­‡kÌ;W\Œ·œ·{:Æ£ñ´É(9âÃf"Εr"!<œ·„sPøhòû;ŸDWä}ƒyŠP… ©sÎk.ŒJ&’‰œåv\<¹pjÛ>è˜AWZeÁ(áäØŸàï*LƒA† šâÔ4d5w‚øæàP3ž'OsE2é–BÐJàþUéðÿµµƒ¶ SK‹ ý4Ũ7‡L(1¯WÒ4NZàPiͨx¢Ñ~¯„˜¾¿1õãÏ Ùm^½°ö3þÝX3ãÙŒ„¹x¡-gÔŸ¢Äî×Ï7ïi¶Ç!+5-€f¸±eXóõ­êŸk>tŒ…‘ Ï!áÉùÞo¢ò×)5û4ŠÀ)‡›ªY °¬E6=é)ׂ•ö ÷bÜvi9M–âÕÕ/¢©™Ù 6£(0Š·ïPËÏÿ»‡Ò˜ŸÂfÂÍ7; ¥f]øõ¥¨zëGÌ"pžycà¦Ìrí§¡4aÁ.¾™õÃ1é"M@…šüš>ÏDù©å@eá‹%…^e%Å xÝuD­Œ\dþýq 0ŠBL¿ŸÈ>j.–ó¤2 ƒÇ¦ ÖÔÈ÷Â)蟛\\&¡“ ‡}ø»ööpªƒŠúþBž¨ “@nƒjµ—cûA()Á¿¡'ì|½/®@¸4†¢ÓN±¥ ®¥‰¦à ³3¤¾ Ø ¦k«IJ"H‰îçÑrëKèYBãGP4ç\³Ÿáwä/¡Ç.K“)ÜõfŒI°´™ÂÛiþÏmÃ^Š’ÂO—……Küþ5l~h1ÞÅoZ’õ‡î§1؇3 —7?u¸HèÇÌ g`óÎ…Œõš9ÂISOÁQ£Çâ_Ã/c[Á8qn jæT¡ì¤k@ÂС¡RcíF¬ðså×®A™U¹ ‚‚…A™N×sU-‰l @•…þUÀU=­œ5ßÿ÷ç&Í•òËNæi¾óà‚ë×–HZ ‘Þ%8´a6IÔlBö´£_S TbB›LA¦òºQ¥ ûP1•Ÿ7GÒkŽ— ðpÿôÿ± ‰æ{зj“ñ÷Ï>Ö|Vi¶1+½e®öî<±e–W@²E’Up;l;3$V"¶ãQ´ÝBý'.@¨`®Ù†ýçú½}ðÉS°ÉqXe€ ýð#íû)Rè{ lÑ‹ÒüÄf.bïY‰%?íÇ÷MÄçÇ/@(ÇGNÅs­+,œõðÙ ÀºnjÎ}0Qþ¡|g\Î0«~Ô<ƒo9 'ÿ"‘bãò…NÓ‚ƒƒe´FEK. ÎI©éG Iž«8(¨8‚©¼áhÃC•† E&´²vÄ 3â®Û«ÙNçÅqå×^h¼í¨(˜AàO¶Ú‚``úçû* 1Ö ùSQ\ééoù)Ù¯üvß:QZý^µÐÞ$Á ™m¹‚·X”‹M\wVÿºG}eB%g™“£ß®} é§@RiTxï;¼B#®ê´ˆ)ØŽþ—~è‘Çk‚4d Þ>"òrhþ‡<“¾ÊûÜ‘ÎIö¦yµ ¤IgŸE–iðözßíÄÞ Ë°ð®0Nž¿á¾A\ùÝ1XÓ:Ï4?z¸Rp„£¤¨ ß?¶—~¶ {›‹ñÈïOƤ3ºpö´b`S7~wÅd¼ûÊ6”÷„"§ éÖÙÒsºk®›°ÐshÉþC… +·à´RP_š×——3¬K0åW.EüŽò@ËwD @W{ A94oÔ¼–´š|G!äê«A6 ^0*I3]¸Ë¬ÀHÜ %ýà à1ù—1¥ £ëÁh0x˜Éص~­jlý«ÂJÌ;Œ~ô*$ÃÐ+ ‘ÿ–Kp<„q˜qªS®Ê¥Ùš±ˆ>o•nñ>3kVvwˆ‰FÛγâ6T{ŽaÈ4ñûmÖ1Ç)ƒDù[dÿ¤¢v…ÈDš¦0H)d'®Ûc·sl±’±’ëÍf€­»Ñuc÷Þ6?7/¯ºuŸÖg‡Gú`îÿÜQ'à½4áÃ?ìB¼¯ -k&bôü„ò«mµhÿ¦5Ø{O'ê>òäÕ_jæuƒz‚y(dÌ|IþÝG­r±RâNn£r˜‡ ÿÒ „†õp Gú1œ•R¹ |2-iäá›1j†k‹0ž¼F(ƒÙþŽ €¼åÁ•98öGMäàÊÏ>ê<Ž*$^à“–)È‚–]‹‘ Ö_ã¹+†Ax`!ÄÑh·þ°a)ºÿ€¡×–!R×§pœ²6ç×à™ã£<PâU R½ ©X^Ë2xOÙ60É÷R{ܾÜìK·§ÿ?ä)’/Èç5=±JÄk~j…Â_ä¹]ž2ô8èl4Ÿ/Ç–{;qÅŽÀâ­[°³µñÄa7`£ ¿g×MÀu_hÇäËGÁ‰°5ûÒº+°=(’ñUèx| *Ïýºy,G›¹]k#ÿ”ñÿ‘†ØÓ9-Ä7>Ë5ƒvâ¾J+oÊ‘ÆË²Õüï¯x–AJ\w]v P®X#æ2 4Mè={„ËB¬éçàï(´T,`Ð ¦à‰ð«k¦€ˆ::ÂûÐ’é]ŽÕä§`+¸¢¶6n[‚HôQŒÂ7èÚþ…Ѩ±Bä8gðFá/„Sr‚ÙÙdØnÅÎÓ4V0Á{éļd’À"*šNÒ›P‚„aH£šùÜ…ºT¾gÏal á*`Ê!&f>­ ‡ V½F(6öóµîÃ63A—£iÁFt>6„¯þå]xdåÏÍdŒ§îùáx`öX‹¬¼´ïÿV\ý³Ý(ŸðVØŽ@Œ×X¥lÌú¡¸1b>ø]½¹·y––$ç¦ö ðWtMÿ¥ñ8gip®js‘\íÂ8†#‰ð§2 T¹„>WðMˆ7ÉäÃU=mÛ¤ªOØ|Üð&hhÐAK3ÇpÁF¿ Hƒ~’˧™¯$Šäì1?åAw±²ñ\¥‘ƒœ‹Æ”rL†K?S|àfsð‰æuŒœ[(7Ô®b¦ájàwâ*]mPžGàM)‡¤ïÚíý1ÚÄ»O½¥UæmÇϤèÈm  ×»2*™!ó=Wx*‹BOyôy%Ë<¶Ä-ËÑ»þ9ÜýG vm+®)Œá¥5/§Ê•'Oš‹Ö¶]æ>î>Ôòö†G×ÎÂÅcâØ™œH}_½>†ªé'›'3Úë \oî»Äjøœ]·ÜÜ×RÛÀFæ”ët„ð†.ª ¶ú2<9Èþ88†«ÿÎ*H)šÇþé,¿¾º)ZpåÂ{³­*Šb–9†«.Ôÿ+0H‹(ÈJ™¬Ûdí›1ánhHXëDHEÒËŠ™Ià_joEVQѵCxù°)´ ï/]ƒZ³ŸsŒK4"EGÒœMJx,–s¥w]v;b°Q9«½}R`ùÔ4HA.Bëbx`ïñz.F;|.0þ–Ê@ÚžIZpÚžÆÓ_Ü‹—×LÆ’Ò1ذûA£(»ÐÛ7€xl„gbƒ9Þ mϘk8Ì £´¸•5øów›W‚í 'á˜ÏͳÝÇ(—JŸ1Æ~ø<Êt«l;;¡ÎsÝܔϯmÃ3@&'`¶•?[ Ûÿ9rQ‚ÿŸrˆ 9WJò ÜÐÄÓ‡W!&e˜Btí órŒÁBƒÌŒ3d~–mõÏôû©˜hö³·`kkØ##õQR™x‚ ÒR·A+¥=™Á¦…A¥"M»òóx~Ùz,IZˆp2™oË[üAVâ‚‚A[SÀó).î·ÂÞ×—oÏ£¨¨ß**" óòXcP`÷ˤHD`Çñxž×/Îô!™.@¡wÇ^*p|æx,Æ®vAâ{a°‰ÉôoºïhÅýOœŠuµ.F¿\Œs Äÿ–‰ˆqo¾_÷$__„[OÅ‹[þp˜<ÄŒüh>.hœ·ÎHâ#7³â¸ññÆÿŸ+€-K¿LåOkŽYžJs¯ùL múTàê÷kª/“”VrœÍ”h$ Ûû´jÀ`ý=ýu┕ëŸTW';§°ûœ|Â!Hed6ɵÊgþÍU](Ÿž¯§@¡‰¥ *Sø92IH´ii­«?‡n#çà¤(Ȫª¶agg¾3Ž™c‹2ˆÅ¶­9Y`I!ŸIcº ljÊÏóMÒÓ¨=›Ÿæåµ›ßUZÅÁAåA¶"úŽÒ ²¡UÀš–z×EËBºÙ؃µh™ x“1m{–Œ­Æö»A8¾ñ°ƒå¿ÚÇáSG?ˆèqƒ(7„Ò‚>üáê)¸jU%Vl~Ù܃<3‰ÿq«CÆ•:¯d¾ÿ®VùåN83' Í1ÆüL ¨xšeÐ’JAôí{Œ`ºOY”W}zk ×DjÓR¦é¨Ò¨ª²= ¥õl¹1@W—OQÎíÊËcVA°Gï?Ó £4qì5÷µÈÖ‡Ëý´dÄK~–ÌÇí¶°$y×æÚŽ2ÒîŒ+½¸"âš»±àöB®Šb»Y½˜JlÅ`óÜwy#Žœº³¾µN¡1[»ÛñÍN­Ëwavt6:ÃåxiËÿ!y£Ñ0Ž9ò8~à œrÂvÌ{w*Î*FÙäY áÀŠN*ïþó%¬L±X…_œ“RC’°ÏÏœs€V%º©œ›Z çsþ§÷¨AlM*Üýu+€\}¸âS)<\ih ðĹÔ!ûA7eúQ¤áR|Áÿg³”Ê‹û“z}9ž¡Äìs=ÈdzC’ é¯]‰‚7+³¨([›s­dd–€æq 2AÀk”b ö °f;Ó>ÚÎLÜv%Ê·¼p>G¡21¨3¿)òˆM$Ik€$RãÀmzÌù–›ÏÃÞï Q¦ $ !;ѸêHʰÛâ D)D=b‹W…؆Dl=6ß»‘²AŒ?Ëø¯‰¶`ç‹­xè–œ…͸ê¹"¬MÃÒ]/bpèË{±±ò²JQ7çO‹/Üð‚ѵóPØ@ÌÇts?™¬²hL–þÒÕ£@ëédYå¥D— ßÓêLəÅ6ͧ=µßkFJ¨` …Ÿs2©½6¸u-reö—"LµO·d¥"&ŸÅ3MM!qçAƒfJæÈfªäú;\Ê/HN²Ò††!¼öZ4%Ä™µÁýûÐe "`6³{Qpåר†i5P8)ìÊ–L‹@êB)UEE"Õ@ˆMÕHXä—Æ(Ôµ¢b))aà„ PòSéP%o ¬Xt H+­}Y£—×g9çd[*Å„Tböóe4§Íô{i@V"vÚkADÂtlKmoD¦·š¯7ÃÙÚþBØqK¾Òþ>,«\ˆ-[—þæ KŠKðî‰Çá¤ñaLÆ W–£hây¶ ˆ-sèû³5xAŠD[y©Ï¯óT!a§"c°P†ÃËDÁkšë[|¶\øhQ+¶…ó™ ]_¢lùÛl™„~çg?s]áÇ“Uû𤔉‡+²Ö-£•ºÃ\c‚ŸY^œ-ׯœÊ# øé´TFÆêOÌA>B®®DöŠBÞh^ŸšêÒZŒåÄy)—„ABQ*@uUíÊþ".…]åK’èòV¡@Oˆ¹_Ôa>/DwOa ªhI®T¼lmÆ !ëÊy|áG°9fº <Ý:Ž€¬j‰L¹r3ˆ¨ÙâHö,„$Ôî1¿fnÎ*ÄW·à¥ïOÄoàÝCpKzÐÜÜô¦VEEÆÄ/Ë3×Ù‘õûQuøVÝ|„ë+pê7`â¥ïB(uµ6…ëÚòìóLJmlˆÏ“+¿Ö¤¨ ‡Š€s˜÷Têö¥›GFkQé"¬ˆZºÀü-çZfðð@8÷Q¿ø…( 5˜¦÷(tŠå§PpòÒ ÈLõåš Ã ¿¾ÏÆ+ qíO B/ç%‚Î>>Npß*Ô¼i‚ÆÊî&ž~vƒVO›™ÕÞƒôé•]HÁRqY™ Âé÷3äùó /@E«aÈì;Ï’–.JÓ_â"ü‚>Œ™ë,LY’ÂLظBÈ4{)ŸW!ÈÕ_…_[œuØÚA ÒJèóþ ¼Ù5ÂßüüVÄŸëÆž8/~È(¯¼ÙG4/Šù%ÁòÁûÑÓ—½‰ËäQ3ñû³b˜rqòçMF´æ8¡Ùæ›1€…pW˜çC ÷¨COZwP­Gͨ•Gì ùý$eíz9x‚Å}”á®\¼tQâï´ _0•˜­UX¶¬A®¸€sûíIWÈ:}BÕ<ê3«U L¤Ù:G0Ý7œïŸ íÇ ¦éOذ æü@c¶ £ 5Íh Ê©Ÿ­¨ˆ¿©¯O¦,!Fiõáƒ†ÚØ”VŽúaZ=Ș‰`#>ÈH|{ó*J¢£3ìÝ×c)ö)Ói}ˆ«¶H9oŸpÕï’D €~>£ÿà‹Ê€& Wû.9 ùc7d\dÝ í@Ó‚%øó X¿y÷¶oÃúËö¹·‘HGq$–/_iÏùÿû¨ª¨Ã)E¥ø’y¸ïìiG[Ov àÌYᇓWcʵí(˜z‚¹osÍÕ“t‚Ç\ož}±uÔÒÔЉÆ”ø†.€oUûó— ‰Ê›òQÔÕ Š„1#Z‚»v…R CŠ"Ì• ÎÎa-:Ê zôѤ-§Ð/¡Ð‰¯¬¤ª-Iõ¥›àÙÆ˜þ™Â/ùwŸHAQƒZΫÍC³3D´¿cWÞ 4…Xµj•Èó# Yàž>_!…¼¶VÚ™«RP«D»‹% ¢œ4åŸ[žs¤÷>ô‘TİĘéDå6¸À€‡4”béjd–"§ÝËôyß4´}ÛžÁþ8¬jjÄÒ¶Û°aó¦¬Ïô¸Ñ_FGÿãØÖ¿æÿ-Ó0‰<&ÔÌ‚ã¶á±÷w ÈÜß‹Ÿ?ϬZdîá¾A­’âR¼ëÈw㟎hÅÙ?~ NÁ8ô¯#Z"5YD¢Òšÿ ø Ÿrºú_f‚‚+ÏÖE°D]ŠÓD‘Ð:˜0a¯q¿Ëíþ){tÅ5'Ö­ëeÌ‚–®,–ÜŸÖÞäT[·ö»›6åc÷n9©`:/(ä:ùr{ «ÿph¿  Ju^:¨È®Ç8¼/ä7óX™ ø>òù%È'lÅHšÓš*ÈT?ÏUä#?Ò;oÚQ'bhÏþø_ó±ymÖ¶µàñ–¥¸°á,L-ìGi<†ùõ81´ÕàU oLf}¹y£Þiö|¬y³ -B¾Y28˜g37‚9qR‚Ì—öµÈü Î%¡˨LZºês~iPPŠÛDPnø¬ø[®þZM˜+M(ÏÖXwÞ™t©e¨-è›dúvZ„ð¯1ýsQˆ1]Ç‹â9ðF;¥ìï8û{?¨xÍÊÿÇϤ5¹-ÚzøÂäÓ‹~å]ÿ7Ùk”¦œûòs·¾àC¤BBÓ`Ûs=&ƒGz¯Š‹¶#éÖšgU虀Ž×ч‹µæzÈAZÝR9hÿO”àJôo|‘òmˆ¶ÂiîÀ/¿þ^üïkXøÊŸÍ¤+1÷¥!‡ «—N~/Þ}ÎS8õ#[°ýÅr¼ÿêZ4Â)-{poÞ[±¼÷sÞ‡ZÖóCLcÆL¦Õž„ŸÕożK›ñÄŽÉ**Ç{þ3a®»Þv{J4ahýkxô{óðôæ#ñïþ€Ú¶cùGÃ-`öñKÐùD9^|å Ì>g ?Tˆè˜ÓáäŸaŽ4ÇÜï:ø“…@ÒÇœ;\ à¥+ÐÚJ²1e[è´>…rÁ@xM˜sKÝv.š‚çd1KïG˜–ÿ÷öïüêWI—C°ýÎ>‘ÅL!fޤÝçöÏdý Îu*‚ñ¨\8o2¹4ù½Z©êÖRž½-ß3žÆãq¡UKBKwÖ"/ mrYAN@s1úPáð˜YعÓI5þizq¸tb¶Ï´`¬#ÔfÂͦØ~m;>üꯀŒ}ë4Rϯ)úïååôÃ)«Y–àƒävÁà¡®þü\\ˆ¸5)™V¥@e¡¸9žA;yPá<—@· ·áów©9‰§1ôç5XðíSq_Å;ñžõwáÔKžGècL‹¢ei#ö¬¨ÄôQΞ„BTÂôáò_µbýíÅxâµé¸»û~?ö\Ì(]‚«NÞŒ§îšŒv÷™óëÁ%§ãÅä ö¡°×7±MÙë©7ØJ%Ƨ4ûšT? 3 þ§ö(+®ÀÝ3ÌÿL3ž|r2~¾b z»Ñ4¸_ 7"4·^3ˆò ìéGí¯HÔdŸdlYVíÐ%$׉&¸Ï å·»è«Ã˜O¿Û(†#mp‚’Éqfîæ›ù €ê6jí?ƒ‚Šñ×øQkC¸ðÝî}Ó¯Íç|<'KºÏŸ£´d•ï¸XiÌ@‡ê~è|sn¸!éJîQ&65MÐð“+(·¯/ìr* '/Œ03µ¸¿ÃpÖE6e   ºÚ_¹¥E¹äi¥knåT\ÚªŒìGB~’¾¯“&‰¹¾¤,¥o_W» ¶ŒY3éPæô⤠ÅÁûDág-›(—gp{ÁHp²°°ÏÑMP4fãÜÔ"ך‹^„æcÓ]cQVÙŠµKÇ «¬óG­ÄÌ[è܉æã͉še"TK$¤† `¶>¿Ë~êà7{€¹ˆ3·ïÀeßy…³‡pÍWÁ›‡06Ú€¯^ŠÏ­­À´x%v;»1Ú©EkOZºÊ°»ôhwæ{ìvso÷¹ï\ðlX;îÎu¨*hA"G(R‡ÙÆ_Õ׊ÚÊ*üÏôeøÒêóМׄwMŒâß~öªätÞŸÄâÌÂÏëNƨȾú™Ç1ê¼S.˜c®¥Ò»L…H’˜~¡sOz}Û­²ìyîAÜ~u罿“þå2£æ™o *7ó¦ÈÈK¡µÄÔP,€úûAH°Ì™4š- ÂÛ³YÁÅ9Ó=Î\|¸¨i÷?…/ˆZ¾~ ¿uX ¥®¿>éJï>ÅgWÃkæ}ÿaŒd ÀFÒk\!¥ÔXrô§sþöç÷MûL @f°Q„¥mR(¥UsY<Á•X)Ђ­Ê2-%ÑÁûÊ€!¢º´ô˜¾È~ÎâÛóÁ&,`ˆWè¦÷µL¸MAA¿y~Å)ŸN¶: …H°‹ÍÚz z_]ŒÍ +1íƒ DËÛ±úæzLsßúÒ}è¼É`á÷’b"P®Æ|@»w‡RéÝ–1Wï¶9#V 3‚TxÁô•*•©6)¥¯O-ÍØƒFûƒÇRÌ€r:Ì ‡Of’Ž à6ª”‚ H‚‚4{!x h›‡$K±ëMzNø°]©“Càö·š‰.ŠÛ„„ûŽÂ±´çÜ®Ò­Ë ‘c–†Cîƒ÷^æ“ã¹lÂùÐÓ“g][mÎù¥mÂ÷§FJù­c©úà\æbÉÿÓµsøšk\—« ¿ð ÌôÏ&¨jnpåÔ>}œœAø¬žðþö—KÁ¨À)/ø¹¦FD™2e¯yùؾ½Ø* âg>ÏA£«T6T`Zœ´ïÍMOÿI½€À…ƒmÊx¯å!;ÇÑ8ƒkƒ¥\ùI2ÑÖ ”•úûf䤽Mªbà~²Ì  뢖nL˜†ú%xÈ•™¾¯Ún™ü+Ðá‡ß1:κ÷~O¸ž©l.ÈëaàzmÉħ–JC‰®n¼[öçnÂâ€GïkÄÍk^ÂÎÝ;^N ¡n4Þ6í£øäûÿŒc?m.04ݲôŠps‹Àvaâu0òŇ¥¬Í²âÛk³¼~1Q^‡%awÖó.÷ö!åÓöšQ÷ÏçÖݵÁrή¨tïTASø<®×L_«i3Á@A7`¸F AáÏ´œs)`*›sCéû4Nà|ï{B öIÎ?óý¾+´øøÁŠ<Ý.Ûª?Rá.ÍT EK‘LTÒhŽ§Òƒ3ÙpÙzãôAf[ùƒ«¿* ~&Y'ÐË=7W¢_È£VT„±Ê,ØâL-V‰¦||á÷Kœeå/+mCž«$…Ÿ«ª°‰ ¿DWeËdóF‚@ÔÀMw `]Ý vî,Hü²UPæÊV0š«1^‡p ¤ûÿR¢÷Å •€$iùé˜T7BÝ‹ÒÒ>s>ù6õEfc]Ý»bkç!žœö8ìôfÀnÒŸ“E¥KÝòã{P`Ë>D—ƒûj2‹ð«Hö,ÇÎ?Fð“›fâ÷{6aÛŽ-,üz“ÇMÇçæNÁ‰3öbö×):Ò­G¹ú’VX¾>«x%õöš¤y »Þ«¢dùuŸeôå|`Öd` ÏKŸ ™«t‹J˜ç¶J]ø!˜–¡VÓ^¬\?`ÇÁ¹ ±(>KZ\hÕ*T >K‰/¥órdkz .APfÔOͧ«¯vÝáLðá8ÁÎ’ým›Kè3ýìÌÿgúd ƒüŒ‚ȇ§Ô\|Á @.†£l×£ÇÍr¢ÛCmËIÀ‡ÍµÊ¦@„Db Tr[ZìpÒ~—©ð4í'ÔQ®…ww‡íDrRe¢[³V cvåËÏgºÈÁR뎫ŸøÃ´bbþÛÕ2©4dÞV”¬å0è ³(ÜŽmw=‹æû“x±k4Ú;„—V>fû¼žQ_;Ÿu&ê™yôVwM!òkO3ߌ†øõÕX‰Ç¯÷Ò{=–¹×!y <̼\3-B^WAA·Š¯/¤`øež šçPà!ùÄuS0—Üç¤í/ÁçC¡ vûÕç¬P`Ñ¥â…ÁÿœïµÃÕHÛ€e ÿþ¬;i‹ÜUWí»ùpfùH•ÀHþ ¿?|©)NSZ©Ä8¤PC…ßI¤3¬È&üAË#]éxTaÕHUWêà ’fî3³÷ö<ðÏgÿ¯iNfŠŠb––š—ßiO:®Fƒ½Fe¨.cÅÅqköÆbEže@ÿ™7%ßš÷Ž®êŽv+æMõÛÙ®DÂ2äÚ@Ç« Ü¡…Xru3ì$ß¶ß)šŠ§VÜybï cŽÄ'Và´w¯DsádŒ?¯ãÏöxú iO@‹$î¹/T¤´F*­é?8(`6oéé)ð|õ¸½ÏJêÉÁ{Y^ÖžÞ2ÛâK2Inªñ‡l#¼TÒŸr_ž¾àó¦bÖÞ“tá$@è¤R…Á‚ûk :\\ ×<Î6œï|'}Óý ÿë1Ý÷'ø#ýPè³ÅÒ >ÑÔ䤥ù4]B!UœtPëf½INöWÐÚР'³>©…Òƒ~z 4RdŽ`Ð082•N°XHpRuÈã I¥RÊ1*NT®rêJȱ¬»Àæ&Üž„#lsMŠFät*⃠B¾†è’(<36.@ë Ùìs#¶ÿn œÖ6”nhÃç_¼ ÷®»Ù_/tÌœr>R>ÿÖs(;w‚9<ûñÍôÚ«³¸‡V€QMþ¨\âK€P‰D]å¹ò’P•ðlþ_„sß5º/¸ þopÈñ:ýȳ¤bÐ PˆÑŠàg:—r)Î9¶rFŽÙT"Ë}ÕüÏÅ0ê/ý,øwÃùö·³ÇF"ì¹z$‚žKÈ3.ø~¸bm½L?‘ €7•CᾺ/a”ɘ’õ&å~5»µ3²0'ù¬J™Š%WêÐ%mš’ +WF"¸ê«ÛÀÕD,{‹rô1è~p°²RÒŠ:4HZZ’@~A™üev¢Kð*f•^c$²×&fhp¥§©Ý±P’ž¡Â¸AŸ]o1g³Õü)ÜŽ—°ðsÓpí+x²é)#l–$) Û™Ÿ<ç|v|)οn Ц°&–¹7¤éb—æ2ï\‰­µõì¼$nKÒ¦1 àaÍ~,æzèSMñ%<|>I«_ÅNYqDïù þCâóSß>ý àêóàÕÖz‚ãpö©ÈÍ–)óïH•@šøkB?œ`gûM.“;Ûê/Õ‡<2ð§ L¤kz&B57_4¿†S#IARˆ¸/r òá57‡ÒAæÎËú8~☡È,H n¯ÇÓ<¿8„î’’A´´¦ ÊÁëe ”¿æÇSIÁ‡u!éæ{D¤~u¡¬þ´z!\…© ÷¦º ‹À)1ioK €ÓôÞ 7¹›oÚ‰'<®Úô4¶íÜjöÉÕvd±€|sƒ/<ör´t.ÃüÈlŒ­mÃ'¯¹±øäUÌDþä÷Àòô1øç2²ü‡®[m„²ÐÞOÖRÐìg;¶þþ¼âU ÝTÖˆ>¾ÆkÄ%êw~ž 㯂'd´òФëO¶À¾ ÒÖZyï÷Ù – g"¶p¾õ­ìÀÁ^ý³ üHÒ}zòaýƒÂ¨ÝŒêêÄäniqÒ ˜Á!l¬’¡ ÖΤ˼ÆÌ Ÿ °ºŒ;bÉ}q"I÷óŸ¹Į̈?W®þûR¡·÷éËîx«³üžPTñe´˜ƒ´U£q¡ƒg-Å-ã°ß-Ù ÜSÁõ†Ûèç‘HTá ‹0èåÞ ¡Ýaþ¿Êìj³ù»­¿n ·¿[Ìßп³ÊNǃ~Ý{š† ù8bÜ1¸©¸ÍcGã”™/à•§ÇØ™;1X[ŽñïŠ äØ› bãNf,ò­à˳d»¶¨M§òž —b§¹ÅÇOá˜Döé>ÑzR$¬Þ#ÖYP £¯Ïò“iá)þCƒÎ™A½àóTê/í'¡DÒGÁrð²ééÂIf*}#*€LÓ4›üµ‚¾U~U›˜¬Á¦¥Á•Q ÍÚ.ÜÇÜg(í; mÎÒkû3Ï}øà›~Ê6þ9+i®Õ\‹}¨ˆ4*œiþg^£Bšõœp£Guà ±Kù>dªô¤ ËdK'*%·¡Ä D™ˆì×———ÚØ@_Ÿ0¥ŠR°þ5Á?RóΜù„z¼]„?±]Ï<Ž¡ÞVT³ ÍÿWÜ·ÀÚ•^å­}Î}z<¾¶3×cߨžØ“„ÎR’iU 4"!@-’¤¤š„¢P©$“0BEA!(”*Rž©*Âcš–¤ÍC“’ŒR2Ïxü6cg<öµ}ï9gw{íoÿkÿçÿ÷þ÷¹vØÒÕ½÷<öþk­=¿õ±ù£ßÿ~yÍÞ¿Ï?{|ëæÃrߥo“Ï\ø‚\¸xF®]ÇsÆõÜwî\‘=;Ë?¿õŸÈâÜyçüoYý‰§%¿’Ë_ýÜkä[^û ìúÁƒ2w;À9_Reøí)”y¾\6ożÐxcG1•††7Š×Ö Á¿RA³¹r]¬‘EyÂ:©€œ”ï#ªÂpŸvÄöÛr©S{‚×pX »¯„þ aCR;%¨§íȅ cŒ_Ó×ûÞ7­ÜÈ«€Ä¯)–ª*aӘȃ ›¤yþ¬ePAaû„˜ '©-쉥$[æÓ€b,«³«p¯³g3˜Wâ‹Õ&ð} qðÑv!ÿ‡_l¤à*ªÊÓáÇÄ!+ôgf¦¤*Õ~/ÎÕQ ¼´6¿ti[²B·d5æª:‰Q© deÚ/L€Bõžœ«@žý_'d}yA.üŸ]‚†O_Ú#ßýÎËàP±w_Èïþê¿”W®Ëÿ•;äÔ¶Éç/|PŽ=YŽâ;^þjyËÉùÞñWr6; ‡ß|VV¾}EòkòøoæÃ“‹rç[rË7½¡x>Š| d¹òNÙØÜ]ÃËñ´Æ:TUÿÖj8›¦!ÁfÞ… ¼\ÖÖž->¿£¬ë`ö˜†öÊkÕÝðtyî¹ßŒdÞñ>h þ,0V³™©B !º„@_»ÿF ªËl‘Ä"¢ùÜ~{^ª¾8Á^ eùµÅÿ}„"®äuáûºÁ³Ž“Lì7kŒ f21É €6í£ 4ªãÑt`Wcbñ«­ÙÂ|œþx Î/mVÑôM@õÚ†·”0_ýŒ¶:GâL–¡é ¨|N“…òÇdüô§%Ckôã_-¤ñQùÌ‘o•WyP¶½d‡\yôºœÿô’¬Êi}r(ïúÒëå7ÿî¿•½ùp--.ÉÏ~ÿ•w¼ùOd׿¹.ÙÊݒͽ ¬9XÐå#¹öð³²óµ÷ÊpZÀjUÀÚ~ä?l/…uD´s…ЄV$k¯77aÝð„"¢;¶íw¬COÌ“ï3Ììmàþ,á%»bÛ¦¢2mÅDöjУ/b Ð% n„hö䳘~DéEx*ñM©mðç‡v÷Ék~ãùwܱ.§Nm« Í¦aÕBëJ{ž­£m¼?ÄüÍ5ÐùFN'0¨Vz)‘úxÖi‰uÃI"Œ5kÒ¹?jMJBsæVV ×›`$sÃ+Õ°çªÏ]©Â€(³}¦LÊåkrñ*Ï|q"Þ´]æoÃi½^j rùkòÄY“ÿú—¯’ßxä#êcpÇŽ[åÝ/ü!ùé7ÿ,üðÞöÅcVL®™Š£S_”ážWË`þ›yyñ¨tud¢qÊõB.•B€ 3dB¬º0! Ç] ÚÉ ë„õã&‚mÐá£ýZÐ×içï?£041ÙƒÀ6ÐXÌ6!ƯŸóÞ÷V¤×aûo5Ü—*ÚB¡6Þ°Ÿï¼óšU~> âY0/y “„’í—êÔeÔ &nãw©ú!Â1‚`0 6ÿC’[ˆ¥ÒO›§¿mÌ~ÂO`œÝ¿mEûÌÒ|è¶~0:{%:Ç¡ œ6ìI‡#ˆ`pUý:™\Í ·°%Æ ê2©`ÝòwpccGÙ¾—fA^S  ¬Àén;gj!ÀkHÐxZFÿ)yôW¯È3ß"Ë›ÏÉò3Wä·æ^#_;.o,ÆÿÚ·~L¾ôÀËåÅo}N¶ßó}e;.µõޤíJ5ýe–ßÆÆ¼ GšTÃ:7ëǵ¢°ÄzaM°¸ µr¯é¹'°'#ÐTkd‚ ‰ö‹ß§”ûZ:ñÓÅAk¤ešgˆ8AP¿¦ö’¬Ÿñž÷45_Ø{+Œ? ÓÇNB­íW§6Tó°Õ$À"Pô1ÚÆê±¨ÿÄuã Œ CMŠc*¤ÌßÇ4ijpr+úŒÎ_± }ˆ¼¡Uð V¡ßݳ皜;·TÚþö´coCF#Èüü>ž_V·í(ìöñme¡ 2 é]×gµ`¤ëU>Àµº<8+á·*|¦9YȈ¯Èù?*ËÏ{JWåìoî“?9ý£òæïÿu¹å'‹=ÜÜ'ãËk²pàUZÿP_¾S´¡Jý-óýWŠ1懲m¿ÍýWí¼LÛ¥ ­hXêå‡S5#1ßöê8œ‰jM‰óûÄÊ|ÛŸ‘’Ë‹ÍtˆöËžŒø¾†˜hŸ™S@Ÿß¿Wß›ýbˆ)FŽª>Ûœ“¨½~eUŠ ·Ÿw`‹€¡ÖÈÊ=õ"²;²Z‹P•#ŸIèþýW æ_ªóÏCfì½i²0j óÊjõÑíO^÷E´ÝˆB¬BoT®µjÃRÓ€3~˜ñxX…/¦ÀSʤÈ,Í ‚ø‹† OH¾ù5ÉæNÉøô£rô«òÑß'÷þ”Üý[OK¶í›PÜYYñ‡_„ûVEK{—‹çouüeå=××·×B€½ú˜µᇓRÄœ“‘%ÌšÁ=lò]OÐ`5–O`YÕÌp05ŽßƬVá¢ãcÇax& &RÀ¬§?ƒIp¡ï0,‚¿1Z¨Ú F6PfãUêCé'dgu×gFÖUk8Òa(ê÷œÊ6©ÚNó™¶£Q^«ý¶kLh­ï'¢ bN®]ÈÔ¢¶¡V:< {y<ÉÊ#*á4­8«ëÔ1;.~#sê>˜õX ¨ýH®`ÅDÛ”iM¢ÿOžú³ò…ßù6yÅ¿þ”¬¼áù’-¡Ü÷ŽâŠ{Ü®Œ_¦$ÃØ­!¿¥Êñ‡”Þõ2rqåÊRéÃhväQS€µû¸ÒÕ¢ Æî› =mh–U WxæñC:ÃåG¡˜ íÃ¥ ݺk³ÝCÂ#Õ´hðÀ, ‹ñSm.(ãx–M„ñ=¡Pƒ¹Q°»™ôÂØÇ‚Ãó;‹ˆÊôÀÃÔ`¢4 mTlmýûóµPu£uÞáדßA<3=æ´ßÇI‡J_8ÞlŠùýp£F[Fågà5gxJ‰:«“Š //_-Ö…8ÃÒ_0À4¸\›êÀ»¨gÈ8_E s@+õAyä?–½þïdñ•/(ƒÿ•P¨}¥°§Tÿó|±ÿx|KÕ)Iª®H× Á¼PWñÙF~¡Žen- Ê«Œ?g×ûkë´ª¼.êA%a³½œ2>{Cð€€!†@ŸTÞ˜€H.Ąʔ°Lï €!ÐÇh‰Å9ø_O4çIJ*,N°ƒT)¼1D_Úv¶yGÈÁc~û\ßöWhqVö71bÆ2,«ô˜lÄœت8ÕlÏy\~í€?×W³Ëò:dú¬ò@!3üà9Ú7 ÍFœ”`˜‹‹h^²Pµ(S†šŸºUø1mU®XçK˜rÕ  +æðˆ\úó'äïÿl§Œ³Y{ÕYYúæU™¿ãåų^(Rb®V@·•)Ê´÷!ðyBãB’Óúú°˜¶Uwˆ¹3/Op5⩼.\ªë &‡àgµ“¶«`óNr´&FÌnOý»ñCšDÔè1U>E„îÃS•é`.¶ “FÛ+©=ŸX@|WC7ñÄŠ>Ž•6Õß2TpÝl'`R" )?{²à9ìV„ ‚„uÓŠÇàÔ­êÛ—Ñ íðl… qÁ¸¬s(ìûgªî7L’±J…½ÉæFqân *ìq 2‚ta]Dpò#,ó¸ûω– Ÿ”Ñùÿ)ãÓ_’Þ+ÞvI†;‡òäû·ÉâüuYû¹yÙ8³K_ôÏŠ‡¾¬øÞ DÁ@— &Þ]0ùb©1OŸ{‚\ÍËç°Ãì1·–Š«‰åWŠÚ5c#¼Fôêê¤Êp&Â9h½ó0„CÙe t1×çB¿g¾S¬M¤цMé¨!`)ÇAÉŒËfc¥:=ìXº˜ÔzÀ5XÁ>”ù§Ó<»LŒáC~62aN8ˆI;Zèï,kŸE­É¨ØŽFv 41c&NÀž=e\Þsb6U`]C¼á c‡“oX% !ãP1öª} Ÿ®ÀQÙ<þ yà­»ä¥?pLž÷ãßR< XèñE¹þå/È3lÊ羸W¾÷'.ÈÒ+ß"Ù🠪ÿ&ùî²Øv6Ævñâ¼il“×%½·Ý¶QÌ}¾ÆñÇøq:Ób×PÓ…Õ»-“H?¾àšq­@£®¯äèÑ5î$£Qmpàm`fO1#jZy÷»›a@Ÿ‰CÕwÄÞ÷?ï3{ “ù'k¨)µÃF±ýÜRÜÆÅÚšJZ³Iñ ºÊ'Ù±Ù*Czø)¸cÇsÅwn-}ÚÁ}— C® 1k˜®7b^u*¾Vá@í¿R … ÇÏÆãŸ”«_–mßù2wû+‹Ï6~a2ŒO}R»·ËøÒ³29yLæÜ!Ù­ß!Ùò½Å\ÖŠýX.LJr_¨÷0˜¥‡‹…P»w_-ÖçÎÍÕ~W·!ž :³ë—«Ð$}À?ÅÄ.úlSß÷ÐGô ±ß13 YXu7óÇU·m‰R…@ÈáÅÊ>ˆ‹á>fÚÅÂ)>ãw9åBãòpSÕÿæ\YTÄõu&N"à 0e—~Ûž,¤°¡ÉJ•+Ã*¡ÙúèwP(uõz±ŸËe{UÝ~ƒÈ‘0¤¹®ÂÍ/qÚ¸ZÜŒ¿^õT!€eù•ÿ.Ùbal{\†«+²ðÿUñ¹‰”~H2‚-¨@ž²ùPa&<(Ãýo)ú]=¬•'»})-hŸ‡{†/'å<ŸzjXõ¿hBtûÀô0Ês²²ÙhZ+>ÃÚÅš˜F n«äK±íû€.áP €6‚õD`0(YCsy­Ì’á0ëpêÒüêö]w]•³gåøñÁl’”ÐçäOaR2"#81Ô†žîמ",€™ŸÅ@X?v)¦‡ï)¨¤ƒ§``¸)äÜ$íSŒ®„ÔNM½þªí€ið]?± ‚Ùá f&Ò—(:‹‹°ó&œ+krB‚ªö#=xtôrúOÈ'>½M~ìg7dñîoám¯–l€taÄù!нeT ‚<B&çÿP«ÿ¹øûeT¨ÿ㉔h8*àt^,ˆ2ALýê%-Å„€®©Úø~§®…8xÁ:úñG xÀ#ÄžÜ ÜWŒ©C¨- J7žøz2è‰B)ÄÁ±ˆxŸ„‰…`R«åür\&›PEó S|ŽI_ÓÖ˪ŽÙ\ÿP8gVõ¿:Ó“ ó$¤3„6Òo眢þûaOhJD+Æ<ÙÎó¢3T[‚oŸŸÈ©S‹U›©fËé6Q’˜´Bx2ˆuÚüì1úDBÀAØÑŒ€ÑjMÁ¡ßÃÆÆ7ªîBÉ„j Œ‹Ï/@#Rh2þ ùôúœüõGòΧÿÁ×§ÿ!Ñžˆõ³Ó*„Ê|¢ù·Å¿ß%×7öÌ5WÚÜxa»ìÉ®ë’×M]5‹Rêvmtj2W ¥ÆÞßS=œþ {ÛíIë5ô;ZÂëÂܾßÊ7 b?ÿ €Hµ~˜¯aQñž``XBˆi÷¨¥¥ ¨[ejCU†Hí DX‹ˆ{0ßem´ éĘ1Eý÷7”€Ywl Ê|q?ô˜*4d¦Â…ê%^×Mt­¾ñ4ŽC‡ž+“[žxb¥®·'Vˆ@Ü<ôdÂzù^ÿïÅ©²*`´HÈy»møpÚW¡aÂݻǢÀ¢ì5¨[eÕéÁôüçÈø‰_—É•ó…]W1¹%ÉnSñ™C¢ÍE€í¿P}¡¿«åã‰?ªbÏUÑ"…èFj®¶é¶Læ„ ÓµUÃ×¹ü¡&±õµû«ÑÍ>ÅádžƒÏ0i]ƒm.ç'èÎø:küÂÂoA½$ãÒ>t‹Å÷°0lI¬6cÓy¨Í •ðñYen·Aô`µ>Ë´MÚW1æ¾&@84ÉZl•ð , SEýð‘o†„O|>Ã'&{ Ûnʸ7žÍŽ.¡0’ÿ|BL‰·Ïâo0=UXEV€&9á>,0â½lv"ößÑY®óÌ*'œ–l/,Àï?šn•üòÉä™32·ÿ‡‹ÿ_ Ú婾ÛK!€mÚqkYÞ‹ ¿,C.ÄœhåŸÃéWÍqR2€- ³Œ@•èÈ>…ªêbZ…&xfìE!`ê°¶ŠPmó\Ôt¦ f¯Š6­v«NÀ)z¹ï¾¦0D´¾½ÈM%„2U!¼GÕÞ°|9üøÍMRئ¼Ö(¨n?õ”+nÐÓqÓŸvq³Ôþw%ý€¡‰`\Ø <—ªxhQÛ˜?äcyÿ5]W¡ºÐWŒ§^yz sÅ@èÙþ8¬#Ò% ÁÙ¸YžªªédŠ … ’HŠÏƒõYYåÀÔ ÂååQ™—eÏwp¡Ìú›<õû’-L¾ã‡Š× »¿ìC¸RÌkw™¶ Ü>h(8‚6¡ÍU¯æÈr¹ïLúÁxq©ù2*=ýÄãó N+h¸^÷‚þ-d j¦ªÔŒ¶Ðvª&ÐÅì¡÷²w½Kÿôsþý×B„”Êüî´iª 02lÌ••qñÿ†<öض*C7ØOzÑgæ Ãæü§0ˆIlá ƒ ÕrŒ QŸb!Ah?X#h+eÃVÌ'Ö.¥£Q[DÇwüYA˜`Ü'Õtãf¢˜Ïñj†¬N§Õʸ¬nu¾s稘Ôÿ/KþìG$‡z¿ëÅD é:>W|èíÅóößÙVyºù,†¨-¹­á.ªÕL×"ÔdîÄX"M Aë`öµK»Ööp³a¡uW§¶îáÞ½rüøBAÊ×êB¥Â[ÕB¯µ Ÿ‘S¾+ÎO۱Ĥ¿ªg¡¾ø¹²UÓÉ“óu$ŒgUü“ûRšWjÀ÷èq'"Æyúô4cŠs1U°&ž Á{P)ý¬„CätL„L h¸àèS.¯Û¹[†ñó4páôÒL@ý<…¨2bVµ#—yùóóÇ%Ûü½bs Î\þцž°ï.Ë$qÁ€·–ðÛ(/žŸ×öf :‰!,  "ÓB@ja‰ñª“oꋟads Ÿ‡ôÄ!Ƙ¸¦éSb;´Hì±ÖVÄÁDÚ@ŠÐö^P„&°aªlã&ÒÙ·o_.‡Ÿ—'žW€A]’‰…ñl¤,Dhsü¹…„€õ†C(t”uó]>†6æçÿ¾ýoCi D0¸Ö”K£Ì±áô½n:4ÇÀÄÚG1¯š™LW7Úq“ù™š ærDŸy¦Œ:öØ{è)Dam3804!]”¼0&¹¶ÞF».¨ú¸çÒÒ¤ªµwMR Ë¥hÊ£²Osši½RA~±dÛÂf‘&¨E"‡AAR…NVÖø ¯>C…h,DW¬zÅÿ¸÷-Uwr š1¿ƒû?‹=«5|&i«Œ „éê6¿ÒÌi &0K;RZÏ)}l£Ø†t1¬3¤ÂÄs@F›=n÷Ç„@¨Üש†®òæ.¨®„”æ3mh?0“8¦.´Ïäh>ÒŒó*ÃÒyÎýûYç/Öæ½íöyœ3xS±u]'¥ @NúòAèð&táÂb™ã€gcïéh¾!³üXæÙ½{T¶ø‚=íCyU»T×n(v^4¸{öl–(“¬¬jÞ‡æ¦MK&>ŸÅë>“6lÉëŒKKkÜ{î§mÒ'ä·%éüÎpãIAŒ:†ØX>Éfêñž.¦H=ýS€>cªíŸ—ϦWï+êPÚ=»¢}˜„Þh´µE›Ë–Ôyæ~8ôl_3qG!ÂTà0ìjLÂï‚™YUhS¾I ¸Su^j«k=‡ª½Ú//8ñ„H óèqOôJ„ð `Â…±ÃdÁó!ˆ ˜Ècíh æø-Ú¹NœÖ¯clƪÜëÒ8}zÀÚAÃ`ó­îÌêd3<cı'ØWà…q¸X¡Øù'j @‰ÔW´1SÅuM=nçTS‡u±AZ×­H+xš¥°Å]K•Ä]ªº?~2¤ŒfQ[æyý­í¯(½J¬HÛõa©š¥kéth^¾ƒÑvÂÚƒð<‹%z&™„6³‚Š4ýJÁs@ÈkkëÅÞ.W„úîgâ|ó† …Ó÷„B¦ÃF‡&pá Î!:1‹ÄÀ\ÄF´ÉaMqšý½d§híÈìBƒì꓊ÞciΧŒ‘á>?™J©* OÊjÁÃûr¿‰Ll»]õ9§ý•#½èã…¸èøƒ4¸ \è©Å€t‘³ÄÄ©mÔªú¤\þ˜±¶ë?_åïbþÄ_0Öê!Ámåžÿ|­˜ngfŸí3&ÖSËu™à4)Ûeaý-f~ÃCì­ 3mYpÓÎu>t¬!3ó2[]uMPI[¸/ÆDXw!•Fõ¥¥Kf.–›a¼PHÌË(qØ«ó´Z@È6O1Èä@ö}:cÉàx sÅE˾Š$׆cŒÏuÇë6Q Ï-÷™€„O¾Q TAh±ü÷îÕ@ÕÓ&ˆÍ͵(¸Py0q«Þmµ¸K´Ý'ÅæŸfB©{í9›>«5#BF±? “Ÿb KÛ6{z>¯&žyðàFY?o™Î?ý¡æuûk]ó¬ñÞ—Â Mçž\.;j=Rv1Wæ €áVV6б,Ö­Ý(`@üôÁØF«Zp£ßÅg1Û‘7ÊböÀ)†”؇ЬŸÁ{8¡ŠkìÿÆd6†´×L×ê7ö„ênÿŽLÁråÐýéSPGŸµeõûZ•çBtx É1Öÿ¡N@÷Úç°õmF(µŒ‡‘ ýn=~˜8…a©vk—^âüÍî ÑJHÄ€°x&øƒ±mÎðгhR«–¡¿5‚¦˜ ¸Røv‹½ºœ€¡ a£I0”t°ë54DgHVÇ“qÊû]R­ïB"µœ¢t…»;å31¡èkN’ª\wTþ\>Ó%º"1' M¾¢ÀA@ÀâsDŠ1E›–g¡ÒPtîܰSZ†Õº1°Üy­™ÀÌ0?õj>Nx‰±Ï&´I\¬~ ÷¤€ÄªÐvŠ}'Bpá}„t—ƒV³%¡MŠuܯ~u©2kÂt¡cmö2¤AŒknÎ ÏõÁ^•Å|m DPmDÁP$3›v;ãΈqŸ;çl¬Õ&±øÏ¥§yðY]¾¹U ØÆ´1ý,ÌóÂÛ裲;/ˆŸÙnñúôv¢j{¾­3 ®!½A,4ÅÚÌŠX#1±ç8ÅÀÄ,\²B8˜«mGÆN7l¹m ˜öÍx9íh+@Ìkk“’®˜Òk“·ÚªüBëÉC 4ËR_ë_HÕ(úúO°0k´Z4« Ðúó›—*X«žîš¢í2UJõ9†—õ{XóÚÐÆ mêmˆØlz)›_*d´k¡å&ã.äÈ"q¸Ê4žï©ŸUhcþ£u­QL`³êK¥;æF¢ÕÄ2CÿÐ8BÉF¦ð8+£5™Ì6mÌ·Ã{#Bµ™SÀÂúul;2=kÔéëLBfìaß±6M´h¥3͘”ïA³!p¬ß­'E°ºƒŒ=t˜L4+E(BÓôiXser4À+Ìó³2“&ÖógÙ½&.9Šõ˜¾g!áJÇc¬x–Óß'rB%AåxB3ŒÇôÖ¶õjSý-~#þ'Œ˜¢í4Ãy¼´ÐèÀu#v9 ¸¬ãͪ¹JÌÍècéª)ª"׊sZôC»§UR² ‚é»4ÑðÙ–`íµ™‡ÚwÑùc È -Žê;‹æ˜(Æ<\ðøÎr_@…^‹B‚µV ¡S¢á”Ã…M±V)j˜-=†dÄ$Sb³³^©êßÓßwö(L·2>?ãÆ)jk ºìÕÐXB¥ÍšÁÇVjq<ƒ6bõ÷˜Ñ.÷À lmV«±`/ñ=6/µBÄ &&šnñÈÞË÷¯€¾V"=ùäöºÊŽLŒÏ[3+æ?òçÌ^7ì NÙX,>Õ`Í ø´]»3Ã(ÜèÀM°Õ>‹çãóŠ•áèˆÐæ(·fi†û  ©„#xKäÈDðaw[[ÉÖEضò R˜êaWH°¯ è£úû›˜Êü4gtÓUz[b×ñæuÝ8çc€6ä ®žemý6ìß/\¿àr;`ƒ;̧'VSËà}›Î^e~0ìYhŒJ´Õâ;-ĶâÝ¡²Ï‚p]Y[âúÄiÅ÷Aц&“…¡ºóýe™‚Ô,*?ÑxŸ¥Õkk„ŒS, Œ…Mhm¯ƒ_Ä|SÍAÛ„€uŽpcýÌ&¼§1Z×>‹ñG,$%h(É%&xÒ0Šm¿l÷×­t9ÿbÀw”Ùy0ÑÄd!ÎýµH ¶©þøÍ:F¨ÆÆÐ„c{à;1í¾àtÕ–âÆc•ÿœ¶£CDÖñ{cßuˆD®l0>´E–+C¸dœÔ8:é™SýnKÈéŠÉÛñc_´a©kpË÷ZU4%Í…†³mÛz!à¶Ëc-Ö™¡öä)ƒ ªþSêã¯í˜¬=çÞÃßñt¡%HâÔu m®¶&N D@dk+À,Ž?ÎÕ_ÿ”ômfÖ„ƒH‘…SÒ†«|§hW†Wh½pÙF+ÚÅX³å¬#«Kø'mUj(d\««›e;°3g†e‹_ÄÕ&lxuš .ıß%­ëÈŠJ†–Ûƒºxþž²õ;«C59ÞŸ¡ÍñìkV¡}¤fă~´C‡.¼sKiŠœ<™U-Á›½b –À”½÷½MbþæÀ\H^Wªi”dTMðqÒÒ>¼ýçiû¸;¡JÑìÃø±ç¦¬._X{›±mzb­DAhªG¶ µÕ°Ò´FÕcdzçC“C÷µ ŠSаalÍDü¬B€—ž;·ÔÀ*ðûïù Æõ"Íì߯9¤[òÌõ°ë‰ñÀ7dÊÄà°`*¶‘šÄçA¸ìßO`ýmÛÃõ9tbZd(4HÌ &ᇠ„œkÿ¶åÏQà}ïk!ó1ä±úZêNi „¤“×nzJU ‚¸&Úª0Ëéoý!¡qâ´%rC3ÉdñãÚ6]sˆi¾}Nè45»¦ý/–±BªI%:'Öÿú‹pX0ìX¤…Tͬ¼Ø)Î0“½0V<ÌÅLE‘ß%7q8–,k)ñ4plèTä´9¤™ÅH`[{ï¾>€où{Èp1 ‚‰R³0‹x•à|OkÚ5€†8rdzÈ)f€³•è!¡08œÐPµsO·TÕÖH#æ)J˜IeüØ|C÷ÔŽ¨¶ ™Ý@è`ªþ]vdjLÙ÷Z㹸(tàøó ~º°üÑ_æË—ï6dšÍ¨8û˜.§ gúù,ÃÅ…±2ÞBsù^z\¬O`‡$ÞÓš¨ô1´Ø× °ëÂÞ‰8…Û! ͺo!ÞòS«!tX¢Ìýí´ »EÅ–¨øÅ_ý}Ð6àð ]~?ìZ Šx¿õ”Ϊ¦ûQn*m0Ep;šRNϔͱc±¯…€¿66) I««#yôÑùBMj~wÛù€¶#<Ì >íëXŒ•2ó„‚vA£Ì®¦ ªæ ‘6gï_žbáFÍïæUucÖ¸´ ü¯xýaÜÿ˜0lÓð\6Ç¡©ÓWÄèËš‘ZQ©k¢pâÌžÕïð3ûö©ðU­2 .Ú3–ÝÿÑÒ….† 9Eècâû üߦö—jõšžjËU£ÞÓ0Úl€ þ¦„þN¡Y‡¼£^jª«Ó;CÞî­ÚÿD[b®{+ØTÖT"E6ø0?»î°gcu÷ª+¯š;6óÓeÚ{*XÈ4ÞáÔ©Õr’Z Ìïäl³ø¬vÑ×÷BÓ…i˳n}aÈÈÓz]ý„£+¬=±5BvsíÚ´žÑh|&{ÿû7¯æùp‰¹ÇmŽ{ 0Cj‘zå¬óÍíI7«  6V+´¸Ó±ò® ìsú·ýûñípžÈØ,ªi,ÖP0”þ¶d›iF³Œ'3žA„!bÆÐýÃ@&º/ì›@uŸ†eÈøžÚ£-fÄ1W!…nb>jŒxB÷â³è[ˆi§þsbÏy×Sh¯ÍkÓ¶¡úãžìlĵe±Í–kƒ]*5{uL;+ñ3É>üáÍëƒÁpA1ʧ7ÊÚ‚ ᤠí]§Ò l+µ›Ågiv¶ΗŠì+`KCoæéßW„p°Qì™hËž)ÁAŒ±äœ6‚·cñ…ކÔt_´ ‹k•õ:M»T„u‡šbR·½jùò¾¸ˆÞ᧘-¾vÂõÝ·o\¬ï° =+3haQlÖ®}è™!aчöR€ uÜÓGÒïéÜèÿÀwY¸D(=Ì t‡ïÙrú&ÏŒŸÎ>øÁÍÍ={†stÚh®øt/9Öò³¥6¿Aظ¨=(Q¹6Ѱ êØGºÚ¿¹08q qÐÇp3mÿÔ?¦ÂYõNb¦÷’9´K°+wî«!¹õÑ{±c6žY—~§›®5o3ì>°y*~lòNLmo:6SDŒq3‘(FôÇî«Ïšœ$%Þ Å˜jó bê˜ÑÙ¬‘§˜ýOMÚ‹š/aí {®k©{~#ª4aõi¦„}MãK… 0º²°0Ü‚„ªm0;hÛœµ0E¼¹]NÒfì¥.ThsYDÓ•'Ÿº ¡ÿc§¿o ǘŸÙqãþŒ·BõOó¹.# ¹¿ñŸºwó‡ë3p à PÃé“hÃß6S€©ÄÔHSª÷x0AF°æ„Û e†Òeyÿ.m /ãÇÖÛ®¬šŒ9Pí½\m†b.:4‘'¥¦L¬ÄprÐø|öK¿4:777ÜCTW¦e²Å7;¾PBƒ ‘hñøãYíøñó¢ýELU­ºŠ1^Û†éëqú§Ô@ØR¬Óp™°ÑMÕfbŠj9¦¬0d ¸ÍÉo[#Ÿ1C¦ Ul6)ÑJ»xÎGhN!Û]Û1o!ÍAÚ\e~Úù¸ „aQ‹ €ÍÅö,B $lýÓ<†û0·+qÎú ¼ËtsQ‹hÔxã'²#GF_.ÀK| ˆ7aü‘ö%ÛVQ²'{HBlóúxºqQµ¶ˆ1}¦ëÿ6`Ôƒmº0–6žµý÷ïŸÈéÓƒVT—Y…ã4ñ+S¢è‡ýYîŠÒÖ:vò[@Úÿ,HéêßàÏkÚ{¯÷…_ ¿qzÙVì!Üá2×nBQRâ䳨k±Ã'dûÓy “…pçþÁºy–ˆÍÔ„\dÀV…ƒ0ÿd¡äPü÷#Í2O=Iئší“£e’3a“÷!ì¾*“O07Ãé"J¿ðO°˜B8eð7Á¿¤ª˜ÔmÜÃosÖFh)s 1M$v³ Ý7å^¸ü²_÷V‡QÓS#t²v!æ„Æ"f Ÿ…KD•JõLï® «I1V›)×–܇†guú%Û :VC]±B÷¢ö¤{ïÀX‰Çu$²2ïQEñÞVh“{†Ãì!n‚è“ìÀ\ÖÖFò•¯Ì— ‰LûlCZIñ”nÅnßÊå3|ˆ ­s&`jžJ°Óºˆ×(8¡zÛ†Šñ¯?¡l4»F³˜3–øÃ°â,ÎDþ¬¶ÃIÂÂ,bü+Æ#°ìS`œ![hNöYJøšqˆuf-—îöžV¥ÖÎÇ*l–a\X ÷¡é˜ùfC  Ö7Øb±6Àý·¯1¯‚¨F좭Ðaz˜ô»R©Ðò€š‡><)OûÇÓ¾}LÅm«?NUýûiŸ«ë;1!Ð<óÚ³ŽüÍZò¥%µ­TMvÅ20›žÿüQ±6ƒÒCÉ›Òâ,u=Bsà ªÀži Öåüc1Óu©}±.D ˆo‚fj»¦×¹k^– XHå„¶e†æâk„ù&¾¾bæõ>sü¾ ‰ÁÍÍÕ¯…vVmOJõ_„IDATÕ~í:ì¡à°?xÎ¥KãŸú©ùÅò+GŽŒÎÎÍ ogÎ=6ÕR\=íñ¬ lÓöÑf1ú.pìÿÐF„ˆÈwÐàÄÓqgSï[ÈíC‡ÆeÌN ùeãäm©™©ëÓ¹˜uî1ǘˆê?³€ômƒ½î üXêÍèĊ­-AY°ÖLÄmóñÍ7š,p^³× žƒ×q_­•˜ÎÅÁÍmÅhÓ8wDV0>;÷®5ôïçÏŸš€Þ;“3g0ßüCo{Ûð?”CºÿþÉ=Å×¢š‡ÅÓlÙd믭g»ËŽj[°›}ÅìþáØ…äß!€‘Q#ª"¸¨:kOºæ,ó i4]kÐùˆ9­£Š™êoÈk5T›uÆ!½Bã³þ'Ô0ÌL§VŸ<{ªÚ¼€&•Ù2¬s^ˆžJ=Ž €q Å€,·o© >åéµ5K9~<9~¸ëg~fp©&‡ûï]‡;IÈÚ¾K Œ·vd­uWë¤.ØŠ@èct1H—:ÜÅZ›®ŒáÈ„)ž4Lö HÅTÍ>óŸõïó‡æJA[2öü6å³@µ9?€úœ˜d¤æSS"t^Vc£ÿ†¯á$D¹º 3Î’p£ü·s†fÅu¥p`÷ ÷†ùƒC ë›e“Ͼîusß^~ž7ø•_`nnðvz’±h°C°Ì¢ÂeKNœ¥Öúfh³Øýö½Y™‚Ré˜p8© ÇÚ‡&£Ýkúcÿ÷w[„Ã-Uàùe!Æüʽ6ͦK@ÅeáÁú #;ÿ…C“Ö2YÕnY¼„Ö3Î"¶âà„aöàÿ€Æí4 ´ Ñ Ø*~XL477š,- _úÆ7.?ooòk¿6:¶sçਰB`zæÿ7»Áæ §Š…ŽÅUÛi+á¼¾ïÇ„À,Z€u2±*’€ºY}ØÍ #Ì69™Õ HaüØœS™ßÍÕõd¹10CqõüTÊ|(h eØ Æ¾€IcŠ’ÃUªaÙv#N Þ¨èVÌ_µ…s•`#~4%vïÐ>²ÕæKä"\Å>¾ñíoüvý]ÿfûØ$o&!4;‘èM\x…h3 v¿sOÛBͪÌâèj[°ÅþöýŒ½ã¤a% cüôMbâ{Œ ´Afõ½R™¿kÚ“JL,ËÆXI'ö”Þj„ƒÏdSP–P÷—ÑFp_W‰™žØ%RçÚ3Ž4³Û €¶4à¶ù+˜ˆk ª÷˜<ðŽw ¿§ñÿ&ýèäžâ„z(Ô@Á>ȇ›†J¥‚ )BL³JN»h¡ÿû ‡­ëý': +Ílx^$@Ö[èš…ëÉo–àÏÅÿ¿ÛþÏëdN…}'‚Í* LqñPéúnl>þ˜Ð… ëç„ÀR}!Ð7{³-ÛñiCx©ô`'bVèxÆ.- ^Ç_ã;¡}èC“{ ;é!ÛœÁ–o:§ ¶™'‚pAR„@Ÿ+…àCÿû f¯JkøDt61 Ѱ8ñ^(ýÖJehNgÏ:Д­j7Zõ¡1Ô ¡ÏB°# W_?@ìêcÿÆæd³í À4WCaÌɈEÚ›7*¼m™”Þ ±5ð箯M(´€×ýÂ/4™¿|¯í¦¿üË£c“ÉðŽÐ{´Y(µT%tá{/oÔb¥€ÿZè»X¡×ÚUþÍ–TL‰UF2ÏßÕ^w³W5nÅþ÷áÌBÂ-dîЫ-jªeœPd£o8¸ëµ6ûןkH`Ýyúc8ioßÜlöFdôÚ ¾Ïº—6!2VK ¡9°àNµž,™&âk0.F;øñûîs6ÿÔw¥ã:rdübo(H`§}ˆ% 9°ý0Tà¶ 7+ fç†ÊŸKhnþÿVX˜2 ’+B5ñ¡gÑÅéc%ýVæû»M ð`çæ s´xÕFUí 5,7uáMõÜHçph¾¡p-aæá€³›¨ºxŸPçx.qè§¶–⸅Îí¸gåwñ¤øîç³lðÓïyzû£ßI½9jÆãÉŸÃÛù0+àwXåí˜n7óê+bf@×iBÛq[M|ÑÓÄ:BÛÆˆï6Û‚ÍF0±y·­ELM¶a#õ K•^LsGM?EíiÖ7tµã¶sì£ö=CûeýÐb`ÆÜu×õBp/”­ÄXÙʱBP`îÔL†@áÞ,í¶?=Œ×õá<Ï~>¤î¿7ËÀTd??Œï*ˆbO!I·jÔBA“*v97¡xê×ëòOñæB5/ë,áÿ)±[n0­Ôªõ)sžõôO1Ú„aÛÀ–úâ0 …¼Æª¡: ­g,ÇŽ-ÔŽLŒŸ#ž¿ß¿q–úì§_s~>Ž!ûâ=fl"1Œmß„¢UÿÛ ÛR÷2å3£Ñø|ñ #AÿßóÖ zýZ±Ö³,;VÌæ‹ÿ;•éíõÿñW¥ónpnIEND®B`‚(0` €%þœœ þ‡‡qþ‡‡ÆþÝþ€€ßþ{{ßþzzßþzzßþzzßþ{{ßþ||ßþ}}ßþ€€ßþ„„ßþßýššßþßþßþˆˆßþ……ßþ……ßþˆˆßþŠŠßþŒŒßþ““ßþ  ßý®®ßþœœßþ’’ßþßþŒŒßþ‹‹ßþŠŠßþ‹‹ßþ‘‘ßý¦¦ßþ¢¢ßþ••ßþˆˆßþ‚‚ßþßþßþƒƒßþÞþ€€ÜþÁÿ‡‡fþ‹‹ þ’’qý˜˜öþ““ÿÿŠŠÿÿ€€ÿÿ}}ÿÿ||ÿÿ||ÿÿ}}ÿÿ}}ÿÿ~~ÿÿÿÿÿÿ……ÿÿŒŒÿþŸŸÿþžžÿÿ––ÿÿ‹‹ÿÿ‰‰ÿÿ‰‰ÿÿŠŠÿÿŒŒÿÿŽŽÿÿ‘‘ÿÿ˜˜ÿþ©©ÿÿŸŸÿÿ””ÿÿ‘‘ÿÿ••ÿÿ˜˜ÿÿÿÿÿþ››ÿþ§§ÿÿ••ÿÿŒŒÿÿ‡‡ÿÿ„„ÿÿƒƒÿÿ„„ÿÿÿÿ‹‹ÿÿ„„ÿÿ……ÿýóÿfþŒŒÆþ££ÿþ  ÿÿŠŠÿÿƒƒÿÿ€€ÿÿÿÿÿÿÿÿ€€ÿÿ€€ÿÿÿÿƒƒÿÿŠŠÿþ˜˜ÿþ££ÿþ««ÿÿ””ÿÿŽŽÿÿ‹‹ÿÿŒŒÿÿ’’ÿÿ““ÿÿ‘‘ÿÿ““ÿÿœœÿþ¯¯ÿþ©©ÿÿ™™ÿÿ––ÿÿŸŸÿÿŸŸÿÿ””ÿÿ••ÿÿ¢¢ÿþ¤¤ÿÿ““ÿÿŒŒÿÿ‰‰ÿÿ‡‡ÿÿ††ÿÿˆˆÿÿ””ÿÿ““ÿÿ‰‰ÿÿÿþššÿþ››ÁþÝÿ‘‘ÿþ››ÿÿ——ÿÿÿÿ„„ÿÿƒƒÿÿ‡‡ÿÿÿÿ„„ÿÿ‚‚ÿÿƒƒÿÿ……ÿÿˆˆÿÿŽŽÿÿ••ÿþ¥¥ÿþ  ÿÿ””ÿÿÿÿÿÿššÿþ¢¢ÿÿ——ÿÿ––ÿÿ››ÿÿ©©ÿþ««ÿÿ  ÿÿœœÿÿ¥¥ÿÿ  ÿÿ˜˜ÿÿÿþ®®ÿÿŸŸÿÿ’’ÿÿŽŽÿÿÿÿŠŠÿÿ‰‰ÿÿŠŠÿÿ’’ÿÿššÿÿ••ÿþžžÿþ˜˜ÿþ‰‰Ûþ‚‚ßÿ„„ÿÿŽŽÿþŸŸÿÿ••ÿÿŠŠÿÿ‡‡ÿÿÿÿ––ÿÿ‡‡ÿÿ……ÿÿ……ÿÿ††ÿÿ‰‰ÿÿŒŒÿÿ““ÿþ££ÿþªªÿÿ˜˜ÿÿ““ÿÿ““ÿÿ™™ÿþ¨¨ÿÿŸŸÿÿ››ÿÿ¡¡ÿþ°°ÿþ¼¼ÿÿ««ÿÿ¤¤ÿþ±±ÿÿ¦¦ÿÿ££ÿþ««ÿþ­­ÿÿœœÿÿ••ÿÿ––ÿþœœÿÿÿÿÿÿŽŽÿÿ””ÿþ¦¦ÿþ¯¯ÿþ  ÿÿÿþ††Þþ}}ßÿ€€ÿÿ‡‡ÿÿÿþŸŸÿÿ––ÿÿŽŽÿÿ––ÿÿ••ÿÿŠŠÿÿˆˆÿÿˆˆÿÿˆˆÿÿŠŠÿÿÿÿ‘‘ÿÿ˜˜ÿþ©©ÿþ¦¦ÿÿššÿÿ——ÿÿ™™ÿÿ¤¤ÿÿ¨¨ÿÿ¢¢ÿÿ¤¤ÿÿ¯¯ÿþÁÁÿÿ³³ÿþ±±ÿþººÿÿ¯¯ÿÿ¬¬ÿý¾¾ÿþ²²ÿÿ  ÿÿššÿþ¤¤ÿÿŸŸÿÿ’’ÿÿ‘‘ÿÿ””ÿþ¡¡ÿþ¯¯ÿýµµÿþŸŸÿÿ‘‘ÿþŠŠßþ||ßÿÿÿƒƒÿÿˆˆÿÿ••ÿþ¤¤ÿÿŸŸÿþŸŸÿÿ’’ÿÿŒŒÿÿŠŠÿÿŠŠÿÿÿÿÿÿÿÿ’’ÿÿ˜˜ÿþ©©ÿþ±±ÿÿ  ÿÿžžÿÿÿÿ¤¤ÿþ··ÿÿ¯¯ÿÿªªÿÿ²²ÿþ¿¿ÿþÅÅÿþÇÇÿþÊÊÿþÀÀÿÿ»»ÿþ¾¾ÿÿ­­ÿÿ¤¤ÿÿ¦¦ÿÿ¨¨ÿÿ››ÿÿ––ÿÿ––ÿÿ››ÿþªªÿþ­­ÿÿœœÿÿ——ÿÿ˜˜ÿþ˜˜ßþ||ßÿÿÿ„„ÿÿ‰‰ÿÿÿþ¤¤ÿý½½ÿþ¥¥ÿÿ––ÿÿÿÿÿÿÿÿ””ÿþŸŸÿÿ••ÿÿ••ÿÿ˜˜ÿÿŸŸÿþ°°ÿÿ®®ÿþ¬¬ÿÿ££ÿÿ¦¦ÿþµµÿþ½½ÿÿ´´ÿþ¿¿ÿþÆÆÿüÛÛÿáëìÿíèèÿýØØÿþÐÐÿþÂÂÿþ¸¸ÿÿ¯¯ÿþ¸¸ÿÿ¨¨ÿÿÿÿœœÿÿ  ÿþ®®ÿþ¦¦ÿÿ››ÿÿ””ÿÿÿÿŠŠÿþˆˆßþ}}ßÿƒƒÿÿÿÿ——ÿÿššÿþ££ÿþ¯¯ÿþ¯¯ÿþ¢¢ÿÿ••ÿÿ‘‘ÿÿ‘‘ÿÿ––ÿþ¦¦ÿÿ  ÿÿ™™ÿÿššÿÿ¤¤ÿþ²²ÿýÄÄÿþ³³ÿÿ©©ÿÿ­­ÿÿ²²ÿþÃÃÿþÄÄÿÿÆÆÿý××ÿùêëÿ²õûÿžîøÿèõöÿïéêÿýÔÔÿþÂÂÿþÁÁÿþ··ÿÿ¨¨ÿÿ¥¥ÿÿ««ÿþ­­ÿþ­­ÿÿžžÿÿ““ÿÿÿÿ‹‹ÿÿˆˆÿþ„„ßþ}}ßÿ‚‚ÿÿ‹‹ÿÿÿÿ‘‘ÿÿ““ÿÿŸŸÿþ°°ÿþ§§ÿÿ™™ÿÿ••ÿÿ””ÿÿ——ÿÿ¡¡ÿþªªÿÿžžÿÿžžÿÿ¦¦ÿÿ°°ÿþÂÂÿþ½½ÿÿ±±ÿÿ»»ÿÿ»»ÿþÄÄÿý××ÿþÔÔÿýââÿöõöÿ¾ùýÿ\Üõÿrâøÿ²òúÿúææÿýÖÖÿþÊÊÿÿººÿÿ´´ÿÿ¯¯ÿý¿¿ÿþµµÿÿ¡¡ÿÿ˜˜ÿÿ““ÿÿÿÿ‹‹ÿÿˆˆÿþ……ßþ~~ßÿÿÿ„„ÿÿˆˆÿÿ‹‹ÿÿÿÿ——ÿÿœœÿþªªÿþ©©ÿÿžžÿÿ˜˜ÿÿ™™ÿÿžžÿþ««ÿþ¬¬ÿÿ¥¥ÿÿ¦¦ÿÿ««ÿÿ¶¶ÿþÆÆÿÿ½½ÿÿ¾¾ÿþËËÿþÊÊÿþ××ÿüææÿúññÿàûüÿ¨ùýÿN½ãÿK¾äÿ¹ûýÿóööÿýááÿþÎÎÿþÉÉÿÿ»»ÿþ¾¾ÿþ¾¾ÿþ¯¯ÿÿ¢¢ÿÿ™™ÿÿ——ÿÿ˜˜ÿÿ‘‘ÿÿ‰‰ÿþ††ßþ€€ßÿ‚‚ÿÿ……ÿÿ‡‡ÿÿŠŠÿÿÿÿ‘‘ÿÿ——ÿþ§§ÿþ´´ÿÿ¥¥ÿÿ  ÿÿ  ÿÿ¡¡ÿÿ¯¯ÿþ½½ÿÿ®®ÿÿ¯¯ÿþ¶¶ÿÿ¶¶ÿþÆÆÿýÑÑÿÿÈÈÿþÕÕÿþÜÜÿýääÿúññÿåûüÿ‡ÞôÿDªÓÿ(Djÿ/cŒÿdÐíÿÌõûÿúîïÿýááÿþÓÓÿþÌÌÿþÉÉÿÿ¶¶ÿÿ««ÿÿ¤¤ÿÿ¡¡ÿþ¦¦ÿþ¢¢ÿÿ““ÿÿ‹‹ÿþ‰‰ßþƒƒßÿ„„ÿÿ††ÿÿˆˆÿÿ‹‹ÿÿŽŽÿÿ‘‘ÿÿ––ÿÿÿÿ©©ÿþ³³ÿþ°°ÿÿ¨¨ÿÿ¥¥ÿÿ««ÿþ½½ÿÿººÿÿ´´ÿþÁÁÿÿ¿¿ÿÿÇÇÿýÙÙÿþÚÚÿýããÿúððÿ÷ööÿíüüÿÎþÿÿoÔëÿ#5Uÿÿ ÿ=z¦ÿ±öüÿíûûÿùòòÿýææÿýààÿþÏÏÿþÂÂÿÿ´´ÿÿµµÿþ®®ÿÿ¡¡ÿÿ——ÿÿ’’ÿÿÿþŽŽßþŒŒßÿˆˆÿÿˆˆÿÿŠŠÿÿ““ÿÿ˜˜ÿÿ••ÿÿ——ÿÿœœÿÿ¨¨ÿþ½½ÿýÁÁÿÿ®®ÿÿ¯¯ÿÿ³³ÿÿººÿþÈÈÿÿ¿¿ÿÿÄÄÿþÑÑÿþÏÏÿþÛÛÿúííÿâô÷ÿÉõúÿÇùýÿÂüþÿ¡øüÿ\Üìÿ4Lÿÿ ÿ6ˆ¦ÿøûÿ¹öûÿàüýÿìúûÿÙôøÿíçèÿþÐÐÿþÄÄÿÿ··ÿÿ¨¨ÿÿžžÿÿ˜˜ÿÿ––ÿÿ––ÿþœœßþ™™ßÿŽŽÿÿŒŒÿÿÿÿ••ÿþ¥¥ÿÿ¡¡ÿÿ››ÿÿžžÿÿ¨¨ÿÿ³³ÿþÃÃÿÿººÿÿ··ÿþÀÀÿÿ¿¿ÿýÓÓÿþÏÏÿÿÌÌÿþÙÙÿýßßÿýééÿñøøÿ“ãöÿM–Ïÿ\ÃÞÿ`Ìàÿ>|œÿ%oˆÿ+Mÿÿ ÿNlÿ5}•ÿIˆ«ÿéóÿ í÷ÿqÞôÿ¯èõÿúààÿþÆÆÿþ··ÿÿ©©ÿÿ¨¨ÿÿ¡¡ÿÿ¦¦ÿþ¦¦ÿþ««ßý¥¥ßÿ——ÿÿ’’ÿÿ‘‘ÿÿ””ÿÿœœÿþ©©ÿÿ¦¦ÿÿ¤¤ÿÿ§§ÿÿ®®ÿþººÿþÉÉÿþÃÃÿþÍÍÿþÌÌÿþÕÕÿýÜÜÿþÜÜÿþááÿúððÿùööÿâýþÿíøÿ5bÿ*BÿB_ÿ ÿÿÿÿÿÿ ÿ%ÿ,{—ÿ.[{ÿ4r¡ÿ‡Ùòÿ÷êêÿþÎÎÿÿ»»ÿÿµµÿþ¼¼ÿþ²²ÿþ®®ÿþ¤¤ÿþ™™ßþ  ßþ©©ÿÿŸŸÿÿ˜˜ÿÿ——ÿÿššÿÿ££ÿþ¶¶ÿÿ³³ÿÿ¯¯ÿþ»»ÿÿ½½ÿþÏÏÿýØØÿýÞÞÿýááÿýããÿûììÿüëëÿûññÿ÷øøÿåþþÿµóúÿlàïÿ'kŽÿ ÿÿÿÿÿÿÿÿÿÿÿ ÿ7n‹ÿµòúÿøïïÿþ××ÿþËËÿþÀÀÿþ»»ÿþ®®ÿÿžžÿÿ˜˜ÿþ’’ßþ’’ßÿÿþ©©ÿþªªÿÿ  ÿÿ¢¢ÿÿ¤¤ÿÿ°°ÿþ¿¿ÿÿººÿÿ¾¾ÿþÎÎÿþÖÖÿðííÿØöøÿð÷÷ÿõ÷÷ÿîúúÿïûûÿìýýÿåþþÿÉþÿÿm¿Úÿ*Koÿ$ÿÿÿÿÿÿÿÿÿÿÿÿ ÿ7™ÿ¦õùÿãõ÷ÿýÝÝÿþÆÆÿÿ¶¶ÿÿªªÿÿ¤¤ÿÿ››ÿÿ––ÿþ’’ßþßÿ””ÿÿŸŸÿþ¬¬ÿþ´´ÿÿ®®ÿÿªªÿÿ±±ÿÿ¼¼ÿþÍÍÿþÊÊÿþÔÔÿüèèÿÚøúÿvéúÿ²ûþÿÃýþÿ˜ìúÿ¯øýÿÅþÿÿÄþÿÿ¢úüÿI¢¿ÿ/ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$3ÿB­ÿ¡ÜðÿûääÿþËËÿÿººÿÿ««ÿÿ¤¤ÿÿžžÿÿÿþœœßþ‘‘ßÿ””ÿÿššÿÿ¨¨ÿþ½½ÿþ½½ÿÿ´´ÿþÀÀÿÿÁÁÿþÑÑÿýÛÛÿýááÿùòòÿØýýÿlçúÿG°ßÿTÀßÿ;±ÜÿL£ËÿgÏêÿŠùýÿnïõÿ(Qoÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ8oˆÿºêôÿûååÿþÎÎÿþÀÀÿþººÿþ¶¶ÿÿªªÿþ¨¨ÿþ¢¢ßþ  ßÿ¡¡ÿÿŸŸÿÿ¥¥ÿÿ°°ÿþÁÁÿþÄÄÿþÈÈÿþÒÒÿþ××ÿüææÿùòòÿìüüÿÉþÿÿyôüÿ/s£ÿ%?ÿ$=ÿ+ÿ$6Vÿ;£¾ÿ/Ïàÿ#2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ5oˆÿÃìõÿüääÿþÐÐÿþÀÀÿÿµµÿÿ­­ÿÿ¡¡ÿÿ››ÿþ••ßþ––ßÿ¡¡ÿþ®®ÿÿ±±ÿþººÿþÅÅÿýÖÖÿþ××ÿüääÿüééÿøôôÿßûýÿ¯ùþÿ’úþÿ@±Õÿ.Mÿÿÿÿÿ,ÿ`žÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ‚™ÿÛòöÿýããÿþÍÍÿÿ¾¾ÿÿ±±ÿÿ¥¥ÿÿŸŸÿÿššÿþ••ßþ––ßÿžžÿÿªªÿþ¾¾ÿþÌÌÿýÛÛÿøééÿóòòÿó÷÷ÿîûûÿßþþÿ²üþÿQÕòÿ<³Øÿ#b’ÿÿÿÿÿÿÿ 'ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ&ÿŠÁÏÿñõöÿýÞÞÿÿÊÊÿÿ¼¼ÿÿ±±ÿÿªªÿþªªÿÿžžÿþ››ßþ¦¦ßþ®®ÿÿ¶¶ÿüÍÍÿëìíÿÜ÷÷ÿ¶óøÿåïÿ¦ùþÿ•õýÿ‰óýÿUÖôÿ4x«ÿ,ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQ–¡ÿËøúÿøôôÿýßßÿþÑÑÿþÄÄÿþ½½ÿþ¾¾ÿþ··ÿÿ««ÿþ­­ßþ¦¦ßþ®®ÿÿ¶¶ÿüÍÍÿëìíÿÛ÷÷ÿµóøÿåïÿ¦ùþÿ•õýÿ‰òýÿTÖôÿ4wªÿ+ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQ—¡ÿËøúÿøôôÿýßßÿþÑÑÿþÄÄÿþ½½ÿþ¾¾ÿþ··ÿÿ««ÿþ­­ßþ––ßÿžžÿÿªªÿþ¾¾ÿþÍÍÿýÛÛÿøééÿòòòÿó÷÷ÿîûûÿßþþÿ²üþÿQÕòÿ<²×ÿ#b’ÿÿÿÿÿÿÿ &ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ'ÿŠÁÐÿñõöÿýÞÞÿþÊÊÿÿ¼¼ÿÿ±±ÿÿªªÿþ««ÿÿžžÿþ››ßþ––ßÿ¡¡ÿþ®®ÿÿ²²ÿþººÿþÅÅÿýÖÖÿþ××ÿüääÿüééÿøôôÿÞûýÿ¯ùþÿ’ûþÿ?±Ôÿ.Mÿÿÿÿÿ+ÿ_ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJ‚™ÿÛòöÿýããÿþÍÍÿÿ¾¾ÿÿ±±ÿÿ¥¥ÿÿŸŸÿÿššÿþ••ßþžžßÿ¡¡ÿÿŸŸÿÿ¥¥ÿÿ°°ÿþÁÁÿþÅÅÿþÈÈÿþÒÒÿþ××ÿýææÿùòòÿìüüÿÉþÿÿyôüÿ/r¢ÿ$?ÿ#<ÿ+ÿ#5Uÿ;£½ÿ/Ïàÿ#2ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ5n‡ÿÃìôÿüääÿþÐÐÿþÀÀÿÿµµÿÿ­­ÿÿ¡¡ÿÿ››ÿþ••ßþ‘‘ßÿ””ÿÿššÿÿ¨¨ÿþ½½ÿþ½½ÿÿ´´ÿþ¿¿ÿÿÁÁÿþÑÑÿýÛÛÿýááÿùòòÿØýþÿlçúÿG°ßÿT¿Þÿ;°ÛÿK¢ËÿfÎéÿ‰ùýÿnïõÿ(Qoÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿ8p‰ÿºêôÿûååÿþÎÎÿþÀÀÿþººÿþ¶¶ÿÿªªÿþ¨¨ÿþ¢¢ßþßÿ””ÿÿŸŸÿþ¬¬ÿþ´´ÿÿ®®ÿÿªªÿÿ²²ÿÿ¼¼ÿþÍÍÿþÊÊÿþÔÔÿüèèÿÚøúÿvéúÿ²ûþÿÂýþÿ—ìúÿ®øýÿÅþÿÿÄþÿÿ¢ùüÿI¢¾ÿ/ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ#3ÿBŒ¬ÿ¡ÛïÿûääÿþÊÊÿÿººÿÿ««ÿÿ¤¤ÿÿžžÿÿÿþœœßþ’’ßÿÿþ©©ÿþªªÿÿ  ÿÿ¢¢ÿÿ¤¤ÿÿ°°ÿþ¿¿ÿÿººÿÿ¾¾ÿþÎÎÿþÖÖÿðííÿ×öøÿð÷÷ÿô÷÷ÿîúúÿïûûÿìýýÿåþþÿÉþÿÿm¿Úÿ*Jnÿ#ÿÿÿÿÿÿÿÿÿÿÿÿ ÿ7€˜ÿ¥õùÿãõ÷ÿýÝÝÿþÅÅÿÿ¶¶ÿÿªªÿÿ¤¤ÿÿ››ÿÿ––ÿþ’’ßþ  ßþ©©ÿÿŸŸÿÿ™™ÿÿ——ÿÿššÿÿ££ÿþ¶¶ÿÿ³³ÿÿ¯¯ÿþ»»ÿÿ½½ÿþÎÎÿýØØÿýÞÞÿýááÿýããÿûííÿýëëÿûññÿ÷øøÿåþþÿµóúÿlàïÿ'kÿ ÿÿÿÿÿÿÿÿÿÿÿ ÿ7nŒÿµòúÿøïïÿý××ÿþËËÿþÀÀÿþ»»ÿþ®®ÿÿžžÿÿ˜˜ÿþ’’ßý¥¥ßÿ——ÿÿ’’ÿÿ‘‘ÿÿ””ÿÿœœÿþ©©ÿÿ¦¦ÿÿ¤¤ÿÿ§§ÿÿ®®ÿþººÿþÉÉÿþÃÃÿþÍÍÿþÌÌÿþÕÕÿþÜÜÿþÜÜÿþááÿúððÿùööÿâýþÿíøÿ5bŒÿ*AÿA^ÿ ÿÿÿÿÿÿ ÿ%ÿ,z–ÿ-[zÿ4r ÿ‡Ùòÿ÷êêÿþÎÎÿÿ»»ÿÿµµÿþ¼¼ÿþ²²ÿþ®®ÿþ¤¤ÿþ™™ßþ™™ßÿŽŽÿÿŒŒÿÿÿÿ••ÿþ¥¥ÿÿ¡¡ÿÿ››ÿÿžžÿÿ¨¨ÿÿ³³ÿþÃÃÿÿººÿÿ¸¸ÿþÀÀÿÿ¿¿ÿýÓÓÿþÏÏÿÿÌÌÿþÙÙÿýßßÿýééÿñøøÿ“ãöÿM•Ïÿ[ÂÝÿ`Ìßÿ={›ÿ$nˆÿ+Lÿÿ ÿMkÿ4{“ÿIˆ«ÿéóÿŸí÷ÿqÞôÿ®çõÿúààÿþÆÆÿþ··ÿÿ©©ÿÿ©©ÿÿ¡¡ÿþ¦¦ÿþ¦¦þý««ßþŒŒßÿˆˆÿÿˆˆÿÿŠŠÿÿ““ÿÿ˜˜ÿÿ••ÿÿ——ÿÿœœÿÿ¨¨ÿþ½½ÿþÁÁÿÿ®®ÿÿ¯¯ÿÿ³³ÿÿººÿþÈÈÿÿ¿¿ÿÿÄÄÿþÑÑÿþÏÏÿþÛÛÿúííÿâô÷ÿÉõúÿÇùýÿÂüþÿ øüÿ\Üìÿ4Lÿÿ ÿ6ˆ§ÿøûÿ¸öûÿßüýÿìûûÿØôøÿíçéÿþÐÐÿþÄÄÿþ¶¶ÿÿ¨¨ÿÿžžÿÿ˜˜ÿÿ––ÿÿ––ÿþœœßþƒƒßÿ„„ÿÿ††ÿÿˆˆÿÿ‹‹ÿÿŽŽÿÿ‘‘ÿÿ––ÿÿœœÿÿ©©ÿþ³³ÿþ°°ÿÿ¨¨ÿÿ¥¥ÿÿ««ÿþ½½ÿÿººÿÿµµÿþÁÁÿÿ¿¿ÿÿÆÆÿýÙÙÿþÚÚÿýããÿúððÿ÷ööÿíüüÿÏþÿÿoÔëÿ"4Uÿÿ ÿ=z¦ÿ±öüÿíûûÿùòòÿýææÿýààÿþÏÏÿþÂÂÿÿ´´ÿþµµÿþ®®ÿÿ¡¡ÿÿ——ÿÿ’’ÿÿÿþŽŽßþ€€ßÿ‚‚ÿÿ……ÿÿ‡‡ÿÿŠŠÿÿÿÿ‘‘ÿÿ——ÿþ§§ÿþ´´ÿÿ¥¥ÿÿ  ÿÿ  ÿÿ¡¡ÿÿ¯¯ÿþ½½ÿÿ®®ÿÿ¯¯ÿþ¶¶ÿÿ¶¶ÿþÆÆÿýÑÑÿÿÈÈÿþÕÕÿþÜÜÿýääÿúññÿåûüÿ‡ÝôÿC©Óÿ(Ciÿ/b‹ÿdÐíÿÌõûÿúïïÿýááÿþÓÓÿþÍÍÿþÉÉÿÿ¶¶ÿÿ««ÿÿ¤¤ÿÿ¡¡ÿþ¦¦ÿþ¢¢ÿÿ““ÿÿ‹‹ÿþŠŠßþ~~ßÿÿÿ„„ÿÿˆˆÿÿ‹‹ÿÿÿÿ——ÿÿœœÿþªªÿþ©©ÿÿžžÿÿ˜˜ÿÿ™™ÿÿžžÿþ««ÿþ¬¬ÿÿ¥¥ÿÿ¦¦ÿÿ««ÿÿ¶¶ÿþÇÇÿÿ½½ÿÿ¾¾ÿþËËÿþÊÊÿþ××ÿüææÿúññÿàûýÿ§ùýÿM½âÿK½äÿ¸ûýÿóööÿýááÿþÎÎÿþÉÉÿÿ»»ÿþ¾¾ÿþ¾¾ÿþ¯¯ÿÿ¢¢ÿÿ™™ÿÿ——ÿÿ˜˜ÿÿ‘‘ÿÿ‰‰ÿþ††ßþ}}ßÿ‚‚ÿÿ‹‹ÿÿÿÿ‘‘ÿÿ““ÿÿŸŸÿþ¯¯ÿþ¨¨ÿÿ™™ÿÿ••ÿÿ””ÿÿ——ÿÿ¡¡ÿþªªÿÿžžÿÿžžÿÿ¦¦ÿÿ°°ÿþÂÂÿþ½½ÿÿ±±ÿÿ»»ÿÿ»»ÿþÄÄÿý××ÿþÓÓÿýááÿöööÿ¾ùýÿ\Üõÿrâøÿ±òúÿûææÿýÖÖÿþÊÊÿÿººÿþ´´ÿÿ¯¯ÿý¿¿ÿþµµÿÿ¡¡ÿÿ˜˜ÿÿ““ÿÿÿÿ‹‹ÿÿˆˆÿþ……ßþ}}ßÿƒƒÿÿÿÿ——ÿÿššÿÿ££ÿþ¯¯ÿþ¯¯ÿþ££ÿÿ••ÿÿ‘‘ÿÿ‘‘ÿÿ––ÿþ¦¦ÿÿ  ÿÿ™™ÿÿššÿÿ¤¤ÿÿ²²ÿýÄÄÿþ³³ÿÿ©©ÿÿ®®ÿÿ²²ÿþÃÃÿþÄÄÿÿÆÆÿý××ÿùêêÿ²õûÿîøÿçõöÿïéêÿýÔÔÿþÃÃÿþÁÁÿÿ··ÿÿ¨¨ÿÿ¥¥ÿÿ««ÿþ­­ÿþ­­ÿÿžžÿÿ““ÿÿÿÿ‹‹ÿÿˆˆÿþ„„ßþ||ßÿÿÿ„„ÿÿˆˆÿÿÿþ¤¤ÿý½½ÿþ¥¥ÿÿ––ÿÿÿÿÿÿŽŽÿÿ••ÿþŸŸÿÿ••ÿÿ••ÿÿ˜˜ÿÿŸŸÿþ°°ÿÿ®®ÿþ¬¬ÿÿ££ÿÿ¦¦ÿÿµµÿþ½½ÿÿ´´ÿþ¿¿ÿþÆÆÿüÛÛÿáëìÿíèéÿýØØÿþÑÑÿþÂÂÿþ¸¸ÿÿ¯¯ÿþ¸¸ÿÿ¨¨ÿÿÿÿœœÿÿ  ÿþ®®ÿþ¦¦ÿÿ››ÿÿ””ÿÿÿÿŠŠÿþˆˆßþ||ßÿÿÿƒƒÿÿˆˆÿÿ””ÿþ¤¤ÿÿŸŸÿþ  ÿÿ’’ÿÿŒŒÿÿŠŠÿÿŠŠÿÿÿÿÿÿÿÿ’’ÿÿ˜˜ÿþ©©ÿþ±±ÿÿ  ÿÿžžÿÿÿÿ¤¤ÿþ··ÿÿ°°ÿÿªªÿÿ²²ÿþ¾¾ÿþÅÅÿþÇÇÿþÊÊÿþÀÀÿÿ»»ÿþ¾¾ÿÿ­­ÿÿ¤¤ÿÿ¦¦ÿÿ¨¨ÿÿ››ÿÿ––ÿÿ––ÿÿ››ÿþªªÿþ­­ÿÿœœÿÿ——ÿÿ˜˜ÿþ˜˜ßþ}}ßÿ€€ÿÿ‡‡ÿÿÿþŸŸÿÿ––ÿÿŽŽÿÿ––ÿÿ••ÿÿŠŠÿÿˆˆÿÿˆˆÿÿˆˆÿÿŠŠÿÿÿÿ‘‘ÿÿ˜˜ÿþ©©ÿþ¦¦ÿÿššÿÿ——ÿÿ™™ÿÿ¤¤ÿÿ©©ÿÿ¢¢ÿÿ¤¤ÿÿ¯¯ÿþÁÁÿÿ³³ÿþ±±ÿþººÿÿ¯¯ÿÿ¬¬ÿý¾¾ÿþ²²ÿÿ  ÿÿ››ÿþ¤¤ÿÿŸŸÿÿ’’ÿÿ‘‘ÿÿ””ÿþ¡¡ÿþ¯¯ÿýµµÿþŸŸÿÿ‘‘ÿþ‹‹ßþƒƒßÿ„„ÿÿŽŽÿþŸŸÿÿ••ÿÿŠŠÿÿ‡‡ÿÿÿÿ––ÿÿ‡‡ÿÿ……ÿÿ……ÿÿ††ÿÿ‰‰ÿÿŒŒÿÿ““ÿþ££ÿþªªÿÿ˜˜ÿÿ““ÿÿ““ÿÿ™™ÿþ©©ÿÿŸŸÿÿ››ÿÿ¡¡ÿþ°°ÿþ¼¼ÿÿ««ÿÿ¤¤ÿþ±±ÿÿ¦¦ÿÿ££ÿþ««ÿþ­­ÿÿœœÿÿ••ÿÿ––ÿþœœÿÿÿÿÿÿŽŽÿÿ””ÿþ¦¦ÿþ°°ÿþ  ÿÿÿþ……ßþÞÿÿþ››ÿÿ——ÿÿŒŒÿÿ„„ÿÿƒƒÿÿ‡‡ÿÿÿÿ„„ÿÿ‚‚ÿÿƒƒÿÿ……ÿÿˆˆÿÿŽŽÿÿ••ÿþ¥¥ÿþ  ÿÿ””ÿÿÿÿÿÿššÿþ¢¢ÿÿ——ÿÿ––ÿÿ››ÿÿ©©ÿþ««ÿÿ  ÿÿœœÿÿ¥¥ÿÿ  ÿÿ˜˜ÿÿÿþ®®ÿÿŸŸÿÿ’’ÿÿŽŽÿÿÿÿŠŠÿÿ‰‰ÿÿŠŠÿÿ’’ÿÿššÿÿ••ÿþžžÿþ˜˜ÿþŠŠÚþŒŒÈþ££ÿþ  ÿÿŠŠÿÿƒƒÿÿ€€ÿÿÿÿÿÿÿÿ€€ÿÿ€€ÿÿÿÿƒƒÿÿŠŠÿþ˜˜ÿþ££ÿþ««ÿÿ””ÿÿŽŽÿÿ‹‹ÿÿŒŒÿÿ’’ÿÿ””ÿÿ‘‘ÿÿ““ÿÿœœÿþ¯¯ÿþ©©ÿÿ™™ÿÿ––ÿÿŸŸÿÿŸŸÿÿ””ÿÿ••ÿÿ¢¢ÿþ¤¤ÿÿ““ÿÿŒŒÿÿ‰‰ÿÿ‡‡ÿÿ††ÿÿˆˆÿÿ””ÿÿ““ÿÿ‰‰ÿÿÿþššÿý››Àü““tý˜˜öþ””ÿÿŠŠÿÿ€€ÿÿ}}ÿÿ||ÿÿ||ÿÿ}}ÿÿ}}ÿÿ~~ÿÿÿÿÿÿ……ÿÿŒŒÿþŸŸÿþžžÿÿ––ÿÿ‹‹ÿÿ‰‰ÿÿ‰‰ÿÿŠŠÿÿŒŒÿÿŽŽÿÿ‘‘ÿÿ˜˜ÿþ©©ÿÿŸŸÿÿ””ÿÿ‘‘ÿÿ••ÿÿ˜˜ÿÿÿÿÿþ››ÿþ§§ÿÿ••ÿÿŒŒÿÿ‡‡ÿÿ„„ÿÿƒƒÿÿ„„ÿÿÿÿ‹‹ÿÿ„„ÿÿ……ÿý‘‘õþžžjþ‘‘þ‡‡uþ‡‡ÉýŽŽßþàþzzàþyyàþyyàþyyàþzzàþ}}àþ~~àþ€€àþ„„àþŽŽàý™™àþàþàþ‡‡àþ††àþ††àþ‡‡àþ‰‰àþŒŒàþ““àþ  àý¯¯àþàþ’’àþŽŽàþàþŒŒàþŠŠàþŒŒàþ‘‘àý¦¦àþ¡¡àþ••àþ‡‡àþ‚‚àþ€€àþ€€àþ‚‚àþàþ€€Ýþ‚‚Äþ‡‡mþ‰‰ ŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽ( @ €þ‘‘HþŒŒÂþˆˆÞþ||ßþzzßþ{{ßþ||ßþ}}ßþßþ‹‹ßþ˜˜ßþ’’ßþ‰‰ßþ††ßþ‰‰ßþŒŒßþ••ßþ¦¦ßþ››ßþßþßþŒŒßþŽŽßþ  ßþššßþŠŠßþƒƒßþ‚‚ßþ††ßþ‚‚Ýý„„¾ûŽŽBþ””Âþÿÿˆˆÿÿ€€ÿÿ~~ÿÿ€€ÿÿÿÿ€€ÿÿ„„ÿÿ‘‘ÿþ¤¤ÿÿššÿÿŒŒÿÿ‹‹ÿÿ‘‘ÿÿ‘‘ÿÿ••ÿþ§§ÿÿ¢¢ÿÿ••ÿÿÿÿ••ÿÿ——ÿþ¤¤ÿÿ’’ÿÿ‰‰ÿÿ††ÿÿ‡‡ÿÿ““ÿÿŠŠÿÿÿýšš¾þŒŒÞÿ””ÿþ––ÿÿ‡‡ÿÿ……ÿÿŽŽÿÿ……ÿÿƒƒÿÿ††ÿÿÿÿššÿþ¤¤ÿÿ””ÿÿ‘‘ÿÿÿÿœœÿÿ™™ÿÿ§§ÿþ¬¬ÿÿ  ÿÿ¦¦ÿÿÿÿ¤¤ÿÿ££ÿÿ’’ÿÿ‘‘ÿÿ‹‹ÿÿ‹‹ÿÿ––ÿþÿþœœÿþŒŒÝþ€€ßÿ‡‡ÿÿ––ÿÿ––ÿÿÿÿ––ÿÿ‰‰ÿÿ‡‡ÿÿˆˆÿÿŒŒÿÿ””ÿÿ¥¥ÿÿ  ÿÿ——ÿÿÿÿ¦¦ÿÿ¡¡ÿÿ­­ÿþ»»ÿÿ¯¯ÿþµµÿÿ««ÿþ¶¶ÿÿ££ÿÿ››ÿÿŸŸÿÿ’’ÿÿ’’ÿÿ¡¡ÿý²²ÿÿ››ÿþŒŒßþ}}ßÿ‚‚ÿÿ‹‹ÿþŸŸÿþ¦¦ÿÿ——ÿÿŒŒÿÿ‹‹ÿÿ‘‘ÿÿ’’ÿÿ””ÿÿ¢¢ÿþ¬¬ÿÿ¢¢ÿÿ  ÿÿ°°ÿÿ±±ÿÿ³³ÿþÃÃÿúÏÏÿûÎÎÿþÂÂÿþ»»ÿÿªªÿþªªÿÿŸŸÿÿ˜˜ÿÿžžÿþ©©ÿÿžžÿÿ””ÿþ’’ßþ~~ßÿ‰‰ÿÿ““ÿþŸŸÿþ±±ÿÿ¢¢ÿÿ““ÿÿÿÿššÿÿ  ÿÿ˜˜ÿÿ  ÿþ´´ÿþµµÿÿ©©ÿÿ±±ÿþÁÁÿþÃÃÿý××ÿÑðóÿÅîóÿïäåÿýÌÌÿþ½½ÿÿ³³ÿÿ¥¥ÿÿ§§ÿþ¬¬ÿÿÿÿ‘‘ÿÿ‹‹ÿþ††ßþ~~ßÿ‡‡ÿÿÿÿ’’ÿþ¡¡ÿþ©©ÿÿœœÿÿ––ÿÿššÿÿ§§ÿÿ¡¡ÿÿ¤¤ÿÿ³³ÿþÀÀÿÿ¶¶ÿþ¿¿ÿþÊÊÿýÙÙÿúêêÿÇøûÿc×óÿ£íøÿøååÿþÎÎÿþ¼¼ÿÿ´´ÿþ»»ÿÿ¦¦ÿÿ——ÿÿ’’ÿÿŒŒÿþ††ßþßÿ„„ÿÿˆˆÿÿÿÿ””ÿÿ££ÿþ­­ÿÿŸŸÿÿžžÿÿªªÿþ´´ÿÿ¬¬ÿÿ³³ÿþÂÂÿþÉÉÿþÎÎÿþÚÚÿûëëÿ×õùÿqÆáÿ3jÿnÃÜÿßòõÿýààÿþÎÎÿþÆÆÿÿµµÿÿ¦¦ÿÿ  ÿÿŸŸÿÿ‘‘ÿþ‰‰ßþ……ßÿ††ÿÿŠŠÿÿÿÿ““ÿÿ››ÿÿ¬¬ÿþ´´ÿÿ©©ÿÿ¬¬ÿþ½½ÿÿ¹¹ÿþÂÂÿÿÈÈÿýÚÚÿùææÿïóóÿäûûÿ¬öûÿ3e‚ÿ ÿ2b}ÿ¶ôúÿïööÿ÷êêÿøÚÛÿþÂÂÿþ¶¶ÿþ©©ÿÿššÿÿ’’ÿþ‘‘ßþ’’ßÿ‹‹ÿÿŽŽÿÿÿÿÿÿÿÿ¬¬ÿþ¿¿ÿÿ¶¶ÿþ»»ÿþÃÃÿþÍÍÿþÎÎÿþÛÛÿûêêÿÀëöÿr»Üÿ{ÓâÿP¢µÿLfÿ ÿG_ÿR¡´ÿ‘Õãÿ¨êôÿ¯ãñÿú××ÿþººÿÿ¨¨ÿÿ¡¡ÿÿ¡¡ÿþ¤¤ßþ¡¡ßÿ˜˜ÿÿ““ÿÿššÿÿ¨¨ÿÿ©©ÿÿ««ÿÿ¹¹ÿþÉÉÿþÎÎÿþÓÓÿýÞßÿýááÿûîîÿìùúÿìöÿ,Vuÿ.@ÿ ÿÿÿÿ ÿBTÿ)Rmÿ|ÂÜÿöããÿþÄÄÿþ»»ÿþ´´ÿþ§§ÿþššßþššßþ¥¥ÿÿ¢¢ÿÿ  ÿÿ¨¨ÿþ¹¹ÿÿ¹¹ÿþÆÆÿüÚÚÿæìîÿóññÿòõõÿðøøÿëüüÿºóùÿL«ÿ%3ÿÿÿÿÿÿÿÿ'4ÿ‰ÓßÿììîÿþÎÎÿÿ··ÿÿ©©ÿÿššÿþ““ßþ‘‘ßÿ››ÿþ®®ÿþ´´ÿÿ°°ÿÿ¼¼ÿþÎÎÿþÕÕÿõîïÿ•îûÿ—è÷ÿæöÿ™èõÿ²ûýÿ}Úåÿ3Fÿÿÿÿÿÿÿÿÿ ÿ6gÿÂßëÿþÐÐÿÿ¸¸ÿÿ««ÿÿ¢¢ÿþ  ßþ››ßÿžžÿÿªªÿþ½½ÿþÂÂÿþÌÌÿýÙÙÿúììÿæúûÿŒîùÿ3sœÿ#Onÿ&IgÿG¡·ÿ5£µÿ ÿÿÿÿÿÿÿÿÿÿ-UfÿÐèîÿýÕÕÿþ¾¾ÿþ²²ÿÿ££ÿþ››ßþššßÿ¨¨ÿþ··ÿþÈÈÿüÛÛÿûååÿ÷ððÿÚùûÿ’ðúÿJ³Ðÿ.ÿÿÿ  ÿ3XÿÿÿÿÿÿÿÿÿÿÿEiyÿäëîÿþÒÒÿÿ»»ÿÿ©©ÿÿ  ÿþ˜˜ßþ¤¤ßÿ°°ÿùÐÐÿéììÿÁîòÿ¹õùÿ¯øýÿ}æøÿ6}¤ÿ-Eÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ',ÿ—ÉÐÿ÷îîÿþÒÒÿþ¿¿ÿþ¸¸ÿÿ°°ÿþ¦¦ßþ¤¤ßÿ°°ÿùÐÐÿéììÿÁîòÿ¹õùÿ¯øýÿ}æøÿ6|£ÿ,Eÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ',ÿ—ÉÐÿöîîÿþÒÒÿþ¿¿ÿþ¸¸ÿÿ°°ÿþ¦¦ßþššßÿ¨¨ÿþ··ÿþÈÈÿüÛÛÿûååÿ÷ððÿÙúûÿ’ïúÿJ³Ðÿ-ÿÿÿ  ÿ2WÿÿÿÿÿÿÿÿÿÿÿEiyÿäëïÿþÒÒÿÿ»»ÿÿ©©ÿÿ  ÿþ˜˜ßþ››ßÿžžÿÿªªÿþ½½ÿþÂÂÿþÌÌÿýÙÙÿúììÿæúûÿŒîùÿ3r›ÿ#Nmÿ&HfÿG ·ÿ5¢µÿ ÿÿÿÿÿÿÿÿÿÿ-UfÿÐèîÿýÕÕÿþ¿¿ÿþ²²ÿÿ££ÿþ››ßþ‘‘ßÿ››ÿþ®®ÿþ´´ÿÿ°°ÿÿ¼¼ÿþÍÍÿþÕÕÿõïïÿ•îûÿ–è÷ÿŒåöÿ™çõÿ²ûýÿ}Ùåÿ2Fÿÿÿÿÿÿÿÿÿ ÿ5gÿÂßëÿþÐÐÿÿ¸¸ÿÿ««ÿÿ¢¢ÿþ  ßþššßþ¥¥ÿÿ££ÿÿ  ÿÿ¨¨ÿþ¹¹ÿÿ¹¹ÿþÆÆÿüÚÚÿæíîÿòññÿòõõÿðøøÿëüüÿºóùÿLªÿ$3ÿÿÿÿÿÿÿÿ'4ÿ‰ÒßÿììîÿþÎÎÿÿ··ÿÿ¨¨ÿÿššÿþ““ßþ¡¡ßÿ˜˜ÿÿ““ÿÿššÿÿ¨¨ÿÿ©©ÿÿ««ÿÿ¹¹ÿþÉÉÿþÎÎÿþÔÔÿýßßÿýááÿûîîÿìùúÿìöÿ,Vuÿ-@ÿ ÿÿÿÿ ÿASÿ)Qlÿ|ÂÜÿöããÿþÄÄÿþººÿþ´´ÿþ¦¦ÿþššßþ’’ßÿ‹‹ÿÿÿÿžžÿÿÿÿÿÿ¬¬ÿþ¾¾ÿÿ¶¶ÿþ»»ÿþÃÃÿþÍÍÿþÎÎÿýÛÛÿûêêÿ¿ëöÿr»ÜÿzÒâÿO¡µÿLeÿ ÿG_ÿR ³ÿ‘Õãÿ¨éôÿ®ãñÿú××ÿþººÿÿ¨¨ÿÿ¡¡ÿþ¡¡ÿý¤¤ßþ……ßÿ††ÿÿŠŠÿÿÿÿ““ÿÿ››ÿÿ¬¬ÿþ´´ÿÿ©©ÿÿ¬¬ÿþ½½ÿÿ¹¹ÿþÂÂÿÿÈÈÿýÚÚÿùææÿîóóÿäûûÿ¬öûÿ3e‚ÿ ÿ2a}ÿ¶ôúÿîööÿ÷êêÿøÚÛÿþÂÂÿþ¶¶ÿþ©©ÿÿššÿÿ’’ÿþ‘‘ßþßÿ„„ÿÿˆˆÿÿÿÿ””ÿÿ££ÿþ­­ÿÿŸŸÿÿžžÿÿªªÿþ´´ÿÿ¬¬ÿÿ³³ÿþÂÂÿþÉÉÿþÎÎÿþÚÚÿûëëÿ×õùÿpÆàÿ2iÿmÂÛÿßòõÿýààÿþÎÎÿþÆÆÿÿµµÿÿ¦¦ÿÿ  ÿÿŸŸÿÿ‘‘ÿþ‰‰ßþ~~ßÿ‡‡ÿÿŽŽÿÿ’’ÿþ  ÿþ©©ÿÿœœÿÿ––ÿÿššÿÿ§§ÿÿ¡¡ÿÿ¤¤ÿÿ³³ÿþÀÀÿÿ¶¶ÿþ¿¿ÿþÊÊÿýÙÙÿúêêÿÇøûÿc×óÿ£íøÿøåæÿþÎÎÿþ¼¼ÿÿ´´ÿþ»»ÿÿ¦¦ÿÿ——ÿÿ’’ÿÿŒŒÿþ††ßþ~~ßÿ‰‰ÿÿ““ÿþŸŸÿþ±±ÿÿ¢¢ÿÿ““ÿÿÿÿššÿÿ  ÿÿ˜˜ÿÿ  ÿþ´´ÿþµµÿÿ©©ÿÿ±±ÿþÁÁÿþÃÃÿý××ÿÑðóÿÅîóÿïäåÿýÌÌÿþ½½ÿÿ³³ÿÿ¥¥ÿÿ§§ÿþ¬¬ÿÿÿÿ‘‘ÿÿ‹‹ÿþ††ßþ}}ßÿ‚‚ÿÿ‹‹ÿþŸŸÿþ¦¦ÿÿ——ÿÿÿÿ‹‹ÿÿ‘‘ÿÿ’’ÿÿ””ÿÿ¢¢ÿþ¬¬ÿÿ¢¢ÿÿ  ÿÿ°°ÿÿ±±ÿÿ³³ÿþÃÃÿúÏÏÿûÎÎÿþÂÂÿþ»»ÿÿªªÿþªªÿÿŸŸÿÿ˜˜ÿÿžžÿþ©©ÿÿžžÿÿ””ÿþ’’ßþ€€ßÿ‡‡ÿÿ––ÿÿ••ÿÿÿÿ––ÿÿ‰‰ÿÿ‡‡ÿÿˆˆÿÿŒŒÿÿ””ÿÿ¥¥ÿÿ  ÿÿ——ÿÿÿÿ§§ÿÿ¡¡ÿÿ­­ÿþ»»ÿÿ¯¯ÿþµµÿÿ««ÿþ¶¶ÿÿ££ÿÿ››ÿÿŸŸÿÿ’’ÿÿ’’ÿþ¡¡ÿý²²ÿÿ››ÿþŒŒßþŒŒÞÿ””ÿþ––ÿÿ‡‡ÿÿ……ÿÿŽŽÿÿ……ÿÿƒƒÿÿ††ÿÿÿÿššÿþ¤¤ÿÿ””ÿÿ‘‘ÿÿÿÿœœÿÿ™™ÿÿ§§ÿþ¬¬ÿÿ  ÿÿ¦¦ÿÿÿÿ¤¤ÿÿ££ÿÿ““ÿÿ‘‘ÿÿ‹‹ÿÿ‹‹ÿÿ––ÿþÿþœœÿþÜþ••Ãþÿÿˆˆÿÿ€€ÿÿ~~ÿÿ€€ÿÿÿÿ€€ÿÿ„„ÿÿ‘‘ÿþ¤¤ÿÿššÿÿŒŒÿÿ‹‹ÿÿ‘‘ÿÿ‘‘ÿÿ••ÿÿ§§ÿÿ¢¢ÿÿ••ÿÿÿÿ••ÿÿ——ÿþ¤¤ÿÿ’’ÿÿ‰‰ÿÿ††ÿÿ‡‡ÿÿ““ÿÿŠŠÿÿÿþšš¾ûJþÃþ‰‰Þþ||ßþzzßþ{{ßþ||ßþ}}ßþßþ‹‹ßþ˜˜ßþ’’ßþ‰‰ßþ††ßþ‰‰ßþŒŒßþ••ßþ¦¦ßþ››ßþßþßþŒŒßþŽŽßþ  ßþššßþŠŠßþƒƒßþ‚‚ßþ††ßþ‚‚Ýÿ„„ÀþE(  @þ““¢þ……Þþ}}ßþ~~ßþ‰‰ßþ˜˜ßþ‹‹ßþŽŽßþœœßþ››ßþ””ßþššßþ‘‘ßþ††ßþŠŠÞþŸþŒŒÞÿ‘‘ÿÿÿÿ‡‡ÿÿ‹‹ÿÿœœÿÿ˜˜ÿÿžžÿÿ¥¥ÿþ®®ÿÿªªÿÿ¦¦ÿÿ˜˜ÿÿÿÿŸŸÿþ––Þþƒƒßÿ——ÿþ¡¡ÿÿÿÿ––ÿÿÿÿ¬¬ÿÿ¬¬ÿþ»»ÿñÔÕÿçÖØÿý½½ÿÿ©©ÿÿ¢¢ÿÿÿþŽŽßþƒƒßÿÿÿŸŸÿÿ  ÿÿ££ÿÿªªÿþ¹¹ÿþÄÄÿûÛÛÿ»Ýæÿy¼ÑÿíÞàÿþÃÃÿþ¯¯ÿÿššÿþŒŒßþŠŠßÿ‘‘ÿÿœœÿÿ°°ÿÿ´´ÿþÁÁÿþÎÎÿèáäÿ­ÔßÿSŠšÿ!=Mÿ˜ÅÏÿÎÛâÿúÂÂÿÿ¥¥ÿþššßþœœßÿžžÿÿ««ÿþ¼¼ÿõÖÖÿñååÿïððÿžÍÙÿ:Iÿ ÿÿ$ÿY†—ÿîÔ×ÿþ²²ÿþžžßþ››ßþ±±ÿþÀÀÿûÚÚÿ¼èðÿe¥ºÿm®¾ÿ8kyÿÿÿÿÿ*@JÿÛÑÖÿþµµÿþ¡¡ßþ¨¨ßöÍÍÿÝçéÿ¼ìôÿR’¨ÿ ÿÿÿÿÿÿÿD[aÿìÙÛÿþ¸¸ÿþ¥¥ßþ¨¨ßöÍÍÿÝçéÿ¼ìôÿQ’¨ÿ ÿÿÿÿÿÿÿD[aÿìÙÛÿþ¸¸ÿþ¥¥ßþ››ßþ±±ÿþÀÁÿûÚÚÿ¼èðÿe¤ºÿm®½ÿ8kyÿÿÿÿÿ)@JÿÛÑÖÿþµµÿþ¡¡ßþœœßÿžžÿÿ¬¬ÿþ¼¼ÿõÖ×ÿñååÿïððÿžÍØÿ:Iÿ ÿÿ$ÿY…—ÿîÕ×ÿþ²²ÿþßþŠŠßÿ‘‘ÿÿœœÿÿ°°ÿÿ´´ÿþÂÂÿþÎÎÿèáåÿ¬ÔßÿSŠšÿ!=Mÿ—ÄÏÿÍÛâÿúÂÂÿÿ¥¥ÿþššßþƒƒßÿÿÿŸŸÿÿ  ÿÿ¢¢ÿÿªªÿþ¹¹ÿþÄÄÿûÛÛÿ»Ýæÿy¼ÑÿìÞàÿþÃÃÿþ¯¯ÿÿššÿþŒŒßþƒƒßÿ——ÿþ¡¡ÿÿÿÿ––ÿÿÿÿ¬¬ÿÿ¬¬ÿþ»»ÿñÔÕÿçÖØÿý½½ÿÿ©©ÿÿ¢¢ÿÿÿþŽŽßþŒŒÞÿ‘‘ÿÿÿÿ‡‡ÿÿ‹‹ÿÿœœÿÿ˜˜ÿÿžžÿÿ¥¥ÿþ®®ÿÿªªÿÿ¦¦ÿÿ˜˜ÿÿÿÿŸŸÿþ––Þý””£þ……Þþ}}ßþ~~ßþ‰‰ßþ™™ßþ‹‹ßþŽŽßþœœßþ››ßþ””ßþššßþ‘‘ßþ††ßþŠŠÞÿ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}fractalnow-0.8.1/gui/icons/icon.xpm0000664000175000017500000001550411764667445015732 0ustar mpegmpeg/* XPM */ static char * icon_xpm[] = { "32 32 297 2", " c None", ". c #8D8DFF", "+ c #8989FF", "@ c #7C7CFF", "# c #7B7BFF", "$ c #7E7EFF", "% c #8181FF", "& c #8C8CFF", "* c #9898FF", "= c #9292FF", "- c #8787FF", "; c #8888FF", "> c #9595FF", ", c #A7A7FE", "' c #9B9BFF", ") c #8F8FFF", "! c #9090FF", "~ c #8E8EFF", "{ c #A1A1FE", "] c #8A8AFF", "^ c #8383FF", "/ c #8282FF", "( c #8585FF", "_ c #9696FE", ": c #9E9EFE", "< c #8080FF", "[ c #7F7FFF", "} c #8484FF", "| c #A4A4FE", "1 c #8B8BFF", "2 c #9191FF", "3 c #9494FF", "4 c #A2A2FF", "5 c #9D9DFF", "6 c #9797FF", "7 c #8686FF", "8 c #9393FF", "9 c #9B9BFE", "0 c #9A9AFF", "a c #A5A5FE", "b c #A8A8FF", "c c #ACACFE", "d c #9F9FFF", "e c #A6A6FF", "f c #9C9CFF", "g c #A5A5FF", "h c #A3A3FF", "i c #9696FF", "j c #9D9DFE", "k c #9C9CFE", "l c #A6A6FE", "m c #A0A0FF", "n c #A7A7FF", "o c #A1A1FF", "p c #ADADFF", "q c #BBBBFE", "r c #AFAFFF", "s c #B4B4FE", "t c #ABABFF", "u c #B6B6FE", "v c #9F9FFE", "w c #B2B2FD", "x c #7D7DFF", "y c #A0A0FE", "z c #B1B1FE", "A c #B1B1FF", "B c #B2B2FF", "C c #C3C3FE", "D c #D0D0FA", "E c #CECEFD", "F c #C2C2FF", "G c #AAAAFF", "H c #ABABFE", "I c #A9A9FE", "J c #B2B2FE", "K c #B5B5FE", "L c #A9A9FF", "M c #C1C1FE", "N c #D7D7FF", "O c #F4F0D0", "P c #F4EFC3", "Q c #E6E5F1", "R c #CBCBFD", "S c #BDBDFE", "T c #A4A4FF", "U c #ADADFE", "V c #AAAAFE", "W c #9999FF", "X c #B3B3FE", "Y c #C0C0FE", "Z c #B6B6FF", "` c #BEBEFE", " . c #CACAFE", ".. c #D9D9FE", "+. c #EBEBFC", "@. c #FDFAC7", "#. c #F5DA5F", "$. c #FAEFA4", "%. c #E6E7FA", "&. c #CECEFE", "*. c #BBBBFF", "=. c #B4B4FF", "-. c #BCBCFE", ";. c #9E9EFF", ">. c #ACACFF", ",. c #B3B3FF", "'. c #C2C2FE", "). c #C9C9FE", "!. c #DADAFE", "~. c #EBEBFD", "{. c #FAF6D9", "]. c #E1C670", "^. c #8E672F", "/. c #DBC06A", "(. c #F7F4E1", "_. c #E0E0FF", ":. c #C6C6FE", "<. c #B5B5FF", "[. c #B9B9FF", "}. c #C8C8FE", "|. c #E6E6FA", "1. c #F6F6F0", "2. c #FDFDE8", "3. c #FFFAAE", "4. c #836530", "5. c #040003", "6. c #7E6230", "7. c #FFF9B8", "8. c #F8F8F2", "9. c #EBECFA", "0. c #DBDBFA", "a. c #C1C1FF", "b. c #BFBFFE", "c. c #BABAFF", "d. c #CDCDFE", "e. c #DBDBFE", "f. c #EAEAFD", "g. c #F6EBC0", "h. c #DDBC72", "i. c #E3D37B", "j. c #B6A250", "k. c #634A1B", "l. c #040005", "m. c #5C461B", "n. c #B4A051", "o. c #E5D793", "p. c #F8EDA7", "q. c #F2E3AD", "r. c #D7D7FC", "s. c #A2A2FE", "t. c #CECEFF", "u. c #D4D4FE", "v. c #DEDEFE", "w. c #E1E1FE", "x. c #EEEEFC", "y. c #FAFBEF", "z. c #FAEF9D", "A. c #775628", "B. c #3C2912", "C. c #0F0805", "D. c #030101", "E. c #010101", "F. c #020101", "G. c #0B0504", "H. c #53401A", "I. c #6E5226", "J. c #DDC27C", "K. c #E5E5F9", "L. c #C3C4FF", "M. c #B9B9FE", "N. c #C5C5FE", "O. c #DADAFC", "P. c #EFEDE6", "Q. c #F2F3F4", "R. c #F5F6F4", "S. c #F9F9F2", "T. c #FDFDED", "U. c #FBF5BC", "V. c #AD904C", "W. c #31230F", "X. c #000000", "Y. c #E1D489", "Z. c #F0EFEE", "`. c #CDCDFF", " + c #B7B7FF", ".+ c #AFAFFE", "++ c #BCBCFF", "@+ c #D5D5FE", "#+ c #EFEFF6", "$+ c #FBEF95", "%+ c #F8EA95", "&+ c #F8E78D", "*+ c #F7E998", "=+ c #FFFFB5", "-+ c #E7DC7E", ";+ c #443018", ">+ c #070402", ",+ c #806834", "'+ c #EEE1C2", ")+ c #D1D2FF", "!+ c #B8B8FF", "~+ c #CBCBFE", "{+ c #ECECFB", "]+ c #FBFCEA", "^+ c #FCF18C", "/+ c #9D742F", "(+ c #6A4B20", "_+ c #634523", ":+ c #BBA547", "<+ c #B6A435", "[+ c #0C0606", "}+ c #64532A", "|+ c #F1EAD0", "1+ c #D5D6FF", "2+ c #C8C8FF", "3+ c #DBDCFE", "4+ c #E6E6FD", "5+ c #F1F1FB", "6+ c #FCFBDC", "7+ c #FFF492", "8+ c #D3B44B", "9+ c #2C1B0F", "0+ c #201509", "a+ c #563212", "b+ c #010001", "c+ c #786944", "d+ c #F2EEE6", "e+ c #B0B0FF", "f+ c #D1D1F9", "g+ c #EEEEE8", "h+ c #F2EEBE", "i+ c #F9F4B6", "j+ c #FEF9AE", "k+ c #FAE77B", "l+ c #A27A32", "m+ c #3F2715", "n+ c #030102", "o+ c #060308", "p+ c #2D2710", "q+ c #D4CD99", "r+ c #F1F1FA", "s+ c #D2D2FE", "t+ c #B8B8FE", "u+ c #B0B0FE", "v+ c #D1D0F9", "w+ c #F2EEBF", "x+ c #F9F5B6", "y+ c #A27B32", "z+ c #402715", "A+ c #070308", "B+ c #2C2710", "C+ c #D3CC99", "D+ c #C7C7FF", "E+ c #D3B54B", "F+ c #211509", "G+ c #573212", "H+ c #786943", "I+ c #F2EEE5", "J+ c #ECECFC", "K+ c #9E742F", "L+ c #6B4C20", "M+ c #644623", "N+ c #BCA648", "O+ c #F9EA95", "P+ c #F8E88D", "Q+ c #F7E999", "R+ c #FFFFB6", "S+ c #453018", "T+ c #816934", "U+ c #EEE2C2", "V+ c #F2F3F5", "W+ c #F5F5F4", "X+ c #F9F9F3", "Y+ c #FDFDEE", "Z+ c #AE904C", "`+ c #CDCEFF", " @ c #3C2A12", ".@ c #100805", "+@ c #0C0504", "@@ c #53411B", "#@ c #6F5226", "$@ c #C3C3FF", "%@ c #DEBC72", "&@ c #E3D47B", "*@ c #B7A350", "=@ c #634B1B", "-@ c #5D471B", ";@ c #B5A152", ">@ c #F8EDA8", ",@ c #E1C770", "'@ c #8F682F", ")@ c #DBC16B", "!@ c #EAEBFD", "~@ c #F6DA60", "{@ c #F4EFC4", "]@ c #AEAEFF", "^@ c #A8A8FE", " . + @ # # @ $ % & * = + - ; & > , ' ) ! . ~ { ' ] ^ / - / ( ", "_ : ; < $ [ [ < } ! | ' & 1 2 2 3 , 4 > 5 > 6 | = + 7 - 8 ] ) 9 ", "& > 6 - ( . ( ^ 7 & 0 a 3 ! 5 5 * b c d e f g h = 2 1 1 i j k . ", "[ 7 6 i ~ i + - ; 1 3 l m i 5 n o p q r s t u h ' v 2 2 { w ' & ", "x / 1 y , 6 & 1 2 = 8 4 c o m z A B C D E F q G H d 6 d I d 3 8 ", "$ + 8 y J 4 = ! 0 m * m K u L A M C N O P Q R S s T n U 5 2 ] 7 ", "[ - ) = m V f > W n o T X Y Z ` ...+.@.#.$.%.&.*.=.-.e 6 = & 7 ", "< } ; & 8 h U d ;.G s >.,.'.).&.!.~.{.].^./.(._.&.:.<.g m m ! + ", "( 7 ] ! 8 ' U K L >.S [.'.}.!.|.1.2.3.4.5.6.7.8.9.0.a.K L 0 = 2 ", "8 1 ~ ;.5 f t b.Z c.C d.&.e.f.g.h.i.j.k.l.m.n.o.p.q.r.[.b o o a ", "s.* = 0 b L t [.).t.u.v.w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.L.q K , ' ", "0 a h d b M.[.N.O.P.Q.R.S.T.U.V.W.X.X.X.X.X.X.X.W.Y.Z.`. +b 0 8 ", "! 0 .+s r ++d.@+#+$+%+&+*+=+-+;+X.X.X.X.X.X.X.X.>+,+'+)+!+t 4 m ", "' ;.L S '.~+..{+]+^+/+(+_+:+<+[+X.X.X.X.X.X.X.X.X.}+|+1+` J h ' ", "0 b +2+3+4+5+6+7+8+9+X.X.0+a+b+X.X.X.X.X.X.X.X.X.c+d+)+c.b d 6 ", "T e+f+g+h+i+j+k+l+m+n+X.X.b+o+X.X.X.X.X.X.X.X.X.p+q+r+s+b.t+u+b ", "T e+v+g+w+x+j+k+y+z+n+X.X.b+A+X.X.X.X.X.X.X.X.X.B+C+r+s+b.t+u+b ", "0 b +D+3+4+5+6+7+E+9+X.X.F+G+b+X.X.X.X.X.X.X.X.X.H+I+)+c.b d 6 ", "' ;.L S M ~+..J+]+^+K+L+M+N+<+[+X.X.X.X.X.X.X.X.X.}+|+1+` J h ' ", "! 0 .+s r ++d.@+#+$+O+P+Q+R+-+S+X.X.X.X.X.X.X.X.>+T+U+)+!+t 4 m ", "0 a h d b M.[.N.O.P.V+W+X+Y+U.Z+W.X.X.X.X.X.X.X.W.Y.Z.`. +b 0 8 ", "s.* = 0 b L t [.).`+u.v.w.x.y.z.A. @.@n+E.D.+@@@#@J.K.$@q K , ' ", "8 1 ~ ;.5 f t b.Z c.C d.&.e.f.g.%@&@*@=@l.-@;@o.>@q.r.c.b o o a ", "( 7 ] ! 8 ' U K L >.S [.'.}.!.|.1.2.3.4.5.6.7.8.9.0.M K L 0 = 2 ", "< } ; & 8 h U d ;.G s >.,.'.).&.!.~.{.,@'@)@(._.&.:.<.g m m 2 + ", "[ ; ) = m V f > W n o T X Y Z ` ...!@@.~@$.%.&.*.=.-.e 6 = & 7 ", "$ + 8 y J 4 = ! 0 m * m K u L A M C N O {@Q R S s T n U 5 2 ] - ", "x / 1 y , 6 & 1 2 = 8 4 c o m z A B C D E F q L H d 6 ;.I d 3 8 ", "[ - 6 i ~ i + - ; 1 3 l m i 5 n o p q ]@s t u h ' v 2 2 { w ' & ", "& > 6 - ( . ( ^ 7 & 0 | 3 ! 5 f * b c d e f g h = 2 1 1 i j k . ", "_ : ; < $ [ [ < } ! | ' & 1 2 2 3 , 4 > 5 > 6 | = + 7 - 8 ] ) 9 ", " . + @ # # @ $ % 1 * = + - ; & > ^@' ) ! . ~ { ' ] ^ / - / } "}; fractalnow-0.8.1/gui/icons/icon192x192.png0000664000175000017500000012120311764667445016564 0ustar mpegmpeg‰PNG  IHDRÀÀRÜlgAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAgÀÀÏÀtó€IDATxÚìýw°-ÙuÞ þöÎÌãÏ=×=ÿê•yå ª Þ’D‚´Ôr-3RS-3¡˜è!¦¢G­ÑÄŒzf¤I”D©)‘)‘@´A€(˜ʽzUõêywýñ'Íž?V®Ì |[£A§ÝvA­†ÙÙÁ q ÎA’È÷?ÌÃùÒŸ‹ßËÿ°6ÿ›1ò»µàûÐn;º]! a8̯½êsßÈ=¯¡|­‹~Ökµ<šMhµµš¼Æó Õ‚µµ˜ÉÄpû¶e4’ë‰"ˆc˜L Q$×™$ò>çò/=ý|н”ÇÐód;ÇÊ ¬­% ‡†7 £‘\‡žß󳙌ótjæÆ±êúÊÇ!ÿç€  £ß7†×Œá£ÀçW<“ëÿïÿ{³ï\~ñ—òOú}¨?ây¼ øà4`¬•×Õër €éTDqàþ°&A•ñæÁUúðêuù}21ÙÃ-> ýÌZÍÇòðîôP2þÃ\›þßZ‡µ¹q;'ãkŒ‡µ0™Àl–|yòê¤-žsÕÿ[4ñ‹ãPuݳ™,":n€C -Iä}ƒÜKñ<‹®ï°cZº4 /kÃàí€3†Ï9Ç/wŽgþÞßsÉßù;` 'Ï&À§?ñ¹ÏÀu<$  èÄ÷åfåæ a¸øáþA&ÁVüâχ™zD ‡2quEÓkÕëõ<¹Gß—Bè¹î;]{ùºu§ ³ÙüÎàœc2‘kŽã|GÒïU¥ç,~^ñ÷âÿËÏéN»¬µ²SÕë°µeÙÝ• Ç&{]¾;1g#Åk-~þáÙU¢Èdì€É vþ¶ôëÏÃÿË9~êïÿ}ÆÅ×Zýáïèc ÷ÿÒóø[ÖÒ+>k妗—I"+ÓlVmÅíýÅUç+]E½&Š`<6 ‡çdo4ž7¿Å,-9 Y‘õ^ª®¯êz«Œè0ã FE¹Éï&g½Ö;¹U×V¼G=Ï¢{¨rÓôKÝ/ßÏw¡éTŒ}8„~_¾Fòº¢Û³hlîô•»°2 ]û÷ý°µü?¬åsŽÕðò³ÿï;~ñ{NÇý߃Àüçáùþü`4âÌffßÖ»h ‹{ÐÃ:èTÑAÿ¯ú¼Ü`ĨÛmT½Gß—{lµäÿ“ €™[ùº‡ò羑¸¥ê:õË÷]vmâzºÊÏ:¤!P¯ËWœø‹Æ¿¼êWÈøììèd5Y Rüª²‘ƒÆ«ê~Š1\È÷âµV]wÑö¬•8ªÙ¤áûüÏãuŽöOÿ´¬ÜêÕ/]2YZrßßí:ú}ƒµnnk«×õz>»‹~•Zõ€Z ïd\‡=Oùuå×&‰ø¯Aµıl«ÎÉhÓ©ÈÅ•ïN×Є¬ºî;Ý›sù «.>âgÞÉ(K£Iâ˜ÍL¥A–ß#n¯, qlð}—ÅQah˜NçݱâÎt¸Pö髯ªx ú¼‚@ÜBt= ý G³).mñ_yŸNù'@ìÿÿ£Ã9~x:å/÷ûxÝ.¬¯»ôÆÄÖ$x¬BFªnh‘z˜ã0«mù†z­þÇ&E'Éð<¹/c Ù”ûçwÑÃ:̵/òûïtíz¨ ê®9Œ1sÁ¦•ºGåCVP1‚f3w_Ã;ˆ¶ZEr µìîšl,>ë;´‹òEŸ¯èX£áh·åz‡CYÄŠcpÐsŸÍtqsL§&¨ÕÜO¶Ûü$_ôFóvçX CC’8:|0F~ÄõYdüåç ›+‡}ýaƒâòö]å¨Áˆ+$Vv73ç»@.úý+Ù ît.] =O_#±Øl&/ÖçR¼ÞyC0ÙJ˜$rÏQdæbŠò{õý“‰­–Ä€µš <¾/ö’$Õ7S^«Æó Ý@0$ƒ†Ë» ^ùů$1ŒÇÐí:ŽuXËÙÉ„÷¿òJôEßžrŽÑ‹›Í`{º]™1Q¤+ÿ~¨°ê‚¡ ‡1ì;ýïN3½ø÷ÜwTŸÙdÓAõ<DZcŽÍMÃö¶É&xÕ5äf, ïtù®›8<ÏdãÚhÈsh4$.˜LÈ Ñ"Zµh9gˆc—áòUï©rAd¼ a˜/ÖŠAEìîŠKr˜üÂÜŸâï:†:Ñg3—½ç û-Žcñ>4¯2Òù‘~4øE8ãw9'FáœÁ9qΜI¸}Û°»k÷aýÅŸZÁ”7âË/ú[ÕZ+~ªµj Ò|‰ïËjæy¹aL§û¡ÃE“ûN×éy3éjuØû*~v³9DÕëbpIb²I¥ƒ\ }ðéA-ºÇòu们üá¡ß×üˆËâ”Ã<ÃìöU×PD¯Z-‰Ût×)/XU|½.;_­[[²È{ïlµÜÃ>ðáâ…(†å+üæû2ah²×ÁÖÙøF±Ýâ÷¯dÇXìNÈJ§“lù.C(¦S¸}Û0™|_üLÏssþÿaÜ”ªI#—|vq¬¹UU“N¡Ðòï³Yî¦c€ª]ª|=šÃ©Õa˜ïй@EFŒOâ’"úSLÈU"Åq:(·hç2ÆÍ!vÃáüõ•=ß—±×$\­KK7ôû»ÔjÎ6<äßV¼ÑFCVÇá†CK­&+ï‹ÑD‘aåm¨*atÐD(p1^5!ãS !Že¢noËÊïyù ×r_GŽ*2æç:(v˜$ŽeÐ%[Ÿ'‹ªÞWõ{ʃ*úýŠU]OÙË×# $—ð¢8%ßÅd!…‚=/§^r‡ z{T-Ι4(»Pq·+O¸út©Mº]qãG#YØã˜t!wûA@G²{.…˜`oO˜1&Û>Úm™€”/@/¢**_t“‚0å[ë2®wò½‹‡žk:Õ‡mæ|BE3’¶·Mö€‹S &©Šõ ‡&A õµ6>lòªü¹Öʶ/+Ìf.›L‹&jqŒå^óE¬j‡+®¢úžNGVßÙŒÌeœLòIxXNQ•gpÛ\މôõº 4ó fyh,»¼,îÏ` +¿ú,Lš~§ãêÂåÈ·W½P¥ììÈêÓl |hLŽ”Xëð}“Ak‹ ¸ªÔ­U·¶¢áôÞ*÷¡ê(ž»øótjˆ"™€ËËøïîæƒâ+è k›¶äœ !Ë–=ïn £üЫW ÙÊ‹¯_”.»2:ÆåÉVÇüït¶Ûbüí¶cwWü~k÷ÓîäÏ—Éx‡õÿ‹GænMý)~/ò¾ÊI.cÄèvw%‹[Ì{#+ñl&[ð"—¨Êø5+-+ñ<±pQ¬TôaóUÞ¤e’éÔlqqбÕëS AáæâJZå¶„¡¡Ýv¬¬$Xë¼B!ŠËЕE ÏÜ8ae%§NÌï6w~žzBQáÐeô|YqñsŠ…3Öæ“SÉoÎå&ºRª¡(ÿ˘üþ2MåüsàÎT^¬ZΡòÉäÎÏ÷ çX\Äf\6Er%OÊé}i¼óÅCº3j}€Æ c€ÃeÌ? %0®Õë벺lmå«nŽÐ'î4o$¦“pÑ€•ê¡.Š®x²²êuuÙtRï7Øòø•a_qAr®Q»ÐnÃæ¦UMù\—º9!Ô ²:ùlq©¼p&ŠäKK1“‰M+Þ\açžgÈÖë.õ¡Í\R°xMû}ÿÜ¿×ÄÛd²_ î0»oyÜ„Œé²+ID…N];-b*"såÝF†JŽsY £%–>€£œ]S޽L£a²D…¶LÕ+Œ¥nEy€íÐ0œßÑ §‚lok>!ÏÌËNá²,7rëùçYÞtBø‹.j‘Ñ4Š'×TµçÁ±cœ³¼öZ=Ãq•UX\½‹Xm™&pÐ5–¥ ÛmY*ÐY´ ”K¥b|_ŠfŒ‘UNÝ,¥)(1°*©ú …‚ÅŸuY0ZN ŸÈe«]CšlRǰ¼œÐí&4CêµW1¶A \bˆ"Z­I¿ïÑn')¯Hvèé4÷±5PÖ|äŒPÕ‰*’éï7)À¢„4qçqøƒj)ôKÜWA50Þ™Éâ²¢›Ey}zÕÊ_môó¿ÏM€Ã$'’¥+¤®8L´ÛqZƒk°v?²!ï•8a‘æèA¬˜sy±DÑ¿.»B‹&y•[DšyŒ"ͨŠÁ:—+eW¨4Tà)Š ½žË »"N]DŽ&1D5T!|¹Ôý2ı%bê=lü Üø^ã-`¦øÁI¬÷6Œ©cLL¿ï§<oAWZTá3ÐÝ­H¸Ók“RYqÿ¶·…g¤Ä=Ý%ËT›*n‘~õzŽ pܸa3J³¾§ŠÝYõ·Ã¿sà/ PŠF®«kÙÈ«^§¤9•$‰"¸qç^·$‰fYsÿQýl%^íí¾& hXÊŒ"—ù“BtS˜¬ºk‘ñ—'Ál& ™•IñïíɉêõœŽ\|àåó—'‚Ày&+ºYZôEã=rÚ‚Áód•=&—Õ7›ŽfSÇ­ƒ Þ É¯ãv~¼6féG©}<3›5ÓIœdÂXµšË2ÇŸš9¨p0È tºP£j.ëQ ´‡EZC2^òÞ"DcšíˆäïEp¡lÀ‹Œ¿øìÊ¿ÿ c˜—ÄÈ#tq5Ü\^_×hHÚZ|ܼŒÍ9›2@ó¤n¹Zp]$^Ý)(®`¥fŒF.«ñcUµ;œŒžNÌrE”¾F²¥9´&“Îì;Ç¢`½¼hU]­&Of<6Ùê+¯ËÇC’>–n7Ïêj†œ#b` S7y ÏxÞêucü6õ©×|?& ƒT:P®«ÙtÔjŽÍM[B»r|HTqå¶ìÊj¡=¸¹‰¢™Ò±77 Ó©Ä­–,*g²ÈÐËÇþ—¹q‹‚K…ËtõW† p;d¦F‘Ë ¼b2BD“HêËN§âß­®ºTyÂdÔV‘­0•+ô¢£ú5.{PËËiÐyPpž½ßÝbï·?Åø5C}ÝpêÛOâ-½Ó|+ÐŦ“ÐÇ&£H4› `ØÛórE=¥…è}¶Û²8Ñq>iV¤`D‘Ÿî¤ÊRÍû±iIãA+üÜäÃNž©m'Åmþ ‹éÄ\J¼Ê[Ëʨ¼ô\‰AM¯ùâïò5V°¡Š^)i«X/ºèÞM(™Tóba†–Jº4~˜o­ZGɪÕÄЋ Oý Éì:’IJ²’°¼œ°·ç²æ’ôj4b:ç<Œñ0&˜>8…¢ô+ÆÔWh=v’Ùõsl}Üãè÷‡4{ ¯ýà ¦.ÀÚ$¡54› Æ$„¡—¡3 _–9QZ%y ³o±T¯¡ÑU‹íméy ª<žÇ‰ýþüQ4xµ»Eö¢RÕªÕ_&ø0Ç¢UŽ®ÜÊ¥)ûƒjP[[‚w»0ä¤/e*ôZµ*,šÅ•x2}‹Êlû ¨«à»ùóå±´]5¬¬HÞ! %x.®|/q,+g»­y 7ç>埧ò%&u¥ºõ §ƒ£ØŸúž8}…ïÞ¢vä6P3Á¹=à8†6ž7¥VkE¾Ÿày ƒ—.&ƒ;…&m³òGš³H’¼AyþePã ´¦j7…ùI•·œÍr·j‘ÇR¶ŸJô°xûAÇ¢IT¾I]åq˜L,¤,ÄÑ(_A‹4éÃB¢znMZéçt»Ž›7½}¼£â9”Ÿ"Æ8”ߣ«–öît\•û”áÕéÔÒé$iÓ¶\TÔ‹tb“æ%ü48aLø`fÀ-H.€»H´û 7?~ãß÷ µc-¢Ý›4›{lþãÅ—xmë%.Ô<Òxßû'_§}æp÷I&S¢[· Ž¦ÙÆÚÖs´Z0ù™»*à„£ÕÒI‘?K¥ÂëïÊ4-ë¿–Wú2zV¶§"?­È9Óv^Uyžòä*ž{ ºÿƒL5þ*B ÑuÕÛØ€NǤ܉„G´ÿæNÛß“ |škuWrßÝóÌ>ô Þ¤O³”‹‚oùl Ûm)rô)§~ËýjñºÊ“˜´rË¥±IŸc¬uŒÇòx1$‰—>²!†°K¼û ãç?Æp{—É+;Ü~¶Ë‘Ç_$Þ‹yágN3~å~Î_=Ž­màœ£ÙìÒŽkŒ_©±óùËïüá¦aã7F4×|–½ ˜bø3ÛbÃn¸@ÏøäÞ5âÿüßrõßÑx‰Áí6¿w‚{~ƒ v€Æ,ã\ k ­VŒ1²u:3Âvwë…ø%IŸ§*Û>ÛBOƒ¢«Ë8fªúVŒ•W|.õº%Ú§x84ÙâQì[¶Èv«\ç,~#èÇa&Éa&ˆò‰ÊXŠ…Ù*ï]®ÃÍ“Jó™êâkÊ™úÛ“‰cmM• ahöA—‚[‹Íò²›C)Ê“LÝ,ÏãLê)qÎe°i®—iæZY+b·“I€®œòY–V+$ kãam„µ;ˆë3fàlóÝw½®é2øâKÜøå€ü{'E!—÷®ðêíósÛ[¿¿Ã'‡Ïòìöƒð>öþ§§8ÑÑn@ÿù!Áú—h>ø8Æ&€Ã³SêõˆÙ¬N­¾ãy1³Y=£†H¼#@†þ.±ý~ÎÍÒ䘖̪L¤"gú¬ ¨p—O•°>V®ZåúÖfýE«ú"WèN¯¯šUHÙ0ç_#´ë­-‰îµ›»Z²æ“hQ°TÙj÷C•ÖX¤ô¦×­R/Úu°˜äÒY³¸cŒ±t:qÖÈB5{Dq9oÕª»F„ıf_À✇µ3êõ PÃÁ;é¸òô1ÞQ0'ñ×/pÏ‘l F|ñæ‹„auöÐ%1{Ã[üܵßYæ}Çáÿðç.sìû{ØÎÝKÊ'`Lˆ¥—’á"¬ ™NëÌf~6†µZœåTźÑpìîÚŒ! ùäÐ|T+®ü:®yI­òÇȨ×EÁ­"w¨ü¬²ËCO€ÃL‚ªdÔ¢àºl”åW)° oÕjRC°»›os‚Iç«ñtH‹Ÿ©ÅäI"¥wÚBÙ®åI$¯‰—fs¾ÛcqgÒ„Z &ž$>N‚1d*z¯Ý®PŽå^=¢¨F½.«t­–d~±13Œ`Ì2‚óùî¶Ò ì3c²1`óÇݵۜê>Àn¼ˆ[ä¤Ç­íKÔ<ÇãÇ/qßÓ›xëoÃ'ÀE,j&˜„ c’¤s^z2©[­„éÔ0z4›Iª¿£fZq¦;·ópÈÜ‚¦sß—kn4`m-f<‰FÙ©çÇCtÑ‚[5$Ã-2úE¿/ ¢»oH F›ô "ã2j®µ˜V—O.ÂðµÙ´fˆÕ/ñE«Ð¥S´Zâ‡æ-:ó×'˜°(Îl·Š]Í¥\3Î$I$/àáû£B­ôYõ} 1f˜§Ÿ€Ûƹ>†).1xy“ÏüìY®¼<ãõ½ë²úâŒÇÑ™áæo51Ý]VÞ¦ˤ_ƒôþœK0¦¢Q„uÎ¥¼$F#­ShO kÔjžH¶LdÁ’*2ÇÖ–Í’Vå¼øø²kN&6 nK‹®²Ëƒ^ï4;Ê']dÜU¥ƒUÉ«ƒ~¯ú›L“± …k¢]÷×á–Ih%²Ä-‘ nˆ°”º*UÁ´ˆ¬Š“fZ×*+˜K'¦É^?H¥U¯§…,6¥d[Z­ˆ$ñÒàÖ`íÏF`|`Ôr›‡¥4a‚ ÓUˆc„‹ÇxÞ³o½ÆïÞ^æò…ËÀáØ`Ã->zõ~ÚϯpâCÆF87F’ý0]p‡Ã° Æ#¤Äµ‰µ3¤ºÌ§Ñˆ‰c‹±žgYZÊ)Õ½ž\¸Ef_¹¶¤U@awWÜ£|wI¹ˆ}˜U\ä;‰¯A‰¢wÚRªŒÜ÷]Zqeî¸â”¨Z44I¶¶–¤"Qv.í^5±Ôÿ.fb‹_šäRžQq"W³Då­–g»»yà¬N›ƒ0'nh5Ç$NJkµ$…e')ª#h`û£”Ê<SC܇s{Âí1qús 0ÌpL1>¬¼£‡ nrﯷYmccgãP a>ÒçÍö:ÝžÀ¹Ùivp$<C NŠcœë3ŒÙù@Ð)¦±Ë˜N7g™L|‚ÀÇ [[~F 3'óÒéÈøîíööTÂê}Gißá·=pc`K>ËŒ1Ʀ“sÔÀ51ÆbÌL®Åxøþ4½FØÁ&pÎÒn?AvÙÝ ²äˆAk9‰…´õ–Iw÷ýî"Ã^døå×ês’À]]P?¯ÆôÅj)IÊ\Zr)))—>)oYÍܺ´îVw•ü¢··kŒF%6²*+ÅzÿpîùþÞ¶Eºôl&Ÿ;›I’¬Õr© Z>iT *Ž-ËËŽ¥¥„~?w`5¸*ƒKk“êüxéŠ7Ę)¸›¸ø .îcj=Œ‰qn‹ñ«Ÿ"Aç‘·`k'Rc2âò¸=\² fŒ#å3A’b»87`í ¾çÃ{œ»øÿ¿Ñ:·¶nßÁø»|Ç}«üÀ÷†å{{鄺!» !8™táàÓ Ÿö݃9"®‹ }­3AvŽØ%ž~šdçÞê·Ô¾“v{°ìíÙT DÜÏ0„ Á GxÊn•í,R›Óÿ«íìOpš” &_L×[{ç6–‹ü|ÍÂ--åÂÐ¥ÿ;åX}~­P]ãÒºÔ#G’tBØ´¸fÿ5k­ «ŽFnnÈ‹Ì%(^^Î%ùÄ'ÏeÃõ=ê"†¡`üÅæ‰-U*k·ž—0jõTœºKÖI†ŸbðÌÏcW ­Gc¶ÙÇÖûl?û2ñžGç!¡7êH¥×’k\ýä ›8„õÇ´Ž„Ãâpz{f}–×ûüŇŸeó•þEÌ ²?0Ô½&ßÕ[毿éeNœÙ&‡$î5Âé{×»,Ÿ9FÐZ%š Ù»pŽ¿Û侺M}íàÇÚ@=ÝÔZ§8Fö°õ˜ðö9ÜxFpöIêõ%¦Ó:í¶Ë$vÆc›urW:h¡TÃ/BÚj[ÅÉ¢±º«è¡Ï\UÊ[-‡/ôo,‰Põ5¦ím9y·«þ°$.Š«î"H}=”¢¬zQ*»(·bŒ« ^‹R-J”ÒR¸M¤™[L«•0J÷ÅròMãe©¡×‹ç‰`‚ø8Z­ZÍ#Š|¬õ‚ ÖŽÀ…˜ …¿j¸ñ™«4.Übx-a°Wcûb‹‡?<À6nÀ,«}¢ékÜ~ñ~ö£÷sÒîò'ÿÚàMŽ_þWËl¾ÞàýïÚàÒ¥Kch^ƒ÷Œk<Ûþ Ú_æÆW2iw€õ#G8åÞÆ{¦—Ùº°Ëoýë5vƒÁ‘÷,÷ù™>Ìû>ô2âO%ô_˜òÌ?êñüÕ¼yçuÞõëÔúàV ÀŒÓ!Bܱ[ì>÷"»Ï8õÝk`&xÞˆVËKtó]PwSÇ\ûh5\Ùfj5—ö›g•æmºs§lÚÀe¥±½™ Œ¯ÆU 2ªpõ*ºÄÿüŸx©Í¹Ñ€cÏÃÞ‹9zBâ×À1M?NÓÜ%&ýWÙ¾è86jà¯í·¨Õ<&“.Qd³d˜ÒK4nSù•¢èX9Q©:UZó]N‚ê$Ò„§ºÃZo2›‰°ÈÃû&óý­ÊUÆZþ¹h°Ú¦f2ÉÕ~åƒ÷ÆU.Uq;+ºG*Ó"«¿4sèvMJ©˜N*N˜0Ì3ÇÅÿk)ö®­–$©Š1ƒøõ4‹‘‹KæÑéH7EcòûŸ% ƒT­añç•G3½¾ËèÊ„ËWO2Û³\Ãã·ÿQî·7lÔ9?ió>Ç™ombk½ÞEŽ·ÜîÏøìõólíâsíÓ<»5æ¹þ5ÎÓd˜ ˆãç’Ôë¹&bÌ?§k×ni|0ØÆXK}§É ˆ½ˆOÙÓÄÿó¿Íãã›çydi›•#m:G@%œñ™m^f﹋$‰¥ûP‡Ö‰%°ÛôÎLWcpˆ‡Ÿ„d Óø^û3¦«JÅ+ÈǹÞÔxÌË´¸pêj>Ì‹/èsH;EºvÛ%³ÎZÜtŠ™Nñ&ÌdbÒX|ñW÷¬TM‚EF[`©ë”ÙÙíÂêêâ‚÷ÃL¬âŽ ¢¼ž••„ ¥"ìüÚäfÛm—Jšäù½ –ÂÐέ2Å]O) yîA³µÐë˜Í$‰À|F’îzIâcm€«Cµ2¼°ÅÕßisúáËÜÕy•¿ÿéÇø×/ìðäëÇéNjì´Æ<¶6àÔc/sã–ÏËŸ´Ì.ÔŽC&Ó!/õoñ¥˜q8$I"¦i’ì+=\’0™ ™¤ü—/½Æïm®ã° ú›Œjmê³ ÃhÚeõ®]Œõ çØ{nƒßýå§yó{^æþ& ‚ÍŒ/aóçh¬\¤óàwòU{ëtr¥u‹¦ÓùçT^ᵨ(§gËÿTcÈG§ãL§{¾“vMÇÆä|®4Ö\YC•ZÏýÝUŠFX5ÊSdEß3º B”•z?}¹øþýŠÑÕL“á¨-( W{höU»!ê1©ü³T«f6sŒÇÊÑ/‹\‚ ¡^—•_‚½‚µõúŒ8öR©C£!ø¾µCŒÂ!ÎY–Ÿe¸xë^KBŒ1´ƒ%ÎüÎÝœ=ó…/×ù»¿²Æò4äöd‚õ,Û{[ ƒ?p28GäfÜê_“g`}¬³<ûqøÄçWX}lƒ¿òw®c}Ÿ>Öà _8ί]º…ó,—^YæÖ`ë]¼ëuŽ'[Üÿߣv×À,c]H«%1Ôxl3—d21Yk¥"á°èŠêDR^ž<Ëásy&£‘(]÷û>Q$+¾j3ÔáÐà?s劗µ7 Êüõj×eÑD(N¡:›Tþ$þs‚T>ñªv„r¦¹xþÙ,ç//çùšÍ¼2H­Ør'G¼dÍw“ ߯$‰Hvä>¿!Šrñô Óâ}Ct¨Õf4!a`ŒÙ‚ iguÁËg8< ‰mŸÁ0àæ³®"Ä› ‰â˜éTTÆ“ Ÿ|©Ã“ÿä?;˜pa{“ñI~Õ á„H"žÛ¹Äÿülšòã›Kl¼ç*+ëŽ_þ§ò/¿xƒ+»WøÄåUŽuºôÃ-¾ûÞ‡øÉ9G÷ÌŒÁkM‚Õ>¶SK3å2†Bsì_y>EÛ*&&uÖ¾gâzæ;‰ªŽh×H-u•b(—õ7("Fq þ¢Ú¼¶&ìKU}†É‰µ·u9úŽcÌ6OƒðpÎ# =†Ã”^qò¬T,YõdõÖÊó“ÖPŽõõ ÛÛ vv,{{y"-I摜oUíNû·n™Œg£•6Pªö}Ù[´Z—'Æ<?‡ZZâ™ÂU‹ôA5m­M#ÊH”ªèk——glo×R˜3°Ô¸›MauÊ ç}í–(»…z»­¼)d‚c‚@¶Wu‹´Â+I Æ÷¥¸>¸]Ä÷ORCŒpĬž˜ñ·–×g5^¸Þd2fã°=;ÏÍ0dšù~8‰¹²{Ÿþ\—[Ï?È+“ ûà“íßñÐk¬ÜU‡Úƒ4N¿8‹CZ3ú~’6Ö°ø"ßÅ]Í{ùº¬!ˆÔ çÊÛÛ F#Q§VR ®‹ °Ñ(_ÜŠŒ\½d_? ²B·Û²*‹zY.U4誌ðAAß«A"‘žs|Ô=)Ž£Êªz‚6˜+þ_ÝéŒnh6m*è*7­5½ú>ßwÔ‚\¤'¿«‹Ôj9šÍ„VsŒçÕƒ¬”RîÁ1µšpá›Í$MÆøé½:„/ †ÏHW&àú`ö€mpCŒ8ötÌÚÒyüx•ðòI~w0ek|ƒÙlÆ`0äâá’„£]~Þ]Áøû'çöx—/~áø…˜Çþ|úúršÏ˜aíßo¦-•LªÖ‘—­Šh®ÉVz¡–H¿€~_”JmQ\Ÿ‚tzÔ(þ^E¢s|•£Öm' ¿__wlläÈJQ¯Ewƒb£»âXÄ÷‘ßUJ²¥·nyû&˜¾OÉÒöz.+ˆÈÏ›óFD@ÖO'±P$´c18%´Ú`¬•Þµ4%îLºrH%–±>ž'ƒ­; Híy1õzB ¶S<Ϧy…czàväË RÃïã¸ÎtëØmê½ $·ÜÚ%¼j8æÝàÁý<ç-±Éͯ·êèO®cŠÄ?­F·?ÃÑ'CV>NÐ=%ÆopMœkÇ–ÙLýw—ÒZt•¨×½Ìè÷öLŠ*JÌW«¹B‡x—5 Üø²è«hü~12†<˜™aKK’+Vî4›¹l¶žìN“@o°ÕÊÕÁZ-;×°ŒˆÑ ¿Û•rÕ-'ì´y´*3hv¸Õî”éÅ©;e³Š£fSŒYz!¨:ƒ‡µIê:|_ä…Q¯›T¿ÓA ôeYç6Á äç $׈'çxéß]¦·z“{~($Mø¹dyî·sc£ÅolÝàÖàF6ä‡Ð¤­áøòƒ<ÆŒ·¿5á}ß3ã[¼NmåLpÀÅ&XëãûÍ´_œ+@ÐâIG!1|-\Rh]]a}å»´W9qQuXÕ$ð‹¾·¶ÃÙm“Uci/ÛÙÌdšùJ#.~È"¢›þ®™Ù¸—\c÷Ùßd|íW_µ|î×Öxß#Û\ë Y †ÜúüiþÝ‹!ýñUöÆw¬âú#y8˜Lú[t‚èÝxžtW<½,U"´â;w}Ñ›RR¶0LUƒ.¾W}~€z=¡&€Bº%š´s¸K¹$â«×ügðîÃÐÁá°v EmŒI°vD­&®Œ®ìÖ„3Âx‚è ñ¼Ò\Îg®€…X®ËÅ8·!HOŠÊ!&XíQ?q›ãŸÙã¹ðu~þÆfÓ)/·Ï°=s»ùëmÃ(ÇÍQŸoòÄ¿jñå[î}×5Þù£'1~/ÝBá>’Ñ´‹*w«‹³Hˆ¬œœ=l}p™V“Ѧ¿ó;?ò‘"¶®”áâ ¥©ÕLŠ©æõ¬JWÖ€SéÇEéïbRcžó“Ÿž++¹Q EzŠ}…ªl4ȺŒ¨+æû¤tÛHÔÜó¸ÉG1ì€"}´< ÆDs$™Në0fˆµR¥¦ßgˆ{²‚9 #0büé6dB`#}_‚ìc}üÆ€å3—XŸ¾ÌËWùÌÅ×™N‡lÇ}v¦;¸;5EþctDIÌó¯;^¹²ÄSo©ñÀ›ë¯™–Wp³×pqˆ V±©ÖišlÐÆ0ßER“²Åv·U»CyT¹?ÅŸýª7”!£FCàÆÝ])Yk·Æ”¢æ.T¿ÉŒä* JÚʤËù;zEq‡–—&›îHâCŠ‘&"b;Ä7Ó<†]ý‘ôjº3f3/Cñ4/#U~.£(÷+I¤ÕU1iZ>Ê;E±¾¥šèÏûúTM)ð– [¾*g¹b°^D¹GlÕ. ‡pìÅ톧c8$£ÌáV]íµ¤ÑZèv#‚ a6 Ržxœº(5Ló&»Ÿ&º¹Íò‘D6d+VeåD\ƒolˆ]zÃZÌY0µÔ°—`§Ô`p)%ر)çdŒ1› 7.³ýÊGƒ>g›÷ð\0‚oÀ öòÚFÈ/éÚç9÷%Ãßó:¥1¯}|À]Oõ ày!ͦKíD^¦•~‚üÈ"¨_Å£ rÏk3ä÷¢¦lѾ=ÏݹA†Îòj11xmÕ#j Z¸ ”Vu_ʉ-m;ª®–^¼êăè¿,/‹B´úö¹¼`Ž+?GKÉ ÓI‹Kâ&¸¨‰x’€Ú3×JÝJ¦´´m\t‘hçSŒÏߢûn‹×~s¶zƒtŽ´¦× ÁÔ0nÆI›.vpñ &;/ñÜ/^áÙ_ìðž•&?÷Ì:¿°yŽÝÉáŠÖÿ8±‹¸°¹Í¯ü«£ü³omïð×cîô&ƒËRÿþâNÆx"lªØ—ÃÊR¨¨û½‰b\nT¨‡$-ó]Í&ø&Ó€ÙTùZ¹±’5:rB¹éS½ÿ&ïÜ^¾5ô049ƒ­mQEÖ¦pF’¥ËUŒj8ôˆ"V+¡^¥²á3\|ƒd÷÷I6¶±ë+ànâè`œ”ó¹d ‰Áø²Â;gÀÜf|á÷Øü¥×X~—Ã6o×.âúX 3çá²ìo¦|ŸÆLÇ×ùÂOoòÏq™s×-ÿtï8;SË`¶óõ¶Ñ¯úq;Jøÿžs{p“NãÛÿö ~âè2'Oì}ù"+ïÜ…¦!Œ¤¬ ÜŠNëA…Н/.Ä*l–$.Í_l]´èXqKQƒ¬þ§NE©ÔO½î  ó‹ÕÏév÷÷²ÖÍñ‘´J·›àœÍôCÃÐÒl&©>³ÐóâtB4°6Æ0ÄxmìÒ}Ø£WŸ»Bóþç ±‹ë˜Z‡èÖ% Ipüiœ5¸IíO"ÂD;çñ{1xgÒ:ØÇà­aL\ ÇiJ§Â²Î :SN½¥Ïã_ñ™ó·xîúkxÖ¸˜oôc4ë3û‚ôÍ álƒÆÝËtïói?ø¶uš$Iðý˜fÓf@Hž›(öV(®ìjOªHR¬øÓ× Ÿå HTÀ![tªúªBn”{]«å<œfS/Æ r&ÚE}þ<&»`MdåÉ%ƒö –]Æ6EšÌÜû%Kíèt┲ Ás„çM±VG^€Ü ¾vé«›ì~z‹Ýç®4Î3~ùã­)Í»F¸x€±}0[xËx£k\ûåe.~Ñ£ÁE§'À.ÃWŸcøÂyêÇë)L:Czr…ˆ+%¯“\ÁmZ½‹œÝº@òÂ:Ï»ì¿q]ŸòÑn-qªÝ㾓§øÁ§OóCÕrê[ž ~ìýï^â¸Ët0›™B ï&œ4͹ìÙk˜¬9Ÿ&fµÄU³ÃNÞÖVë]DY:ó•™²kYDi¶8d Ï´úk8´,-A¯—°½m³‰PŽD9!×á)Jä‰BƒR™»»ÂTíõbF#›µ‚¼¨Ù ‰"Itá<¬qÀçT¢£…]y ÷û¸ñKÔ/\åsÿø.žû•Lë<øÎóxƒOS¿¿Kó‘ã„xí,=¼¿¸Æ/üúÓ<öê«üàú³xÇ.üT‹Þý#–ßÕBÝ.‚%¤JFVØdºwƒ_ÿwM^ÿWgyqcÌîäÚ×Û&¿¦G8›òCw·ùKÿÝëï8ÉòÙ÷âÕŸîÁ¹R1g2 &¥¥kÁ»®ÜE=¡Ù¬(®ëÒ„§ä~tr Lm·5™yëó\žÞùî~jƒúõ3¼¸uÿ±ëœxë˜xºŒ×8¦…ä0êc¶¸ýÊ6¿þK ~éjŸÁ6“Ùˆo¦cÍø½¾å»†]¸w ¯~\‰9©«ÕlÊ»ò©Õd…ö<‡gãTJÒù$nÈßi­†zÂWc.›\dˆêïEò¤sà«»öã-·•¬ÂíÕ‹xÞ‹Œ¸E&ëò¨G‘ÚÐëiëÒÜ/S™E]é…ä±´”°¼E^&+Ò‡žhlú[p_'Cf†Ð×Â[®Ñ{ëÚdž<óú‹üü­+¬µðWF'øÑ+×øÌ3ws)êpòz_Øôø½kŸáÚò=üÚÏÜÃC¿Ófãf—ÍVØ[ºÁ;/_bûÆ”Gÿü&~çÒrÔ!à-VOlò}wYÎ}a…׆› Ãq­Ÿðúã†À6.¹…±R#T².=š ¶Ö`Ò: Em´Šp8Tiyá‡Å±%d\ódZ5ºŠ*íû¾¥Z}£o.K…Wá÷Åh[WyÈW-^PSeCTøJ¥³‹jtÚXB„gçcˆfsB8WOa,é•%KZHòj$ Œ‘=Ô0Å1Ä0!™î0:·Çë¿r?wùM<í׸µu×ü‹œpoaváíüæ¬ÎgöγÚl²k¶qQÈ^´Ã?ºVǼ^ÇzWF¿Ë½õGYýÌ ›g}îýÐ+´k»5 ’[\:7ã?|ù4¯O#\òøV5?b}¶Ë•gorâßarñ¿&ÌD@ ò¹ó «E÷%¯Ô’€Ù2›5¨×£TYÙÇZ‹ïÓÁr@M„\ÝžðNÌ\˜¢3S’xÈøbŒw{Æ,¾F¸+˜D|~ºÃçGu6úçMÆ\t²{ÚØºÅ· Ò}¯Æ¼4åK‰#ÞÞãÄ?lsâƒcÎ~àe¨·¢ †ç¯^ðÚÞ%âoÒ p{ñù7–¿>åCoqìM=–žÐ¾Än.¤JÒ: dG˜¯ôÊÝ—¢p®ØpQ%®lü‹8CÞw÷G>¢lcri ‚ÍWíyi9 ÒõcþéŒ1ÂÍ—Ê“%»´ÚKä]ZOúyŸjÍÏÒ/«V›¥õÂkG)•!3˜à #·ÁÜsØÀÖnÒ>ý:ËÃkŸYâ%÷;ñ ¦ÓÁxƒÁMÂ;;H’˜ë¼<»ÍÔF¯¿…éÄñ཯Q[ÝúÐïóê'üÊç{\íoÅtÊ¿–GBD6ÁLÖiOÎòèû{tîy˜U’¤6çY(;XƒT©3ûèÐû™ dIS¨æýWU„A¡ ÆóÈZý™òšÄ²B7yûNÈ¿5›9T'‡úòµšðu¶·ý ²T¥5©~¸»hfV"öååˆéÔ# %È– ¨Õ&X»4…°æRþIQfLpñ%¦—i¿7$¼z®Œyé˼6l8XóЇ9\∦S.ÞºÂÿÞúçãa³'øðO~†æéwnŸoñÚöÉlðõ¶Ã¯Ûq²µÎŸ}÷2ïü@‡j°üÈ»À,ã\ƒ0ôS:´Iž¹šbmï"6ñq‹~ÖÃ×h¢˜vV¬_žòsÞð,¯Ç”¬šK”œ2¡‘;äÚ=IbR}“I—H=¯£ÓIRxJÏ‘Ðl’*.ˆd‰1ŒŸöËÚ@X—C„’!òáŽ=0¦W®rëÜ6qÛòÜï¢{e™_;×äßìlsåæg‰þ€2#Q±7Øæ³îuZ_zœÇñ$O½ëu’mÃð–!ôf²WÅ7äÑi8¾ïGǼíϬ‚÷ o–pÎË’©ŠÒQßÏí²˜sÎQÕ¨L¼,3?«(ÕÆ”ÈpóQ^ 2„bä¤âSZ•$"¾´$;†µ¨ÿêî"Ðh£!5ÇÒvÓe;C‡4–Á ÈtúÃЧ՚áyQVñ¼´e›áÜU_¿‹1YH«³ØÑyó2Ö¿Ê3?}œŸúT‡K×w˜š)—oŸ'þCÒØqö×ùÄk–ŸûäiîÜ¢e'\º3šì}½mðëzøIƒk×jôÏ]§qÒR[é"­–fø¾G»àyçlVÕ¥"ã ±;Yœ]Šõïg¿CõßôØÇ=ˆû£Ú,Ý®àòƒA>“tt»d=¡4K²³¨âš¶Ú—@ƒbD~D¡PI¨Õë# †Ä1¹ÌÈ6Ñíß„hHp×ÛÁKiÍcŠÜÁkºÏxô®×¸gVç㣫ô_þÎÞUþý‹ïê¯ð­î¯^ ûðÿ1=¬ñ¸>Üå—öŽ™uÞüWS–ëE­”èí6)…Fƒ[‡µ^V u*âjÛÌÂ~/Š6T•A'‚‚ä' H¨d¬¬äWÊÎ4Ʊ´$Eèaè²*/gi)Æ÷…ö*ÔÇdbS”Ç'fAzdôš”º´EábÇä…s˜^€¿ü 8‹K¶!ÆŽˆG×Ùù„Ï¥›5{„†ß`ï«X€òÊæÿb|ÍÙC\`JœÜø›Ýc©Þä/}¨Ã·|ë2'ßúõÞ)$Oã§ÙY0ô CÕîÌIp y*ì© bÕ ­j™T4vç\Æ)ƒÅ=/ü2¾_U¾¨x«ïËDHéâR¸ y¥®v:.“J—ÀÙ¤å’ Îyií€Ãó\ªä+®•çÅ4!ÎøÞL1ƒ15DQ­n€Sî ŽebLÏ¿ˆ}¢m4˜]¾N2ìÓxÄbâM¢W<>úé»ù·7¾Äíí¯®AÆQÌLJœù~^³ŸwþkoyDކWç-g ßö½«Ôï~ Ü1 E’D‘P ûÃV¨–àÊ鍊ʿô(’äôð}—5áVw¾Üø%c’.âÿ”5ò!ß f3ØÛ“ª°^ODµÂÐ¥íˆ ŽËºwHÜ e–v;Lý½kc|¿Žç…€ŸÖäŽ~ÍLð{“Ò] R€(…M‚i®ÓyßI6áU¶?w…S¸MøŠaç|‡£·7ð‚)õ&nÒ`8íóµÜM6yùþDý:|“nM¯Æ›î«³5yˆ o¢îN Ø k§ø¾G½§t›§bù¹+´?‰UtuÊ(‘6>1†L4¡ìéßÄ÷sýËœ·¯d¤üïŠ×+†¯=p63õT¥ï&ß¹pÉþ±v(‘6}’Ócê£1¤BKä¥qFÖÎIÁ:n[¾aë¯ñùŸy‚ŸYÇÝ øòä$wýêé\£~{Êï_Ùc0úÚ01 Y;õqfׯ|ÓN€õÖòýGù±¿ù »ÅÑŘ.ÎuSúŠKc>›#Jƒ‡Eõ)z½”¢4°Ä3ÙÝo®Qž(šlõ•K],9ô}ñõ¥)\NEV­Nn C,½ž¯IêÒêõ„ Hðý$m× y cO9‚ÄàB#–Õ]‹Ì½t¥!ªb0 Î퀻a‚0>oà&ç0þe:½mñÿàGN/smölñhc™·ðW’‹$Ñ×.û…/|‚(úÆ)v#G׫ñï;Â{~ä1ZÇߊ1ëHýu’¢‹5¦S“qøUD¿rDìJ[Pé!]_Ôfs2¥‚(ãñ~ã/W‡)ã«ø¬BOªÖàœÕŠ™tmj@Ö_K[ƒÖjIš‹ÓÀ$UZ˜!†mà .yÌu0Kº§,ÊÎÝL!Í&¨´xª±·ˆoþ&ÞJÓèA|ñs_Â]ÛcøÛKŒá° ¦‡sËÄq“éÔ˸ÿ úÿy",w¤ÜVz<] 2Hé7ÎåmsUF?§K“ +AûNx?ú£÷#£‘IÛÔ+'ßdeÑ2sŠ½Ë Ç5°s œk!Rº`Z@;U]htg4޾ã? æ8˜u0]`cV0»1ÞYà˜ü500Ë@ ñÖÏb;÷ƒßa¶³Å‘û®s_xƒñ¥»yÙøìŒn ø~GÏ~;îno\üzÛÈ7ô1žE|é…!ýs!gÏXŽÞ³Œ4 iI£@ü¹šnaÚ´’+·A©QÉ!˼‡˜Ii9ò»’&E0+·Ñá0O¬)·Hë òü‚Ô¢øZGY„A5ðÕâb½ÕRQ….í½†áЦ4ZÍÑlÖI/Õ‚am ˆÀ¾Ìi` AÀ4Ý WSÈ,-pqc%"»Dïè÷`ÌÜl‡æcæÉóø+<úÒ& îåô]WgClñxc™7÷ðïÆ#eYMŽåå:a3~sÅÓ$äg?u…µð‚:½k¯¶j88çÏ© Š­ŽÂP˜yޱХߟO–Iÿ —5à.Öݰ¬a4Êá'åRD‘$æn%5½·'Ñy­æR½þÙAò,^¯—¤=lÚø¸¥Y7¬]8Ìu ‘¬‹Q›:PK©Í5AÒ ¢ÁiƒÛ’˜¡A2f¸3dì/ñúÖ¸[M¾4¾Ÿ3µ«<Ò¹Šëã|êËk<çy_³\ÀÓO ×®½Î¹sß|TˆA<ãg>¹ÁC÷¿Àé»{tî^Ř%y^€çͨ×=‚@ ÕZ/3ø86Ùj®«õAý4æPö²ï»ÍK&ËbYúúÑ|•%)â¦ê?«¼dËR½ÎEïîupM 1Öv1¦•º%&siÔ:ÌQE‘1jk5ÈDн©õ{¿o¤CLU¡û¢J’&°¹™ÏVIžIP3K—IÑw4Yºá0 Ž õºÁó<ÂÐâûµTö°N’ÔpÎÇ÷"œib0Â55 “ª=ôÒ‹Ý%oÐÿÄuZÔXü4¦ñ Apµ3}ü‡ï 7˜>ãáê#Úõ.ýÁí¯:hÙ[ãÑׯñi;ýª~ÎåcÍx윣Á¸‡€˜œ«§ÐºÕy æÅÕÊO•tb’ú}—•ô.ªƒ´¯Üw÷G>¢]%…¢ªk*NÔíæ<þÑHa›Œ‡!µrC"m.DZØ“©(qn2±)[Ô¥Uý5qɬ!ŠjRãkú@3 ¤†í<î^w ÿÈQŒY‘J·á˜£³ÉÍ7s!ÚeøUäèûχÚ+üU®òe³ÇÅø«×Ñýúa­åÄZƒdÚ&ÀcùİKHM€—ÚÉ\o­"”ŽïrE'‹Ú±"ª°(¶MÒ˪Æy¿>ë°¨jF'¶OÕ6JƒAu«FsÒ?@ b”“-zŸ ý¾—ÁP“IŽ.Éÿ#’Ħ¾µõ¨I;ÉKå0Xó.©aKóñGñ–Þ î(˜c"ôé[xÍ «ï¾Æìó3ŒÛ`N0Ö~ušRx`m?wWÈÛÜËÜwqODö›–4˜ùg¿°y~—•½g9~ÿƒ4Öî"¬­KKÚVÈlæÑhx^Ü é#¬r=ÚÒJ»CîíÍK÷TéÖVé•'Á\EØ"}Т†ÏînŽÙ‚–4æÍõ´s¤6¬ð<—iÿh°\¯ËûÇcÕ.íðm³`Z&N‚sŽÉ¤ xÔjÓThƒ|÷׿ü¶ÇxB #D§3âQÂðK5^¼rœËõ´O1îœäùÛ/ý¡•Dê±Ü=Í<|Šw½ùËÔLÌ=¿êÑw ¾9Ë"—pº»Ì‡~l‡ÇÀÃzc`Š1|ßÇ-ÂP´A;[‚,¤ùbš¯üŠZ–]šEr(UG¦ TücQWƒ]•Ié÷Ÿ¥(>œÕøÕ%Ò-K PQämµbÆc/Õi”ë¢'Q»TÌf6ƒÀ|?!"f3ŸéÔ£^OH‹sKxþ ÃcNAm- @*Å ÉÝ¢ÿ¹]úçÛÜ÷­}þ|°tÙãW_j1°qéæ¹?pQ¼ŽÃRçßvöQ~ä[ÎÑ{çˆdÛp÷9öõåoÚ 05#NoÒyà8ø‘h6±Jâjıe4²™(V‘*" ù„Е\¸Ê*‹&CÕߊÿËÄq‹< U‹3F.lwפªmŽrK$P‰t3§æÍ«¥žSj"o—ë:Ñ´5+äÖ(²Ìf^&ƒÇ>¾ohz1Î`Ü$•>TY”ÌC‚Kº4Μ¦óDiÈÉw^…«7Yý™wýæCüsû'x~ç“ôû_¹l‰ïtZK¼ýÈ>ü䈇>t sÒ`oAçÔ’Ú×4ÿðGíN,?ÿ3 nÞÜâ‘—Sïóh¬+,*ö¡y%eªPnÙÏÏ;—V×ùª _ôn«Œ¿ø?_W{myÔíÊ?U H¹Øša+—Pë‚Õ@$޵ˆÙ¦çti6Ïdh’ï T¥³ˆbÉUîîú™0˜L]؃«©#ðh‚Ô¤û#uŒw»kÀ¸[w5p+}|×6—>3%ÙIRDÈó qtx+5žÅókܳrœvÞÍ›?pƒøo>Oãá6Îs˜Æˆ£Ž9»²Êía‡Éô›Sèêhƒø›;|áBƒxxZÿ4÷>1ëA@³iÓç¨ÙÛ\òDQœ*ͦEêåEˆâßÊ?ëá{^®Þ¦Æ[,F^$X¾¸b/åY4›¢1‘i½kfÙZ—Ö “úz²ƒÈ.¤nQ®<­º@ž16ˆc/Õ ªƒia܌Źm$€ê!’éq‹¢áU¶}‰ÛϬñ1·Æ—o}’ñt„µ†Sëa’ƒóŒÆ#ª„l±0X/àé£oæ>—®ÂO|ðYއ¥ýðÔRnSgƒúrBÓÍ„ø÷Mztý.g:=Þ÷´ãÝo}…dx.êC`RÐÃËz«"œx#²8*LZ^É÷KuæÒˆ°_¥øó\ý°Š_Y«ï‹ãÂþêšùC »×“7Zôì t —•¤c0°YË$GU5w‡$˜ž†£‘—Vÿ$Ìf-©:ófi¶8³LÒ²JG€¡õ:´îóq¯ÔÍ –:ËŒg#ŒðÖæ2ßU¯ñí÷ðéþ«¬5רe‹×®¾ÊÚê1Ž5O`§ Ökseô*?xoƒwz3¶îoñÔß¼EûÄðO!þN¾¡ûàœjryï>^˜}™ä›Pt­åó‘?ðôŸªqâlñ¥âyË®®ð§Ê"’jøë1ηII!©›¤Ý…´‚±,’UõsDììÌcöÅßI«XŒ¬œkí  MìTr­Ï(r‰©X §.˜Ì5Ó¨~ËòIÉ!œê\æ½/-siün»÷UN|`‰èØ*ãS-¼o‹cO>ölc)} ©^©‰Ýˈõû·ùà÷oóÀFÏ^îñ3“]ÆßDÁpÍ«óövÌÑ`ÍW6Yð^ýR!&Õ^³™Çp(ðºÂ ¢áglÏ(²™ òtª™b­– 2ß—ºÝÎáxÉ/Í·H i²AÚ‰>Ç­:ªG¥-i®¤â¹ŽHœìíÙìËÚzßÏ{(,ª‡B¢ÚjiIf÷Þž—E(z$Ùb˜N}œKõ‡LLâ Ö40¦ pŒH6?OÿŸ3ÙZãÞ÷OX}Çéå±”Þ·<…KÖ0®¶OÔ<߇Zøö/rö['´y¼gÿü f×g<„1'S·'Bo қ̖zwÀŸø“ר ¯³ûÏÐëŸ`<ýæ!Çõ€Ÿ¿6ãwþ§5~âm†ÿúo|’æé]'Lmc:xžO0—WÜeqö ÖØÔ—õ–Þ–Á w£µi{­&à‹4ÐpÙê/½¥Ep¡rTEÐz›ZçAª(;O&&­Æ©VðÒŽ~Ò¹ìå]c‚:˜z=a4’ê¡ÙÌdçP¼xwWèºSH§x‹1±Ô4$[~™ÉÕ+DqÂêwÜÏRý4$uLÐÁ_¹®ñžÆØzz³·_¹Æî‹]N}xDûM'ñ»O€w†í³Ðº'o)ô¨ááhaˆRž’‡Ãà\ƒ«_\â?|j…½u‹›ý×ð}Ÿ8Ž¿)\¡áxÀÐõ¹6Ücµwÿ³Uî¹÷%žø³ugîÁ˜žày6 „‹]B Óièªþ¿J$æBÎ&£á»Ãˆ]åmR…Î#9‡v;ïˆä˃8œÑ~)o•z㆟¹LÓé|£Œ"I™[™†m²Ž~ŽKe-ƒMeÕU'ÆeÉ4©êÉW c¬c#tL2¸H²qæÙ5lûqgÓ ¸äñ4AµŠ#ÈÔøxÁ+ØF $øK÷cìcE»XŒƒiâœv¦1"åâ†À Ò(;fÖ¯sí ]^ºÖ`µ³Î;OÖÙžÎo½Dì¾± eZõ%–j=nnЮ5i5]µ Œ^{žÚúehÞG ?L`P3×ë·×›ÕÐã8ïVî &`K~¾b×ù¬Qv•Öºqƒ|_ôZ-)žÑÊû¢«T¼x©3€ííù•_}ÿbÔŽ/»)u•”D'ì¹LK«ÓlFi¶¸Ž1>ÖD{ Û{víe[s ㎠RäZë‰ýº0ž‘«Ñ¼çÝýÁ>“Wn’ŒáµSY?Ú©LË\°iÍs ²l´5 ×ÀoäÍf‹`õ2Ïþ¢Ç{W®ó~ëÃev¿Áûñ éáךgl-ó“?¾ÇýÞäÕÏ=Hç±û±'Âi¨<º«‘‰àcSµ¥bQ ä-O‹‹n™ !‰ÜܒݥĪ:¤Ãv.*$c—m#ý¾¥¶ o·Ü\ÊZ'…¶a*&0Š“JZ§º¬™±Æzc ç=êuÝT@)H‹uÖ@c»8¿M2ñ0«ÀrZ_ Å6í´­R x¿¿Ü§óöÛ~XE ÔSt©‘~õÁ4ÀÒ ÑƬ€54ÖBû^8ùðË Æ|8Ød°ñÿ±_cgï³o°g|ή¯òÁ?Óçþ'=^þòÝÜÿ]ë´»Gènô™]Q[«§¥‘ mP µZ®I%€G¾²‹Ì\b¬ŠüV\xË‹°ºíê:űÛ?ªR̪E.ãý+ANg•¼®úBŠ“ ¸âkÒ!Fο·§ý¡T!8]‘~ÝlÊè÷ý9©V³xž/"Ççh,%Øã«¸xã­€ëˆÑâ!²Œ-¡R¸ôgâõ¾-­>k¥ÝA Î ,­ô)Ï€qRg`X“]‚)¸5Zk§i­Ýbðr——†+¼<»Áì¸g°çùœY 8ò¨ÏÊ{îã­o{¿y€ûþĉv×Áv‰gã±Çhäe‡Ô Ðç®|1¼s’œU+><ô+ŠÌ¼Ä¹&Æø)Ìé§Õi–\Áb,§uÌÒ–Uÿ?ÛÝ幟ñùäGßÎ¥ÁEzÝ&Ó‰åÁζ¦c.î]ø†@…Œ±¬¶–ù[lpô”ÏÑÕfÚûŽe ˘ZÜ¢¨Íx¤%³dþ¿>ÿÜíe*Û\¹1†þ|¨Öô^Ìø6›bŠÆHï.Yq ØÞÎg_9Ñ¿)ö_DŠ¿—/\¨Ž~ßdMöŠYLm§kŠH ÈuKB,oÍÇS÷$¾á"/ ²ÂÔØM&’Z«f3?½ÆzÚ©&ÆÚIRÇ9Y¤¥§“Š4lЉ dVü~¤At€MÂÍ=&×7—–83¾Ÿ÷œñ|§Å÷·¯ñܵ&ÿœ3ÜÜýã¯Yt¢Õá{êòþ?;âÁw:{ãzéØô€6Ò!&ÎâÛÛ¹š`í/Qå1í§øsÕB[^ùË?ûÅ€4ŠÄh·…Æ\«Is<ÁÜódE³);Eñ¨|¡ÅC]ÚwX{ «J˜b¾Åó¹FÍ&©áç7¤.“Áó¤¥v ŸNë´Û~Š&šMKÛ”h'÷bŒÀpB®RwJ‚ÝéTv ð C/ݵšSÇ9)Þ·6ÝtWè§i\ŒKš„ƒý®[,?ð"ÏüÊïyd‹¿ü—èx#.ý/§nú,·Ž±;þêì5c ËÍüàj›¿ýC·¹çímüõ3À‰aó¡s]¨N’8šÍàǶ@””/µ‰*ÊsYò\b—V$Â"X¿j‚xßó=ùHNCƒnµ`yYVýéTéÑyBB'‹JXTz¦¬.O³)ÁL»-â»ahØÝ5ÙùŠ[œÞl£!Ê¿ÖJÐ-²-ÅÉ'ä9iÖ!™ä~ßËÔÅ„TF”ºN^Z´ïð}Çxì¥A·M¯3Ie`¼ÌWœÍl:Ø!IRc6k¤Az"H, Êgç†@¦Eãø³'9ö„¡6Û {ÌéïjcÖZ\¸à81ö8Y[åÖÔ0 ‡ìÜ!k Ë“¸ÙŒ›“:ñè(§î°µ#ï†#ÈnØÄQ#Š„Ñ;›y™üŽèõKõ tÍ£=/ïM-ò›¹‹®ªÐACæ‹Ê½ËÅ0Þ÷}ßG>R®ÆïõÄ8û}“Ö›¹Wµ\Šò)¿~— ž¬þ««b|;;yµXÇ•ÍoPŒ:Ï èŠ¡×ŽnW²ÄÂ-ÉÕ„¢ø²Jñ‘‘±Æc›iM£Ñ‰c/mâ& 9I¯'iãð€0´©RqLKRL&z n€ÁbL[þ–±Æ_bål‹îÙu¼æ1¼Z‹ŸØãÝO]åinräµS\2gØK¶ˆã?±c .q Æ›¼>Ýáó×ý×Ó½\£AHïÞ5ŒwÌŽ%’¤Álæ1™X†Cqcõù È‘¤n§d†ƒ ׬².EÎå [4VÌW{y2¾âéʧ‘vGpóæ|Óìâ‰ÛU½JiÂ9%$™9å¯b›û¢[&9Q¤Óì±N…gµ`¿ÝŽ˜Í¼L‹HƒbyŸ¸8£¡eNØŒwቴÔ8 þ½þnúð`<Ùã‹7/ó}Ï=ÌÎ=·9ù®kÔ<’ÖfŒ1ÆÃZK­–/FŠúIáT‘ÙÄÀu´V9<â‘%F _½‚*ÖÚaÑð‹¶é«Ä¡ÖûŽFâî8—öPòÝ>ŽE•Ÿ_åÿ—/HåUŒ­-uoäµÕuœ.sÁÊ7(ï˜$ð¹Ÿq‘4V‚ É)LÓ²;©EÍ ¯­dË9 ®ÉtfImÄ .T[/¥pH)Ÿ|)¥¤•¬õ´Ì §MDò1…Y™à’€Ÿóyöþ©€m>Ëd’ç:³0d6ý£%°e¬Ç‰f—6NòŸG¯S.ù_nôxò© <úÃuj«S¤—Û:  2dl#Ö6IêHP¬Â·ÂúèÛ¥B ²úF&­#7ûì¬hKER]yQöÕîû[‹îOlUšäª2|uUêuÁr÷öÈàK)eË[×è’„‡ëÑ´õ5b܆F£iP­n”P·…s¢«ÒduewÊ1 M¦{¤÷"+•Æ ê† MW²Ï!Æ„DÑRŠ8ç…)UB[>íáðd"ÐÄà±s+à·žy ¯Þ~–Ùl^¾}Ù?K/ðx%yY4û# {žÏ©¥“üø~âÔ^ùt‡[¯oå»–µ\îð«/?ʉ ;;öÓÁQƒmÅ9CÚt¡Í™žÚ#Ws7G“¡£‘Ø„{æXY™õtatÙ$’|A£ky®êi\‘U„8‘pù²—•Cæé‚÷+…ô0¾~T¥±E·«5óu*ƒR>OqË+Ö!«ñëÏ"Ë"ÛäpH*ëžS±Õø­u™—ÞÏî®)4$5fÙETULº¼_jlöùòw¨×c|?b6k†×jQZ©¦…2{`‚4·0ΉX»kćî~†ÝÝÏ ¦SÙŒ5Üå÷ùë' ?78ÂïlFl7I¢¯Oï1c=Öj=¿É<ÔäoþwÛ,¯9¾oç~6Ç-.ï\f¥¾Ê‰N—½0ææf›þ3W077 NX^}LŒµõºŠ$Ø4hÍãµ¢,Š´äÍI“Ó©¸Îõº!IŒFb«Ý®êL‰QF9ÒØlîoY¬zô¯]“-]›½ŒòÜ æ,ã²Eǘ¼¬(TšG÷¹aëÿò×ì¯X«ÕÄÿo6•ªn.8× Yc—ü+Vq.ñャ8[‹…OÁdŸñTÁ.wåÄÅR½IݦSyˆI0›Õ2MzQ3ð1Æ£^Ÿb­ô30)oȘ„Ý/ßàÊÇGÔë=ì•Ö8î;þOµ–èŒ}¶šu~à=¯±òÃ>O½7á<¹ÉäuþÏ¿½Ì¥~ÂÊÒÑ,f8$¸“ÁƒgÖ[GI0Üê_ÁÙ„Ç¿=ám?¾IÜ}„ZïÆz<þ]çi_ßÀ\{’7¿k³?: rSü+\þù#´ž‚ÑK7°Ñoáßý8q|7£‘—.XbÌZä$Ü}—ºD9ï¿Ü${6S‰Îyo¢^—˜Q:™::˜ ?ë37áΓ°þp(Êͺ5” ô0t9Vªt=­1ÙÞιØ¹RÅà¹ø·âŽRt‡´TÕŠÒÚê~¥„ÿ´kHž;(³QÕR®‰d:Q„£TÌ„¤ vw[édS¬% FœêEHp¤3m:g×8|‰/þÔ]\|þ÷ÇÝã컯³w»Ç+ãÓœúö6ÞÚSœ8²¾~‘g.YÚ:Íz›G—Žðî–ÇonMy®ºk2LÄI„s1oHˆ+•{iøMjÔˆüˆ=Í;OMùÌU_cN£Åt¯M°RcéÄÃàŽãð 'm–Þt‰ï|rJçGhë‚ÙfìG4î™°öž'ÖŸÀ$K@;c~Z+®º1ºC7b7¾/Eïê’m"¯ïÍ¥PôýZ["rý’gÐFà2 kŃð•áY«¹ ý9ˆK±Èhç Ôd«êÎNžD«:g™.¡ÆY5±¤±͘´®x¾sHq» ùòàW?³^w4àùÐj…x^ÈxÜÊ1½ž|ëÍ¥»k5©C˜NÏV7 ¤`ßó‚ L“kkø~‚1 zÔŽ.ÑØkræä5n]Yãž½„÷¼õGÿô„©mð¦½1½Æú+ÀÝ]ŸÛ·fY:Åû›«üWï}·Ý{} ³t/ïhù|jgLް1ì ƒà(­õ—/Ÿ' “ìÞOž@U™´*Ã/ÿ¬¾ûê*i+%ùPU®O:Uj6]ب˜S5´ƒø¼XÎ#¨ ¤¼Ý6óÆ0åw6óØÙR\̯<åÉ(É7Çî®—½.≘NUÁ"! ‚ ‰gމw-GÞq­‡#Úîck}nþÆ9â+>Éø¶yOÊ£ªµ_÷XdÆ_{Óqèè<òfZë?ø×v‰Ã]jí#Ü?½‰9ßçõŸêñ[_¸õ« wF”ý¡Û·Ùó~ƒß9¶ÎûïiðÄoâÎö q’hÚå¿}ŸaéôxÁ*ÝG‡¼åožãÔ§nqß>D°üÎÇÐFªäBpíô3fÜ[§÷Ø#4Ük¸ímXmÇ-F#?5n—•½jq»îÅÒÆ¼¡Ýþ¯ñX’›åÿg“|š×ië%µ7—-œ¾b®€:ŠÇño²íË—ºª]>×Aɳ"º£ç‰ í! nÐh$*p«Š\ñ\¢$—Ë<*ŠñŽVM&ª}*UiEfkqÕפ˜Á9L§D —æ,Ƙô!{X›P«Å8:˜ö{è¼ç\ÜÇKÔŽE¸d‡Õ§–‰Æ€÷$ >¶p‹:`œ|ï:0J¿À¹1^s„ßÜÂÑÌöMÇ?}áIþÃöó Ã!‹ŽY<áWvvX}öMüÝ×_åäc=lý>jµã¬vW1¬‚kã×–î9AmÉ£~äq0ë–&l€c*uÆã´Þ: ™Z¼£á­|$9ÎtêE.Uƒ6©Ž”ì^fCżªˆe¾ú«ÚeOq[ËTÕ›J’¼’ÑCÕ% ïdüÅŸ5©Õå‘,ÝAo²£Ÿ+Á\1X{ºú>¬¯Ïh·c._ndiöBëd–¨X´S4æÒŽcXAÊF¥1‰ß½—N· Nº»@#-ò0ÎÇÑ'mPåÚlýݘõ÷âüÇ Ã.áèÿ€<ñØdC•,™N%O¤cZt•šU“`‘ ®s.Í)¤]Œ4ª"B‡5þr‘²?ÌWí”/(Ÿ§Ì(>¯”i¹NŸÙ,ï5[ÔŽ/O€8–Dž²FËÁ¶Ò«»Ý$mêG–áU,ZÏåyš®'£dk¿Z=·ŽÊ:5Mõ Q0ûiÞ ™ÒÂ=Œ •´‰ð‡œEdk);Ábè 5ËÒW¹.U¾¦ „Øé˜ÍK'£­Ã!À`t›­×{ ^°t&Âk5‘¶-p]Œé¥.r;½†˜çš8WO …QTÇZ­»°ÄÇÃtè§|ª˜ÙÌO°òöEÚ ¦ÓÉëÁµ$²¨L^\Í«v†ƒÀ›ò9$6„É—•ŸÌ¨s”]¡bÒHÿ_ž½U ‹ò å›×G§Á ‡É ‚r|”ÇS†Ru’9ç2‚b,Q¦cËyåAiSq˜‡JUÓTxAóªÅÃQçLúK§cLƒ$ñc,ž!þ³ŸÊ5ÕQÎ1Kbxn˜º!¢{u\ ÛÏìrá·›œŸŒÙ¾æ49»Ëçÿå:SSVŸp®‰tái‚“&ׇ@¹\"ŒMéá¶$©›Ib©ÕšŒF~¦!5H­F½îRp“åQ´1»ºá† 4;;â h¯0¾š—I)ÛKU, ‡îæJ¯Ñgç—_\Å¢+¯Ôeã-Ë*4aªÎ³ÈðÕõP8l<&íEVø¢üïò— ¿L’Rdd8´©âð<…¢¼íŠ¥eùòÇŽqiï —«,:ޝÞM·¹Ì‹×Îðêç OŸ}Ó½éÞ4àmKp¢P|~Ï 1&& ýŒÇŸ$^;I­ÄlæhµŒÉ'‚ ã±K¡nS¥¯ä Ñê¶:66¤gœr†ú}ж¸ËW-¾U®P•­/l“zXã¯ú¹ÊðË1Aq”^:z=Ák‡Ãý½ ¦Ó<³W†»Š×R¾&É< \{ë$(ÅLr³)¾¿rÖç¯]&ˆ$ùiµ’9JvNºÓZe“Å)q"nÖ„¡—’ìb’Ä# ¥‰x­¦}Ñ–1Fº-âD"‰nbÌ5¢Í W6Ïr¢Û£×<Î彫œ¿}ng¬ÇRkŸ<Áûî¯s¼ýI’¤ÌJk= &޽¬­­ EÊé—±X^ŽYZcl¿åÜAyòq(šè¥“&¶Ä]Y‘ XÆÏeÊáevÂAAq6 ‚wùçE~§s@Îm6]f,Žl{ÛÛ9šSvs4ÙQìZ¹èüí¶Ë:Õ+ʰ·g2Ús9“\Nî ‡9$W<¯&ËôA6›Ž8±ln53—*‡v5g`2h·^wYåšòX¤W›¬œÚ\PJ7ƒtÁ˜"]0-˜.l`k=œ†p°Ãñõ=ýsW©§p‹!WIDAT¯%ÔÿmÌwž7üöëoæŸ\x޽Áž xW÷8õ{¿Lç;ü7=B{ÛpdwD¼„>=”¸fÌŒ$ñÒ"v…ËE"Æ÷¬•|ÈphÖ¬ƒB_cÜ>ICíö(èÛ<¡-ïöžgúõDÆ,`eÅ¡ŽŠtˆEvWõ¿êEwZýßÈŽpЄÐ„°Å•XZ’ïý¾ÉZ(Uaý°8ÙQüY£~e©¶ZIšÉõö 0ß'ìN\%jÿWƔ׆rí Ê3ÊšœS†jÈw¹OƒöW¶6I5rrñØKI}QZaVÇÑÆ`ñzo¡óöu:\drÿ¯Cý*Þ=aµxô'o`^~«ÿÏ5ܹc ÓɑҸoFïÉlý jëËûþÑíM0+éù›DQ;ˆŸÉĦµ#’Émµ’Lš\ý|Z ööüôg—‰”óGʻҿU%»Š¶©Ç÷ÅV¤1†r³($"÷Ÿ³ržüJŒ¾êõUùå~¨æv„œN½le(®å›8èšôÜ£‘Éd7ÄuRúÂ~¢Uñüãqö)•¹9‡üMå^ú}!È)rT̈«šµìz’€S…=…|}_ L‹ú5p‚Ï›F œ ðýP m8 ¶ôðz{œøÐQ‚c'0^]AƒµfÄßû(]ªs*Xç­§»\úô=4Þ±L÷Ñ»0Þi¼vÛjÇ’DŠ{F#¡0 Y‹V4^iµ’¬n·H¬T×4I„ެ C1áXeôÅɱˆæ ¯xTvõåeÒs¿-—Ÿkñïþ‚Û*C[„÷_·()VÎäP£ÜÈhd3ÃS¨Lo¼j&/ võoÅ÷i òŒb Q|Ÿ6b¨Ê#äçËѪFCi¹f’úÇzN­9:…cw×fô­:Ë]Èiå!Æ„0l¦¨Ð1×ÅšR»†¿þ­À.†1Îm’„}Ã)'¸Í_¿ç ~îi|?áûÿÌïvR?r8‚4_FÔÛÄÿã:³™% Ó©E¤Jrº‡4@ÊJ£!ؾhyš ÍQ; `eEj'Ê;AÙÊ£jw0† ]’‚L0gZÌçÜ Ê‚à;­îÎÜu‘–‘žâÏêc+t¢¡½šÍ!8(Õ½èzæ?ïK&<—ª çRîŇP,Ÿ+ûë¡+\·›Ðh$llø™Ë&¯Ÿ7~uǜ˹(ú»s9KyPYÒÆÁlVKuŠLÊ›ññ}Zm”ê‘®§ùƒ¸- ¿û8Ç?d‰¿5ÆlmñØ…›lLÖh<Üaé‘{!¹ar¶ÙÂ%œë¦®—d›Á¢rå’›p©ˆ±üZ›Ql±›ß“Ö”ïíÙŒ~Ç“in 8΋Œµj"mSz‰éÃq£Åßýâ/‹ ùN^eðúwßwéÖ?ŸdÒÎ’’ÑÍË&eÍ…« ìE.Тk,gƒUU.Çò…üó>hÑ5+~ùs…Ë"«d=åš‹M`ÿƒ¥ë{:Y4Ðø¡Vs4 ㉟Ò³ØÔUŒpÎáYŠ9º ÒÍÆ‚K°µ°ë®pâ½[t_á­ÔÁ;–JÅ «SŒÙù mDî¨×¥É÷l¦(Uކc§é4ìu¼Šÿdçmµ(РåçnaNת²Ñ.ZÍ‹DN¥VT½¿<à 22ú*7§üZ-©Õ\†vߣMö†Ã¼©¶d¿ŸÓWïT§P5ô3 WU,N$³ðš«pe5pmѪ £(—o)'¸9ùuèç—+à´H¤Ñp`r1Ý5ëuÍ&“nšyÑ^Xj8b „¥Ù†Z“Þݸ\cz)¦Ñ½Ž×=‰ïÒò©IK†w<öð<$A’ŠÏ׎k%Ì77)#kzí㱸(Ý®ŒY½žKå¨QFÙÂt§8aQŒPvŸª&’~?pä}ñWÕ¤(~ ñI¶¾åå¼ÎS çUIŒ¦ŒÊ˜9¢ZñâËF[þ{‘Æ ®Ô~íѲß_vªÎ§m’ä²îƒA5ZUFŒšMuæ¹-űÓÄZ»-É4¥]ë5IR(IWÊ ÍG8]„Ô8Eúø€‡›n1zé*Ó >«´ ^´Ìnž§ñÔ¿7$Xî[BœkEäJ£êf3I]…-s§ÈàÕnB³™+­È¹«+¨Ÿ¡×KXZZùÞ^î Rm¬UðA_å÷•Ï0h§ìÃù:UT|=ˆq ""Ò‹.Õ ’›Ñ¢y]«:zTlñoUA{½.HŒ1²êVAž‹&|Ù…Ò/Múˆ¸¯tÆÔ-»\Qôm•ó>Σ e‰GA«bšM!ÑiѸ¾N E/- 4)Îîãð©y¤ÎÇ`€̘dr‹k¿mXx¥÷=Fû©ˆé _äÚol³tú×YoÓ8ŠãDê†ÅxžÇphÓ„•¥Õr,-EiGG›&ÅòòQ‰aä™Jòp¿zøh”gðWWcue —]´¨ñº4#ª‘~øF)Ǥúÿ.ƒÊª&ÁaŽrf¹ÑÈÝ´²ûsçs‰šœ<ˆÜRÙÅ^/GdTœ©,!¯×$àâö?oüRŸà2Dd4’•>×ÅÏ'€¸ž.¥¸4þ°Ö¤ã/;5Nê„éó¶?½‚·úNðžÄq \ç„çã\çÖ‰¢˜L¤\q0ðÒ˜Ä͹¦·¨ÏïX^–ÜÖòkÔë ŠzQr_¡änW¸=ƒÀÓêÔë.CÊ òþ0&ÄÂL°Ö½ªA+iI% ÃÐeêËêæ(uX#µš¼Fxû9!mkKQ]Q4X’ZyÖøÓßÐúæ}ÿ|ÑL•߯‡ìlf2jvÞ@P&úÎN š2iá‹æ)ÊhU>)S)T"|yYüm­+Ã<™ST®kµ\Ú¢Ö¦8ºÉz¤I ñ ˜a˜a|³t¦ý­ÀYœ[!Ž»„¡°(½4¾ˆÒó‰R÷` çl6“´»ŽNð<ì÷MšÇ‘…A {²èÎä¶5ϬUmˆ¡Ùu¥‚hÒ­èd ‡E ¡"¬?µn¢H%CŠ3xÿCUNËî.)Y*ïç++–åöí\³EWå04™òs;Š7¦òæÊÁÑÚÏEdºò½ëïE#žaÈ|s)·û³Õú~½Æ*ãW£!Õ©ÉõMåÃ|2N$cú}ááëî¡Í¥g3Ÿ ð€MÜô‹MÀkãbv8n0›ù ‡ê‹O§†zÝ# ]Æ®·N\U|ó lòšfÓ±¼,îîövõ8–c.¡1G#‰×z=X_wL&²‡¹ [VŠÏ¯ Š4QŠ¶î—  øàdvÎP&,B£z(Ê!%޵58~<¢ÝN¸p¡F­fÒdǼ U¿o沨‹àÏ*Ã/âç¢-“Pø*‹¥ª «jð”¨Ön«èWžv×ÏNs˲ñW­–jw¥giE$I]­ím/£ˆ×j²b‡$Ôj1Î pÑpq„Yþ³HN ÇlÖe2©cmBj×—5ÑÝYãq7$žw(G¤t5–„™ÉBÉêºBÀþ]@iåÅâ&ùݤD@q‡––r‚Eð¼ŽMq±®šåçQ|¶æMˆbƒŠƒäÌs·!JÉRº•æ.É<ìi(àU×P¾ g³\áy‘/ºhUM‚|órG5˜b÷zelÞi×*'Ú4˜,º]eD'J½¾_ß”´9 ÐI’³ïѨ} Ô$GtŽ<¦ÓƒÍâ ÈK$m/k³^ý}öw Òk^^v¬¬H|§:Sa¸ßí\Äæ-;;Ò¾*O:š}¶VžX‹ÚvUíðÅßýƒÞT”o jvª ¥åq7n4æè±ÅòÆ¢ï¼(“·hBæ«G>aX¬bኼh¥(Þ佨„©šç-ô¼Ó©|i|Uq~UV¹(è*W®zS—P!h­(Óx+ßù\Ú>ÖÒjuh4Þ”í¦Q+Â1›Y)܉ó"• @õxŠTÉž+ëu>¹¥«öd" 1f_³ºªçP54À÷}ÙaA’jZ2©ò5:V2>.mZ8ÿ™U6[ü¼…;À&CùDeõý¼†¨ðÊE_»–|£¡¥qÕY•øQÕ¤¬º)iŠ—÷8[dUÛiqÕ-þOï£Õrlm™lõ/Ád²XµxÍZ۪ʭ–ÖT·ˆU…dPžT¾ZªÂD·S«ÁÖ–0Ñf3“J;JAT ¹técË2½·Iã:åŠ;¨Ä=n.–ÒCUoÞÌß_^ÀÊ¿]k•ÖT´'IÄí\]•]eg'Wá––¸òót:?‘tÑ©ZÈçmÖåâ¿Òc~gHKRݲ"lnªæ‹Ëði©ÍÉòÀ,ÚšgEì|ÑýU­þ¹qQþ$6Q¸¯§(^® UП<QC]ÈÈ{0—ÇU€íY¼EФh%we4w£ ©œ’kXAžK­–ÓOÐÝG«%Ô%&*é­8)ôPwj:5Yéi^H´8ž,??U|Ö|ŠüÝd !ÊÖkR¤¨ßŸ—°,‚ 妨O@zDlвÍßrUBη  Ê(×½˜=>¬ûS>Š«¼®üåÿ—Wõ2:£+† WnëvåEi–êíÝ,¼^uoâ”U}iI'LndåÇy½kq¥,vJmÃêê®âÄa¨Rõ ž'~˜ÂÏÒKm^jF»)V‰Ô.Š©Šuý¾VÆíÊ‹[y(Yq>ö’ëÝÜ”šƒÕUéÿ•sL¶ƒ•ãˆâ8B¾›j·¥kø‹üà;½þ,z8&3 fSV T›Uƒ.Má‹ÄI~UÆRõ}‘Aë¡§ŒïW¹M‹‚"MÔ)¯]š†»Œ“SD•Zü ¹®\!¢Ñp™"²$5®(ºb²µïïM Po³)5ÅÃ!‹o“MŠéT( Z.¨²ŽµšK)ê9ĨM³©4t—1>‹Æ;¿äŸ+‹œ 8Ò-'_äªråg^æ Y2Õ÷¥gð‰rÍ7oî_ù‹çÓE­ÑÈÝÎ ÈÑG¥ÙûU†_e,‹ücñùeÆË*+pIdK,bñš5•Ôÿ|[£ƒüĪIR51ªV÷²q.2Z-ÐWH»-«Y¿oæ>÷ ¼Œª¯÷}™dƒ¸)’éÌ‘Žù{1syˆbÁ‰îRņÅU\]¦8vÙûŠ ¨É„´ÛNÞ3M))í¶dz¥£§æŸÑ"CVu6sôzêv±ð½=Ã2ª¦$@!!J,©HSðçJgÓµX^ÿéÔdBfº@åí¨ø÷b’¬Ó8O«·F#e`š9‚XÑâ8/$׆Öeã>Èð“ )cýU÷R~8jHúûíÛ6+äH’œ§r«VÂÊc'øyîƒ[ã•91ÅÜÀޞɠÑâîW¤¯§¨KÏ„"ÁîM’œ%,€f,’ýª+‚€ŒÏTlMZ|ýA.nÑøUŸi6ƒ«W-Ý.™¶“óÈ€a´)£ºbJâ,&ç&À¢•¾ø·òV,@füêª\¬D倰Œ²h{K•̨ºùƒéN+{Uä £¼»I½°øà‚“»ÁšwW«jRª‹¥uÉ‹*ÓŠ[ú|ÒG\á9¹Ô6s@yõ"(%‡0MóëÖ]c:-×C+¢eètbŽqã3™¸ì>ƒ\£µ¼šëýjÏénÀeÁíac¼â¸‰ˆ€ü¼·gR¨Vë1òLi)Z¿,J~ó,€b ¯ßýò/2úrAL®ß/Ea:áÆìÏè–}cÝ*‹“ªj4Pw¼2ÄY5!ö»u.k¬§Zöš_h4毯êá/r'QjÈ|#èƒ&îþI+(ŽÖQKg›Ùc7ÙJ_|^Ú®VôGsº¸0Éû6Uu7Õ’B7w¯‹PÜhÅÜþÕçNn.¬‡Å|¸=kk°¼ìÒÅÀ²½­­¹æ‹«Ê¢[ÅÜ/B9ÈU_¿ÙtYÒò¿å³3_)‹z‹ KÝV5Ñ¡ÁØWbøe¿ÓÏEc+CŸZ£¬ 9>?ßÇjž]5ÁŠ_ņ}wr Øx/ï’éûd¬Ñ¼då‘h‹ÌƒêjËFVƒÞi¨‚x‹E‚ûO&JqÞï·4ª&¼s¤½j¿ùN|Þ°\FuÐ_}úª8 x¿³™îÇ3eˆ{0pYM¸(Eäêméóè}ÂþçzWrš§%”*±¢¼/i>"2íͦK]Y—Òc\:EžÛ~¯‡‘æoóªši6]V¤(Þ²"i9£âÏw2~½9EÔO}£…ëå9Œñ—r™Zà\£éß´A_U€¾Èð‹-^›MÅÆ«¤YAñ³t!R¾½®ädû'V1è­ßÎ+îª&bñšŠÙØåå„$±™KU¾Æƒ\ßÃÄPåg[~¾z¢$ p±]•f¹õ«×“I«™cE²Jn~ÇŸÍp†  ªž<‹‰¿¬JÓŠœ£“£jºÓ ópÞÞûF ÏrònžS“»*k¢)ànîA/º¶ýŽK›\9.×õ\<>ÅÏ*þߘù¾ie˜yQ iÙ€Š|˜ƒv}ÖäjœÙ,ïÛpPp¹È8Œ]Ç¡|MZ”÷Î_STVäk}]h&ëP,ݬ?˜ñhD ³Ê]è /³_>äÖ­¼dN_kdï´ T äE!‹‘E†_¨ƒVý*ã×ÕT•ã¤Y…ö¢¯U.Ç6®Z–$. ´UQ¡jòTÝcùÐkÒ~fű®ZxôšÔo׸¢l UÁ¸•¹‚G±lòN^e‹v…ƒŽªg«ôŠñxñŽRT2¡^7VdѦïùaÈmkYÒÎÝ® è8lÀ¤ Zô½ž£`ÃyÎAe¹›M]©ËoÑŠvÚ$îƒ*ìOz•ßW½Ú¹Œ–¬õÃÿÿÖ®ßÅ+O»Šö´w†³°«Kc»È&©Cò¤¸ÆuÚ4ç€Á„`H‘&eŠ€!] iÜ8G •!B 1&1„€97Æ2ÝI§“¥ÕK1úö=ÞÛ}çdAh%íjgfgçÍïé÷Å¢M, E&’feNˆÅT'žKÕŒÇ:ÎVŽ%ûiÚé!ÆMŽ cDõ) 'b½‡ø=m·»»î~ïõ¬- ÜËüd->á…•ív…y†C±þ9ýO—ÅŘÿ¿0¶fòÐ9Íž—ŽÁÀ“ßj„ºä… /Ú:ãÓOâkzb7ч«Z¨h Oÿ7ÝoŸ‚xdDµòÇ ÅèN¯‡?•1EµÓ¨DeY+ êíBºdCÒ8…fMt]3ÞO­ÂiÚû Ü^¿–•¸,¥ùÖ*í{¾XàQàÈüc ®Jñ·3|ŽŽ:u‚UŸ6$R?õÍ$Y-U妻¾šôø neꢫ)¥oY·å>¯]Ãì1ØSpšNÅÏ2S{ãF# ð^±S6UÐ<bÁ /G}_´:"Ðb0p]®Éld¸¦ûœª„Ô[ªe~ùe,™pÓ–qîÏ<·¸|YRy^¾ÄƒÓSó$_.ñ{žãŸY+†sXe¹Ÿ*çi…z&ÑHƘ$•Hú{ßCBbøÿ%þlƒgÏÜÔAé³c6)eUÓm|2ÉúVÚb1Ú†ðæ> VºƒõЍácÚWH ’àÆª4ÀyºB^­TþhJQ8;l½qWÓ5|µ—sŒ« SßT~¾v &ñ880X,ÌäøØÌçöûªÂ‚Ë-½>ìäL},ÕeØ–ø¥uØ©êŸú=ö  ÌÂð~Ћ/YíäfJõ—ÝøßÔ•¦é½Iâë4 v¢úovYˆÑ_¯Üç,c]H¢¿>W>Ûºý<'ýd™Ýè§ÔTå£W®‡Ñ¦¨‰÷Ã:;ËÅ_U¾6³ë×e‰¯±»wßÇÇW« ‡‹…1Ë%Þ±¥˜Óýü|’6£ñM·Ð²Êéic"cDŠŠŽÏÔd³æöô I;Ç|—‚ONÿ]ï¯gÚºü!î3žQ–¨§K†ÜžmÂ!Æ`!œšhΩ(œÌ Ê2‰³ôÒ/¦OM°ó{X&ù~¬¶%€ß|j-¾Ë2œ8ä¼¢øpçί^aRUøÀ¯Öâ=kñ1€+« @Tˆ²´µ{-E§?Ϧ Å6£·Mª‘]e´ú]˜Ci“ VUXëé m’;dø†`×pË †‡ú6öà÷ ­ºøŒ“² …èÜ„“åRF u»ÀÞÞ½žÁhdêÂùPªHúºMt ­¼~_ÒØ-€9€­Å}cðgž7n(÷tèìÛ·åßÇc˜~ïxÀ‡>( \*K»ÕíÂŒFÀtj²ª‚ñ¥èÿ¹iÉé¿ëßpñ¾?Ówgǵ$a¿Ì˜Êt^œbR3¶ïç&IµD{Ùø–cGƒ ³™ÁpØ©gkQ}ãàïóTÕ¥®dš†\¡¶·-vwÁ@aËgAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAg€€0á1šQcIDATxÚå½wôe×uß÷9·½þ~uú z‰BQER$%‚M)Ù²¥eË–%KN¤8î±”XYL%±DzgE^Ž—wQ–e/µŽ( p€ 0õW_ï–“?öÝ÷žwïÍ€Å"œÜµ~kf~óʽçì³Ëw÷Þ†üúÀ,ÆàYËky7ðNcxG«ÅF§c½½=¼áЦ`­ü|-—1åþ»ú{Ï“?}_~:K· ý> åwëû<âxù½,ú÷4›òšý}ÙðéÔ0ËŸªe^Éšª«×-iZ®…,çûëaÈm¾Ï{áb£Á—xàA‚cÇ,O=å}_£aÿf–Ù Qw¦8eã1Ìf‹7ÜYýsÙk–ý}‘9pO“µ$òõz¹(Žœ~½ÏeB¸è³ ƒ{Âä;,Y&µhá«—nBÊiÖûw×GŸÁ÷K­Óë¦ÓRø\Óâ®éՙ牰Öë$–8.5¢ûŒúýµš=:™˜_2†Ó”O?ì C~Þ676äF#‘¨8.m‘»X‹nêj7¹L’— ƒû“$†8¶¬®‚çÙb“F#S,Ô+€« {%‰a6³Ôë¥Ir7Õ] ÝÌn×âû"”®@Í«ñ3ÔܸšÅýq?ûj—1ò9ͦ¥Ñ 0z¯ÕïW¡^]µÇ£ˆ¿T¯óXe¼7I¸;Ž I" ÝíÊÉwíë¢ðJnrÙf,U‘APªLÏ“‡j·eñ¶¶ ûûóþÀµ@Õà+ ý~j6e%'QÕúÜÖTÿîiw7S??Iäį®fd™œH»l­®ö\*(qlˆ"‹µ¦Pý‹ÀZHSáC–,ãmÛÛ¼5Þa-ÍÙL¼ÏC‡DòOŸ–Oò}Á×{-ÒÕŸZÍÒéÈ‚êª=VaX¦-–9_õ:X+6²jªªBÐhÈiŠ"hµ,Ibè÷eá–i‘ZM~F£åPF¢¦{=qô’ĸ窖]tÐæŸÝErïê¹ÚQ5X­&i0€ÙŒ0ä½1< ÜhÀî®! å…*j‡³lþá–m²ë•ºÒX„E¶UN‰Øxý®8)ßÜçi:õY=q‹¾C¾Ñ€éTÈ¢ª`O§¦ð=êuQ«Ó©)ž½ú<®¦rŸß]_ÏÁÊ2ý\æ„ò•ªþêÚe™ü,Z q¢-Æêuùý} ;ƒÀÞ4lÔjb¿†CqLêuËúz¹ŽKšÊâT¥Õ½©(’׎Çå-ò=¨†vîŠçlé÷Ë{Ñ?u³ô{ £ï‹V©×aoïà&ºe"pž'ŸEò]*‹@µ•záUq\Uƒòp,:Õµ]ædëŸi*æ[ïÕ½ä067-³lo›ϘNÍ© Ó±A’ˆ}Ó“îy†+W,ͦø½žÉ¥Wþ^õV« E"P³Ù¼:º–*ÓkQ$Ψ¦Øe±{bºÊïY$@.ñ¢‚ÁÌ…uËü›$)O®ï—ZPß[ÚW[ü~™ žÍ ëë–VË2Ê!«úXºa.žP]çª_áj®zÝÂ(¢ø­–-€,c,YV„š·{{"Aª³L4ï¬ fmÍ’$r¢ÕW#×Þv»úY–ñxÞa[$4‹®*¢Ìl&ŽjÚÜë5 7Ð] $k}ݲ²½ž¨àEàúI"‹ªš°^·L§"Œî Sm¡ÿ^$„ª±ú}“÷<~±èt{žÜ§‹.òCD ˆ°®®Zú}ùe»-ë”e°·gŠÏr„?܇©:S“‰,À¡C°³SÆÝˤ\ß[ž”òõËlô²X½‚@6À÷åÏÙÌÚh‘j®.¦1kE¥ë†TÃ5©Ý°/ ņª ˜NÍ>Eâ4fÙ|$óÚ¦VAe]ù0úï0”Ïu®EgÑO«%ON¾<ÏåË šD ƒj8¥_âûrÓYÛÛåB(&¯Ú½\gGŽe'³ªÊ®u…¡ØPMMK‹SWU™ÕÍro^´G³)ÏQ5n^@×ng´Û°½í1Èw©¨M_]µž$¢^õÙšMñ?&SÄéj—aò>K»-‡N…c‘冡z` Ë‘#òÂévwå V×§€EΓû…£v»âˆª“0™Ì‡U‚s[jµÒ‘Zôùî,ú÷¢ûÄyÑÅwÁ] Uo‹¾G’*âGÔj×ë)t Žå»j5y]–‚ ü\S(ŸÏPµj9 ²!µšÜëÞ^éÀVÍ›~^­&B5™”æÍ÷¹‚ Œ*äsåœ8‘E–gž‰rˆy±_, ç4ôê÷Ko¼×3t»–ÍMËh$ÿ®bªT8m´»Á‹´À"û¦‹¥ÇâI7›²A`‹u™s—¦ò¾n·ty×’aTÕ-ÂEr¢Th˜†ó¤f@¯,ƒ£G³\{yxž×|¹¦ Õf8,1e¾çI¸®9 Í3lo#7Q«‰–L’ym¡÷¸è @5í« Rªê¾Fã\×^t¢¯vêùz‚]A˜N í¶emMlåd²8>(âH6›óø¿û ®àdž¦@,’ 5…O!B(‚(¡¤Éͨhˆá°¼w5-ZGÂÄò-ò¡\µßn[êõº¾xÑ,I'[8µz@4* …îŸn>z63lmɉèt,“‰ü~<6…ôÃ׎Ó/†E6² 3ËP³Ûµy>ýêgUÚm‹1åFºØ† .šµò¼ HiN?MK§Ñ÷MŽRdNõuI"ß1™˜Â«ªvõ'T¸«§¿êè{$)››bj.\ðPÞF–Áxl ŽCØâpO§î\ãÒ/ÕBÔŸacC•½½,évmáü-ÚäeÚÀEÒ®¶qú»ZMâ] Wƒ@ìŸ:;Ë„Mí¯ï‹ð:dÙÛ›lJç· /g3¨×Å«žÍJÔD0¢H4…nølfŠm«%¦Ôõ—\!Óg‹"Fu²«‡bÑÁP Óhˆ *® `– “FfŠƒè{ƒÀ–p5ÒÕº€i*ê¥Ù”Õ›QU¼h³—LáFî"d‹ü,“E*“FÛ«}××k„à.¦,‚-’0.CGO˜Q$w0™˜ü{ ž—qhÓ²·ïžz˜ÜQ¤8ýÆÈ„¡ªÿõs9ú<†Í@ÚÕDUV¢¬¶ÐDêŸlm‰vª×-†„É®)N^Ï+£Ÿ °ó&àj'Ç5q, k-››òAáaoO$NV7Ìý¬Eaššï]ðcÑ=¨3¨yô$)óñ*P ‡¶8úþ4{<›É¿»]9Éj¶ÔQ0KÑÑ45`„Éâ¬é³ŒÇ*P–ñÈP¯Ë³4›¢a4:P³Õï—NYÐ6ƒyP«šwÑgkµ$¯Q«Ékúý[ÐÌ pæQ[ýûl昀k9dîÿë¢X ÍfÆñã1§O׿`HWÅ-:Õz)(†ä(Ý|Fk‘¸e21j9µQdsa0svÖ K§ÖR«•´/(E…P5Z˜N kk–••}êáçÁ#£Åtr˜á¨A’XÒÌàù–0´E„ Øˆ†w®:n6Kah{>:¨®ƒÞ·¤t ;;†Ñ¨Ì‡ˆC|pã«N´þ=Xb¨zÔÍtA%!D‘„6;;A~2Mñp¾¯È—)§«9gq,§R<а–!_ RŸ$[{ž-/=Ñ‹¾d¡TJ2¬\ü86´Û++¢šƒ@Í]n¯¹„ü.Ap¿õ'£ã !žgs¼ÂÒëy¹&Zc6“ÏU3P¯K·¿oæ´‚+´Q$k£H¤š–z]N¾K­þ,ª *IH’6ßU)&›ß¸<ÐÖôz>Q$B¡j§^/ãf7w°h3Ô¬ŒÇB”ô<Á³«Œ_W»„a) rjëo6ÅãÞß?Hލ:^.±£Ù´y$!ø€¥$ÔœÍLá[x^€ñïÆN…ä^ýQÔ¦Óé¦>q쑤†4•u“ ŒÇ^qÏb"J>`ÕA“"¨¤ ‚­¬È¾\¾,S«Ùü𘅛\Õ˜Õƒ8¸¶X¼8¶9Úd x<6…TºNÜæ&4áa0×]-g¿Ìô¸xý"¸Yøm…èƒÕjÐj‰ï÷ù÷ê=4óYJ±ñâϬ¬ˆGoŒØWtE‹"ËúzZ„{à5ÒiÄóý8'ßÜ¡u¬NÅÚˆzmL’¤xæ¢Èg4‚½=¯z²LÌØáyÀ§Š4ªï†f³Ì'è¨]w7¸ºéW»‚êIL$_6Y4€f ÝÓ¤?ıe}]µã¯ ÐÿŸÍ ûû‚­·ÛeVËÝD÷µ£‘-<í8†+W‚œß_†Tî{…èƒø®&HSÃÆFÊtꑦ¢º…H³™‡µ–Z-%Š<3,^СÞÈ.~ »yÞ‰a†=‹ÏhµþiºÆh$›§É¥f3Ëf¯Pízð$§P®qm)=¿$騗¯ûrµ(n©,r¬Ò”œ¢¬qðÁÍt¥-Šä‡Ȉ²µLý¸§æÙ±µZé]»™2ýÑ7ITøÄ<Ébe ‡Þœ:ÕÀó$6WdN²‹¥£Öigı)Â,ݸ8örtÎbL 6ÃïÞÅõïÜgçcfôÜïS¿îFÏ|º]K·ksz·Øï••k=¢(Ã÷§ ÔÁ;JóÖCô~ŠÉWž¡~ã­ÛÞ‚×z#?^$)ÔnËwíîzÅFjÔj)§Ð8~¹c+~‚ú*³¹çðÈ/ƒÑ«‡M×o)èbÿî uO•¼Ææ‰ S¼f2Q¿ D¤šMŽÕ/XæÝƒ8lQ àr «šÀ½·ñ¸D;E Í\ÆPéS­–˜,׈#*¬]¥¿!Ëôoó[çÆüÀäŒ/sêG_ÄÔÖÁN0\‡ç*œ¼(² t:¢å$d59ši Ç¢ú]ô"íéâk¾dgg91§€ki«TWKèé‰ò<=e®Ú}í²Ô­†JhWzôU\\È%1ÅE*g3Y8É♢°S¯éT ÛÍÅóït2¬µd™ü;IB>ÆÄ®öf¶ý9¶ú›ß•’Mcf;1ÿþ¹)¿wæQZñý¼ïíbÌ“Ä{Wˆ/ލ_÷GðëÔj>¾ïÓïyjµŒÁÀ#ILá„6›äjß±Õƒášawí°\“~Ÿò6Wu¼˜€e°«« ®& 6M72"‰K5®¨è˜^ú`zã{{õz)PZz¥&§Õ*iWîâD‘ÍUiŠ1B’pJ0yˆeóä–zý)Ó©¡ÑHsÄ.Ę6½Àäì0xîq^úÌ*WžñÌéÿás_Þ½‚gàühÌï|p÷¯?I²ó6[¥~ýÆì!iÚ-ÅF#f8ô‹{ßI¼µZÆxìcŒ-œBåŽFó¹5µšD@³™„ŠÅ]«‚*X´ùÕ¹ ‚]&š÷ÖøVÒ©ó°¦ïË)Ò¬•° ^r»mYYÜÛ}m–‰C×n—Tç2ë'?qìÓje…×¢MZ5ê õºa<óŶ´Û Æx„A_œ>bŒïÓ¼óõ4nÜåñ/ ø_ÿõ*Ïï_à…ݱ™¬òCçŸæìà(_ݹŽûE¼é}}’þ¢ÆCBM°¶A½žðˆ"Qûbâtë÷ýÀ÷Ÿ[wªš6P‰z% ™Z$(Ëþî"QÓ©`î++‚Ôíì¤q¹ä WèÀ§ü`%®-Ú®ôûeâDÉYf˜N=Ö×ãÂÁ‹¢Œ ˜áy)ÆŒóMOToam_îÝöÅû·C0޽yÂÊGfLYÞ–dÏØ2'Œ™`í.Æx"¶…gL0ÃóÚ3!IÔêžÜ Þ©Õ„á3‰]ælŽ“”Nâ²æz˜$€räq:5ã–eJË=]lõÊõäéæ.ÓFY³¦F»2›œÑ+¦W£!¡‘rðU8G#¯ W« T;®vQŠ4Ê÷5š†5€Éýߟø=ŒÙÍQ½éðL´Š®õ0гŒ€}Œ×#:rÇë¶9ùá6{ W¯k›|Ç;VïÈ€]Œ©S³&8†±«ø~ 6Í Hfúøñ£Dµ ƒ×’$µüy…å£UIƒ˜U·ØcÑÚ/JÿêAÖdT ö³¤ ]-g¯I-Óø¿Jø¨þÚ%¯ïõ IÒéˆDïﬨ°¤d¹Ža«%§Ý…€ÕOˆ"V+ËO¹!Ž=jµŒ•Q÷¢Þ A°GºóÛÌ®|èäq²ñ.[?ÅÚý·Ñ¸îXšÓ§î)[—é±4dLû[Dõùö7žãg¿m“ÿæÒ*/Ž÷Õ†ÃQ—¿x_Ì¿ã²Ù”én þ šëkôN¿ÄàåGßøVüúí`Û€Á0Ê…m›lø ²Á‡©úyÚíŠÔzš "X í\õîÖ/ºÈŸÖH¾¤ìST«YϳWUÕÍÌ2‰1›MòÌŸ ‹nHY4êõ+£Wëú4öu /ÄÉ““®¡¸€4WŠ™Nvwý¹ IZIX¸º*ñµ1‚ìÕ뾟`ŒO$3Á‹fŒ/>Éù?Æ¥ç:lœ¸Ì¡·ÆØ8„›Øt›Ó‚þëÞóöÓ¾£ÏoýÖ*7lNØ¿Ò%;7ãöú]ŒÚgÙºò+«kÜäÝÂÖ¹³ü£_î⯩gçɺ»üÉŸìóȯvxúÙ“üP퓜øÎØ Òªk†ÍÎqù±çhÚdõÆ}šÍ iZcgÇÏ›t•ùIwÛ¹°Zò¹»ØH½nsX¿,xi·E³ax°¶üjÉ¥8{ž$|ÄÆ–ÚcýÊ…!5*˜Í$á³²"B¤æD=xeiº´L}úD‘Íù÷B«ÕJ5?›  ³²b‹jÙ̧ݎ‰¢>ž—€M ±×isî³3ž~êw¾q‹é¿Þc}…×ÿpFØ_ÚâO^á±çÜÓ²|ðôy²4cg6$ËbRûŒ_ª¿á Ççí<²›<Ò‰š4ü¯91}ÆçƒOŒ¹©“òƒ“pÌQ¦—_bt¾Góú&µµQxžl’?†dÁ}„¡ÍÁ´’ûoŒ„}z¢õ HOƒþÓˆ­×±Ib-`’ok ‚Àh,^Ý|×¶/vè ;;¶ØDm:°Hsè{TXDÉIïtæÙ»z 5LœEõì%"ði·3¢¨Ä Z-›×ð›Â?èt& ‡ÜqJ1&ÈMÀ’MûŒ/eÜú]gyøå”¿ò›–cÆpòÈ>×y÷-|²Éö`Ì£¯ðñÌcšŽ°UéÜw’$¨#9K¶ó|öÅQÈ#/wé͆¿#eë«>þ<§îZaÿÌK|äïw¸ëÛöY¿Û<Ÿ÷.PëüÛï&mn³mÁ²êõ$JÐ a¹fÖÁÊ2½ À„¡ekËm UM’ ³Ì:rÙ”EݦŠçλt ¢ž¥õÈ<$»Ì'PÉ=\ùNë•0©À‘R˜¡Ìÿ+ý̈«^Ô zž!M=À£ÕŠ™Í¢câuRüæ*Çß{>¶Ít”òÌ¥øâlÀæÖ¯ù_6øôΘ¿°Ç82M/õ븒,fg² ÆðÉ3»üù_XçGðyþôøÇï¿öñç9ñ™fÔå]·Ÿà½œÇF«˜èAœÒlŠ?ÓïËÆ+åÛ¥™+ UYCª­ÓTk‘p¼Ì+Ä1ý¾É©Ñ%>/hÔ¼#±h…”!v»Õ²¹:;£d }½Vи¹€$1L&¶hœÐï{5Ûäur¶`çŒÇºÁÊÇל¾¡ÕJ™Lü"£7Öhµ&Á$?ý  ýȰY‹3_=Æ“{âL6¹7›ð÷¿ çW˜¥³W¶Ã¯ô²– £—ÆCz¿¹‚}ºÁ¿|†'·¶y8¹r”Ÿø”“âz¬ÐÎ3’^‘û4SƒøV²>R "XB‡ìíq IÑû(Oüî˜ëN>Çæ}ûüê/uùÍGš¼Ø;Kœ|c¶þë,Ð Wø‰;ZüôÏ÷¹þ]kïD*Lð¼„FÃ# a0ð ûûr†Ã’)'Ý\I!ÄÈÚ¸ò\•í¢A„¨SØõVKÔ¹‚7®ýv”1¸¼W¹êRUc - —›ä¦[-eðxt»#Â`L ðȲˆ(ò0&Cf“gí¦Aø¹€YŒéçN‘!Ah[Yçö±ÉË|úߌùÝÏ´éMC޶VxöBÂó{/a³„oÕµ7¹Ìo¾°ÊÝ­®_dó®+ÔÚ'¾†kŒFµB³ŽF^‘ñsO¶KªÕÖvWk¤ à¿ë]>%Õ¨d÷ÈIÖ®Ür™¢å™1fN\R‰œ««ex¦@PÙܘ¢,ʸN'£^¿„Ÿþ;<.àùàûA`ñý)¾Ÿày¾?Æ3SÄ``XYÉX]•/–2o‹çy`|âóÿÁáwá5߬‚5@€ñ,رdçÒ-ð ¤jB±óv &C”«E<ÿ1ÖôÁ›qÃ[{¼çËWøÄ“ÇøÌÖlój¸¬MyòÊïá"õdÆà¼¥±Ñdðä9Z7Ñ!<Ï+ŠC›ÍŒÑÈíPš[½–å\²ï\y¸Jˆ¢uš8 šA*›ºP¬V¯èk”ÕUñ´ÊFš/ŠŸN=êõŒµµ$Ï$3ÃRc²µOsýçl(tl3$<Êô̧¨ßú^LíV°M Ãb¬ )0Á²M6=ÃW?ý,ç?’rúi8?`í·Ní/º;ãñ'Fü㟿ö%~à}}âá!Ú·ï1†G’x…Š×ÞJuivn§3÷pêþ¤i¾%± 4Ë&@¤ôks3£ß÷Š.em| 6mT_!ËÄ»WÒƒb­VF’xyj3 ÕJñý 0ÄNŸ‡a;;l²ÉÁxM`‡ÞcaÏѸãd.Vo`m˜ Àcö^|žßù#þí„\Þµ¼4ºríº©?ôËò©—G|ìƒ=6»#¦çnâ]ødÓ16‚éTê ¤£»Éét¥Ú×ÍWV´ò&ÜÔyhJ^s-. fó4ËT«Ù\ý—Õ´J¼¨ÕDíN§¥wo ‡««í¶Í9mò%Ýn (aT5H€ißM¸ù“/}‰~z#ÄöG´î¾…`õ:Œ?%:t‰­G3v{Osê]{xµU¦/õhÜx'^t$<,=`—ÖñïþŽçùäG=é_ù–:}W»†ñÍf‹ÛwyÃ÷EÜðî{Vî!N½¼³IéOi'oML•—¨ q–ö‹X>îåû6§c‰pù²ÏÚš-)»EÓiÙ:EÂÆ2×ïy++¾ŸÇ^¡¦šMáßùžÍùwp˜úmo%;ê±÷ðWyì—1L6¹ëM_âð;Ÿ¦q*¢¹ú"»—»|ð76øSÓ/qâÔ˜Kt¹á§GÔ¢›0t 7Åpž¾¸ÍoüÖ û;X›òj½¬µÜ{(â—~¾ÆkÞ÷mDwbía²ØÏ7ÛæŒ&9l.*«§lnLÑ”Z[÷‡¢Dj»õÌ[.Õ³ÊR^]§#¶]¹húZclÞñB´‚–F)ǽÝêµ\JÑe½>þŠÕû˜àþÆí¬¿é íðþïˆè‹]þ«3;lv{¼t~…|n•ùâghýó Þq}ÊÃÏ·yóÆ‹\wÓ‡¿s¿¹ 6Γn]áÉçC>¿w9/ëzµ^–g÷2vf5¢Ž‡M§àY†03ÅØ ˜)é¸Ïî#}æ8{ñ ô§}²É}$iÌ{ÛÌÌKl ¶øG_Hù_h0à¶û'¹édÆ÷6ŸæÈëVðjuH/súÙ /ìX²ì[ò]ëš%)_~¸Ï·|ŠÕC>­Ûî'IBú}?o5[–â 0™xdYÙ]Dü7;‡ ,jq@pzí=£_Pí â¶hWnžäÝÅ1 HÔŽb‚ØeEË–é4 Š Ýž>A0ÐÆ¤`GÀ6p¸ˆWÛ¦{ä wF†Íڽɿ}áIf³éœ yï< ìßÿã©>'_^åâ/ÜÌŸú¹ÓÜðÖŒG\9½Æ‹ƒYöêUÿzm'üÊohöóÇþÛ¶‘If9JjŠ&ÜêjJ½l3Ï\†Â(5EšV«¬žUG3Ý®-byˆv;#M½¼œÚÈŸ:„šøY]M˜NƒÆLàñ¹_Ç_ÛÀ_½+×[ëSÖnèõ‡|øÒ‹ì®|] y~÷E~å#‡¸ieçÎOà? ”ïmrÏ›×XYi‘eµ\ gÔëʉP§ÜÌõ]ð¼²ÜÝmŽQ­PÌà@aˆ ‚æŽÓTh_ÂG;®T#(»„v:)Ói@½žå&BLB³)U7âOÄÓË3]Cð&€aòìgiÞ{™l<ÂÆ;øõ^øƒ=Ÿ1ž ¾þµ´–‡/íò··¾‡gíDè^Ý—‡Ï÷¿¹Åüµ;éÜt?Ö6ISŸÑ(`4*kþ¤Áy;œŒà<ì«u…*©Ä) q =ܾ?ª"´ÅáÃbßUýki•ö®©×ÏK°6ÈÇYÞÑ´¬ÝÏ1û`LtÃqFgžáì?}ŽZcÌÞ¥'ŽíҲÓ—¯0KÆßЂN³˜ÇNLÆ\þVoﵯ7šÜ{ïÍ´}ž$O™gÔjiÞ¦¦¢åNqKÁÜÒ:­P_÷òúI™8YÒ¶´Í¨jûÓÙLêò•Ï4 GxæLž…; Ô@'¦Hâ;¯¼1lvA4Av›œ¥VÛçcÿán~ÿÜ€K“)·«É .?ýMYÔýá'‰ãW¿úoù!ü]7ò½æmÔ×nÛ ËšÌfAÞˆc¾Q—0má”»åù¶k Z­ÁtMA§c Z-[$~T‚@gì•E޼¡ÑHñý„ HJOžmÈÆŽÏ`šos(ßô=lzã1°‹ÝÿÔzÎ}òK¼ô;>qnÆŸ{”$ó1¿Æ'Bbi[[ûßê½½æÕˆþÌûnà/þÂ[Y»î~°+@k½œÙcŠ0ÛZ‰²|¿|¡ø~SÔ –-ýKš¸ç•}›|‚nWÞ ’Ñl–cc­¥¨¼=zt›Fý2Ælc¼ Aºž{‘g>òû<ô‘3üÈ_>Kgãflû,Íë®Ç¦Õ°ƒKô¾ü½³Sš<ûéü½O6ùøù§IbQ÷I:åôK¾úr5ÿI.íëé/¬ó'æ~ÖŽÜ%‰-| Ø„0ôóF>ah ÇæÅ.:¶V~tt«3ûxžWøa(½‘”Yí}-7j‘‹”3iâ géxÏ“ÿ?ùkÍ\’AÓ`<0žÅxàɧýÿö²²«Äê×zï²ß¹“ɽÞZ0¿þë™U ­H•СñæÚšÄÿ««õzF¤¹ ˜ˆ£Ç6dŸÄNÏ`® ØÅ¦/å&ÀG|‚]²Ý‡0µ}ˆfŒ>ù/ÿN›_úÐ1þùsŸ!‰G^›N¾–/=Åä*ÀÏÿ—®zðg¾ïþ‡ÿù=¿ó°7GHÒ.ÃaÈ``Š’/qþJ0š"Ç¿Èôze ¹kšMK Éõ•`à¶YÙß×n †Á Š|šÍ€ ¨)QÔÂ3oÂ4^—;5 sÜ’‹Û L¬tòpðÍ7ùœŠç­OF¤æu\O¹=˜±’lð²É7aq7­Ïbö÷Gßê}^zMâ„ñÛgX­‚ŸûÛ¬]¿ vcÚEli©C MŽÊ–ùEÕ_Ðêlu%áWæz¢ü÷¼çÁ2Ô7ëe­)v»òEÒNrÒ£‘Tà$I„ç­’eG°¶Aš6±¶ D@ha¨ƒi‚5¯#BâùoÈðôŽÞã=oßá»ïLùÁï{™µÙ>>Sgwò;pÇ6߉Åc0|uDZ͸pảڌÛî9IÐ<†1!Öhg3ieOÞÍ”¢‚Ëmëþ]{­ÇpÃÆ8627Эüu›A€vÆ°Ô »×÷!ŽMîD†L&>FšC—2fÅZ?‚ZxÞcVÀ ãö™½pž°åqýßB6±™ìà××éœK¸ë³œëcX@Ý‹ø¶‹1ŸËþ)ß_çuf{ÄOœæÝ?CÔ½ã¯Ó©ït·EDFQeë߇CSDª9‚$ÿ½ï}ðA—4¨I)õ*‡HÞß䕪C tpÒtjò _S ‘ ÃŒñ8È›/{ø~ 4Áä´m»Oºÿ8ÑÉÛðZ¯Ç«Âk†Ð£S?ÇÎgWùÔå ÓÙ×éÃÛŽmðcçy|2äôô•þ0.‹e{ǧuÅpûkÖhlÜ‚µÍ¼&Ã÷µs™ÕñõRÀSæÿ"òÇâìàvñJÛÖ¤~¿Ón‹ã±»+ÿn4lÞ†E4‚²P”ø9z9Æ`èv¦ÓFž ²`60'<õÃ’ ²0š$Û/°û|‡¤Ûä½GNñqßçÂ× ÒëÄÚuüô;îºé,7ÿûÃðåð?ƒ|€%áþ·mÓ9² ð½?}ßAϧŸ¿‘7þèˆënŒ8ôÚ»0цBý7ßzšë×ߎȾÁ ãê+ îúÎ.'Þôlú¦üwq>íÔ£V3ùZ ¶ÕÊrR¨-ØÙ:žN³½º¯zN zì.÷Ïåh- ;éjmMHzú¡œDi-ìî–´r7 ¥¹á`àÇÂqzXÆtÚ& Sü`A§l|ž´÷ö>Ó¿²ÉOÝr÷›{l¾³IãÄ wöÏqèË>ñü‘{†ã§VésãÝ@´z3Ø.XË0‡z¼öæç·óé­s¯bf°áÖÕ`Ì´—Rë†yã,ñØg84yQŽÐ»Å ,ë3t„¬#ÿÖ¾ö0Æ×÷»|pYÙw) &O¡CÒLYgáÎwò¢hN íN¥¦ Ù”æã±ÇpèåeIr£³™/ÙªPª‡Œ`xŽÉ3¿ÍìÌsâ{NݳÏú÷ÜEíØ·áÕŽ1z±OvqÂ}„Üøž[¨Ýp7­+ÔÝ‹ñ¯ÇÒÍk<0!+›ûlŽ^äsŸ yf¿÷ªc<ög†/~±ÎMôY_Q۸˳™_tAW;›¹Êáå ]Ù×ACÅZ­,Ê Cgxô² R¥ˆiuÐd"¡;ª]}‚ɤìf-~ƒ€Z ª`R:úyÏ`*Ã@jú²ÁSÄÛ/ÓxÍk 7_”†0Ñ¡¢4l¶ý<Û{¬=p&¼l—à6€ÖjêÙ`ˆá…ÿñ‘›¸È.7vs¶w‰ôUXÔ[ §)_½8àÑ'¬Ç_â®ãO@ûö¢àV}.Ö¡l`Íá@Y Y]íúâûÒ{IôÚ@·¹cÙURÅñööL^\Ž+“ Ü %_ê?h’LÿòŠd“ö·¯×c¬õH³:AÐÂÔoÆ´:˜èàn`¯äÅ¡)˜Mº÷ ˜ž °ék1ÁÍ@l^Š’D!Ò:z3ïû±}^ê_}~ñC‡8;¼ø*«4¼åT‹÷|g/:Âûß×cÖð¢Ò§^÷ ç\Æ÷–½ÆûÚ›Ù-/·):´Ï‡ºeaŠªt»²ùzºÃP:o»s‚´å‹¢S:Å÷EhÜHB;ƒ´Û2Š¥× ð}“7’Ž SÛXÁ ŽÇqËÃ1Rî·:4î¸üM “‡‘Œòòp°v"Âv¿–pëw ¹ù¾Iÿw8öñ6çF™}õà‰¸÷5M~ê×±õ×R_k1|ê6Y!ñBF#ï€Ó­5‚ã1sa»V ý{›rù€ ÿ©3é÷öÊÒnÍ*´è NÙ.¦tDF#3×Ý[r6¯.*J²É¥ž…ðÄŸÅø·bí1¤_Ž’Ú,À˜cÖ0ÁIq†Œ'Âaû`òL$0á!ÆqðÂG;|è÷ë|¡÷$õ NjC¦ñ·>KhŒÏk¯b¼#Lü{X?úÀ&×xdæ’±Wl¬¶†q»„T§¬êµý›CuS¤Ýz9öÕ§LTý‚ýý„p…ÆíöÑn‹à¨*‚²]¬¾^'kw:ÚØ#\0ÌeYVmÓÀ÷Gk&'¨›™äÍ•èaXË5F¦Éäò€'þã »½?xË€cí˜gΧ|øå³ßòF·®uùkÿEïyƒöúMÀIà8&\#‹×ŠÒpf­ë¯È ;æoY¡oU ¬ÍF¸'½e)>IO:åʇT‡¹ø€ŽqWÌZG¶) ¤}k·¶LAT!Ф„l¿W' ê9Pd˜L¤õ›¦D}ßÐhD¤©Z0ÏK ÃNŽ.Z¿ô?v8=<É™Þù?ü&QùµZ?Ì^ßâMß™qôuGò&Q- Eš­ÇQ”Òhäy™ÓªœÄæÎn4l^(bæÐÀêåÿ÷?ø ¨l±Á««â\ôûÚgÎ@ÑÕ:‰û¾tÛÜ”Ü@õôKÑh9Q\gÿè<^©.{àkn!IL1r6a !e<˜N½\(2¬ ˜ÍBéhˆôâ>Q£Ã]Çnæ('Ž4ø£?{†oßÏxão®ð+oñBÿ žõ˜$ã…ièk]¡ÒVØŸ xË «ü¿ê±ñ¦›éܱÂOýÕsÜèÝÄ]¯ßgãnC|ú%â^3ÛÃN.’Ø»¼‚í %êçö˜ÍL>[ÐäÀ›@ÁÚš¨­-SÔrJ€%è÷9À);ÀwT¿nR­&tqUû‹FT'}ªôé\[Ï+)Ë*<:QLTW¨9m‡Þhˆkcå½Ífe7Ó45ìí5r2‹ ívŒµk[&xµ.Í£ýÆõ¬íá—ÿèk·Y†á ‡ßz'êüK[üúç»Üx(äž–å×¾:&K-;³i–Yü”ÙL4D`²4%ðC:Qƒ¦òš#5¾÷^ï=Þ¥m°~S“Sw¾8B÷ú—y÷Ïöh]ß$Zí±õÑÏàGÇhÜò¬·I21…¯#U5bÓ]SmòA²>â4JH_¯›|ƒÍ›{çšV«Eª@«ÂÝË^ ¥%¹ï©¦’]¾a³)Ž_ššÂitÍÞ¤ •ö'ßAª…œRv$ÑNcQ”sö´’9ŠÒ||\‡z}‚ïØñÒý>×½qFmò~,ãæÙ hßYŒŒ‰Ž<ÁÛ_ÛåÝß}šÍÛú¬ÿöQn<´ÍþåÙ— ÿî¹›yÌ‘+WÎÐlu¹Ë»•ï?q†î½>þFƒZÚ®¶ø‘Ÿèsû?ióô3'ñ+ÀÝ`7¨¾ƒÚa‘1/1K^¤¹ÚÅk¾Ùìöâ¤ë©W$”þ5ß0BT}9YC ÉÅ„FllHz>Є|àr4©ìA'ì¡$²6½*0ú9õºÐÌܱ&Ê9ì÷FÆØP/tC-ûûaN|(± .i3o款¯l$“WÊx^;«Ó8þZVßpœSã]¶~’¤áÚë°¶ñûÜü¶€¿ðšË´ßGópÆoÝ¢V“=³Å¿ýÀ&O?ñWÆ{ųïïíòÕðiVO®ðgÿò>á]LG'À;Ism7üäKÜõr#÷½¸hç\Èc¼6‡ï¿l0&MVê rªWV„ 0Ú| sDOÝ»~ß8»Ü—NWV±6ÿ4Æ!¤ìrÐïú¾_ЏSƪ>‚ é ÕÙ~›› —. %—M¯(R­bæ4ˆ&¨$.¦:eP‚$K†ÃÒ9T4s<–­õº4¬H’5‚õ÷ÓÜx+2=¤Ï‘wœÅ‹V€U)o³CÚ'Ó>¹ ±vŸúʲ8æsŸ‰ø»N87~±zT¸÷ø‡or×§oçm÷¡¹q?p X§sãëè\/cã°+`4ÕfÛÆk½ Ó¹éì8ƒ)òÿ†h¸V˃2Üuvñÿ*T[üºæYÊþ ÁtZ&ª›W ý”bT5 Õ(Á}ýxlŠ2¿WfãZkЧ®æqag8±cYÞ¿Ø+ú}n‡l¡µÉûÜ)[Qd C™*’¦!­Ö:AÐ-Gú­S€L‚µ5ÉmÚ˜!PÇff—cžþB›—v¶Xv]ØÝâ‘æÞ·z¬Ý³†µG1fãµâ¶«X²´…1S’¤µ-<¯CÂ÷3›„źiSÍàIfV@¿¯3Ž—¯šôª‰Öu Üx}‘Íw/µÕU¼¹Ê5s…fÞq´»ëåN`9 ØmHáú ºÁÖ–NjŒòžeˆôöö|å‹–EËd±ŒÁ È›YAxŒÇuÂÐR¯K…“ƒÁ˜}Œ©!£c#°`cm ×é}5 î/¯«m„5Öcñ…„Õ×Ö%'a×!'¨d¶Aš6ˆcð Æt½£‘Ÿs.Ä ‹ªT㣑Øñz]ú3L§FgÍë"»Ø¯+ÛÉáÜÿ¨†|‹üsv¯êæ»DO`­¦£ÍÉ OåuUÀÉ}¿B’Ì¡)BŸ²÷m9EÛ]Ĺ,–BÊYfhµdâF– íû‚HáEFF@c¦9Aµf†ñW8ò-¾ë©çøµg:œÙ]´ý†ÌD$–õ»SIcùz…xëBÎv–ÍŸLL§5|?&IÈ' YfoÏ+˜ Ÿ&zñdš›€jú»»Ê­°ÅÄ0·¿ã¢®– Ü“W=…W‚e¦B²‰ÂÔL•¶ŽÓÎcê°ˆÔ—Q„[—¨YEÍLJ¡êù Yu00EÖQ?C»‡a6Ÿ*yr‡sФç¡a4 r¼¡MLñ˜`³„ÑÓŸgð심ì¬òwþÔÏœ^á?”­µh­ªBfÃñ9ƒLÀ+QùîÆkÂA ¢2Òæ§KdJòÖó›XÝH÷’‡"åë>p5×àþÞ sTà0reoÏ+âgív.¥¥eôûQñLRÙdHÍ žalXŒŸÐ¼iŠ=1ä–/¥µi V!_h$m&“ Hˆ¢€áÐc2ñŠ\Æî®W”ÜkÇ/Á¯×¥eOöö$ï/¨ ¨ ÷. ÷´ȲáQs°èZV$rð÷2âÕZ[Lñ”¹ƒâä)Уq§{3î©u76ĉ”ˆ B—„m‡¢ÓF‡CSС\ àûê8–M¯uªFŠ'=™b²I³)ÌåÑ(¢^Ϥ°Õ[Eº6À†L/Lèšõ}†_ø"áõm¢õãX|ÒÔc4ò˜NÃ|ø†uá2"jµl1´LÛŠ‰_Ääã`A|/ÚÔEäÏ«Aü ÀEà•‹é‚+H3‰Íêvm‘²ÝÝ-íÚ2DjQ¦Ñó„Ü ¼‚ªÀ¸E«‹„seErß+œ?UÔ Ü.gA+˜VV‚À°³ãŬ{{~ÞgÏÃ÷kxfŒð &]dtz‹æ½wS»îãgžeøìç^»ÍÛóé(6Gö$ÒX[Ë™À%®o-½K@az©èÉÈ2¿@•»ZrÙzЋÀ%Šglò®Sóö»ŠÔM§pè ‚¾xÑ+@ËÒÌUÓÏT®»ªCWýWý ±‘%`T¯Ë½‡^a\¶¬ÚÓj¢i2Ñž†~ß+ ä("kkX[K áiùÏî?ɹO}‚c5·>€ î }Œ=‡§¤iƒÙL’Sš‚MSfSQ{/è á@–Ϭ}¶·Eåi‡86ü1w“mø2a™ó4f× žÄòrª¥)aÙ@‰ºÒQĉ¢rJÈ+»y@™-¬ed‹úá«ú §\¨0„C‡Ä€nm…Eƒ+2Ê®<ý.Ý÷-ÛÛ~þ:[dś΂J$©ÑjeøxdÉ€Ù8Å?ö&x#pKá]¤&e8è2™€U2:Ž…½ÔhH¿eéùk ö“«®HÓ‘ñͦÍëúlî@̽|­×vñZSV/M1ÃW{Ó6ä=lqR´'­@¬s}•&¶ÈUÕ¿þ©ªÛÅ ôõê +G^Ã:‰éý¼"ÖÎ…únK\—–Öé””6c,JWW²)ÀÎŽO­F>è2¦øµ·¾ë ˜ö÷‘ÙHân>×t¹>… ”–¸ )_¾»[bò’9Mðì“`à™=Ew ¢bJ—¤)œMR·ÃGKž_óôîØWýSq æý}ñ·-°»[¢‹’rË€½¥>€nÔ¢a„ú!ÚFF¼õŒõõ„ÝÝZßêæ©´¿¢‰’D4²lóÝ{,ññì÷÷•1c‹h× t±q(KÔ4bPaÑÍŸÍT±ÖÍ™5£é…G¡þS¤¶ÅdxˆÑ("I$]Ç¥)UþB–‘cõ¶ø·Ü—FQ"ün}ŸH—[¡Ü ¸\GÝÝh—¾hÝõ÷s£cõÍ®ô,ôŠÖhäqæLTœüE ‡E¤Þ€ªú8†½½Òó_fϪ«ú+Ò•D…Ϭ.- aµ„ÝÍQ¸%Ôš`ÒrêZÍæuy+´ZßNJS‹¢•£‘)ÊëJÜžÐ*aiaôÚ| È|Ô³(rRsg \¹¢X•AeŠfÐ2ÁµœäV½\ü$Xô‚E§­ª®»]ñ¶·) ÚVKl“Jñ"b‘ª¤WQ»e÷V…}µo¡›)”äQùy¥ Jéì{{¦ØhAåGdz¹>†µ^*Í}:5E©Ûþ¾TWi£¢¨ìÏ«ìr “®\1¹éÀÍÅàŽ:²jóg3I w:%ä+©o ïÌâ:WãJ„Q)_vâÜð ÔûW¤®ÌOë¨Ø«å¡«¦ÀuЖ}·ûo-1Ó“Ðnkš¹Ü|YXsà³ô÷“‰-*¡ÜâJ½¤î¾„d¿ßÚ2E¸jäÔ){G³—“I¨¶,O~¹¹ƒÜ˜&¿4Æ_”‡’®Ÿ×ë‰O°¹)†&· ü^W{h‡QÈ…ýZ@/-¸0FªyÇcò‡¢ÒD)®=º–èC¹©ËEñ­«-tüéꪨY¡Fôú«‚£¾¿º|Ù¥’»PrÙë@C\°—¡V#·ÙrZ²Oûø‹4¹Æ±Å˜}†ê˜—,§¹Ý¶s“A–™O]-¸Y]•ï½ÝÔS®šMŸUèsùÿ/ZäêF膆¡|Ñl&¿º¨DjO eÀ"3Pýs‘&pO„œlâövYäÚÐE‚£¿÷}[´YWtco÷Ù¥àRžW£ M) Gr!vÎQ“Çä=mÁQPj·û½â4Ëkx«òüÜuÓ´·vtÝÝ5Ôë†f³¤‹k©¿Y¹÷eŒÓ)t‘ƒT ™Ê\{éØTGÉIÏÃÇËBÀeaá¢ÍsÃ6g”eB5l¨Ì…aO`s„ï`S…E@«—4LÔÄh%’kvÊ>‹º©BpGµ×+k/ÝH@Ý`éî«È÷Ù"fϲ²×b•Ùãš7-…k·a4*YÓ®s…M_¯c~“ÄòòËAMH+! ¸õz¾¸´´ùÓ©8u°³spyõT»!Ž&uª\}ˆE¾è†¬¨Ò ›EÌ…\v ä[:o®“å~ÿlV¶À©×ÚV:ºj57A5‹p(šèj휦ëÑí–¾Ê"ŒEO²„¥v©`»ë­÷­%ú¾—. Û¸Ó‘úÍË—çKňÍÒÔøn㕨z]TÑÎNYMê::ÕX¾ª=”²Ì|-‚ 9ŠZ­ìr©toUÃîçWµ‹,€-¼ßETtu0ÕÑSÔS½Ío¸³yl);sºfHK·0EM¥b%n«wwJW•¾L,"Å ‡¥s+àR91Äuók¬®b’¤¤U ±‚|ì«|€ë¼T±ýêæ)xRÒ¬®.ÛôEô3Eèööä”D‘ͳT˸“8ÀfQž¡º˜ú>Å[$üº:J·ª\á²VÚîjöo^²è÷îéŸ;ÂEd3ŸE5FÝRHè.©ðb_‚ ß7q­fk­––²°ëëòâ^¯,ßR¤nÙ¦–‘€)nh™ô^íôWù…ÊOPN»\(øjÉ&ý~k/¸VT¢À‰nhµîN/9Q&oLµX4³¨y…86ʼn¬nvum¯uxô÷µšó €|ˆ·0‹¤å_Ù&‰Ò`<æülfn ¶-8~®·»¬èp‘4*g@“Õ›_¤¢ÝK IÔ‡(O£ÄÈŠ¾-rþ £Ü¿¡ß·…W½,I¢†%$¬2ªà{©s¥¡¾VïCàÛ²¿Q½^j\w]®†›\m •ææ:ÅóŸ+Í!„Û`]¢ísµ|<˸Q°x8rDìÔéÓÞ\¬\MR,“J÷á«×µrÓP¶q;‹Ôjâø•ÒAïyÙ"é¦iZ¶*$UA¨×åû£H´Îtjr&QékTïßåVŠ{JM×Ïá´t»HÕ/Ólîët­ª±+džÕUËêªUë¡øˆ1ü±(¢-¸ºÔ¦I.|^]¾X÷•\ËA+|wwç“=Ú¿@—e¶sÑâ”~‰9ðýÕ{Ò!ŽE E‘™k²\õ5ôž$1TFOUpŸOfÿe¬­I><>xÏ_« ³bp0õ¹4²VÍ£G-ÛÛÛünày|Ø÷ùbÚ7kí¿¤3máõWqé«9%Ë6»úÚjô wyj„õ"t3my¢ÎÎÕÀݤªC¹8R˜7šÚu8Ë4€öæ_¤%õó¥JYXmõ¾\x¯&®i C›#¥%í¾êàÊ÷‹ ïîB­ÆïonòéàŽ;ì•‹ÍßªÕøÕím«íŸNM>-Ü.tœ®f£®–Yt_»èßUAÓÞ@êùƒxÒ‹ò ׺ª'ÒýN÷÷ »BqµCÇâ,Ëtσ*ØÍD"ÄkkRÙ+=þƒp¯D(9'ËÞTA°œÅýcø[ÖÒ÷f3xÝë²Füüxl¶´ˆRF’™¼ÝØbÉ\F^X^é{ðs®&D%iCsìr*{=St)[ä<-ûYv²ªÚAséÕ‚”EÀ ˆ¦Æ«mÛÝת©ÐC¦“ÛÝÌ£{b­yõûõ»]X¼º/z?“ ôzæ+³?ÛéðÅ$ÿ7~ãorûíÚf3}l0ðžÌ2®Ï2Ö³ŒH‘&/:__«PM¶,û»;¼R Q Ê–.¸>¼Ææ¯ä{]Áª&¾ûWÁ¢¤¥¡æ"á®þ»Š..:¹ú}QD^ÄYæ^êuQÓ.ÙA©þÝM!/8TØÉ2~ÇZþ’ïóP¯?÷sy»ø¿þ×=>ðká÷¬åkyðÎ8æ­³™9E6ÌÙ*Þ׳ù‹Â³E>À²÷,²¿Ï^ ®bÕÏwO¿›ø‘’,©äÕ n1Æ2í²h×­‡µò}ÙÌ·u-‡?Vß³hòû²V$i u~ùÏ¿ wÞ@Ô¿ÎZ¨µ¡yÝñB?ßz(/O,[/›õ=3ΦÐȪÍýRN´ñ@BA^"“£gÇo–X÷‡åžt€åK4Íêáo™êˆXŸlò. (;4Î+ÒOßxøëѰé‘ëLÀ2©Úù2³ê×¹š®9ðœY³A_îTá?IFó§. k(Ù£_Á¸/Î#’¯À÷¯úOÙÞ¶ã©K¾t^øY=o†•Ï3Áµ×Û](h°’®ÏVûŰ٠3jFÅ-a’  ¯\ùa;!½ ´/D¤˜,6„[k_ùœÑѸÝ2V¯¤Â2{æÀ3 DÊ7þß.ºn5®‘aç“ZÞ˜îÙÖ¸Q7ŽŽÊ|„ò5=H ûL”4âK:ñ÷S§ï8V³UÈ{FØ‘—õHàÂy‚ÆaG[ŒÓª…Åm¤¨Ú“¼L÷~âÏû‘ȉ™í0Ù\½m©¥æz¨F]ñ©?¹¤K‹¶y‰ΰQ·‡ˆ<Ñ0.fýI<á…«SH ±Ï‚ ô sá`Ge·Ü°!Ød؉ùž°MTc‘®ŒÿNÜ[ߖ̉î–áRü§¬5¾®Þ,tê=翜—dÔu| âµA‘³BΜCU¼ÌÆ %$D+æ Ñ<ϼ 't°üTr¬sh?t2*K-±¾‰z׺M§ËØT⢲‘*Žü_e¨z_ÚjoÀ¥ÿûä¹òwóg¹ðzŸ4ÓNN%¶”ýlÒu$Ô‡»¥ä%¬˜Ã²+­;íë’~º7u¸à¤:ç‰[L´wšÚðñ«<4³àËñ{F«‘¨‹ÉäbÒàwÜÁü ¤wíÝÞ³‚‚Õê U„Ï›¨„ØŽº+Y`.‰ù*-’úŒ\>ƒ§ö·X’ÿsNXö¯‹ƒš:Wäq=к»h«íK›Ñ(ÀåÿžSpS{õ¹¢K#×Ͼܟ}¯}Î…ë£÷£»±¶aÈr\`8ÆSžG´™OÅì/¨Â O{$~Ê¿þvTgˆúµ~ª¸V7–“臈fñ&™z¼BÊfâ8 á$Í`NS Î6‘.¦ïŒÁ0çTö@ô3gÈÐcL6$˜×ØÙkdÇ77¡a@¤²¦¼àîzjÓdæüoFÕ?4˜:›ÞúuqU|†,™Lå1¢-eüþ+!çŠ4¹­“uð‰õ:+·ªy`MëjE_·lÈZƒ‚âtƒÜž£/ç%Óܽ¿¦ýPàH‹¥–ç>@aqÉ»t^ر7š¹/›DDìŠ}ïº1C~oHR賊x×ÖECBbEˆ…0Ú6X;ªÖ}íÔâ Ôe£Z²âD(Þ¬dX­$•Ên'Xµ† ¨¡8 ël©‚Þ‰£êp þ©Uðò#3þ¢™4®‚ÔÊû²ÙÏñ8 .h¶ˆÕÀŸÒb–²`*X!û3ÊÄ—e®ÜŸ?«L€ø”?tõg Xƒéï§C,žd¥çE"Õ3¿’P%7x„h=W¼eaØexœ8j¸Þu™-¡pú¤¨U~> ‘OcÇ~q—­›æ;î‚zE}Ç8ék'Ê€µ»_ä>qQ„ îh,!Hq¼‰My9çϦ&Åh¼-C“¼·ƒŠJ€Û瘺°¡ \Ú‚T±6̯ê©@Oõ&8»E/Tõz¶ E©Õ’’¸[DÊXi=ô•©}É«õ»Aûj”+ â)¨<(5ë´ÉO¯Î(Ù¡âÒwì _Z]ÑGf­I=Šä@wøêƒFivÐ\*üóº„|¥¶›ÐD¼ù/¬>Ä—ukOä+ÌÛUÀšJ©ÿISL‹•φŸ……_1nê±¢¯_ìýóË­ôˆ¥‚r¹cíÃkõDßÕŠ}€()¼ºvDôŽw*Ïœ¨˜ŽÜêeAn‚'£û+ÉV¼M/éQ3÷…F’/Q3—o`6¥Eí‹fNÍM}ÌÒFȱÈî‚Ë•c˜/ÝWæÌ&—†§–’Ьjͤ\‰Ç’Ùt­7®YÙk!òb`ó¸},º_-—ÕïòPI¸)­º¤õs³IL±%Ät·&§è}ËöUp·À3fÞ:{EžªJaÔª>YÞ„Úng¹[ÖÑ›{ÆÑQ<9âÉ Ug©‚=ÿ-©eKVÁºLŽÖ™2xõ ÏÖy[ÜÂÙ‡#:÷q)  ÏÆ‰áA8ß1³ýµóZ¿¶r!0ÊÜ4Qü>n”€öìD¸<©ð/‚DûÌ&¤ºTÈÃu€žû˜%Lv]Ìõß®æïçß½ÍA1ÈŠR}­{eÿ+ ¡õLÿ\0hn:—,Œ†ÈP€$H¯“0|þ9Ù[¹=ÐD :§n5a¿Ï¼N}âQ÷ˆ_Rlv™‚?¥’¸U ÛQ†_›È1ekün|áž‹ån; ³ÄB—F'QµÏ¿¬™÷õ_?.¼@ÀAº3.ˆˆ[bòuÝcNÿ £ºTlR51è¼"Õ\÷c!>Z«°yZ‡¼È*±K=·E‹r²jè9pÓJÌ«=½=j˪Ñ=3ȱak†t€ ÁYÊ´?³ä ÷ŒsÁª÷@]§^J—%Ôg«åÄ”áyqk´ØêRuDS”ƒ÷¶i0šïÆqvJ0ªzÖ»ÏÂŒi½¿½T›0·‰£N(&@þ)ý‰ÌKôÂfi+«C}K £¹+SA‹·­Û{~"8bK!Ú¯ÙY»’™tÚÍÓ:.C™C}Ô÷ VÍp‡#Õf¢÷MÔxñ¤Pñ¤e”†j“J–£§ ü{ ÓX>Nm¬XrìBdì·Â8‘³$m”w¼œ¡ 6V¯ÐÐlþ7Vƒ*zÜùfÄŸÖç8FÛfìÊŸ¦³Ž¶¦Ï¡xsüýYf,Œ…’ë&œçå¦'£Žû\}n7ÞU³¶îo-z™xÒGlg4'2})÷)Zit{ðâoûH`û½×Q½¢:Ž›î×Ç)1;PŸz̦pÝ丞ÜQF˜u#t¿‡†Vn®ZŠ$~!a´¢ŒÂþåCÓ?«Ú÷ 9Hæ—jDȼ`ÔàÅ×ÚIYŸDA…޾)-\˜OR²ïŽÈˆnДi!Üßvà¿ÚHQ(´eç¼’Ã<_|¯¨¬ù$¬é¾CŒC¨¬¾¡Ç(•HŒ¥»7Æ ‘¾dheÈ» ò!Ôž[$™~¥ÑÚ«Ã2D(À¸I[¨¶Ç.ùI3ûŠ;iOqÓé<2)5qíÙOñߌàìBÇ7«éFÚ¦«ÊÙ±þnZœ}’M‚mIDù…Qß¶Q]†]¸D¬³®UæN¿ÀŸ:c*3s­{C Œ;„›ó™¶'âºGí: \³?¡výÊU%¯¶Èß«Ãò½ *NãJmV^3š¹}äj/2ê Ž>¬+–ŒZ¨'D’fZ¦¶ùd–Æ ìŽÝ%–#[ùé1¡ÝÀ¶”VVþMÛzJGÏf ë}¦¢.¢å«ígh,Ç—½!>ÌTºM¬,Ú•"®}_Gz'Z±6Ä1ï¤2ͯÓgè†kš}@æ¨ =hcEô·ã©Væ#/ªÙבˆSYúhQ/–|l–àYÕ"œ{4=u¿¡Þw÷N*q‚à¢H,+öÁ InÀ¯Ž=ªÿ}ZÿW>D+ϱWLî¶ùK–fõÞæeVþW¶ÌÚ4ü%†:¦GÖ§Ø(ȯåɂԠ-÷Vd¥Ó®^*ܬ™øLŒ‰ðf­©ò*Ÿ5ˆ‡Ü£ ªYNlXd‰Î‰À¾» ŸLh‚šöûo4©±ý¯ÇóØíÈÜ ZM·1ÆåŸ¯ÍüwVÍ\³rì¾Ϙ|ôpq·yÝ3 ûÂ~‘?‡i WI×}ŒËÄ+<‘¼±sð`½ñ’‘j :šÕxl=l)š8/áÖ‘VYÀÀt6éy#ÏmÃ4ɛǠ&¬Üš,¯O*؃V®¥˜Š,¾ãÉTW¿Ò³_qœÃðÚ¹f·6Ïþz]vS•‹@„a°Õ’,éP‹ÓGÓz‰ž³œ´+_ Œ£ÕðëÄ ëÙÍpvfƒ–fÙ­0ójì6ýÐ2ŸÝÁx“î57hÀ îÒ§±]l…Tu^FHdåjwœ¥¿ñÒ@(ÊÝULpçãë ãªm瀩[|b³ªÇÀhéO°þF‡" ýa]·ørÚá ,#¿–¿Ä¬ßVúˆ›†.уâ4fíÕwàpXa|Kc7qµïB°>ÐÖ`¥c}²H:ø¹7‡ÌoÃB ² ]œ—í·B ˉA«©‰1oyD}ˆž– Pd‹ÛÉíøvÁ0Àá•qAýa\€ëNTK‡Z2]tƒÚ.(÷LÞá½K\Ÿj!JŠÑ¬)²Aßè‰þ×­wžÈS{ËAáso9…gÄm ³î‰/®|ØPÉÐÁ’ ýU2,·-316¾çR2ú¢M¿­ÿ ¢ Þ3ÜmD>öÈôê(|³”§ÀÛ:5 )‚c”# š¨z ·VšêÛ^±X…9ª„reÍ&0Æsn§ÿ&ý8ËþÚNb½„¯¸Í÷5Ó)Ãñ†Ä«rZùVh¯1ªŸ¾8I±3(VN míÝêY]/é&Sʼ_ŽÏí÷õw^ ¡Û\2>å8wmż…˜$J°áŒ½€ ädóC;¬µƒö*^‡¹­{ͩӘž¹ŸÖ5G+2gàðÿ)qþ@¶¿áä z#5Œ¾N)tBîâOg @s]iLkiÀyIu dr8ÊŠÛªNir¸nâ‹“Ëø!þ£n¹sT0}ñÃø§wFPbú}pŸ4̱ºë>6  D ƒG#Xz`Âe¡þNËTqz¨!g ÕÒóIg-’eÈ<7“íF·Çs]\×wÑ'mYþµEÃålT*â;®<€`d蔳;ÝŸ œp¼ì¼õX`Àºú÷ Ó=.îóîhuíjùÕ<Ÿ\¦<%’-Î=Öe5h¨À›×ƒÚ\زՔœ»À쥼òAA%]+ް`Z•.¦íBÑ+É¥½Ùèi™Nb–¡k-ܽžHô¼ègì“âûàO>Ï¥‹ãxV‹)d›y@+ý’ܸžÖŒtsykÔËÆ’;=û¸ÆËÞþñ ¬+ q'6±·Æ^ IŸw|Ã[i"ÁÉŸyËîær– ƒûTE$¹—4j•$ÌUúœ({ÓÄjÿ»ZàÖ,_Ÿ=r¬x- Æ¢T˜“Ï=°{CûxDØÆ2vzk~Ùï!Ü”i!ÜßvàÜã&²NNúÀù„<./±£Ûîü#{Ò®´0.gÙOqCè½Ò8¾5½#ê•%„ä¤xj¨ÿt%t¥ŽÊÏ æ6C­*GèÇ:61~H&3¯XÏ‘Á"©¶V¥)̽©Ñî6u¸Ç»‹ÊÑæ ­%j5H‚.âIå²I—ê]ª¼3$@H ™VŽg yQ·ÃÁª—ÙÔÚXYò‘‰¢V‰b~»nÆ= ‡>E”T(lqªåËÉF¿ÔùÈ.ÇDß^Ô”‚ÿ*Žq/½!Œl»p‰Uw<}“uÿÂY”±ÍȱZ±Ì€G."^ýÝBÃÜ R¥>s>6’ˆ’Š×¸z6ÕÊ¿år+r’ôéÒF™qs¦’;ÊP ‘ÊQX@”(¾rÞçÓt1"ÛMr¼ž×¿ ›#É+5ÄG‘l?ÜsåäSN8âÑñ<lVüö Z«ÿ'6Åû#àw|3Â2Ñù‰Äy¤3ÍI÷|ȳH3J*u­ÈïY†Ädµõ<Ïûhj+Ò“1_Z”ÒË­_2æ8½6…Ð[~e¦§°™ÓäÙ_Š néëxɱZûÜ çõ¢2¡Ì4.× Q²µ_sßbþ­YÅÒÇë¼øiöOaÂN:öuÑ_.d3u­WÝæPœ9¯#ºÍõ}*šÜ§Cé&ßÑ«@¶€?Uøà¿ë ö‚ šBNkcÄžàxÏÛ=¯æÅŸ­Æ• Ïv×× {7I4þŒÓñÔÂ\S‹`‚ø’oÞä'ëòÝ29jÊ|t»¥:\HWåõ[.lÒœ¼›@²úÐAn|èû‚¯îÞR<÷œ´= òÍ܇;—µ’Õ jW@êq};tP˜º;½6ê™ç¹L÷®0è+f¸·Bý’éËeNMrÔE? ×LúTTŠgSí‹*-˜W:bD›8þÌzõçÄKW¶”tä©à6ø= Ùb÷Qü½Œ)«ŸOGõ‚; «Q;‡ªœ1dÎVìi™j%ÈèL;Z‚^Aã‚–T= ðEΉæ$Ía ²««§YJ‰Š%Ë瞀¬Xä¾}Nðˆ(¡‰åC䯆x¹jûYÚ 1åïHO³.’dò"Z„Ñ‚­O (iÎ(]æ¬oö)÷ü Fç„Ë¡¸æ}-cÕëC0Òj«ùyßþö…b(ëd?q‰‹LÔóšåWd&º‚ë5ðéÆœ—Ê«-,u‘ô³ªœnHý×ÈbÔ3Kçgöþ¦ö 9©9\cuJÚ¨µòxøJaËu*9°e`Ñýfæ”ûÏähqÓƒ*Þe› V²rï’*Me¿ãÊ 7‰Ô+gÃÃ_X5œWxrI¨Å;•ͬ}ÇŠË4f¢~Æ e(ê¡x¡´^ ·râ‰Å°à¥Í}%7ÔYä‹CUžšBÅósE%8–e­¿Î Âçõ´ÆYq+ƒ"ƒú¹Öœ4<¨–(þa9 ¾Ü…Fá€W\;ÝôÒŵq…¥Qÿ,2‘·ëx6opq/Ã'á2Ñe Û_@T²Ù·´•³÷¹^Xº&7‰¥žxfÆwŠ ÙN¹&׆ÒJ²W8‡>ê¶j_Ñò‰@F£&I¢„LG²Tg5-ÑQn³•%iþƒm®ª²QMÁ+§5P1Í¥ðÞÕ!ÒrDßT7C¡¹Ùõ‰ïJÖˆ¨[ؘíºK^—Å‹á°tw¦”¦SlêÏêÇa\{ó*^+ÒL§•x¿ÏÃc§á°sóÛ ~(NF9ôÌ6 ò m’!P9àtöê~°!Oº´p#7ù¼Ïid¢®Á6à˜±³¬Ô…ëÈg5¤ŸÆÃj= £­m}õMÏ#ÿME‰”?Až“íýžÁ”ª!“4 gg jðrg.a¿öÚ‚{v95vÀÈ"Fv(FeVgð7쪭Uûh=BÔÝæÿElÿí£óô{ü/ÒnY…÷ìÐÔ¶0%€ˆÜSš}!ÓòBÙzFâücù–êŒ$hú3¸Ô¾kJpJάÃ}}<KmI•°ÝAì^÷gÌ‘Âäç°Pî×å¸Ë-È`©37#Èjh‚‡ÀI¼° *!”(r¸ ÂáB¥;®7ì0Ðõ‰!Y?'<i™r¥…×®·]k§ßÍ®<±cþ€~(«3ÍÐJ;W­¥.ˆØV%Ò"u.õý‹_þ²SB#½%Ö(zÙ´Ìû”·‰JôͯÞE‹œG'½ÚŒ™¤ž fV“ET)ç9ä¿pú(MüÁFÚl|Á€òŸ •âȈQ¬ßäTèoÛë㱆V70]ÿkqÁ?É‘DF]>7ãþ ¸ãY ×ê0•ðn~Ã4‘Q­$ÚéÝ|âkaT¯Pò§~á“Qwü͈Lð™ùºXak7’^VµÖÿ+'ÎìtêCpýŠw+Gë—JAð/®ÝW—…-‰Ë.dý¶Af•TR÷{ñX@¬D“›ûògõ–Ê´'W=žì©^ÁkMRÆ:!32â¯bÙÿ9§ˆGÜÁí™bZ¶bÌáŠÎPùJM¥Ò]Ëÿ§ÿC°krÎ3Eºq}G‹ÓÚuÑÿ/Ÿ „?îlÒIÉû (Æ8{g,°&Á꜂RÛç58C*hÇÕÈ:Ð`Ô‡¶‰JY·_õ΂«üÎñj¹"á:)ömGOþnÂéy£æCÜ5þ¤£<þ¹Ù›¥„qhœžíËâãév÷‡§”³,{«ìëüÇ«´ÚRÝBÛOÆ1Âðšo:ä¯å¡û†)cãÊåsÁшp£TnÌO¸v#³æ%(Ψq_ÆúXÿP› ñ†äVh’ÏE£øÔ'Ù…Ý#°³o1®çìËZ T ˆ"ÝET‘ê:°ô÷"ÉV³×H¯å#ôm—nbÚ•œW‚3 4G ”À€/žÙö|׸¼ÒÏÀ‚~3ó"zÌ€9à%ìÂåi7Ø(6šiÕZuuL,’ïÙ½‹/ ^|¡á˜J]ȧÒ×/®dÌ¡”ʦï»1R¤É°.C‹K÷6MÁÅ`è¾ÊEj–[óÂïWÙ̓?¡»Ã¦äS„ù¿ÏÃè Ÿ‡Ñ ‡Ò­ÇxªÌåëðøÇëD×q7hÇÕ"àðEÔ¹7F¹®˜Yü{¶Pkþ,3×2öYtŒ0:xÊx–kÿ?l:QMê+¢d-š5n±Sï…¾Ž$Ÿz¨Â Ü<¢×Ý-6ÍÑ Z;Â{æ"cŸÑúø,} ×VÖV@8’Ðàû?^ ŽÍÿGìÍPç€`Ä)ÒãµÚ>šÎÅA_[(Ö¸s\…í§I ÙŽoãÄÒ’ýk.ïO i¥ÛÓñ‚@÷5oæ/þ¨*d )‹`×›½ië<¼peì¾7‰¹È¶ªÜ!Ùã!L*•=!-C§½À‚ï=!öñ’+û ¨ˆ%wd{`À’‹‡paIiâ1ÉøðÛîg‰}…ô¤ 4±rfDùßÙÖ2-Ž7á?Û*(>±Ù6q¥ñXë¼”uñnù:êŽã&N|ØÓæŒýNÚ¥ ¹¾7~›`uJ¹`’…YØOêf¬˜ŒVB¿ãqÅpŒèñ-^T3©g¡§.š\ ¢ˆÝåy“n¬—;.À–¥&Av“¹Á…Åàdͺ¿¸5”Œ' »[B©®äÔҌ̒l’æIfí"îî·7S½Š9™q –•ïQÁÚÛ°â5ɸœãgÈJÆZozfÒN±f¶ŽžÅ#+ÚhhmÓX0ÙfÁûè‡*>7#À!S;/À&¿Û÷\Ðjk¹²M2åô}VÁ#'0mýªôãØ-’²}ò–ݛɾÛ/ëO>e8ÇM êk¨G²šð`dzˆX#Uä†ßÕÁf#ç>jMjõÒUÊOê4˜IIÆË#4ÖÍ£”dûòÁ7µ’oÝzé7m±¥wÜn%éè,#þª¨›£ÊkÊ( ñ¯øA´^ÃU¦î!ªŠn\ཀྵ¯]¶}3|ÿévðDì裳ÉþÜ ßT»8P¥îÛ4Ílÿ€˜ìPWiþtîñÔŽ2ÊÓ‰s/‘§F‚í¯©£«§XAêtí_8<ÅÚ zþ|1`7ê~ %“9޳FŒËjZÞV·ª]3½·FÍ•5æ¥PxS^}¨5qÕ&–V”8ÖÍ¥rpRaYa)´Ì/4O•p®uxV&Šhå‘€Å/;Þ‡n-±âÖžFŸÎKSîyš¿JËø`r1œU˜,} ¨›rPeÚÂJôŽõböWÔh¾,HÊ©!Gx.ßÓk!tŠ‹mé8ŸÎq°Rb¦ZÜ”I‹…ŠTÍŒËÖû,õ¯¥iÉÍeÜ[Ãé¨|>¬&\êuœ'>ËUÞ‚îÒö3èNË“îë<‰ç¤Õ*Ïì©‹[}¤£ì>wŒSÊ3QiÖ<ªæJᣊFÄ‹Uú|Šõ¯W £‹HHu-p'·ìUk›6£T­H Þ`1yƒì̃øåBõ!âÎDV}Ú&³©ÇtK‡¿GP‘Þ‚óo ó>°Â°¡/‹šwoxyBâów´½•]~„סŸì9L\kž¬¸¤â/Ì7“¥ÚÖNµ?ƳŽÜCq­ë¶rËhçgòÐÍíd‰I74ìÄHÙì‹*þDZ¼ÿf, ¿£cªÔÀòl•káØG¢}8“-Ù¿òÚÊÕ‡/6Üõú!M¥e°Þ =+Éïž54ßA½Ñ®Ñüá ¸È'2–NOIƤ8@õˆétˆžá3]Òq÷«-a}а5ù•„Sª»g–!È•”AÓ s)¯/´#Ç> [9ªÍZÞp'sL6çpüyßfršTô&kÛh¯~Á½Š0±V—‘exÒê±.ÿvB2÷×úÅÕ7"A¯»õ7tëãEÐÿX¾Æf?Udf­L9NÐÕ¨½ÐúÉnP’±°æz-Šî^£w?füuR8³`Îç‹«1q¦&í²öUs$‘_ª£@Çjù §ìÕ}4Õ–EÒ†`j,ç»á=ªw~®¦£%Q m›=OÊ:åeVgs3ká£þç´ÍÑŒkÂ3H,¶CBHt„/¿ÝÏõue‚åA4‘üü¡Èí"R‚ E®uU`6ÜœívHÝŸðƒþÚl¤1±ñºÛa=ê{áþµ·ÈÖµt€˜W•¿YàK˜`ŸÊPÔ* -ÀSBÛ7e`)4ωQêçÌêÚ; PJ$ŠúGUL:O/ ¶À¿Yˆnàž’Ö §pL0š®>?™5pùô$m‰0ËØR¦õºWÌÌè## øbVÞNãh ßuĬ1uâ‚Ñ¿}Ö¢÷û²Õíá¶Ëµúd󥆀çT¥—› ØË¢šOâ"ëÚKOí_ùúm…3ªl×1}¿“`*=Ó&Uc@/·Ûá½èX7– gi,'nlojX Ûk»Ÿ¹¡Çð¶%Y¦e³·ù¶zrÝ5}ˆ3_÷XÈ]ò¦·´Æt-––D”É ÂÅ*£^œpT&_Î.†´Žš˜ËR±ß?öfhÿ8XÝ'´¦Ê»Šp_ÈË2ð t¿æ­Ú¢µvV¡6ØrW“½œI=’åÇòÁe:£ã0®µÌ«Õ¢œcK‹Ú¹ ­èø¹ñZ%„¬ð’w=Öv¬¸UÃÁ™ßyÔЋ/K -ÆÊþõl±U¸Pÿ+“ÿÑ2€ý[Ö!X ëÔ€½bw1¦üí:«EnÌÊ« ËòŽQ…ô‘G¦ÆÙ €lÁjÚ¤~´ wæ3:ÅFþœ—_Š×ƒª¼YÈÃÒ!IšÌmJðʨ¢w¨v‹›#•Z[æ(l†$4^¢bèý½K;)¾dw«Œ‡vƒÄŽ¢F6ÅS—‘ ý±½Hj˜êMIóÞ…?7Ú†Ÿ‹…ª“]µ<:®úÃÝ:—Ïõ_[‘߯Ð%ÔŒ G³¾îËK”‹Õ^qâ‡ÆGÜ^©Qõ‘@¨tl¾5Qe·LÇÁ*%Æm¯/påÜË6hG[Ü:_`Þþé.oq/NÇÑ1E“Èßð(Á·0¬ÝqËùÅB­P»<”ˆó?ئ;8}Ss{GÍÓmæ­ŽWv–Ìl0ÒqKXí +—´6³M+@ÙPH3âWr)GàÕ´®dÐ$0Ó¯w+B‰òçù Ï‘/œâ •Ó—+KCÇŸ?·ôË?õ¾K£„󯼫è3|¥`?—å}z•O쯒‡ž7S{Áéq`t{$Ý+¼3_îØñÕë_ÿ Ž, ‰Z‹>hóB”ÒI|9ÑüEÐÀ6A” ‹Δ‰1Ì;‡»ýjæ+ „4-Ë÷æêåi6α4à!6f=&Z0¯ÚÍ8K+J‘–Oø›h×û âÕLYêtQ_5g…çldél·ÙÖ2‡èD󞈽ﵞhBKžYè—<ÿAJº¡`ô½ÿ%µÑx˜H&¾Ÿ_Í?9¥•¶ÄiÌØ £‘ýDbnÃØÔªª?á‹¢”4A£†0¢ñIý¸QÇÇeq²Tv[}?êQnŽGì´þÇæHzuË$’ñwżQéÿ h× óóõgßA B±]¢ŠFyÎPê5ô€õ)W‹.ùàÅñ³é:  GÉÒî{c—T| ¼@ÞºéRý¢•ŠoêÉ\}·àú! ËÓ”óÙKËÔÕN~˜à–ÃìÚŒnð‘|7»Ž¬>§o›JöÎkFÕ<Ûye½ä‡ƒ/Ñöòïêóù²UxÖ<dz—vÉ{Ñ;Ѭ†ïÇ8ÅDïã@ fÐÕyu°°Å©IuÓ'<õp-n¡€“Ø;O·§¼*ê)ºîœgN”±‘èºÒ(îqÕÒŠËÆ¡×•²¤yg=BJgá@´y• væ€ã„lRΞáåïûì·Û1%:¡YiŠk”/ïŽçdÆ[6“þ ý¡c­;¾ŸtvÆaDâ â'òÉ2„ЬÕˆR!(>Ê)þ¥WÑÉ"¬c%ý¾tZ k9wêS¤ÕIC<†™ÔjÛ,>ãÌ‘Àbøm€9|ÛiÆ~³gª½©ÙØ©S-Ù «¿O×X‹ð­ËÌÛCw¹¥ßôÚñ ã«ã¢ÆÁSøŒ±ÿ=Ê6›)ÊM˜W$öVÓËx.½x¬'q8Ì¡iá¶V¤—³Ñð@A­~«ëJÉÒ4÷ñ¤8 »a¾…ÂHœ`:í"qœm$±Û&¨.,™’1ØÄ µLNÀÝÃû(¹8ùTº¿œù]ö ÷œêëé] Uû>št7Óêø‚à)jÊ}hÌfÞo¼» ¨GÏ{DÎ雚Îé±¢÷ˆV#ãÖøÈR'Ž·>HšUð õ¤n:6 æu‹s«ã’»¬1M6=‰F©n EBmç]û’“9Då«”w ÄV~Œz›Ý“‚ÃpÿS?”.÷ѱ&ºAI¹olé5a²ú Mfq¤ —kê?Ø Åh:F6ÈòÉa UšJ9æÇËpüÍü+$©é ’+¡¡RWYÀž=Iû(Mñ/t tmö ¼ W——²³ki\r†U!2Ö)¨¨;ÚÂ??*Šè¤~€Vݳ€°³ºe8B½W–»Ó¥^ Ëâbˆ6ëVÚ¤¡X¡4tMiqºZùÄ´q >Ì Û$N39jq™1è×…Tùĉ¶™ÌÊt šÁÁñŽs­ÝroƒòkqCt¾·n~ Ë-çŽø +±÷âó€Oñ,I$ê4÷ ô¡ÓÎKy‹éi‘!ˆúµÅ©úþ­ ×$—ž2Hr{’"“R7²³Ú{‰&#kä{y^ kö ‰Ú*¯ïhsî9‚ž†ì^¢Y«Còb¿¸Æ6{:¶¦9;tÓÕ˴ظăè^y¯1U›FÚ«,m¿>FÌŸÖgoi¯ïØlë´F¨ƒ¢ÉzåÉæF“Û·\Còà ]6Vb¢ëy¼ãÿ3‚ Ô„½0ü8òTŠƒ^þ!ÚÈ!}YíÄžqÖÒºÒöÑ,#hríÇÂÕ°Ç’ Yç¨î§@ZQy¿JQ¢CqâÉ{1bq—0yJKÕ&Ê"ç*ÈÌS;Äm’p—‰á²ü¾S)Ö”’"B 4òAÆ9uÓv[¹þ{6׆Itm—Q5Ç¥ÖºK'Œñõ`Á‚BBk«J¢¦Ð¯+$eÌ2㎠;„ÓŸhLCÚ°ŒÞZ±>’ð€ Ý>@W‰VWhtzNF÷RV:„l‡ÌÚI¸¸IYkHJ’M"çBU‘äpÃÞá¥È4ßam=ƒÔý/lI€Âï·*tÔÓqiŽæƒÓ ˜´ÏM½¢‰R²Ú¥Bï§ß’ÐQ걪©2QÏʇ3Í›tø`ÓùõÚÿ@Ÿ)¾<ªÛ’tCŠ, /Äya6<7(–V$Þ¤TÒ˜­¥¬e¯&¿ Œõܶ~´õíñ¶Xûœ}G›u Ÿ‘/–üX±Xìl‡ÒŒp\ÐC»Nªÿ.,÷[³X×2¨ò›2º—hZ B :,ùÄãÎ+*‹ý~’xÞìã¼I‰¾qÓ· ДòÎä:ÿ$Y^!Ýlô5ÝÝùîùá$Ï ÎS»ø® 4õ¡Fa†/A·Õ[Ãê& WÀ %ãþO16E3S+)5OÌ ŸOÒh¼°E“{ ŠŒ} !0c:yË,%ØN{Iöùaø%£K:€§¬Jî9³wVôÕÌ:ëðiÎÑ­ ËòèuÅ¿J÷Q1Ú§ÎŽÃg£žRߔ΢ù-‹Kþ·Ì’Ùo€ºMëéÄÒïné–bM« ‹{b½Ã= /ÛÚk+§/íŸ1Î3×mø@t&~sÇøˆlãD—hå¾ 6s9 ^1%¥‘‰Öˆ'’/àÃU _»?­E$†Ug^¿ÊÔŒ™&’„I‚¯Ç›4æ*ˆð¨‰TŒ{ÆžK–Ý.T¡-©ÑÖèBA?m  ­Ê‡hê’Ç#Ÿ<^vÔFÎÄ»‹!ÔÕj¦ñº¬#:‰‘+‡§0ò=Ä(ðü“À¹þÇåÝTÙc W9]÷ý´˜éèlÜø/#>JOíT´˜Ù½v‡‘"i6Ù¿TÞmuŽ9ëÃß½ªb(ç+¸¢MâN…|¸Ùèʉ<ñ‹îšÇj z¢¡Z½àòmR$)ZížPxeõý|_¢ÜŸ«í$ºbˆ ɼ¡3˺»{ê¼ñÙ\]†ðþóJ¨)—Êt xYÉcG«‹‘s²ë"2QC6¦Öd¨ÆýÉu—+n£8VXµ—ÿÈõáIéßx\”Û¨*ßøW3"hé'F nƒ=ªü°(ÔQüCøló”-dpô£Ãî/¤*\2ÛNC%»£œ_.‰Ž±üÒºÆRP¸(øQ?ßì1'‘’ǧ.¤¹µ Búµd!oKÍ9,Ü»x´V©áù!-Ò xëÒF …šÔhCwÞ´kâF’Ž)9Y· †•‚àÔnû2V$gz˜dCPúŠ#׫XîÑÅ䜬™oBþñ•kzôŠîI/Q­Ÿm¢Ê*C‰¥tfNd»a’¬‚ëMGfïh´q£Çp‘!ùƒîöhCò…þ80ô”GÅ539 êÅ0‹ž4´§ìÏiX‘ç®×ª1¤=×€½˜Q.¯ëv€jóÀ÷þ÷wp»:+Gˆ³0™†Ï:?iÞd2Ë/ÚÌékõ›ZÑpç¥4 EC½¯d`Ö«"áZ±äé@÷¦®¬µkâê¹ZvF…lZâŸ~˜HxËU#qކ¸7ñ§ãanAâ)Á$Þ2Í–¶ jŸË¥¡D} ƒ¤.–Ppt-Õ¯@Ôˆè ëàäÞ¨m6I䌨mr„]„a~ï/Ä—ày4#ÿ~A\u‚–¤øÊñ_{ŽjÑ •ÉЈøìfµ^c]˜ý_à}õ$h.Ÿ¥&b·Íïõ×¹6„ùZDõ´³Ã¢56ƒN¸PAºFë±.õˆJùóΠ1/ãìaçe›3p]ÊLüuv›NϰÆ–ÊR¼{ž÷[XRZåa{…ÁŠu;ÅÇ5v5¨„´Ä$%g±tÌw™³Üëa8dá9ľÈ<ûæáûcÏqÛ݃ý¿H ýµÚšô€\lÛŽælÚD]—Š^æ|wEèJ§ŽÀèß´Ð÷5hoS—Wý,ÝÀÎÊš…7f¿yó Žs²ÍshL{V8ÌzÇ2RhÍ™q\MZÞ+ˆ„å­¶~ÉëIýèE?\@(B‚eìY ÉkLt™-‡ð[¦Ü ß=ËÏ^‡”’PSNúß(ju%”A9[véùÍf‹Þ1âÉ:Ùß\–oU‡˜\ÐûŸIH‡€û+a’à úÕX ýëö˜$Õ®…Þ† 1p±iÔõŸýY#ÇÉ4ž›ƒáþ£ƒ¼“ŒäžißèV2ºú·ñì˜YßNâzT-ÃM¥øÆÕ-zÓ˜R"C[·ùwŸ°Õ§<Þ0èËËŽ=BRoIw½uB%S¢±Êö—ÈLÀñiŸeå??ú¢ù‹YÆ?UëoHÃ)ô’ G»v.ïy}¼h,òùu€þ$2&_V Féfî÷Ïñq—$Ùz‚E !„Nl7o™j"Æ38#ž.*Û âÖtÉŸªnì‰&0-ù˜á8ª MC°Ù DÞ“è#³Ô€¯Ê_hZ?ì“ÐÍÎ áo^éh棥ʀ‘mÓÞ>§£3¿mèÈLDà‘1(å™üÝÌ'ÀeƧŒ7@ÏÃ赟‡Ñ‡Ò6­ÇxªÑ[2Fe"¤ñà» ¯´Â Î<±Ñ|s©éúR—ڂψ‰”‘¾Æñú„ ¥“uz7-yƒÄB÷ìXÀÿlA†íý$f¼6'Gל™!›Ÿ5Ôh¼Ú²©*§ÐGGæÆx ‚‘‡£äÅ`Üznðæl* ÏOo¤ï¨C¾ ï«N4Bä}Ò„$wFº±D A¦)îé <ÀX“ýÖùç5Õ…SÏ|,”ï=í¬â-ƒÞZÞ#hie)ÿ 4›í6"FóTxˆ¼*$´ÁQ÷Pð:ÿzD²¸±ÑÙÅK­4#K<ý‘Õ¯ˆ.åMFØÖÁ«Ù-\SYoµìѺY]°Ü@Nm½Vçš#'Á•ð¸Èá©£€žÆ{ô…¶ÙnXm7Í|DÛ ¿6͵J¤h#Ú"¢C@IôFyw¿²5KlÀÐÃxެˆ V–Ðâì:*xűÿtKšÖÌÀ´]Ï”¦vmŠÜ0ÏÐaŸg†„Ït Uý?dÃ?®S7‡v°¿r ‰<äÁI¹©ç­ËŒå³Šp3AªÇÖv/ßhüV 7D0öœÆ+•Öéâc¡ërðî$Ð\&oP¨»Né÷É Y[aåDdÑú[Êa ’ÌpÃÝNÛÈ¢s¡<KÿoË_˜¹y]ÓÁ.ÅŠçs†iR`LG*t 8¢•Šb&•ÿ‡ ÈwÔ| *xzˆ:MpãFùÂUÇuÅêgX¼_!²‹þ±øA±‰Ud»žõ;‹Q¡õDìîÆ0Ég-7D\³ŸfÿUM¦ÖP õ¥”z/Â"qX•eØ=ëø'“.C…§,RIýJAC áø‡úmfäH~Ud‰IúT}‹§›f4p›}OéϹ×|z÷]öþ ÑcÓ €†˜ qGeÆùCà {AmBh 3&ÿCÍQ¨íVvÄ*j§¿öŸÒ°ÇSE>ïùà„Oc‚ ãÓ·¤}·¾To3âˆK_dŒŠ…6—:×ý·mi†uæÖ<ôPã+íÒ,¦8- :&m÷Ý{Ôaþ¶!¾±«t7¤óÝ¿w­|û¨Pk=h=Øêﱨ¸rx¯‡2mӳءð©û9”/i)”‹jZÈé480*Ý®â d™wøŽÐ`T‡¹ã.ùsÏAùÇ4Oyoêƒþ­MÔD ÆRÕÙ+sÍî†þ¿`˶װrƒ{u&IŸä³6sý(DzS*gGÅäÕ¡y¦õ%Š5¼†Ò«û>ú³U›Æ S¼Ü@\rqAtT"濹úo‹ðŽ¡'e„ÜôM"§.ã„Ã]-Âk·9ä`k°Ë+fÅtD4̃ÑŒœ˜šÒ<‡ ‡É=uϧ¾I ‹5(sUñ+ÚÂKLØÌ¾¦ýjÑçÊÜéfÙxç§ M9nѦér½¦æð«û±£X¬õvë"¦ÕïWsQ§Æ%nP/Ùõ‘%3`¿jÆB2½#³á‘µÊ®â3RK™ÊŒR-Wéò+Ö½•–€”µiöŽ ¯˜_AlN‰…v¥ó5á |Õ{ÁÆ]‘¼©/B”ah!¡e=àtªí& ~EI:ýêççM‚ˆD I ï4#QkÇñ±,«€ÀϨ¸/Krî¢N{¼ßÌ´üØË&¯) Çðʤxæ^¸³WÝëŽH7SÖÌC´ô7êŒG€‡~è¯ÌoŸ`ª•<ä!”©Fu¹Ü#ñ#cä<$)ºŽra¾ê¼};^NÆÁx°‘m}çy 2N–o37ïŠ#íÞí+ŒO'Í1t‰ö–8šû/<¼ ª63Cvå3^ÏÑ„¼@:’ÂæªEºÏ³.q%Â¥&? p¶ÏdöþüÖ.‡ÞÅö„xçÂA‹g5P9 Bë[Îâ.`)†ÜîɤýäÝãó^iÒ‡µ1IwÁ][ä&Ÿ³Wæd ›³W%¿îë»á=ª‹ò¾N÷ØqrÓ²QÐQ9,†y;ÞGž”¨‡4)¿Í°¸ÄcšÃ±‹äÀ Ž~iÖK2žrÙVY’ÉhÓ9ú¿ôîš<³ClsËŒ'ÚÓl8P|®0˜å—bÙŠRX˜ç™߬·¨Êa¢ÓD¥OM¡ ‹qd[1H›BÙky£¨â}0Ôj\oð‰ëqUb€m®î~æ‡ÂØ•f™–ÌßæÙéËtÕö Í|>ý§‰:;‘Ú(™uÕÉS’™!z, x&ýë½8à¨L¿œ] iãÛ¿Yß×6‡îXwú<¾¾jòБ<Ôr£ÄCã@™ @ÏòŽÔËÖ¶(\Y^(`àµ)oØFb† þ»AZÊÑÏÌ—.^?7î$Daál]kTÈ•žÀô«LæwÛ‹_+u8ÇâÀ¿›Ñ`Þ@Hôe¯%­P«XÑo¢nqtþ=T˜M9ËîaM&¦åb™1cóèFc«p‘G­:½š;¹é…q¶@Ã%·0Me5Éû¥¼3"M•·¨ßÓ’ëñZðsµW‹9aúD!É3GrîÏu^¿ë h®v,±GoaGáðЏ±¶à°õù%vd¹Xf<T‰ÎKšJ Ùó~ÂdcXv]tûÌ0“2»÷6t¸ Kœ¿n¯&p'½2tÂÇÄ#±e}¼*q·7§n<åoµ£Qñ}°ØÊÎpùî_§D˜ø¶¨ØâÚ™©ào¬S‹¤ ÔõU¤lrÇ‘èÂÑ‘¡Ö9i!"7QCYcrLþ×ùcõÖÝ¦Ž°eN§ç­ÄUî ‘Úgö3²•_Í-•»Vpû¸ÇB9ækÄ -óå­AÒUmùOW]ˆ‰Å&†3÷6†g(E#Ùw‰j<ð5ªãVJ¬d"v8ûC ¶ëhfï#SÜÎÑÊT"8£ëÛ°z ;0_lî ƒ0:ŶÉ54Ñ ¹/ÿ#Ä(VÏRŒdþæ%šñêÓ¡Æv¼`aþö•ÄP §Îöᥬ« ÔFdN­ÕpVCºf*J.vz©ÕßE²–1º] PŸK l¦E°S ÊßÒÖÌž3V<¹·çf‚é6šåKâŒláOØ+®gì€G`OxÂ;º¡Œ¤~÷u«äLv°‚Dܪ3Ê©w2\œÙXwÛ0‚±úBøŽµ:Á:¾OùTsfS†Š0e‘ÆðkK…©XÇø+ó›HìKÜ”ØG)Û‡CÌòÒáÜýç¹~qŠ×!jWÞùœiØÒ)Ýæ¾‚çC/Y»óÒ°‹SÿoUõ–we|Ø©•6”¢íÆ;KS8ófSEš˜´(pžóC³ÝLê}”³0Q[ºˆXÞMÔfdHöRz’–±`À ~Ḭ̈Ÿì 0 2e»–lë{ïäéÓ/ãëM_¿ž§‘Mbp¢9ŠÍW+½Ðh˜cÿt_,ºÔj©ˆÙž0ÀÙšŒÇNcÙß›läq<󛸼T‹ºŒ'Ƥ‰¶/·øV¨b!¥â4ù@Æ|‚J»•ôI ·L¢*pÇN⦟½–Ô^N¶àÝ€ùÛ¨‡”4òȨ ùWƒ{ ¿k†?:f¤ §vm5Zs€.µ.*÷:‹©bñÃPmåôWbHÛ†èÛN= ôË1S~t æ«;–Gñx®Â(uÑCd¬P)í))X&gÊ?ÃDÿ&oÃïZp‹‘hCgÛܹwÊÐG ák(/'gxŠõaBfR¸Ãìû¼¹y¸àâ.I­¦W*ü,_'…Ms·z’¤$4Ø |ªåÜŸ%îã¥~n•YD'{¯“YIÕõyV}PãCÜœ®óˆMTäJŠ2`ÃÆ%ª=ÿ$~׈O•[LÀËS BËQ‘£Q™EŠCñ—˵IÊÑ3‰ÓtÞXü&ÃÚ”mçœeÔUIyÈÑÚNh=—¥øô†r—Èöõ¬ &â÷ž›ÐtÔÀ²‘÷¤¿U†›×KÌJ^•¬íê0Ú 1uJ¸Š¬‘=©pnäâvÚ˜ƒ¬vÜô –ÿF_Y™ ]­Û³PîQ†pÎiE~å´Q“ÁnÉÙ¶Ø«—bT壙rZɈȤ£u/â°ˆ{[IðÀn_îÉe´Þrt‹® ‘Xá]Q×U¥?‹e¨c<0/äÿ3nÂ?÷î0„`‚ÿ<¶#¾;].üL§1íPv„2kêi>&#7 ¶)ÃÔôR›«síU¡ä ²ÕÍu¬SQPwµ„~~UÐ;H"ý­»gaj¾=* heãºÅÙj*çLz¯@öcÚÞÄ!nq‘çt¨:È€†§TàiÊá_æGMø·C”.=ÆõèÉ,n)„Kót–U8[”aŒâþÓG%®Pc-½=—8 C;ÅÎt‚OÀ;·s⊮[9±;KoR>X°wÈáAâi\¥¢ ô7°ÓØ_Ç2x}¢OUpð’Cû“Ü‘𑽕˜†ÓÜI1>©ížë$¨«¹8XÍûÔß‚qäƒ87‚ñð1ö¨Ñ\±²²fΔcá˜%YAv5ºÝN£³T1‚¶Uœl:ðþ³8¥yä|s´.†K³kÃÞ¢ÃE‹îþ>…øÄïí›Î-dT ç‘gàb§î-¢Íb!É{¨ºHSž½¶ŽÅ¨RÇ÷-"&G<}‡šÐÜdÐâvG4gdø@ =U룅d§Aö þòVþ¤‰qñ¨”ž½"Ò¸§ÀëÚ6°>MëU‘™ÍF¯ñ‚™Ý)§WÞqÆÈ ACúl.ãdܓd…µqÅ3•ø¦8½Y„&ÚÉ™á^•v­š>ÑA[zÕ32]v ·Þ×UÕyÂl”ÝFÅíŘ|úKƒtTú5^$IY]¡Ñé9ÝIX8ê²;3i&âày% ¹6E™´»„!áu‘Y"x:žÈÅQ»?+… £Wnm€_XYa྾@M]=t#W·aܼ¦H@|)=ï 0ßP @ï('zÃPVíÿ(ù£ƒûm¿ü‹Û€…ˆ÷]µ—Y Ôæ·eàdÙüa4-Sζª:¥o©Y>qÕ<£ý|þXñœ-Œ,0ÿæt&ËwSûMN˜( yÜš]@äf øêj ±gz6eŠ!ß+ªZWžK˜6••>×DÞžÒ¬^a*}Ý9…—À¹‰}z3›¶ü‹{)ùUqrÅñM# ÞšýYÖETêøÀâ·S¸¯¡»¨Hä5©r¯Dʱ•F=„“'7ýé n]}fRÙûÑb%çµ+7hx–ÈE‚GÞ}<¾~E„àÿo•Ãfm™ùW¨ùëëlg7µQém÷RU^îàVŽ$W“pÕ¤Ÿ`]¿»ò){\ нu꾸hE'ß«V•VEÐÔ:â#œ>" ׎|ð*Õ?,#W²Í÷ûNkr®Yж$PÈ?˜äÎ2Vgs£h¿–þ[Ò-Œ˜ÍX”iw„ìòÍë%²ß£x.?.€”ëìÌs>À“-'6Q½;ˆ?]C4¹tìõ–ëWÇah%´>¨ÝÖÌ{«´4~øöµs{‹"†âú,×$—YŽFⱕߵ4ÏòÛg`¯ÅYμH‰¾³sÄP}· LÓOG®ý¥Sß |Ê.tÇ$—_ï |ªà÷­…Í3© å”E·¼Ë}¤lhIÐà;t$Ò¼KÊû7qaGÌwSÆ)Äp´êÕ_ñÉqû© ë[K>“¥-È‘Û Ojªìy¸Î§º+Œí{ýqe‰E5Þ½Š[毜6©´•GÀqmåð·àw:ô@Ø‘•*>A­¨¢”~·rú‚‰ë–7ô@^vo'«²Ÿî#éÏLùÚ2^h&ŠDU(â–hÒ§çŽ|¥2I!n· Ê ˆÉ Ÿ†ñQ1V»öÆ.8uÏ› EH2¦Ëai¾Y[ú-+_m&ãë‘<Íõ|!·;¶ÿs Óî³vînòž—-~éÉBýV-ã`Z ”…‡ÏßÛÙÚ•Ÿæz>ÕEOÞÆÔ \Âvšfgá3°e{ÒO­ØÊ9«Máò:iK¸ÀpüÄPí¹7”¾¹þ…ʼ1ø¨“—­Ý$…Í’÷@Š 8Õcr}«.¡„÷ªdü×½ÓˆÎ).“Û٠Ѽz% âÇüµv–Oç¶š¹Œ·€«´uK“¿ËÑYƒ•¬¨!ϰ `.‘œâ¥bêM6A]–Ö`$ù#±-hf³X§«‰ÀE‚‹g‡’?7ŸÙú&ñš¹ŽtÊÎòTýÛ.-|§”’àKMëS2Ã@4éXFŠž¶Ii@±Œ ƒ,ÙÒÿ7JZÛGÏâ(ÍòI&-%aä|™ýµ8ËúÁ·>=a²·o'9?ÅÑòá úŒŸŽ"0à6¤Ž¦Óü¿KÆÍ©ð“½½,ÄJØØ‘ÖÑ×sã–Ë4eÊ`œ=» 7lï M\y÷åÇã#dîßü›M×dµÅXöy÷V˜;?ÿ#!óy†ôï,R¶2gºÇp®?Î ·ð¿NþîÐáy­€„­(c™ª¶”bµº¾kµðÁ]eò‹¶…§UF| ŸÌ""ƒäß=IN­ÏjÝ>4U Uëd ‚¾w¯‹Yè¤efqnÚœ?\r©&³Ì£˜6MÔòöçíu&§”üj$ÄL9·¹i°Î‡yA¢Vc5):Ÿ ª¯é<Ø ·.ú¨Ûí•Í’™º£êtyåtxdž ÛùÔ¦{¯Ö¹‹ú Š¿8pyè‰]»éõÑvŒ!ïÚGRMý|BÇŒÎ狊£öȽ|7ûn«€Ê 'Jò(XVwµ¦Ï*QÊI'eí-Sbdϵ_hZ?ì“ΠªÅªHœ±ú"ĬRöÝ/êúˆ,´µžÿô—\«^ ½£ õS¤ÓÍF†›t¹ˆa_ߟ§µùúxGáê ­Çø`™bÓá¸ÆÖ5TµZÞ$r,0:æóüú-ñ›l˜†û½RŽ˜̪ÏUÀõ^sÉW¹”Þ@û"ÐÓ0DÕl”p(tzàÓ4ÿUðnm…ñüx2Ë·«n¶¬]`ƒ–œ–ƒRFš@xÑ[–œò«ÜT]~Â!BM5–Õ—{OõY0øÜ'î»&Dhô-8 a­@b©“Ïè%FÀU7ÑçdhØEu;[–A±oßóˆÐê;ÁoÑ»å,tÀq"B`pVª›ŽcW1Ð5*°ˆÚÝ cܠ™nip;Jn˜}~ÍJ ¿ù™•ìFÓ’»{…¼Ã‚I½T©ªÍ[ùJ3>xsÊv²D›íPþsP4ÂîXLS‹–õ´>õ²¯¾ßEã:×wÈo ý›nûUæZ´¿SÍæ ¼­jayŠpRaC7ÄJ–õg?B8uÖËAc\M¯­/IÆÓ†ºö­J>Ù¸ô²( 3BöÖל—ņœ¯‚<õžuX ihÜGn“ýÅä/{p7Q P”3´õp‚EÓUûrÈù•¿f dAVj  æŽT[~Ї+ÄKMÔ•$3íj¤bVé: ±Â”>ܦÒßzÈ®77ÎfN»‚ïõzï ç°“©,™>RWßú÷¼«Åße¹'Ž¿“5#c·w<{·tðüª,Ó_@Ú.¨N€½ïŒÝSY–Ž=N bc)åS*_«wJƒÉÛ˜sbßw¢O€ø({ÜÅÍT8üÜŽE$ðºÖ0™üçâlo®¤¹ëô¢ÈQußB7ÃÑ¥¢n×>™ž§y£)Y_§á¸UÆÐ„HW¾”uóNSAADÊ!ï ­Ð'Õƒìv&z&:Jm@`©ÆFi’qY“ß”i%®-¥·ŒõÜqÄðZ0?«Ý¨éØP¿é"ø½a„ùâš8x-æá _+¼ä÷Z¦²ÀÓ¥TwÉUOÑìäZ©%Š%˜rȺŠÉË` €ÞŸçýÎéáÄŽÝÜ[z ù_&…iHrâ1ǯ øô¸4v¸ˆ¾ÐÈÀãaq%ëEda°á*÷Ö©dN'_€`ÊÉš‡„!4±‰-Í4£ñ£ë§»;œVOÛbAÚOÀ”aj^ºÔ¿ôôÃé w¾ÓèÕøI9Š{Î’Ùò0(6µGx.j9ŸÎ¯"®p H&Û¼_tåEZ—×qg:µëÖSã©:“Å›½v+º]‹ «NYm)ˆiZÕßþ0BÖúÇ$ªúSæ¹(}Ï´1ÛŽæ™cç~|†¥è³º^+"¶ž7*ãÿL¹Ç8Kð±ENHåæÑ×~M>–½2ðü¼×°AE$1›%Œô,µ‹e´]Øú#µ'}Ý´7‘zo«ðå@ì[D€gF}ÁÇÈ9GþJ¢c-@j™M ¾j²]-ÅIlÔ•ðëCm?õ2õg¤9‰ÞŠä ÂG2%§§F=¥àUʆ•ÿ66ÿo­b6\bݰ&wto3G¥ÈëÆÌš½™¿é'…Ã…à ’ÔN>­¯Ó¶Çxâá|I+¯åÔC8¹j:°àvØ«útžz,ðhàl€ä!Þª03Bì¤ÔSаŠÑ ¶Ú´dŠ Å¡“г=¿øR—Op£”|S¡)];2,5¡fiãKý¥}Û¯PN*Ò8ñ*#ø9o×½dÔ"×4š‰‡Ñø~ùjwË0\p@ýç`*µÆIúK—ÑæEä”Þ­·yPÁ;Ô°%U:6å·ëž—Ož: Xq„”rªŸö4 ƒ&YjMë,tx³1ÅÀ¥ŠÒü$´·àv)ù’<½ß¡±¹TŒ†/t|k9?OþsŽ)û“‚nb!<BéH"¶ÝÝ^å…FyçÛpsLã È 1ü¨CSaœïaÔmÇ»ø½Z*-¨6 ¹¼’4Ô¦©t¡Å·ŠiL j;³œ¿d¼V—«·xzû•"“òÖâ@wZó³ˆuƒVZºÖb^ó×tÔ™H&™ Џš}_ÁõDx2pí³ïsmþî)-€@Ó~­ÖÛéÖ#3‰¡g†=Í ¼ •F”©¾¹x/"Gq£pÃ^|Iª³ÚH­¥[Ó†ÎØ4/,»+¦x°ÉfÁ -h6Š­¢ïÞx22ùNÇl4ÕNS5Ü@ÿk¶ Õ·àWU ΧVÄ#]Í¢Å÷CáNÍãÃ¥ÓNPP ¯ìBÆôOvñ»ïÿm¯ß´ÒdI×wµ[®ü…T„úÎ@„N… Ô#fHAZ¿ßäj~¸é@Ư¨O#GbW£6« ³·ææç.ØÙ5ô¤ºH\ãkå ‡Ä b<›[¨QÅ€ˆüµ< Ÿh-[–×6âØ )žDPöÇÜýûß¼U–绵€=¾¨}V3´ YðGé±{ï>jõ)nãÜ25w‰#ýeÌYàèávKÓ^‚¯V=óÜ«ÝÒÉWÉ–XØÅ€L«—df<¾B÷ÙÿzÂiÙ#"Ñ(Ï}ëÕë¿tX-oýéÖ0Ÿùð.B]'Š—PÙbí¡±X$~õÌ=°°h œ—Ñž%ÞG&#¹3NFµö››^&CJ4 4šÞGt.ÿ¨Ú“ê3r^UAÎ+1|ï]PÛwººçÐ ¬¡ÀÀ3|µòñ˜ãûŸQýÀüùuzé‚jÛ¢ºµfÐô›tŠîùn—ë` !¿ðç¥é†=z$·òÆ´ 4ËH²ÖüFõTI lR·|û4¼ë äÞ™8!zhœÊ"#µ½dãÂÚe²'tÞ¼}̵f¦²e¥YÊ‹=´Ýã]™z¢ƒà5¥ìì%7ÅuŒÖòådáÕÅý|oc<á¹,¬Ÿ›T><¾Ôæw´}°©Èo˜þíÔ¬áu]ü7ÈOD›Ìw! ð:ç‹US±±äœ˜ÇRsfÏQÙûñOò%<âç­ÕÙ'2ùíJ¦ÿr¥E¡™ÈÅìùJ¿/ð[Œ^k§Žøn&ЦjpNÖ4v$D«ÂtJ³§òýˆ¶¹úí~Í]Äû”Õ¯­„,ÁÚùHÚ¹›Ê79üZR¹g2ü™¥x«[9ÿVtVq+å x“Bÿm»‘KÊn‚‰)#ò‡Ó*„Òö.¾j½ó‰€äú­c"åv¢)iè¬j!ßú6”?Žˆÿ`TÄÈ5qø‹6smIQrž€AR/ü:ÏÔÙ\VÉ/Ùœ>P˜. âd×R+Uê~Â\ÌÃÞêhÖ—FÜ‹pÑŒËÐŸß Gh´t±¹0cw˜,#déª=þŽ)û»¿·ÝT79ÔÌWµØ7ÿ@oOb'Ö÷‡(Mßn¨_³Î®`Ií#»@ã‡}exÁ'Ån½Ÿ`³cTvòœmnUñ•yÿ1÷rªÊVñ5uÿê¶­äVfm©6y•g?9¨BˆI‡CRòÌ XfK›.ÝßIµPÀHdî!§‹(õ©©þ[Ȭ“7ÕN²_}[×ú3X øc·ÓÖsq×¹ÕªšB Døèµh1Ya2´¬¿[”oL,ødÖÎæ•‘Ö/ǪüôL­ª¼KJ±‘ 3•ÀÅb¯Ê¯¼‡¿ ¸Î O,Æãk4¸ç…·^‚g§>¹ucP­•CÍ·R¨½j®"é{nT³SüUú!pTÝ…JËb½:©Þž“c™)œÆãºWè7Êþ oU 2Š@f‹ÿ#¬>KÙJ 1î\3‰šÓ7m‘@t• }Ifohz;ð,YÃãŠfÀo’ÛUA &sl á~/V)X£T%kàÓŠ¨àÁÉêc1½À“‹›•SÉæm Ø‚I°osw‘Ïfív0SÕ'ø!Ý -‚D™kÖ9ý”!í˜ñb(ça'ÐÅc–Á}3 •î/õy”„sÞÒEn¬iâ^„”#.¿½yâÆ¹÷¡+6€Y ²3Cê©é>wàµ-‘ñ[nÑ È\'?H@£ìC˜ Ù-Ò>L[a¢Lf}Ó×"¡Šè±®0ói ! d,F<§†³ÂïFÅFé¡©”,Œ¤®8–påÆtÚðÖ.jäÞ¼ßÔxËîeÚІ伸¦Æ~ˆM‡"”1íqf£û˜ºªgã÷• ¿5¢ º@F”1ÍJ=g™›…› = íT܇Ž¿ž¿öó¤c©q©Ïp®·Òo%©º2eÉ¡¦³ow2¬p*æ×FD3uß¾Äð§j„ô&)÷·¦Ú“©ÝX¿RžŠýpÖÇ{4w‹ƒöŸ/çEÍk–\T~>:ƒË‹T÷y×FNÄ9Lç;Ë"¤h—…ÆÊ}©…xì?KÄHÄ¥ÐgP5Ææ·o§p5IÊ/æÐ%ÚçêÃÅÁ½¼9†~±a»šÏ(nÿtÅ3°SSDz êB¥ˆT„>"Q÷ ã¾lšÌùO¯…{v¬ÿnèL¨Û~Ì,1ý, ©—~{¥K)ä¬G3µ`mš,ù£MÀ Šžvž‹™žÊ}á Þ«I‘b³uPèjàSxå^ê0 {[pæ…é<\%ÎÐk½Zü#GpúŵìfJ¤_'˜ŽŸÿ€k6ÿoËé&ËÙ‹>µGùC8>DVó ¿Q·©S7;ý\з1Þ'GÖÔùËÖî¶›qwÍ ê”éå%Qú”Žn,¶dJÚ±d‰ZŠ ãÖ-Œ™ ‹ú¥„í¤"ÂÁç õH>iaAÖA5ÇS£ö0¯KÜ ÔSàöó!Gƒ–A‚õ1Ú¸Â*ãìjײ¿Ë)y¿K _KÊw²HâóŸz£Éî!×mø=%LšiÂêêä-ÚºçWÄÌËÁ/ivr§ÆF`ñ7ð‚‹©Í[±)Øö[¯ß=8: ¾ÿ`,MWÌ Zð—åoº ßUtgÇ|±T#S³—ÚQ\ì8o8²7†Ú{‰TÐû¦ƒ?H  NºÝ[qP/\ q™ê l]™\lúáa)°³"¬4yžwÒ×ß Û·èaA¨ûùšÆ¿6jò hÞ{>PÆqži’í d"ÍÆßšMù¤Çà˜­Ç÷í¼F¸qܬª¸¦'ývΔk䈓«­ xÁE€°OùÜW¶÷×NaGnØ>œ«MúÔ:Êa Eá¯q©e¶%•¥.·øRw†&$z˜¸,Þté;bw aicÞšMÎÇæZ Ëo2é…y™…µ-¤ƒ èJ¨¾…Wh*I›Ciê«ÁÍ9¤²0—Õ– GMaèû¸Ž¿EÏ{œß4œõª0]3n¾iJêž ÎËd9Ÿï²Ä¨d2©TÛJõ&…fÊ¿ ñIJž.­ˆlÜÊ»•žPrmo1åöúþ_{íöþ¾Ùü=w/·×²û}tÿC×ßÛë¿û}h¿o®_íõ³¡ â#J˜;áF»˜Œ,Í$U¥ídÑì[*–/’Z…ìá¡äÕý×b¥ÓJ’ý×hÝïÈ©ävçx6Ú.+qÔ^ll]s\ˆXè©§ºÂ@pl‘¤ô eI 奱öš´"­!ì“v9{®¶³ ÷1£ž|çƒÝš‘0qΧ «×nÕÀÌ)0¼îð.¾Ñ8ø¹â[0%9; ¯& „²-åƒÉlÝ‹Cø]rNOî {ºÕØîŸdß&Y àMõ¢õ×ÛÝÙFðäñ¶‚€ÐÔ "‚èÔìÆ§ÂbDq®¢'¯ùQ»ÅY™ÁÎÄ+¬q¨²Ó !¸Á•Ћ}zt½Ùô†1ßÖá£ua±Õ})¥ ê×DüÁ°ÇÀ`Fz'ÈPÌÕQ¶áYfQÛEnsFÉ•¹^ŠNbù¸q¥Š4¹j¦îÁ5˜ ؈‚sòŸ*‡ò¬¡òûò;wá/Gf• Ý!ÔHE(;§Þ>¿mø åöK…­„dˆZÀt@yà~D;!.½¸´uö¡VR–ÑÝÎð:'¬ãƒL*C{|YR†XKž2áòžîÏòaO]‚Òøð£ÜlNrÊgÏdṑ8VÅàŠÂ&q™ –Á¡¼S¥¹^½×fx‡:úU´µÏ¬˜lž(çÜ2iøë MMdH#Iïúœ.k'R:·sÛPãö"×õ0QC›÷¬샲Ϟâ’ëf@ò¨;ƒŸJË S£EÁ¾íA.-\÷ n¥Ú«òäpƒ¥š)B±KƒjèˆA FA2sCT?½ÿOfv„ÿ;<1Æ7“,$ŸÚÐÀà±ÎæW±#*g: ª˜ A¾òÑŸ¨0¦T—sP‘Î €kßÚ4Ô29¶’9¼2ºY <ãp$$®î”;c£Ÿ¸,Ð…=Ì€L×ñöŠx×nýL'IiVC‡AýsKÒÂ%ûá¡dª)Šó‘Ì|ªù*[¹ÿm‰îÕì(i“g°ö°su*£m8—QY-bæüE~‰¯xbíŸA›Mh"™DxÝžöÂã 7ð`]l­ À ú\<¦›ˆ g;«‘4ýe”]wÌõõ{=–ôG6K ¶¯°™€S‘™V:ýD[ݹ|N†çjfûû–¦Ùs¼­錡ŠH÷œÅ‘ÀÕ2/Vw/Ö †!è÷/æ ùᜰ'7¢%Îõ‘¸h]é&Ð@è¶Ñìé@š1•ÙFyh+·.­.4úLøÆ¢¸¬ÃÝ…™åôyö½ªL^ãòcá5vÜÎ&ÞÿDÁkan^˜à‘ø,÷Úw›.„å˜Y%Їsˆ¸ D`$wèèSXÓßûµ‰eD±ßMå˜xìz`zÚ™¿ÖlzjÁvÄù¯VкÑ4²Bp0ù3?ü~ýQ ;Ñkg•=‘i‹ÒV '1ASQUf7nY$tÚP,ß*yõìm¼Àå†N"±Ó]·[ËžÐ:$ü0Ó4vŒµšGv å|°ö¤áöà8Þ}¢ªÏ‰:\\ ÉŒC´ Žˆ~|‚„6˜Mväjô‘œP‡p›·9ÔÒŸATêÆ¿69’«‘s,ÝŸãŹŒ¥LÌ~fç5컡ºŠ+Ïñ¤–ný’¼S8ÍuÙ«ɪÈ··¹]œcr‹ýÙEÒgàB^¬¡“#šzñθ€UÛÙ‘¾ç€«ê`7KOèv·¬”;¶ûf·Îþþ€6‰¿sÕ6²Jpœ;ô†¡í¡‚O‰±©0*Žô»y}?òˆ<²SoN9iíœtËLÔa&HDç¸ÿ;_Æ‹ª‡Ö µ+-þàV–Uu@·¡o(¥~tH'‚öm8>uÑ£gY>`95áqüÏB1Ú¤}k$o'JjZñ`~•â¬Þǹ×JkZ´BpIB1+¡I–tóGMˆ™¶ÙWîaþm—«¾X‘ez 3g0 G©:pD.ßÌK}_D]›ø—[ðZ,=Oæ÷àEÖ›3ÝØŠ²QôÌظxÕ|0ù ãü¨Ñï<}ÛHÈçzÙðø /nmÖq€¬ûˆÊ|[¦¹âh:ÖunÏÇö!8Ñ>MY€¢ÐBN XÅÒÀÒ?‰úÛ3[?úQÚÍ`V¹DͰ)°>å%›@¸*@,yrœ•~"6ˆnq }c‹Š ½`¸XZ¶\» ¹bV¬ê€¾èèÕ¶Ú£ê Ì4bT´vº—’ þ,„2ÕõØf3'2†¼Ú^ÿSí²k2ô¤à±V*ÿ" vœ_ùv+ÓMü.1ÐÌA-g'u~9+›+ ™„&=f±¶Ú Šaj¯”éõ‡E ÿsÌsHÑÛ¥·½6Û¼² Áâð¯pÄåsïÞ3ÖÞQ}QÓØgº]=ÈÀò©9zÏqïu[u”só´­å¸dÀ-Û/Ä`êÆÛî¡ì÷„Èý|®À† ó¯Áã*Õσ߿ȃ,oå|rà»Ò1¯!;Ä ŸûÔfð˜í÷î7XØ'v{Ô¢m†î㣚¹£dǮܧHõÞ ÆXpÎO=§•CAÞ `ꟂÃÄxž¤ØžHî$qöÕrçžÙå:¹k&b Ñ»n(¸§-x*J¢§g_Ý«mˆ;µ´¥¹3÷ÇÜÐ,µGäs‡²eöõCýY”à1$Ú+lû´°¶Í®ù‹o‚ð£g-Ë6,3.¨†ó©vKË=ÝÐ+l¨®èÑÃ0èt=à€{ïakZŒ àÞ9µ$‹<.ù»6[ÐtKÊBÚÓcÚÀª/¯Ý{S_”ÈS¥ˆ®Ù›F|sß4Î_îh³Ò-ß¾18††è2zP%Ÿné¢öý¬ '¨/£g¸Ýx1‡ü‹àïCÛ6€¶r BÖÕNS~e¹!Ó$\çÓ/ÑËu!ýÿ_5zs`óÑŸ{†¬bãC,åäR-7wüåw&I0&rÂþ„÷ƒN;Ü"ø§öï™Ê?Êsƒv5ô"O±&@DÉ™Ë:ƒ /ÆB‹EHÔéöuÆ'‘‘*hºÑ~Vr.͘þÆi:ŽõÈFÓBP’_ŒÛð Æª>2‘ Sôù­•áúòKÔh„™­í £¹ÁÇÆÓ¨Ã“ñ“{({õ §Ý3á¼ð®¢’Ã…»ð¯!¹9 Ôç­*›%2” ±*§ç¤è$ÍØE:ù APý<ôœeEjʹZi\‚ÁVêŸTFIsL¦õÞ2‘Ÿöz‹ZÅ¥ë6²•:)¹‚A¹&±2¢àÍ…ŒçGä„_:‹ÈÍ]n;U”‡¹Îâ”÷³Z,•§EUÎU`¶¼eÞÜ=§" | -ÑÛðñ6­VýÕ,ó®ÝAJÎ{{!/ý&ÇŠuòÑ>íž·È$ÜÕèa$÷³>ˆqu/Ñó¿ŠU €”´½lÃ~©3ZçoòŒ.—Á=9E>%ÓHW“—ªª=FTCHõª®R$ÀENÈ! À³°S½`GaÆxœnÜ•§e_e0ŸÁ¯+:è}ádÔÆý[ù¬ÒÒ±#%ÜnS„“fãšÂJs™û\¬vÙÚ.,¬“V°4ºhUVdç»>…›†œR1ð¹UM ?M±=Y:oÌ]’¼Gà(Dfâ•G$íl¡¼›÷hydp÷‘`¯0¹½q¡Ð ÿpº„q=î¶Ø‡¤™ÐìÍ8m'Þ¿<^íK]õ¶©$=s#x¨„> Eõ°Ëô1cåšo…ª‡ñAVèev‹D=»Ó ÝPœ-c<† C èW»ßª.Fjhž\¬?9B¼ú‘'HÎZ]èd¢îýZ |¢jGX1§˜<á4n#$I$qýg±~웲 h–¬¯”%Ôêâ£áx…JôU½äEÐ&ˆ™ß(ÿ Ù×ÈäÜ1‰Š‹A_'çf/×}j½{A´­#j&;*8›ˆÉãQ>ÿ á„e½— À3 |µY…×û(Z(“ÄFF¢x웫w À E·¥ÁÉ)QflñÝmvÌ‹À—ÈBZÿ_ô»#R0Û°CjH´Ú¼-”?CZß¡ôÁ€¯ë (ûÓH§i€Ëæ¨kV2e¶"»;F<Ëv»òȆP­p`4K_›^¼_AAÞ’F ¢ßî©Õ0â,ùexØø;”òÎó“7"­T¿ERóº'Úh°QcVh¦¥°EÌ[0+[™ä¾öÚÕ.ËnÔ@}SßoÁäXÞG›7L˜"7æîîýáäûÆhšëR6t„ÐjÍÕã™RþoͲ°Ö÷ɸo^‚“š9¬czŽxo--Ö]h(³¢‰@pz~„#V‚ŒP/ÌÃoêA2ÉJíÕZX1ü*·KèüvÕfù¼?ßÇœVZiŽ<H[ÁŸqú*_ᵘ!F/©f6cñÇàû–RªË'ÔÛƒ P÷ŒÛ9LæŒXS½« ¦~cíŠÞs¢e_’¯@Bø–$§ írqš‹¿IÝ .q)ŒCžuvãð`¾”:aVY~ÅÜ”\Šù.’swh¶.¥Ûshk‡òvaœÄÝs›b"ÍÍWJ™ Æo$)¦¼ó@‘Bÿžà8GüOˆ-‡¨ã*#N¿/®lB”8î"PÊ!²~kþÂæŒ¸ƒ uu»¦Ë)øÄ)¤ÁÏ\tL%§ßåº3tˆ,1ÙP4V¨_g§×[IJI’š·]bQúcYº°N\ µ¡€œ‚¢×O岈€ÍuÄÓ;B*Ž]êÏ#“_QÊD¦ÊWޝÁ¥ømè&C¹• 4 _l»ºLp0E"¿S©+î¿=ÿ*›¡¡1r#QÏÉd<‰ŽL ŸÓ‚@¸Ìr·{œõŽÄyWÊ•“YªbíøÎŸPòB9¶ªÛ’_4òd –Ç(Û­8„:wK¢†ãƒÃ¢eo„'[ßg³ç¢sQ fÜr,u¯êÙú£=ެ8ÕkHz|:$VK=kwë<­˜šÍDLm•™ƒuÞC×NüQÚ»)žl•ä8oñ2TÚAÌJu‘u‡)Ô&Ð";ЭÁúq§àô.Ei¦[§à´ƒo«àï™çVR噇ŽpÊÎÕºu»t£&í?¾½ÙîvVøR7¸†+Y}<!éÄ÷¾f­28lÙÀÜŸ:ß4Q'÷¿þî31Ú:ˆKÜWÀ¶.£ÿZÙ‹Þ -#ÍPð,0ï°0òÆSÿlîìÜyÙfqÝiBB˜€„UÏGâ]$8æFÖ˜ìÍ6gÍ1±jÔ6}̪ÛòöLŠô™/2œÃx1!ükÍòVå  D©ÈA3Ê^%‡]YûØâŽ×œ¢Ayù Mþ?ÎiÈÃ'(Ï‹-’ˆ È åÕ¬z–KÏpÑI+RÊϘÄutq® ’Ä4œzÇ«€˜«í¸EšbÓÉýÀF)†nAt£\âÖÃ3zy&½uÙ<ÑŽS»[á(°lqˆ’þÒƒXßCÀ“]lÄmf©ú O)‹bk$‰ÛZ…7Du?uÏC¤šãhñ½ñɵ4 ý™MP3Ôh[ACÑ…À „iú¥"ù¾¦âA7ͦÓýƒê`{¡ ÑaâªHè“¥«ÿB)ÕðUª8“Ñþ’VRÀ‘ïÞ\†îJºF2Àçt…7BÜ÷7žŸÂt<-·êõ)‘ÿ/ØMà×wk*Hnaã`dcffXf}k;âkðåùh¶9蟨2a# Ò¡!+#ÞÂÝu•pa=Ù’¤ÝÐÁGËÚIVÌæÂ ŠƒÛD÷¡S19'̧ËR hLòm82vÕ³"Þ&žì¦¬r®4ÃY:`XûS£Ò!áÖÏh°•ž¯ã½7Ê,Ð ¦Æöè"¿~zëGY(³J²÷açr^£— Ö zߣîIwÈ’  25Ïý߸Hà/pZŠ+‰€[P}o7-de'ñ„xñ¡lŒ 0ãÀÙo«ÇÊKÎ÷iŸÅ€V<(”€Ñâ¡@5.Ëu\Û¯z5ˆõç˜ÜXIø]…2 WÅÓ>î |/À¸D~ÚÆÞ¿¸€gQVJº÷ª;¦×ˆ½;½ÔÈJoÖ¨JXÎÌÄ5MÑÅ.º®XËM"}“²Tç>g°°þUí°j'ãÚ7Û&¬ÂŸÈH|ý·¨kŸ'ABµõ ¿=yþ ¿7ëSúš K‘w§9ñ¦IýK4p@£0‰š­ ›œîC(€ÚÅÛñ«4»ž¬ðþËí<½‘2yEñnPt ‰)5gt½Û¯Ž@pûô5€xOS>>ÄéñãÊÑå…Úi´Œò%…×nR/}eÙ÷á&‘vJ_x’ÿx˜‘Zæx—ðœAê@¼CZ¯J_|,çû©€[,ÔܵS“]ö=×ÇM«e¦J”¾8‘îc baYøÈˆg}2‡™K›“6›ó˜Ëuyw ÌÅMØ‹˜öð‰›žf¼ø Ý= ŸüEò \ŒOíkX¥÷æüöòÔ;^‘Çë|ÒÓ€kt/lD#ËÊÝ‹Z}·wq«ZnTå ¿X©5‘ò t‚4ß¾xx®V9ƒô?Ð×<¢}¡ŒÙ@kt¸·g«fèú<¿¼Z‘¾ŠåxžFÑŽZë®Pˆµ.Yã3g ¿+ñê->”Sqñ’Òå^)Øé“xóüHö%dgZ•ôT(Õ2]îÉÊ˽”¼ü¶a6N”}_¿¬êŒ M†mœb™ÓõÚl¸“XŒÀ†Ô¥õ(¤òÀçM1•”faÆygÖ·æáã¤I›ÍØ—f‘ÎHCòuP›ý67ŽUguŒ+{M mW ÃPPn@^»ÿUz—«B!ìý‘¼M(³¨\ß—`“gxu ´8)x™*½¤ª­8‹I-Mµ„cþêø0Toi‘*«ZVáæ”1ê­§ž¶6ðÔe‘®.¡µe¤#NdkWŸtŸ:ŸåMÓ?=¢&×,â!«ƒ^»tXØq(¥Oó[‘üöUýx%-Ø.US)95jÚ^Öš¶KÉ´ fPXšTZ\$fÊkPÚÈÓQgs·æÂÒ4Ý"úˆ=ˈÛúv«`r÷ ì™~mšÊw¶wÏöÞ;U\çìaˆ¾—¨y¦öÎå&Wô¼àø%`\Up,;Ijç<ÂËÎມLlwê®rmñÍä©{þMÆÄ‹˜¤öÏxú¦ì}¾_NñQì Æã”Xñÿ6—RHËt¿NFu:•e)j»U‚;â†TIð‚fŸ$7‘B×e A¼åß…xœ—1G;1^bùŒkɤÆ…_j²~,+œ×;â”U¾Ðm+o÷z^Ž%ÒÉÉhð‰ÎÉi•Cq›NÒg‘vȶÙ!ø=k~}þ¢ÀUâô¢ŽÃFÈ‹©!V®V†yÞäy CërF¦ßqÏênA. þ¶ñ«H„¿:k%\x5²*BžÿLDÉ¡eNÔ{—×ÞKÚáØÚ¥: ¡)qn öÜFÕצý-Rˆ›÷\wå ˜'×u_Ço|ãä+}5(ŠNõžYF= ¶ ¹ß/ï¥ÖçòÃjÞ‹Í–7Õ¤¦ЕI©X¨ú¶ãWÞ„¥%0IìY«ûò¦%zø[lÀ'®Èe¥xxFJD#?Ñûæ/÷W­@º#ƒùå°º}!*¥^å \Dpá·tdÖÔ&„VÏWFv§GàÒ¼0Fg•ßÓÑz9 ŸS¾GLø:œó Œ6ϪI^g˜2d±|ZAÓŠ›Hdêdf:†è&Gãkª<˺äó_ßüzô ç¶€oáwœœí1ûë0,‚ìM޽£ŠñøæEçA”uÂcørZX!ŒjN^›p ÎüóÃnýò :ÿËE9bBB &°Ñ¤'LTÆÊò*-ÿ~-ƒöIÈööi’Ÿ£.o(h‘g› Ì5ÇùÕà|@'ÿ ÙÍBÚÅ0^¾À-moÅMi·jt&ÆÒA!Æà»Uûp2á‡ìÝ’v8'½~~t1ëÓYÖñÓb‰ÆõcV²5¬ª E©C‚ëÞ9ýA}FÛqÐÖ.gÉëqJŽ,(ÚbŠÉQƆ\4)ÄqEjx«OòS·j\à7‘7~Ýïë•…Fž×›dÈÙeæ¸@æd€b¿Üî¯Ó€RÄj ¼·;‚ÅÀФ“ÇaßÌXý·D¯ñzüæŠ%(BȵÞl=€š0ÿ}6ó)´¸æÃcÊú<¹îªßx«o«td#ýc%^Õ„‘»“M%¬ºã=ðàå6m&‘t›ÝtZIÜCü§ 1Ú€bc‰Ñ6š+Í.©Qå8€ËØ ðn?6©¬%Ïçž‚üHSPóûC =Å<…ˆK ²èòÝ|á>•™ž+¹‡1Œ§v_fôv½aåÃH~vI¸¬šP} ‘LÖHCáNWA·Ž“Ó DS$ûÜÁv¼•Ž^hq¿ÂU2KÁbèÖUy¸šZõ½nߢ¯ãÆ]¤bžì‹èé 麜\Ï'øà)>%DȺ¨d_Í(e;ÏQ”·éáŸÛ…™±ˆ/Mu¥×¬*ò´Zðtí"Ã{ ڦߴ~@ëÀZ‚ï’0EÇ/NFpO9b¬6óýîIÊr×øøó{Ýq¨fxè ˆ²ñŒ'T«ë1e,Tb]ñlêÿ[oư:\\sÕœE¼Êç[S¬Kâ#)xij‡*$ÔÇçï‡.ѵ¹¢ÿz쌈€/ˆ!§½õÞeбQ}roñ¶¬Ö8ïÁ7úDÚùë¥r.‡ýŠçÁhv¾CRJîkCê^.Üu÷¬çï—±ŠœÝ]ì/xâS¥Û]ü2»jNÔ ×Tµ-h¸BâÔEÈii‚zFí5PƙÑ+ÞS7ÝhÍ„Ý o>Ûèi®QE@ÅsÞß’}eža'”b xu› px†×÷Â& ¤³ŽxŠFQg04]—1/¾Ïå X€ÿV] \îûî$v7jdñ«29Í `&ÎÊíàJ> &b ·õ€v› ^õÓór'zhžÔ´º °¯ñáñŽEÉ…ûbåõÛ â0Hã€û°ï¯à^Ê{;Eù;Öý ÁгÑE¢¦ãƒ÷ˆôhÖzá½èÊ^–¿´»‰Æxx¸'`smÝ[6}/›´z/rYVH ¸te[ö4¦#—é«1Þª)º~¢‰|Ö¿ +¶‘G–1nþ})XJ0cºÃÃ~õ  nwáÿ…ïd:L7g‚BØÝÙ,SóÃi»Š¾MôÛ`­G©YsJïhÆá£îC/ÛÀׂ W¯oÇK?!Á…‡GHaç;Rù]÷½,ô³¢ÿ^c¿ÇZrnƒ~<.†¡–wH#-GæÝ¶Åì”IôÓ·L&bfé¢St»šæÕ‡'}wk¿ÿÔj7Dh›f(ã'·whCEƒRõ~ÅY³ôwÃ*x£®-ºÙC¨)ÑðV4þëñΧ鞽MïŠá—‘½ˆåÃyÊ2§8Úg[!º,‰R~(å»ËöRí`61I‘ŠNÒçàr³Ž³øpúl$×h:Vl#HGTmc””dÙ¸¬0µM´uhw&bT™G­ñ!­ö –;–ájq‡=<0(&KMÒ=ä§ÊE•6µÖ„+íý=ò3ϴض_ßô¸z Á•ÆNéJŒJ—A7;î`g\Ë{oZ ¸©‹;:HF!“‰´n)}"W¤)ÑZˆ›ØH%\ñh%w~ÎA˜Á%+˯“E×v¾ãáJ½^°Œ“æž4v›zfœˆúdçöA…æ•«¬ÿ87b‚;÷|ä‹wƒ5èzÖ¯áù4&¸¨ÙÈûPáÁ:4Dðݶ©‰FÞ¶øÈDŠ…ò i—ñ÷_6•â^„@ŽràS0~5ª™ÖbÕ·»-åÏ•Ãד~+ó,±ÚnêïA;[Ê>Ûjüƒ×éí:?;¼>[ˆ¿ÏU (–‚—Â)àA”·Bæñ8¨U/h\';¨+ò _Ð͘@€ 5¥ "ü ¼iƒÞ¶9#/04m‰{­ ¤k…¾o7{^1ÇD)\hàÅò-M+žßÞ†ã7ÙLã•È¿Uø{OÀ˜|zûURê„_Ù^I_C>³…õÝv„€CS¤’Ý·]ï¸yÕwÑá]@^PvWΰãìõQ›šº)Û€L#§šDý¡^PÚËj1t:A™NШ_q x8¨c%Dy3ü²Á°ÜÌF˜K»VMö÷¸}º¥Iò0r‡0­©ŠO@|“›P%DЉì^0þjÿWöãw±d}å–ˆm<²ÙÄ‘ Æzj˜4³'§íFö‰Mk: xÞNŽn¸ÖúØ‚)Æ+#›Oz3Z3Ú2Á¾Ú(·ß†§Fqay¨â©bÊ&ý¡÷>ÄО=';«`à¾Ó Ø’1O½¾Ÿ¶ò\žçÿ[=?|â6t5µm†H¿õ…D¶Diå„¥Ãu]œ“?ªHj{*Øßãƒnd…—Þ£±÷Ú¦$U8PÄ[5æ# 6…>ûËKo ÿf†I$¿t]}½Õ~ñü4«6 퓾]ô”пÖÊÅ®+¶í’É÷ÐA«È—U€D—t…#!Åý'ÑÍuË^÷kGþ÷XrÊx† ý’Ä_S)80²úŸ²¼Å…§ç°ÀוP~¦nÄüG߇…I‚¤ÙpXÙëàE`[­!–Ê9>é¼÷ZEXwÏÃŽ.>/¿Î8ª®}K5™fñ ¤2½m›(šªš ðÁTË…5$« òóã©,¯Š™âg³+äQ¡´û€¸»Q¶Ô»=#¹Ìw¾‹y±¦†í­lÂFm4ÒÔtò®ÿ7ffe‹ž*Cœèy—Ô;.+U;¤¿±r…ÝÔƒwy߸»\ÁbýÿEĦ.V÷tïZ/–ô+(k,‡ Ôž_œ kÆ’Ãèçy( öÒøë²ÒØO“æSxíÞRü|;x;¾@W]4œÈÄ@ŸsôKõÍ¡ê>ŽbÃ2*S@!]&`ëƒzþTÄ m‹Wx{Ñ—£è‚ŸcÍøýÁÃÍN›cHWž ^™Ø@slŽSƾ&Oâ‚vJ¦ÝóybÒ¾¶• C`à­9o+©1ƒNºÎˆÍ‘žx…ºŠ 8¶röO'+§ëFˆ]ƒ¥j1@M?ÖµšöÓÝËR[¿>{Ô¿°€'+j£õ€'ŸxÓC#xÁŽm /ÌÐFýûZÀU•·‚‚€¬Ã«Hü:làƒ%€;P/Íê@æ®Í67sëBþ¸èº†!ÜfÍ0j/ú‰SJ•úž#Ë:å]üIAƆVno¦ûï‹·@î#xˆLô$tL¬ØgYBÆ 8÷ Z«/6Y‰ž »s™üߌØ;Œ_­W~iµÇh1(Ì ^Ÿ´Å À^ë`2ÖómXümtÜvXC,;ƒÝ œ÷ï(0î-›ñz¡Œ-&؃íÜý5÷â¶"AöŠg^â?H@&ˆ+øÖ‹ï–n'(–2_æ®ztG3®fï3"èQ"cE%6Û•¹s… ^ïÕ¤â×Y™Ÿû-Ƭ~›r¨»–*Ë+ù B ÇZ}q&r:–r¼ ê ®”SÀÐ>2È~Výä²ßŒcIçöØ#L2Ô|ðJ¹á~@ˆúwKݦßèøD]ü_tèßeÍ¢¥Z‹ãúBÑÏî™È"{î©#d–vFóͱwÙŒ,*¯"ñSÐ3ÙW¶þ è »¥°Ú—*ŠÃ Z²o…j?Q{ªó»He„ Šð"y1Æs7hÂ~Ï︤tþTi£pLã"C&­Œ&PÍØZLx(Ò¥“XW‹ü½Ê`Öcäé°!/)iY‚&È«‘òR‹ì‰c«í?q÷@Ú̉Èë„Ôê{†µí0;éEK  …®%é<"ˆásÉ@œëÄ•Šx›ì)£ÿ m"i‘™ãÂÞ“°–»®‚êá¨}|ÚœxÄØ…Q}/ Gó×(§-–åŒ7O÷ÍéBqó›ú— ”‡ðÅ%$ÝYúÂø'Ñ蟇Ñb³Ý3Í!y§?…Ð|öÈ,ó¡[åÛ"£¸ÉÐPù–wz?W£0ÓYؤÌǹFUµŒ05>{èc¶›´§4ï ådEC#+p°D,‹_íÖ¾Þ0ð_nQˆ7â8ì¯âå#Àýç ‰‰A+™Rx¶KÄ­¹Ä¿{y´¨¹XÒA28h^Ž¿òÞäÞ.ÿ ‚›'‰ê1£Æt0?4âI1¡«J‰ªäâú˜ø‚`q<ãè´M·³;ûýx<ÖØ &=ûÂRsžòþi¤VyÊžT¥Øòóg9"Z ¿ì YœªÇ‘-(ÕÑ3\Y8Kz³Oi7¨vIS3·`„k!™¯Çîû9jQà2ã|Œ„kÖП+Ò§kE#m”8¼€ÐñÀ‰ý‰.‚ŽêdE r9dœÔC0ÝÅŸÿ4W„8´D¬%MµP )LྠEÛГ éFä³gcDN)SíçëkÓ:=yâÆ·çx†ÿ2&=Ft=tK¦ì/<ë[b¿•žµÉsx1Âî©ô±ãµt(qÐý"¢ÄÜÍA7ðgíÛªÒßÿ"Û+Úž‚vذN“ÝšùºÑÒŽ|ÿÞzf£±„vÞúF‡8OjXX“oGŒœïŽÕL –˜k§Çdi¨Ÿ‰•ê8×ôàÐÖgÁ꘢/M}úérïeμÉ&¨úg‘äQÓXÕ3ÜHZöj…e²[ :d4oã4‡2ÓÏ}õQw?Ü9Û¤gø¶ÿ±]q%Pb‘ÄÊá¤k,µ‘!Ÿáx¥Ä›þ¶e$ëZ~‡ÁdñvéOUmf¸û¦øVúD3C½„ ß½²€}-G&öJ~V -‹¤<7ªß‚˜O)3-d¨ÃZÿ Z³X[D“²‹óáÁ»Ëêsϼj‘òp³–°ècñi®Xà•Í¥Ð_“E¶V^¿#®F¨% —ñÐëÖ^’½}5jœÌáUc•ÝQÔ ÔæOÅö¸[©R³Ñ´úŠ,¥»¢…câ{²Ò”uœÐ6‰¼à«‚?š¦ÐpUox¤~û%ic DCŒp= š}=åßI»\ŸÈI.Ò}߬âù-5üñöOìÛ§QÞ›×$ziwàÊ•^}ûa£¿D“´SðS­"½J-¼(ÞwcäQ"(2±ù`lò“ xUyËè ¿ƒìA Á9÷“!”uº ÛÜ—¶Ão›ÇZ5¾ýf’¼P¸ÏBiýcîîÝiœ^%Û˦ðÝe3GRŠÇ8"»úQü±ÀÚŽqÕ˾Â*ƒ׳m6AFsý|Ô#èÊîÇéhl£ÄCVÞü± eÂkó/y‘'Þ;n€ mŒ¡ÛC!9í\>'+™f”5·¢Hˆle%ˆh,m…æÒõ ÀZ Ë*D‰ ã ™ŠæÛ•¼òªoíF*›W (l5–™žUkÜ‘éÞÛ/+\qÔÂKùûZTN€^_3¨ ¬DÜN‹À3;´Þ%e÷Ñd„ãPtÿ`Å6Ënq…g~cœËÐpcTÉû^ê}G$+h©HöÞÑUZy³ùµ„, Úÿ/‡ok38¬]*µN­Ÿd‰xj‹þ!d;‰Ômb2[J@IïŠÆSfÏ’¯8oe6¡î”¢Õ¥(èS$]eÀФ—ÁåPK§Àéµêúà1ªª°Êƒ:_]³>ñ¶ð}°[$Äš\´¯ƒ²(ÀuéeîÁo80ÆÏLÈggkv娜xÜá-}/´Ò< ô8%"ù})›z>ðxO£¦EV<1U’H6ú¶ºq 9ýßã¥u”³ÚÆi>‡<¶@•MPADo=±{B¯76Ã:‹ý ÙŠOôaÚJ8¹Ia) …+aí{šQ˜¨|pƒ¹äÿÀ¥—£hYÔؽ©¼c-±Š‚ÄI–³,®¤D’ †¬¼¦\fj"åiF´á÷¡Tç.›¥ÃŸb4ûm›ÂªãžJî›à¥H‹Ê_( CÍãõ¨@§ÜøÄ'm‹00ûÐÅÐY!PÑJy ®í;Û! ×1fó2Ä­gpÕhaÛ63#Âb:[^ƒ &~oléžówêÙ¾.•ɦÍ-ìNY²±ªc‘[ÙÏɉq{Œ_,Mˆ0êËíßµk§ cÍAr£Ä¤Ñ8lÖ*ÊÒŽŽ$Û{Å0ÀY Êªû8”‡ÓꨄSošÏýÌmNž‚2lŠgB«ûÊ›¤,ÔÜäˆsäñÔs£ëán †kㄟ ¥FbÈt ˆ3V>ûR“⧈s¹%GåÇ’`aÊßÁ°Ìø^*«eþ> ‘Êl˜p”Lkݶšl›ÉT£“Ûæ¹õê ®ÍÂ=”6˜çä‘Þ7• ÆßwC‚óç#ý9—kýãÌÖhÔô†M[M>ñ 8Å«UŽBRÙ«ÇL30o«°}†š„ÐdP3Xì‹s¼rç³[àwIö} 4)9–!”¸ª‰Œëøº‰Ý,Þ•ãöOv|.‹çÒ¸ž »Àµ‘Fô¡HÓ? EÉÑçþJ(­`]Yƒ¹æf¬lsJÛÒ#~D(~˜ÅLבÃЦ¡mص6Ò¶-Zò«¥¼ r|´¼#'Äùù5½nl¤èø*z¸“g;hx.´ÃßU®rÆí¯H|üæ3…m`à”LZÀÏGÌu`^ç¥H“ ì.‚zÂÈLK„¨±ÜpAPçP§°¬ù˜ÖtFÓŠs<Ј¨kÌŒüÿpáÓ')îRÝ"þcöÒ®ݲ=J ,Nª ¼uGÁ΢$ËÙßhœ¼–Gpþk›2ðK„âPÿÅ7‡‡û ¢+:68@vZÏz9žÄ¿ƒCWG9Í”ÑÃOh—~Adâa)ª0lÕ &Œ’ïí—¸\ *iþ͵Œ_±8aãÀFòð‹#BéKR,_›’ÖtDb†Ûy­N¦ÑĽÐnèºLcšyæ}–; uR®c³R ( £ýkÆÅþ±ÔC°ºDVÉf“%"µuŒõ’b‡¸Ù‘œÚç¸WvÇD2˜`z‚‘`éž!ø×èUØ&JˆþW’¯‚„2 ;”JX[2 :ÒÇÁƒÖ ^wOòÅnz~h_¶þñÇJüH#[„þÃ6އÍ߈òˈ/ï믆«1]ƒh»5<‹*­-ζð-Pö}Êùók–dW/Ÿc¤>÷ôPòFXΑ¯Ë+dÍZ9Ú>±¼Å9¹ QSȽj¶GÈ¥¾ÈúEÅsƒ¤;!MBrœLLq¬°åP žb$9~P$/0ò]d·)l"JSÑV¬ö6£v­Î5­@5öEC¼XÛÕ|h®;ÔÚVc]ÿ ¢|Þw¡6(‘¾`Y­Ó  Ïü{ttlùì9YQ[Vø}‰ºd ¨ì]üïtU™‘±9ÖÄû¸oXnFq‡çÍ¿ƒ<Gv·Ïg-š…ÇÅûœ³8…Wg†±ôØjp\~>óx]FÅbÛèÙ³2²*Ú„gˆ×‰XØÌÜÅ(·y¬ßïÒš…"¤Ì,9ËKô=ïã,~ïL×ÓgŽQ¤÷žD­Ð7×(ƒ¸®û¯]ÄZ?¤íÛ‰c@C'H`ðZ„úæÁ?•èq2€*åaêcišáeEÑžwÐ,¢)bó3a Eý+~¨ŠBFôNóbÞ§pOd7ýŠ”Nd÷õˆ÷òxåBXa hïmAµ%š)Â:•éÚ|1F"Ù$CÌÒôÀ,ÌÜNt¿›{³ ÔÍ„V™j®Ÿ»zN¥=€m€/›ÜV7ºº)òC°½G9 `ðôÚº)\†Yê1o•Áè•$È]X¢Y]#;‡NAµ,è£ÓO¨-P’¬´_œft³‡P+G3à A:{Íwõ <¹+ßbTƒl“±s*_û®ú,IŒ)©¢ù¥*~ŸY±}µö׊ÄÂÎñÕ¡œ,e>†ò hàâþ“¯ÕSâH ²"¨‚ºÚ„Ép’ ¡Ü3ÓrOC¼4'¬L5*NŠgFÔn@KJ¯xw«ü†ÆsêPÇ: ŒâdÎaHçGœïF“p •“°[–"4…1@§qúX“êW3v2+îG”´U©²õ( inGÎ@_Œ >–)# «@Ð"ÿfxÎ0Á«&þÜî«zŽBÿ< B³ÄÌ·QĥܷذÝr,( «]z”ˆšeE*½X®g»&â!D?¨nâ{wÀœÓ7T%Bn#¸é¶D¯m±ÝÉ,ï(‚ó! ÷ÜТVeË7G)“/¿¡og/“tÁ“ŽÝ‡;‹}SŸ°åÌ’o¸ê”æ]®o”?å M{´ë¾…»lïðyÅ—üª>>NñAjÓÂÿ& ¬÷uѬÙ,‹¿ÇÃÙôt3Ö®1|È CûIƒíâCBˆ=oÎêØúŠA(»+Î5~ßy] V4î;S—¨¢Êp'Ò³¸"ÿ9¤É.‘zİ4göí{ŒHëR%«Øx%ÛôÄÖô !„ç{/Ø£åÝ­¤^¼€¿ì¹c1ÂBpý"þ™Z]QM.NÎ|­å«%¶˜á9`a&>NebƒÄƒoMBl¨°0¢H:k ·ÆY_‚u÷õTÛÓÙ.WWm›f-|›–·cR!pV¾’´V_Ì’¼*+åÀcnîÚ1NL´b%ŵFh¤>û³JNµó\oW†µé!)Öƒ»Æ›ÏhÕß3”32S#Ô‘o°®Ë e:vÞÚ—ž ÄgЩz1Ík§ˆíw†U2=8wŽ;¥K.W¼1:´ã¨ƒlôÖª”ž(òUyÒ‰˜»£@¾ÕïÚÉãÄ*ÝàÇe[è±àÝæ\¾·( ØR9¡dú^÷ߦ*ŒÕ¨B: ÕrØÇp3]b (´.·Ä‚ʇcXU¤bÛd—ùÜùSV¼<Ø! wCiqì?ûS#ÎÏ÷³óé^=ýPƒ™jÒ¬V)ºÝQp"+Z¬7N8£‰t¾~†§1 ql€’Cœ‚$oòwÝʃ¡Â«iFz_ËÝ" '^³>ñÏˉöÔ5bI<ïZjh{3RL´ÄMº/‚’Û}Gl4—×cÇ2—6W£Œ ò!–¹”óu¢(· U&oÏý„¸ctð¯PqÞnªGâd]7dÒ˜¹Í¾ Œ¹…\ÂÅR PmAÄ š‰¬ÓÈnalòñ4ƒ¢ª.‹lõÀïqöµ¸&xçͼgŒa£ó¾SÈò+ÃßQÜ #GL=Q‘S’â9jÅz9Xç¦/»žxÒ~Á.y[!)<#ÎLï뎯ʂàˆa?„î]ìs‡}ãXL¸I,#Úv€«s7Wÿ\?\ <ýØ´Ü»iÓRŠ<MìÑËÊ!ZG´Ä(˜üƒÏy^ügfý(n˜Z©¬eÜ·-$-¶›–ª×`Õ!ì}7Ý{×hk¬ue ân&è™ãmÔYMANWIÝ„´lyã’šäÐŒ’[3 … òUì.j¡³DA iÏü¦8Ù‘Ü0¨óÆÕ|Èwjê=*~ùùȸ^YB¨ß¾Ü—÷ÂâÅ”y(}ÒP*YvÝ1m¼5¸p5ã<'žÞ…ÀWSûßÑÓSZȘÕz]8Gá wdùý}¤ Ge³—k™ùë•/s§<yõ϶ ì˜p†<ºJ,ÉtTë)c¬[.õ¶¥š^1‰Sí¹Ó7²²C¤–™eØHOÜ-§9v$˜`”`å9Cx†”ŠjLQ5ë‹ ‡ß²Ö&3YbK x[žåÕV{“Íçpð¢W9kñw¤D½¹­Ð©¥( Süƒ#f'öeäÙ¢qÚV øø÷zuÙ–7N\ רâ~ñ<ÒÑJÕ5»7÷Öã €Uª¶Êð ‹m‰ÚãA ¹ÿq3ïoŸ’܇¥2Tô€Ç°^ÆÔVãuërÃÙÅlµù’Ì“uèˆaL냶Ÿ™^<‰aÄÙaú½ÓžH+¬1¢%îÉ\õJ‰(íÔÈÖÈRÀ1ò=ªÑP&™,ë©ÅéÛ Îª»[âÂ`ûQõ>lp¼ÿoÿOœ˾E¸ ÷ý“Kšy=3ú Z‚¶Xå¾LŒ/„ PÝ fCçÏ=V¥Ð²øÁgÔ'[{ð|ŸÑØsõ°ü›‹ý%NÃàªå ‹ƒòCãÀGΈÅ,˜f3%[H~¹È/*÷Hh¡â…ûc×ï^¦sÅ›–uÖÂÓ¦r5DŸi§úý¼ y‰ìe“\zv¶..v¦ÊÆA\{F¢X†iª–HZ˜«i ïr&ÅCîRáãóÏÔÄô¶ ƒœ’šÈ™UXKëí‹Ûûë×F·}óòŸÁ{‰‡ÃœÖï·"Å6QÚ(¬NUGž„i?RV9;èÂ{‹ ­Iήó’<¾O/ò˜‘T¶–ú: g|2b9@u)~ÿ^Ç>.ú»„úÔN'ç´V½³— ±Œ9Í[.­mçÙY‘ø~Lh„'ƒ`C¼ÙN Ÿ~uç^Åz]c· ÞMÑÊþiT™Ÿ”÷òà‡Ü™Ë£ 7B‘E$8(!û"á×¥·]“g%8l±ñž ?Ô`Ü,—³ŸRä Y ÃB‚,‰˜Þ}ò± Z,~9¿ÈŸƒˆèbÆ~vM“·Ý 8™ To´3—@ü¾oÄÃ\3³ŸëÓøÏÖÊ.¦´nÒ$¸5†Ú"ò¿…zÊV™i–gÉ:º›‚{N6K°êòOzú;i€ËÛŨúl”öŠ5u{±9r!s‚âÞæÞP&âŽl|j5s:q˺¤BzS\.¹xš—†ë=Wå|ESîŽôA‹YÊÁ¡Ïù×íâƉHò‘³ !t²ÀT~!ˆõ9óŸ”i*VOæg“mŠâÚÖh nkjôßp'Ïþ©ï`9| 7˜s÷Èä5†¯rßÑçÑüÄ&æG¡#Âu—:°¨ŒÙüÌ#!ZÆDd#ßþº‹Ö-·(G^ ‘A[[ÂÓGS3q,ä“Ô7Ý{ßâÆDÙ¿ë§y ÿwy ¾þ•ÿp¬5Íz…nÖ=€Ì³;Þ-z5iÛ Ю³s®{ËüLº½@ëø6-'‰pÝ–„Nz¤éß{*FN“ˆ)³?|4Ì–ž“ú¨ÿ`æô)eõ¼ï¨VZÌ ìjp@$zí¥æ$¬<>™ÿ†éæŽ?t[h˜>Q˜OÐKÉ £#ĔJœã«|ó\cY€Zc~ˆŠùC*>\5Œê‹™¡ßcSã…Af[h…´Ä0ÞëÖ4&aóïPŽÒËÈH”®5BþR ¾7¿¯Ñgå||f8 'ÈÊO¼Ðwº)‹,ö6+É¿ÈvÉÕ7@ý½Ú^¯áÛðoôŸS-ĪHÿ ‚0¿®­ töÃÊMwc±ôRûémœ[{mŸïg}Á<Ê_{R³²šJ–ÊçsJ%Lf9ñÜ­w¢†à4F‚Ëûb”ÏÊ#€IèJÞwN–=­zeàú$”0í’ŠÑÑ—¿U óC†É”eôE=)ˆÕµê› Ü$O+¥’þ xø¨Ngýë䨅N@ëÚÄ4—~¥µö#­—ê±J2%µB‚Òž‰]cèÑéó`lÌ ŠënˆŸi¶vg¿^qS,®U›U¼!ú» {É[ͽãï—tǘ÷,^¶1ì¬DÿùÂ/c¾h#d ’ÉTwÄóžâ”.)ŸnÁ àùà-Њ*ûíúkËÜ]Œ‹ •ıHQÏ_—I˜¡ñ"Ý_üÝë÷~._ 2¬7yëˆW!:ô±ÞÊÉÞŠã*’[ÏVÒž©®ñA/ƒÿWsC­"¦‡¦ãf‘§Mër­§àøôÏEoÈX ïí _=¼bY³Bix™øe‰õ±ö•ø"óuSPÒè}ghS%Sr¤2PaÊkEb84m¥ŸLë Á´T¦m·CëÐ\–éd⃒{ºµº§J™lû,e0ÏÔ¢Üìe9.38 Ü¢’‘½>©‡OJu—â†ÓÝ=–ˆ ÛÅŒ—¦Ä6rãFCvR!öØñ÷õ˜Rh1:M¨×ÓÌ5Zø~»n¶…Þ̺‹Œ&x’xýˆ[bn¦;;(q€†ç< ö³A†©(z„®ßƒ„+BÆSЉš5”½àQQÅÁ¦Y[ ðFP ®k£wæ£k-B-5,ÓA#‘– s0j„„—³–ôëá—†&²uR¼ OlÙÈ#ÃUƒ¤h¹a¸!¼›# °à‹œü‚,3a G^°³e q.Æ}z•ó$U;º—V “ œ˜ÓŽ‹îõzûݘ=ëç‰c¿Øèç€9¹ž¥3LCgì'±‡ 1ÏÄ“™GzìØ+»¯º½‡þƒØŠ‘r85Ò2ÕzR00Ç7¯MÏÅÌŸq ¼ój ©ï“Þ9^ZÇŠ{‰Èað÷œ·r`Aö‘Á¦ÞõíË»æx³Ñ߀,_3ã5Áè;7Î/Bœã ÆõuWl:SÂxƒŒ6yËr‘-¤÷ü1ß±g‹ul‹ »@6"áKÀ`ŽQ ž¦Y½?é&váÝl*j}Äe´¡°µ¡™jB©yíæc TýÊõS¢9~]vÄÒv™uÜÜ=I2p®X•™:HMcðòWÌK(¯÷Àpð¨‰@_‡`+g¾§ n¿x¡Á°aƒ™W/ -»ÇiÎ92. glŸÈ %ý‹@Öñ̺ಸÜKŠa@ìRº•ÅÚü ^ÂãÊ^T EÕó.ŸÄÉÅc~ºÔ0—ÁJËXèPN¯åöûaKíö,þÁy}¾¾ŸÃØû}|?‡°†·×ëöúÞþß^Ûë ¡ â"ß8`‚ô’ÔmWvï0>ñ3ÄøëÍ¡¹£0³Ÿ£ú{~ DqAƒ7دÈE@ËÈë^èhLp™ûüBB‚t~ŒD®PRžaKo“9B&†‹ýã>Ñ LgfcCRôŽÔxÓ˜J¡Ú7fëŠÙY9ð5s…ÔÎùHÜÛurõÒÍ—€Üøå‹1ŒP¨5DW}–Í»íRæÖ­­ Ë+b(eÆXÎùä%˽óönB?Ž·IZ“Go‹˜ŽÌæÁSBy¹~@hÛ8‚.ãmå„£y)ñ"]llÍ(]É6/GË+$ U_îEHíûþc8™-R‚g 7g @å&§ý—:(æúpJÀ|. ¥©™ ÏGµY'måÛÅÛ ¶9 *϶£˜4\ÔÁÄ‹û8¹èˆÒ~UlöÓûéB¬§^/ã+a%mèM–ý$,î.VŠm¼å¸NÀ©P›z¨£¯¨jÐÚõ•àbmôÕŽsÓ·@ìº^ üãÄÔ²'É| ©é#îJ™Ó´X C[;ƒ/„}LÛ°âëTq<Á¸¥ƒ%<÷‹¦¶,™Û$„²ÁÕ£ù8 ÐuiƒžZSIŽ#\8çL@[¨ ðq ~{ db"ì¡€­µ I;N¦ô™ÿC”««Gß %t=Gþÿ7SBÌM .¿Ì‹}æZ³zÙÚžÚ‡°ο¨Áƒ@¦¦£v—Ù¬˜5Iû¦Lƒ+ˆèõçàMraSꥂùÒ)µ:œ©b?Ç{W×À®½B] 8·+ŠW´àhén%˜ªFyƒ~òår«P[8oVV0áAî÷YͬéªvïÔíh «§äJ}.ézr%ëÔ€Úì¯RsùḺR5öùsþÞ„ÚYPtr€ÔýxB¯€Nüéäcù:R‘ÝÔ¿"8¶ÿ?°÷Ç®üãèH$•’܃VópY;lCK.ﯛaíz ÉãCíÑAªzAcYä™Î@óBY½ö‹[×~9ÑÒJm$S˜…ugIuÂÖ7Od„9oTûP3‚x÷§yá?å½ú¸©â#òyQ•¡äÕ"싨Mn6'ðæM̾¦/épòšn œî®DÓõ–Qt ß3×Õìö[ÑÙ,&Ú¾ÀþfMþFeXëõoÑÞiýçjˆ¤ÔÏrÄÂÙ‚ñêØþ™óRr%wò ,j74¾î“æõ;ý¬Ýÿm}ÜÕë-ÁA£*_ †$ºEàׂPqrÔatÆ•µÒMCª„ún -~C yp¦›ƒô³ˆ ¢ÇWjˆµ³Gö3þ樸ôˆA¢¹ÄA¥§vðI½ñ¼Æxr$#¯‡¸LÉEI W+¡pÖ¨åD©Á|鈰šÜ F(7gÛ0 RpÇÄÚN2ÄLL3Ç”Âó¾^e°ø¨³9KÅjñÑ‚›fB  eHmôKCãzi½£Íb©¸ï´µ@z}I¢´×J¿0á¾–Dš}TØÀŠ@¹m¨(è³T‰],†_Ǭž±î? røGî ?ŒÛFûÀk;î‚![[åÛiUî"Û ‚=ñ_M‡3K:š¯B.d,T`l¤«4Äü‚d…-éÀ0Û¦MÑN@56L,l‡ÉfPn¢7&¶4T2Áú1”©™ÌÜæ½—t7QEyþ4’ÂíÃ_²WŠg¯î»5où5@Ùö÷+ ³ŒnQ`?°;(ºLüèKÕ”2dsO^9× »{27Üð5}LÉvì*zãÀv­*âÆ©9÷?*bÑIêÖœØð³~üû—ƒr^‘jΞ—Oû|c²û%Ô#†‚îcí£î;gÝ2Ó5FïÚ›ÿE×AYAô¡S„;òFy‰Jö‡\ Xÿ! »¦M:½#Þcªn:¤S)³A'0¾i ™*|˜Š¤äK;˜Ò+ €9ðÒ[+ à3®ÉH|.Σ½ýó*fÎòCc¦Åbm¯Å‘)#k–!*ñ(îßÑBFùæÌl7žÄ«DüÛEƒpãÌK}_D[”Z¨OÑ?K”¸ÃǺï­ë„ÿ¢!FñP’·3©‘Ã.ðVÊÉûANcrÓ,7 9D­ÑÙÍ4á½>Ï¡s”¾Èö5’ÊEû­L{ÑÂW• >•t¨Àýµ‘õúY±F! wüzº°^ôt«¿Ÿ¾}Q—Ás&crD¶ƒPKqÂÇT}©v:0“W¨R„á5ÃÓöÀ7Œf{‘Ë@~ORÃõ_ ²Ü;‚Ãì$GÒo 6…™^ÿZn=~n‚ºr+¡úÔËι ¤‹j™^•‹à¤1ÚqXúqKs/r0>)ú• !³Ò fRªI£h]WlŠA¯–7òKD_,°šR  ëÓËHü3jÕñÇUÚ òí #tÜcÙê‹(9Xgæä—#>D¶¯ôŠÿLK›ønÏóóúÆQ œâYl÷o­‡þxXI<ÉÜ€¬¸_æ5WQT ñð±º`z…À’@ž%€K­Ú€!¦oÁ“½'¬q€Ê)U€Z¼áÇmëþÛ(=yºU8S‚êTy9ÝXÒÃ-Ö툷´7¿±ûr•‰I;úšâÝ:§nú`Û7ÁI¾w\El‹Ì·Òèô(÷íH3¾‡ÿ͇º]YÁì§šã‚讆Eà4lî¯~_öö ÛÙ cow^Û”ö¹—帘£Æ ‘—qƒ©Yc€~b° \r‰66tÒ:ž=¬Ÿvï7\ɬ‡° ¨wý£$„#Úzdœ§™Y3³š‰u mvƒ‰ÓŸ­Î4ÆÄ™&g,ê 0¿= ,P#S§ØMמFD¼*—ÝÛD»ˆNµ6D]Ò‘#ƒ¦3šMRÀÏŒ¬V5—«êlw, îå³hë`"N}˜‰·Ÿsû–k²´Ç¨*âŠ?Wf*¿#4+ÈSަ·WÔŽ5ð^‚ÓMRIù\1<ý‹a†NÑF®>ËJ÷Þƒ3ÄW²¶‚\º&º—þ|M6£4Qí¹ÓOꎧB:šrŽ á;ƒ#+ÕîÃh2«Ù&s›]LL<ˆìWøu¯×!çê¤^§o×y¨ˆ:ŸI4Œ¬Ý”NJOú?ùU?^Y+@LåÑ.8ÿ@º~*p¯º¯=žª¤­è6QÙž6ÅÒÜg«6à—ÇmÏZR“³3øíu¾6ö£$ëJœâfOjÀF¾ûÌà]-ú ¬$Nð#·eO´À\{®çÑ?§ ?èçq”þzwJzGÖð`ªÛ¦#u¸znn÷F3PÇMÿ4·10ɸäÆU¾ŒÓSÛœ·• Ã\zçª*-#mO裠'y‹7jýtzCg¤ƒå—Ò/W¾ÄØ ×¡f4ô.læR9QXÓï,ô³ò°›¤7 ;…ÒÐßÛÀTi «ÓL¹ÖÊKRywºè0;nËGX°áð¨øc¨šAÄÁn€ Yô®í‚&mæñ üØÐž¼ª)e~¢Ej"-ŒÊŸ1VÒæÇ:hhÅ̓qXέ0ÜúyDÿOö:OÆ„ÄÙÓ‹oŽ ƒ­F]Bë“.['í¯H­ßê[ >¦fpb^d¢XBæ§ñ¤å¢û“Ù}QÞ§` Åwq‰<Í33Ô¤Ó Õ„eÛ ±š¶nqyÃÆØÑe.}ÿ\lHŠâ|nõÚ_ÎdýVXosŠ[g¤ÇÙ;Èv¯°ïÀ\±×ú€×Ò5íK è‡ÜU›Ù ZíÒŽ}ÀX˜²Æ‚ô™ÈŒók<¿Œ´Ü¿cÏrˆ/Àf¿šFG¦×L&R£þZ K®¯“Œò¿ù±Ï»ãu×ò@é†rn£5A°žDiK ¾cB(yµù¹É’Š-“™ V76²õõ=+ØÅím])ç÷(„^OÈšÿGW6‚ È3Š^ºš“¿)#?°å0m|®?g×Ô^‰3 Ô¢%¹"µìb&a4S¿%êBïQ$ñ=2mSȘ籢úÿ­÷·Ì¢i1á1´2GõI$¸’ôœiImTí_æœO5ÎÐcÿ=í…ÛÁ×Ò’žôd“±5ûCJù¸îá›ÿLÞ£-8Žþ”¶(ã2ªP¹²y>ˆ’ÔÀ¹,Ýš6„p2üH{]Söã‘íIÆ JUïGf¯–Qÿ&µúÔòÞ`´Z˜ÜÊ0´Evö„徚ž3”\Ln'> È7#VN³ÿƒ±zÊ»!ÙIS8ROÕë¶ìò"L’ØãÉ$zZ»Ô‚pm[ç4!‰™AF›Åá‰Ö÷Ä™ìùèœÔBÙ·‹kú¶~£èÃc«5ZÒŸ‰’ÄZÝúÏ+f&²—­_ú|r#=ÉÙ_­òbR¨ õ×PU}„FÁÞC(ÊÑL©k"ëo‰¦a3J`§và;/s~2{Ý"ŽN¢h˜Õ×=É’YXq{ö]óáoïëfïÖœi¬%´â ø2DNPo Œ4Í  íý÷$[føO[ÇÅÉ •ÅÌ –_Ô–ÌRhS½yØr6½ s‘S¬ƒwä²À¿Í­»#ÝCXº­ÇÑ=sdßÀ„€1$•ÊÏèbŒ¸¸•»‚W2XêT¡†5V£G$%vyˆb!³ê6{P§<Çö°~ä0B+›¿»Lí^8~ ¸þˆ§gŽXþƒö¶f.8;æì¢Õž®ÈQœWÒðàI´÷é¯$>(|™dø¹Â,#œçÿt@Ãh‚Šª[:úÇ£Ô ”‚è/9‡çEE.˼½dq»}t$ìEtŸ<Â!7 £–½¥¢â˜À‚ H}('(X¥ @…è·äÜe[OÖ( I@xÝ®^hˆäl Íضò‚ÚÖù»vƒω©¨ †ëžÔI_HÛ¬ôgê0ðª.šµÁfÕÑ’Ñ5íNÇü‡¡ý }Ž„?ñoEgh^r×­Y®mtGÑ(ÿ>Ù.M,k¸äpú¾Ø¼þà!?¼é&j)ú‚ègzÖ©˹ٔЛþ%DM[^|\ ¼Tž3½|íÿ<4ªÈßPTYº£Ï)²•ªõš J 5Þé7ÉSg†ú?è¾nÙQöW<³®ô¸ÂòûD¬Nü‰ØT«” çÀÏYý©æEÖ\y€[Òqf3"ÃoÝÿ\áRšq€qB g_éBÑ€ rSQN°*ÛsÐiP?4°A˜ïv¯~:åøYÀËX?8õò…Rš9È­a¤®Yù¯º$£ÍHbz¹R™ógK„¢[±‹e׿fœ×ÒÙ¾§Æ×ßYÍ)Œ†Åu#ÜC *öÖc¾ßQ=ýïÿJ¿$æó¥ûf7?SÜGl¬CÀ`zû¶'Pd»>‰.\ù\D^³ë;”òWùTZa‰ë¤ä Ï/DÕFˆÒkÍægˆº¸¸¡FU°%€˜Êï±î¾:mX«-2T¥ñÄs ÏÆDC;èù”<È \Ü˜ÅØÝXa›yBðÇ1N@÷`4TËW`d¼lN2ýüÜäÝc3ó4Øgs™gÕf¶› Ã2Ú}Qq‰ꩾ£”Ž„òuÕX¾èÇÌ0høNÇ !oÊhMÆ0–މ:MtQ¦áŽH:Ûf¥6¤ŸÝÖE=¾Zâóô—«¤¦ljïr¥ùNçnshÖ¹»¨ýD¿ˆ¸‹¬[KÓghrŒL öÝîµÿ³Òüí½à9h´Q QN„T`ÍÅÎÑø¨±¢`&òP9³Åš#ZÂL—ר/ýÐ븖 Ë›°l&…†'Èp¹¬o’À*¤í3=Fu2J Ï W6O®XÁUXÿOý?"6ÏòiŠŽÕ­Ê®Žlñþu ñºØ‰)eû¸ªØN­& 'BÑäK‰™)º¨‡[d¬`Í'9|þÿ4“(&ïö¨~˜!·Uõ`2Ãì);þú1£ÝŠ‘u¶äFO>; ByÿG™ý6÷cmoåPôU‘Fó¯JWb’³&+cÃç çÀÙ±ú`ÃÖî×R““[ãRà×®Ý6J)SàG<Öä=•^ Kv •TÊNMZ¶—µ¤&­’òm.ðáÌÃ$ĨÊnEäšq™œF©Zƒ#4Yr™Jž $?¿A¨ÈÈdའ£Þlͺk5âÃ?&Ã"éP“KŸ›Ø¿ØêgÿAVrã3Šr«uOñ x0¦B’˜x{çßö¥FýV€î0PÊ©ìÁ|׺ßÞ7áLuÈ™0ŽÛ"bÌŸ€î¸´Ú‰W~·W^LIzŽÖùƒÁð/´Ê4~NF™ÁVËGÂ<åýíàsl”åìkì߸ÌÇ ñ%}}ûÐÏQܸî&Ik\Õï3/³Ä6ê•Ð-d#3lŠrúþL>œXWℸñf JÆ<ººçátÇØÒBÆkØžŽ>Â6`JG®ç`:†Ø%•Â^Wö1i8`*•½yZwEh¢ÑóK#èï±Ø°ó}]À´.Ê2Uà"ã¥6f‡@>RÂ&>ùaXØLí%ãW¦Ñ!CÉ Håé-·+Rÿ\þ‹GW,µE–á‰ÚhîÓ`yÂX!—Blq´Ñ+ x¯2ÍOèüê©®9õf"šN„ž—šåÁ‡©%þ½S"òÛ×òD\FOYU zÇw>óЉZ)ÔN‡¢nè±ãѨbR] !™'¦©úŸ¦?Í¢Ù‰ãÎ`1ÉÔÿjÙÜ‹ ¶V ê ×Y, ³}³›áZ •ž‹/¤Òµe«­aãZk:sÅ©öõâÇ)»ˆ¬Í£œö ð‹&$âíglŽîË‹¥uH±ˆ, $g%B%IB?ƒRÏÈ¡#ï6å~Ò‚ øÏ7—äýýœù©³â0e[±1I}Ã/&RðB@ˆãØãˆ{wÓ¼/yMç!%øh z‡½@‘GÎÅž¾e‘b1ˆÏ§!m„*‡åÕ#ë²ïÁÔ„€½F€±Š¸ðßÎ?䩘ÓM÷4<^ê ›i@ñ>GW*JºÕ …žhfžHÀ@mg bР‡úÿa&¯í¨Ð|p¹¼F3×!¤ûAY4b듃6}ê·d¦f9ÊÏ5xÄÇ [x2zç’.Ù²½nl®+å¹Pxn²MÑÀ‰ Ð \}i|•ub±Ø)¼jënl²‡„óš#ia5Z"É«› _4íÇÔ‘Ù rŽ CÓØ,Õ¯Ì <övЀ¬Ã\^Äbð„9¨Q»X¦ ר­­ø©­"6íN„õÚh#˜à¬mhRÊ’2‹TÉ]z|1ÌNS®UBúÚJ'3+£ªÆA6Ã!•-Æ6û؈•øª!ëk«]ƒ‘¼ ô‚ˆl‚fWû ®¬R woЛŸAX ìEÐ@#Ú\@ö¹àÅ&ƒÀä6Ei_Ê%©×œrßÖ†‚ÆTM׫öÀ’>PüáK#,ø;.âÍ-Ï!p¾ë» sÜ1‰ø):u¶àñPeÞ;Xb§Ä–åf/É$ÎÀ—ºHra©‰Ôö)SÂUÝ;¹¶·È€2t‡.¤ü] r‰[Ù‹^©GÕBsÈßßúâ5¨ýt“Fžƒ(ýOAtvVØÊZ±j{ø‚«¹À—êD· >ܺóÂ…6¿zHλõ¨ fb†ëØï°o-$>ï aHç2sarÄ`Vã7ÑIFŽRë¢|>Hu²¡õ¤¿sÆD¹ <$ýýbXõ‘$Þ\Þþöñw Î5¤n‰ù5<÷Ά¬þ²w’ªe¨ÃŽº ¹„tj“ÊM³w„ƒïïå#Œ—‚¿gÖ+p¢Ó#ö1â)®´ºõ…^P6‹^¤Xp`a;@ÛãVÈx«P]òBf¸åéÈÎ ç,U†Þ½É9NZÿ7½×QQ®áHÜE¡E\¶ÖbÊX¨Ã+”ׇ ƒÒ2È!’{%ám.ˆbí4Ï™R¡LVY…eñCpñ¦j̘ÛǯHJm‚Èô ܇J®”ZÛJ}.,8€žíÇ®Q§ôl ýDƦÈðùeX@¾t]Dîžòn0Ö3,±¼ÉÅE·v{ŽšFÉØùü#¬t²óƒ0½]Æ¢tàHc¢#ñÉ>ÊíD 1h‹ø¨‚Qû¦×Úë-žqêHÑ“W·±¸‰ «s*—›6æ(­;µ¹³—!flã‰5[3ŸžMŠÃýAÓ¾ö¶ÉôQ°Ã³»¼ÇØS•FI.¤gІ^>ƒæaPy¸Ën²ÁM†9†!^§*‚‰§€N ®äÕ B°èþâYuv¤ÀáÈÛ¸@ÔJcÜ×j¨°(¨ŠzÈf&-zKËߥ޼M㈼ÓUåmøVQ/ùñ§+I¾CùñoÓZö‘g=?Æï¦÷Ôê"9É1wÀ»ÚéQ9c ÚO¦r:'ú&l£ J}Æœ¹$[P)â ØG.ÁGÐÐü &ýÃ,Â1Ñjeûá–xUžH0›ñn'ã 'hBb¹£*ñThÝ5¹Y£.”#‘ÇÝ«u«>@E(Ge°ÔŸ¸ÀRRˆ;/øOzA1“³ûÆ£«tÿkþÒoeô EO~¹¢þ Â[•å蓽ö5råfGõ;ų×zí±þ8˜ÊlWPjª„ˆàìjG˜‘ñþsŠ:úŒ„>–¼f€ØVÂÑ]O$â–V>Íà*ܰK;¬‚ÊÁ í§3†t3؃ѣO'dQv‡Ìcñ‚4`0€Ô…YQ´¢^HâîVc>kÖ¹B}FŽï/ Ÿ£ðñ¿äãóX\lë^°Ÿ(ðB•«¥E6h•D+`<·IÝQÍaç·æŠv€¢æE_ðmMƒ£ÏyDJ×qªÐL—a\j)áµPÎèP­9,™³ô –´ÿƒ8íÕ È^Ÿ­üîñVÒûf·úúAõ$ãÔ9Ù™ŠÁÀç¿ j°‚!—‚°­Ž2¿Šq¨a•‚×cÕ?5ÝÞ-³_£­Ä¥åJôïâ·ƒŒ2Ž·E*ã”R}I˜kTW ÛRÊþ¾ Ò€{Úªö‘_ÎØÍÁN±.wC˜6ÇM$¸Ó 0¼r¶·æÉ¯Ë!l"Œì3÷K×óD˜}2dUîV†zzCÅ€IKèæ=b£Õ—‘¦ynvÁëîf¸Aœv“ƒø¨ˆ^­Ò›ÔÕ´óӪضøç{ј½eñÈ  _W/K€è9'Žª{?¸œ¹ñ‚¦8˜à ÿ žòLÞàÌÿh×x;)ì.¼ãRžòFöt5|´MnxÇeƒÐ |å?hg©Îª£D}Í]Úû…*õxrÂ2OšxÑÚméšr s铟ÙšV¶Ë‚r>¶nCt¯9[:G„6ho‹:oD½rWp‘n{2Ž‹púرázº/&syWú†¬Oô“/ªœÛøØèŽH÷ÕøÅ×9–Ÿc…¸Q˜Åkñ°Ã]qG Ê‡Ë%õQ ¦à¬áþ<j$oû{B—ºg=‘2)ú?ù¢ÉŒUÆ¡˜ÇxÒbQ|ø> J{̾¿/š.ÑíÐT¢Ý>@†Pæµ1Iè€Rsj¨š=‹Æ¿Í_áÕý¸ÝìYye¢O]›¿µ'ð1§^š¦ ,ʌƒémLnOVÅ+„M#šªÕ­9æãƦ~ˆ<æÌp^B¬ä¯b8ÈëŸFòvàýl«àß~¨,ýÍ)¨X‹G.â1 ç°»›c æ'xðˆb”ÿYO²ûŽq¡4ÌöÛùõ@Ÿ—¦°\h1eÓ17…-Õ¾X ë!’]hPvÜÞ„ú:›âX"øTâS;®aÜϨûÎ#1÷¢ÁÙÝ[t„!j7äM¸Å¸ÇÿD8Æ›/ wå_"âŠg­±SôÀmoº—l7›µÒÜ‹ø=|-BþŸ*åk«»i¥ßâðb¼$GkŠæíɹ'ÅNé>j N©ª’b*DZMÜ€x?7€†ªZ3¬¾J¨DF(eá!Z˜©cf”&ú=­_¨ 5‡RÍÊ’ò#Cø÷c}‘KžQ¶3Õ/a'­]\ÙÐ.áë¨]ÒJª9'ÐÇY+ó5 EÇç"”ÅÉ%H/5³!ea"¹ŒùZô…FEðk_åª,¶íÿ O½€£Îeúvù¯œž2ŒêoÔEážÚïNF]dËÕT‹lŒ±±Yð¡(ˆ£ÍgQ˜Š¾²z—’Ïyþ“#OÌPÙÏ5WQ9~6ÿ?ÄÍU/ÿ2¤÷±K7’1?…Àäœ'bC®OæçÜTöˆƒåÎ7õM@ ¹ å‹$ô<¦‹vLx;‚‡Í̇øìkúi´µ´÷ (>‚š¸îõîÂ`À›3bWJK‹[þEim-÷iÈD–VòAXC* Ÿ+¡Á$Õs9KP¦.7)~Ûëƒù9ÆÝ,låñ'ÀÕ– ‡‡ÞêÞÇ:0ÜzˆÛ‡ÞtÂM1$îD + T_ÙŽ-¯(Mï\R}„vO7Í7ÓDÈ¥)Ð@Båaø²Tƒ¥™"hà4”¦¯ËÊK0Ñó¥ïoÉzÙ–ŒŸØJZþÕ>* ª°àô‚½\C²Ê6‹è8·tD¡ãLêé—ô®œX„…Öó kCÓFßëñ_Á§®eJdíýÂܰ¢÷CÛ×诟Ð6`à¯<ámvY»Jꉓë¦l¼´Ál¹p¢]flò¿œ^Æ„—ÛÊi±fspê%‰â[š¶{·`ª´Ç¥¥×C°´—ø 6Ý/ÇŽpfé5¨ÿQpVÀÊ3ùxÅêBÅ©Þêâ6Âß[¤M÷ç•áuy“#™ÐXq'Kç Ãv jÙ)ÔÙÛд”O©Ù`»¥ŠQµKé0ox‹ ñ¨µ§;Øy„ÕÃÙG´?ÈQ¶› J%­ÝkÇ\‹|ÔÌ:ˆß™/ìiK}¨fvÅP<Ö¯îuÊÉ å>6ƒè œ&; êj ã_ª!Lb¿“ÈhÕ…©ÿB_£jí°ªE„‰Ó.¢¯ˆQ[f+WžàR ñ1ˆôM&äxGHÏXd¹Tñ{´dfÚ÷Ù–o%¹Ã'Hf¦¯ò¹Cp¹:žèæ¤Çê!ž QHvív~¥·¾!HA-vj üiáÇcpV-”~ãïÑQt6õCK6=åtùg£²tØÖʤùã¾·}UPÊ9ü€Ž3J¢È•HÙ߯_€éÞç9‰ ÏãJâ™}±C`ȶ¬»Cæª[‹hÂÂô ݽ©Ž rñ<§³ƒ}U¢ ììkMã_`ñÝ^2"¶Ú…Œõ6‡ïÒPWŸ\”ab´ûÒãÿSŒZ÷ƒú+35*Ùþ,‡Òô{ ö^qÃ{óÆP}_rÏk¤Ñ¢>ý6R2&y’ e|]Aÿ{Ëb±rïUÄ*´‘tÜèwÆå3úyw€Ääi$*)ùÄóÓ$ÔhìFÜëAõÑ·Þ&ëu'± ‘â*ìR–Àj\¨N+ 5jÈ ¼V¨ýEî«Îí Q–6+À‰äÇÌݤ ‚õ/ÛùQ¦À3Œ‰ š¶0™C#êdöÞuwИ”fr·“»³…€>Eå›Z ©6Ò¿¨ñÃé®a+q?ÙÎ[Ö€Y¶3›ÈDLm^Nx½‘á"ÚÍm¡Ú l¾šwq ç*öìÚ—½It…ä•m:ûeÊf<ˆaϧzƒø“>¤ >‹,×ધ±{tdå·þ–ó€ƒ_Ã>vÆ—ÒŸlÜf[ƒ`¯–d1«†8ŒõÙžhæDz(…»ÎÈ~‹Ã+îº!b:øšUyl»L ƒD»£#çó¾É¼}œB!7Ô9i¹ÿUò‘J 4ò­Q#1 Ôá‰N±Q–ú¨ž%!¶Ù'“4 Æï²Œ|Χ,åŽJTļqôûÑDÃXuK¼FœZ˜‹ôB12‘«âj5§üh‡ çM•· +ãîÝ“IŒ#Ͱ˜È// ÒÜÝA¸3äl«Ö'ýið¦w懞Æâ‹ÃB‹ékáæÂgsw¨ò>™àµdˆheÕ’u‘y/(l„ªO H»ø½)?=ò–m£“…jªØk‡^ ´Ü‹MŒ#G`§ ªtØ '­}”Å(0’ë:;m"GÆÏU LQ™†kìoæJë D1²µ³É.H‡`5` ÅöD'Þçy{Þ•5®mœ4åªÌ÷øTÈå4\ßš0ºQ,Û;GË—óÃn¹b ˆy»'ÚLaž«I¸Æ„¨Gg™Ð£uÄÇËZb;]ôèäg×_¥ÿÖÆHƒë€P”‡MñHâØëÝöüM™ÊlF ¨©|bïePè®f­ h©{9eî;d€îR.9”­i®jÆ+$Ç>ZÏÊωRõ«ùòX „^ëCƒ ˜ìÏ„“˜…^Ÿ‹±®¬]#byÍ»PnKÌ}Îå]°/$úɨ¹ã.È ­ÞsÎOŠ ®óÏ [¡6])éøÚn‚ÒŸ5eÉälÂÀ×Eï¶YZÿA3¤–®, Å ©È~öÛHZöiÙ&JÂ˨ *è1Œ÷ kÑù3vaUäyzµ± EoР,ýkoVP5=°3˜8cÂ*í[bp5ÔÛŸk‹Áů"†.ÂÖôeMÜÍ´ÒÑÅ„Y’J>K¨ÔÊÿ=Fɺa:ØÔ¥eWnYu8$À¹ùǕޙŽÖ¿Væ˜à±1§R=Ñj…ØöºÒ¥&7l[¨TzÍXñ)èjÞ ֙ޥDd\›V]VCAØ]€Ì³ÓV¿—®oV ÌrAqDQŽ*.æwajE’'r~Ç3w¬äÕ» ž\E ì¥?Œ ;šGta™šÊêàîÏþBªÁE”¯ÃcÂË£¡ »[ Þ(UO5|èÙ¯¿^×˜ÄØÈA_8íßRÆr7äêR¡‚<¤æÆ;Ñ*0&<#GÜFÓÆ«D™Ü£­ÐNÞ丶|ØF:Ñ­÷ë4•â…ÆzOç –Og¦zKl\}WFwK>‰A•ºã,fú4!;¶ƒîŽ?4)ÑÄŒ\‹¤ÚÊËÄ&Q5^¿ï„ÑRÕxª?‹ñ·ÖE( 7YÚnÍÅS›g]so'iüÒ32¶£åC*öýš3Ä–ß ;½:§›4âØug 0xqd8àöP“‡UŸ½Ç> †@Ç7:>Õò¶-¹N’›Æ2šSÓSÓ±p g3cî˜g¡àï‚ †€fk)w¦†ço1Z©ç²ú@5oµ/ܨº¡¿¹RA©~}Ÿõ¨šOÂ+Y4I0Mœ)€]HZTè\¶×ÐJW\M‡N“ ¡"«Ömô¨ÒlÒ-ù t-ëÀÙVÛ.'T 3YÈ«Õ-M*07½ÝoÖ/S °~´—#ëS^T –C-Ùe0í;¨…Íôõ­»€l·½Âgκj«î§öêµF«Úÿˆ šÀÙ`KW6sxÛMRôu[]‘͹£ý»`5w{À FðHÎ7º`+?­®üýšˆPÖºizœ‘|¾”ͽx<'ÑÓ"«±oY$}[]8‡œþïñÒºÊYíc4Ÿ)jÿg?\wÈ~…‹ºt]XX‹ [± m±º¶^g¸åb©7.צµ­^¯¤YKÒðWr(q±6š¥À¥—¢Âðª J?Áðågž˜»W+Øe.$]ížÁ-¹*ˆÜÄ<¬ÙÈOó×6om3du%×× ï®ÈÛ„ƒbîÔ+û([6EÁnëòÆC1 8™d1¸Lã©ö¶ÀÑ6Ó{<ÉùMÔ´ož>¿0¿WÖk霳—*Ÿ,Š¿¶ßG¯‘RuXë-I†ç*¼‡?ò™”úØè$Nü˜r*l¾Lð«PsOÿq<‡µNŽÈ‘˜âÞauûÏ%ÚRé"MC/6ƒyq͸]ÜAâ ”*=¸ÊS~ð Žno¿JVlŸìœ;uPG<žÄzk/¨zÝ¿…‘÷òh”µï#,à ”$fcð÷X¹‡Œøt]Ï6šP7;9§ºã÷UÊ C¯3#Ë8ŸBgÃ>ºG\`ÌU%r˜ôC’µÉ#CÁ~8¢jÁºl$Z%–~è¼p!Û®˜È‚¤¤{ÅðSÃQ'Õâ—ðA¢›$ö2Í+sõA–³• Ÿ°ÌÛúš$Oe¬)W*áÞ²§>²,¥!‡M =Çó‘ý> ¿Ìx{0ÐŒòsE æVƒ÷o䯽é@i&Ñ6ÉT÷|°Ô ±ú3êÛà4„f:h¿¿ÙJç ø ƒ•ª-mÕ‡NlìÚÞYcÊÑÄŽQÓ€˜7D›¬is²Þ;¤ö$a§)‚ø±«V%Ô™¯´QþܯÌ7ÎTUž]ã¦æ1èl–ÊPPv?é Åp®ÿa@á=åKÝÆ9§˜gÙc²ÇU*åÁ‚?ð¬e8Á{= èC¾TWű³©qn÷vqÐa»tÐý£‰ÿ è²ííj¬~Q¶;“wíô=û§Ï®öZ{â÷Ö\‚=”@5‡œÇ•ÒÝãp:ú÷ßÂ^ö!UL ‚=—·¹ZT¡XJ˺9´|aŒ9’˜Š& äÒ~Fñ@Çõ¶ô 1vßð̬_«f½AÊp4ª>Ô“’J§TÈcST…è2´IŠà­Š}Ž’Xê0ž‚{Ú?“wQ_în¹#‘߬%F¢ž§:«µ¿áä2“Ç…tßPÏ/®»âZæ¸Ù ›Ò~-öj3„8—Ô3I­¢ífž‰›ùZ¿$ãß ]j°Ýòˆi¯š3§ÖãZ1Aø`e¦]nz¹ßy¯¬å “»æ«õǧöÞ¿ÞÑ; ëÊB²*Z§ÑsaŪN¢©·ê¡XºùÄMÏ8õ6)§\mN(ZaͲž/Ôiª²Ã½Q7›Ó"Ûö‘5#c3s¢Ý泿Jjˆ “0°ç-/Ð÷¿Œ±û½3_Mž>9F“Þy·@ß\¢â»î½wi>`µ€óÓhˆ†N:‘‹(q(ïÒI¡³ó4Ô} ‹Kï¿õ‘Ô¢Î<^¹Ý?°¾ê«Øýدèª9°PyR—úôüÒ› À3ó[[!¢'±~º²±õÛ¼SL0iˆˆK8ÅrÑA^b‚'—Ål/"õj'8•¢h§sœÖV ”¨ET…Èß7q†¿ðqWLvó5O®d¦¤kÐ&R‡È‹ü¥lOU‡Ø$kÙ×JÝ£ò[Æhe˜CÁ6§ól·À‘{äTÀfî;w&–z—¨-P’¬´]ÛD®ïi]2Î×ÑKMøõ@R’ˆ¿~E Ün^§ˆ«‡K}+ý¯à½ËLmƒ4³’WTÈ@U«êv ÷*ó‚édn2Pé9ˆ),g9k½q3b¿'ë•mTêë³;­¹D§N¿£sûMsuì¼ú dÚœ©Gëþ|^„çO*˜¬Rpx»¦¥1ÄÞ…ë ÞR¶¹¬ÿhØM¡9 ê|AKb2p„p¶‘8}©„࠵Λ²‚ÃßÐnLý›ºÍêµ¾¯ 3•­/›ôüqKú úòIw¬Ÿô}êJp2laÖòöˆ@flጒp]Á‰Jy®J™CÂûi]MYöLÑ¢$?åƒÝ36\?9û3íjÂ"‹5FAæ–ðhæu+”°cú¢¥ÈÍù

7nÿG.}Ä•´0,x¾/]x c Zýì@ñOÿ;­ôÄÈC“6äö‚R?p«%&ÍTš±˜*⼯L˜ª %²zw­Vc$‚]Ë…RæXOcͬKn÷½4¤a‡•¤wókVm~<³“GÄK6_ÖLÕx+&ùœZ¦aTß$qÃÔ7æi&z\ü‹Ð/¯›e›ê *§8ÝM»ßa‡|9Lx'ž9ÅKFRš7ï•5kÃGïsÄ廢o-™–{ò½Æ5"ï&÷av4›¶&×n?Hø(æaO½lè<ø5Ü76{w©¸ÒoÚ]„‚®¸ç«ŸUYX¤ôÁy«!YB ïüë žÔÃQù©¶»­xòL¸'×ð¨Ñaáfi >wNƒCT½âá|ª„©nx ¥š"A2À$$—ý§|ê©+\Çf“àÐ<ñh Ö;eW Á­A¦­vP ÐT‡üéiþ\„­£nõEtÍÅê:]„%²•›%êÓ’½{Inr6;Çú¡ª2v˰vôÈ"!ú ðxØH°ûN˜Rð]ü_„™³@o{ÙÙ-ÝØ=­ÕmÀ " ?…߆ë9{¶)íô‹9˜ëLš¼S^0šå ÁÍ÷ý.7Œ¬íy¶JÁ“ßš“:D|÷t¶û™ý†~ˆí¾UÇ0UÂÐzU (žnøï",Ô¦—æë´Ú‰‰‚ç®ý$5áÞ¨_¦F&Æ´5ÎŽN¢±u É¯R”ŽÎ[ԡܳ¿Ÿ8öÖÁsÁEÏÚ&Óîî¼»èÑJ[t±}Øøà½µ8.¶I-™Žn·UÀì.j¡³DA 2÷R†áû@µpÅÙ\…&Om„8žÄ™b^øŠO¡ZêÞ…;Aò‡±ƒ–¸ªCWÔɵ<(ÔnQ :Ä42ÞÝ^¤-¹©¬{sè'µt¦ëeq©NÛAB …c"ßJ£Ëx øtÂÝòçˆÝãéï‚âL‘‘KÌC5ùQö”pu3ä©; – øoÿW½0qÍa+UUkÒØöÈá­/h‘qÞ¿eF=MÐ⤠àŽàû”x{æ†r’h¤À$¢ŸðáÁh^h€QõÓ=‡ºžoaKm“þ¾HwµP¤%v¥ 2_|Ú±J?Jeœs/6uCüºõHï7ÇÚÜ“HÑ iÉ;b :‚óDDåvÖ8ç~ @MþÃ.Fëô*+þd(!}ˆ¿œ ± +:¦õ.ŸøYð:v÷˜ëbQÙï}~…ž])kÕâ7"W5 úk–^~.ްTö”»q ~‘;#ç÷Ø c™FÉBãX:ýTÆ—âÇ€ŠëÎøA…ï †ëg‡ß‡©˜iƒÀ$vï“ð¦ƒÔ™™?C.ÏE«(,ëK¦ù<ùdö‡%;‡'PD—zÈ–íøøö·G3¯SêFçk±¡(€+HìË/x~¦ýa ÷¦ÿ#|þxy»»DT|¶N"CwÓê#ï O§{PÒËhmö¿àÝ#ù,éQlL°4E¸»åª’Êöø¯“mÄòþ"ö&Ãà*ÝBÞ±rf¿k¢aÖ'†ïf±x¹UÖI‘nš©'1׈’ý<«´Û ¸[”Š4V%e'Hp®?!() vùºhøÐ¸q×^Yêäš‘©T˜#bÞK=Ls¨ G¯2xºâ­ Ø~ͲʜwõõGÆß0ÉÜ0|¦ôIÌ ×uÃ…é|4Õ‡&œƒKkm‘Á)ä[2ÏkzßymT+ÿ õx.ñÌUTÍ vÜA¾^]±š»xÁŽ/ëý˜µ éª4¯Z¹fa¤¶_-ZdgˆTé×T}„"8ü¼7w%ÖKsÇ#õkï©Ûk˜1õ£yÅòër+¨×5¬ÇHŒ‰u ‘ƒGE%ÄEVÒCüfònŽWóJ ¼Ìü§¿—>äÎ]P™¹ÏžÌAŸ>ª…D²ËÙÕä.=>Rß<û¬·2œƒö´ögòcv!lt¼”;¦zy¢-å¢]½ò;wa­òÂXh´Ôg¨–/êW‚2:û╪ >ŒLÔÚx‰Á²3ÚéU·¸å`ç­w­…åØÔû'穤¬‹}4ªA]#jû]5½‚qãâè Ê‚ÏÄáî½ÌÎcŒ5ÎàÅÅ?çû;]Ï(XÕTÖâ"'˜=Ø,)ó'Œ<¾ãsU”\ômê ƒê<¾ú|mJmAâÝÆiÔ±Ýs6&=\@!*µyA€«ªïçG)²Ë‹ñAÇ@+Ûì#MKAv>Ò7©;þ=¬Ç…¤ïÖ›¶ƒ»Ï«¾Rιۄp" ¥n¡&ÉŽ¾”kZ”)Ÿu@S™im™Pö0èmžaóYÛß]Ý£¥‡*¶s˜‡=é `,²`ÊJ9VhÉÜ%…uõÔYôáY éÞi&*3$¬¾¤„–ÛpIìÀ ¹3 Îá)¬\àÛb ;ñ™PÙP¥—Ò7¯c²¢â²Ö˜gÌ´9ˆL¬õ® u}ˆ3ŸQÖ×2Ù ê.÷Jf#í‡)–”h‚}­¡',‚¹Ú°}&=pmVëÁ*¼ÞZ!'ˆ(Ù™Ýf!€b°’Û^%—èÏ;„v|TÇGîn"ï†79yF¦ì™²äy\¾k•E¹¸ý'y1(%Tæ`»yÄÍä í’®ÝÇQxà=-Ý +7ØáV¦:ië‘æL%±9þ+ ¤Ì¤¢Í¡æœiSÈëwµ Â|–-¿°¨:Ùur.ÜHÙf&Q³™ÚÔ™#õ!,Žª7 ¼Þúã(Å×È¥HÏØµÓLߨЀYCxµUiœ¤Õ G­zøÎdöõg2©9ZEºge(‰@6Ö5¿Ø£7ç|pyë¹%›ßbŒZÏœŸîJ|À—¸g€€*ˆ·Wb¢’¾ÁèlÆ×É´3™²Æí—YÏný««Ûò:ÈeãB[ÛäÓNÎP½§¾]Û~couø€%kŽ55ꟽŸà©’3ið&ŽƒÍi†nóY­}üE€ýØ@ ܵ#Ã’²Š¿îµE\Е·€IºŠ‹§½åþÍx÷0.×ôù[$s '›zð&¦è/;qlÌrGiCL$ñïhí]àÊÿ‚BfüL²ò+C¥®‘9'KÓRm<Ÿ¬ôµRLaP+ÍÉðÒSÔ®ÕŒKòÈxâA€fœí¹™äÌVž w%/jø[÷˜†æTæþáàFvT#æEGô£{ùUÏ‚æŸq\·r+¶Jó¥Ø÷ íŒ|ðÅ£º3¶z±—ÝdÛ@ylC\Ú~ZžóÍ¡ "kú£ßÑ,ì²çï)YA¬Ð$ºa°Ê©§c_*‘Å}†~iþ»öl%^·‡˜:+ÅP^Kùb×v‚XßçLc}â”h“Þ>Þ´‡G½á8ç’÷1.TK.÷i ’\ÊqÚÛï›J6â9bö/®i¬9j %raˤh(º2fð!·ßÑ:rò÷òX}Ã:OKtë`ÅÊÑdçâk+â_Ih×|¿»c)).Ü‚ÿz­šéÛ³%„ðp öÙ‚È@P“uŠ@ëÉêû£ë; ·"wÝ®4S£E™éìÒ@ǸÌ^Jñ‡Üˆ¤TKcr]ØPæõœ8>r*’ÀjD,jdØx&S{ÿ-7×ÀÄ?qÅp@ã§ž !³Çä‚K3ôyk,?;`_öë•ýÝoùòW ÒsçGï¦EÉc‹áŠâ>Ö=±AЮHB ¡E.©ñb¯•[ÄØ\¦KÓ¡¡ÙLvÔ_mDzöœ~lo’!"Àp÷›¬€^–¨0Aò…-8pWI³Ö¡U&c+Ùûâ–I1~o4ê÷P1 ,eKé{Ú²t˜´kÑĨ7>R÷z6¾»r(éÅ8žÙ³G†«GÝPcOt¤Ö*ûeÍœ‚ÙÏ3F—³¯¢öDüUÏ@ c’Åà äÒ°÷óZAiÇÇÂÇ×Õ ÊõÔsä Fõxƒ\нr3eC('1“18oëtIýzTõ7dŸVTÑ¡®˜ éëŒ0!TÚÄ¥šš”¼Pâ ´…$ÏìÂ\k‹3ý«´Zôdž;õ\É^ƒþ Dbuð€rc{ÈG¸[($eNäÄ À¶S rgqbŠØ%tNz|PûÝ gŒ®d½©T¨€FŠdC+(Lâ”Ûhq…¥ó}ûÈ@аí]òöîuÓ*ÏäZ˜KÂÜg”ƒçd¬Ú¡ QJx[R jxa]öwR"»:ì/÷7G§$Æ&mb÷bðÏíP®_±3ãW=جŘ‘œmýM¦ä÷€{+º'? ºA0œT]ˆÕ‰oþÓ?õ Øâùä̇sl“&#yEÄ„Èpî¶®³îωþRÊÒ½ûÃW\,>Ô ý'‰2n\9ç^ËДÐFˆ·c/•§'™½:ñãlƒàÖxõ)Ń*U“ö±Êd‚ÖFëqFêšàã÷˜»ª%s½y•ròÛ¼vœã“"àÖvÉ ü€²_رd „0'ø+'‡ _Ó¡löÕ‚¢8³®Ú¢zÄJWÅ®Qq½'‚ÃéøÎ‘c•²Š£›}½PŒ ‹t,Ò¡Ë×ëðíòü;º¿áÿO¼=~²ß‡zWáÚÏóï{ößáÞGðíøwx®cÈZÛ› pNþÈï!›ùC~¿o™¬´…Œlƒm¼ŸqÖÓ h œŽdu!y€y•1óqÇ š¥5ß žnžLÞln;OÇØcåÙÅÑô¬)çJ³Tã쩹=$¤«¦ÔÕcãðáÀU¤À½ë‚Ì÷ÁÄÞK+ð±ž'á¶SæPc5}W2þ/1#éj¦QÔÕ‚]Ë eÎîì„}¾ ¯yìÅ]™( ä'?—ˆ¶p æ~Sÿç€Ç«¹Œ ëÃmÓX®w,F†C º‘>?õÁ€"Zð# Õä×åFhRž#«‡¨aRW¶í–Ãw,·;I‘‚º³ìBeˆù}.ƒ!nXÏùóù`áé´°áe>¢Æ]Ï:W;‚„I°ÓLêåu¸û¼Û—°Æöe)Mð;S›Ó—_;ÅÖ_W±!®>½Ô(ùÎɯ £XC ÑÁAm„KÔ÷XŸcj_@±9Rq;Ìw"¹1g}â³›·6á*©Œ ¤˜Ò(žï<õE¤c³:a3UÖ­Â1—Fa:‘ìG»Ê¦ÿ'ùØn§~˜¥z£s]å1ûkªã§ïæûÈ1TFÇ}©xfÀÓEþ×i¤£M6NòÒê³Î¾¹„é1Ãø?B[ŽLŒŸ6¾)CDÌkë6.7º@âÿQjq…ÿZ$Eâ$püÇ8šä“>$ux8PÒ;CKÉg:¹ ¦ÿ&¡¥#"mœ¬I:ÐÊÑ¥ ¹}ÔLÓ횢v*õüý#ýÌT8„òŽZNï´Ž FôÊô\áê;îA–Â÷¿ïXÕû;‚·r¼ø`Ú‹SÔ±å‘@®gáMrU%+CsÞÈÖ¾j§L0Šiuí8"§¸B;Œxi"ìËÉLpr c-lך*mºæ?~4&ÉnÖ1ò ©º1þëý„ }»,Ì ¢?®œ*Eö?žª _-¬0rÀ$óIPî›3ë]ãsk“ÌDzüx±4mqÛ)An´iê¨ó´Å™€c¯flLµ2=ÈKŽˆ½ñáù´>FºâpZÈ’]’úlº!G©ïˆ#¢ˆä|ÎzEÇPÞG„„ã|ŸjièáÿAöìÓÒá ú1yqÜxúÎ:QüÕ|2|VÛ6të$ÅÛî×8€´{ÂÝ’#¼êÈĵޔ4äe=Ü|¨IÀYÖ@ûÁ}ðôN”iAú9Í7þÑBžšßÐÌ c¯d½ ÿ@wiï“t€©®1v9½ì–3k1ˉ* ž3ÔÓ“¿G@  p d£ps™¼czÄãÚå[ÚÂèÀ//,-ñY)k}UCËúã¡Cÿ(©gƒŠ«n+4ò²ycU %¡ˆ ¾Wœ,/d?غóvôD•¬½gÄgÖ´š´þ\äuÇ8!>Ëó d`*p¸oÿ@$31ÆúðlÞŠÛçî:“›¯D« E¤úJÎ 2st™D«`2>b̺úň˜æ«ÀªMÈõìH7ú£I˜ƒsÉÀàHÆ€ÏàaЧ”úE³'ÆvÏÝÍŠÞÑ(õB~Ñ xSŧFIý£Xкê¨Ì’é°h >ûå­Ò¢ä¸#T«\†Hu0@ ˜•¼Zí!›Fš³BÚã¬Z ÷SFçóÝÍgùlÆd3š¬w"Š/Ö¼kÜ1JtNË«ÛÅ’Rt¹ãûâ) Ÿv¹ ¿÷®uÚN×]ÍJYå–›Ú?`N§ON^UúLâùB(yÜHþG!™âLVZ®àŠ·‰î˜)kF„QòLÄê@Åg½#œ™"ÂM[’=†€YþEM‡»a-lãpl—o3뎅y~0vIx#ºR½ZñøÏMu32˜Z°¢Õ É©uñyc–iéü3ù\yRH5ƒØ†Õ“Î'ámûlÍ÷Uò»Sq%1°üׇÌÀÄ>êU\ݬø$ú–ûTwô YË'=½Uq”UQ®øÑ*ÅÒÏà“þ™K1`ƒNNË ¶îqþŇ~ô@ÿ?2)ü˜l¤±…Ý›À”Û_@l¯â1iÝùV½Ò” ’³±x./D¶Ï‘ú{„sµƒùæ UÏŽÍ=N#GþÏ{®E³¬‘#ÿJ5#Ô°iÉÏ·|ª $«F0c10mÝfó×– šÿI6 ‡k S¡p„?®yU…V”¼]/k¦-CšÙ„áb[‰!˜ö-ÙžÓ9‚ÓÇ/<_l3Ò½¶î*Kd0×ÑUƒ–æ²Úº°Îò‡À|0c’ìê÷~›{³®½>YgU·{޳Wš9u•⺌À%åØD¤V3Ôtqi•¯7Û8ÐcÂúVb%‰zu†Êá¶!9%àVöÿS$pbE6ø ÍœI\£È:} ÿ’Èù“Ü´‰êÇt´ðt ç2IÀªÅzoµŸ Å€Zžoßýóît܇ð™õTʾùX“ª¦Ús\‡@¶§kž*¬ÃÙÇÓ¨ Ùß™Ùl„N# ¯©ùq4à(/é£Ë¦uõ£)9_Ñi%,ˆsça©hÀ©äõ™ëc¤¿ÿ^ÓÜWid  #mÒhÕö8M¶ÈFƒ ´rÆÁßÈÿRK«–<51•g —ówgÌ:ÉÁ¹"!*c¢3ó[ìÕhÇèĦŒsFÝVv3ô”÷M‰RÙ_.•Ù'ˆd£R¨ ›‘m9"{ïô××ìšwùÁ×±¢øÿXv¿Iq6w'íè²³B*C©ãv­ïgNz_c¥ÔŠP@T„&®-Ɖ5Ô bD–y¬ ïæoq±a[ð'Wç âRFé%¹…#í[2u(ëªAñ%ã Wo¥$;©…$ž”Ü–$ŽÃT´÷¹û'͙ϥûxýª€CC È€‰ŠmÀ,ÄH×epãÀ™¿KdQ{‚:/©?°N­=à¶÷Ü—bõJ=( ß+9{(Âx›€>4:~6 íJdÃÎ8¯‚ì=ì#ó^,ËUƶš~ˆ¥:?áÓžtÛ"¦Â™TkJÛúOÚâ“0[¬ ‹Ý¤t±8÷F^ÿ®¯}!¶º¤A*‰Ÿkcñ'\6 v;wŠI˜%\‰ùhûü¢À·™qE°‹CäWpc㣡ù|D”b{ŠÂqì:ó9H![¾ô‘£aò¨XçµTžÕú-(HD¾£W{\×*{`\rè"¡7Öc ˆbhIS©¬h¾ª3PAi–BÌq5“†Î «+:}€ùãá©•ŒÁì7»G¬µîy"e‰ŸM2!ôÿp}ñ²ƒû&Ã%5T¨ñ¤¸~dOA¿Øt+溽öŒ‡Jñh<³·žã“HT¡xqÚÕ’Ï|PN½M¡cõÇ©ÐÞmP›5VæZÒ+±Qš¶ÏrIšÅ¡©ù¾A¹å†Ù?1d ïRì6*Ø¢àCyÜ}Ì׫¾â?Z‡wJ‚Ôé–ƒ.Eun™´3­»ÚCYŽáÛiCÕiÖ€&êH¤^y °ÅIù˜}t¼v 0ç×àç•€Ll´ßˆl£I¾nd(Ñ,ƒ1ÍåfÊùà¦Ç‘~ d“©eúH=g ØÔ¶HµÑæ?Â`Xð-=ÿfa;®Á0’T÷—‰Èdd¥kBìG“ZCÅŒr'>vŸáïéúÉ4šáû5Pä°¹BœK¦žN…‡ÐRQ%ÎQ™·Ýn-æâüá}[‹Î”ÈÒZ‡‡ï^ï—Íh[Ïm#> ×ðÊNçº(ª iQ·àfò¢øœM§W›ÕÙŸ…ƒÄãp€î4/)Y”‡tÖè^ýƒÖ•±â¾aT›£»‘s6áÙq[þ`ï!RüSÑtŠ90Gµ³d²Kéuµi¼­8ri ÕÜN×`/”úQÌljzõF8×éBŒ…þVž7GvÆL%7ùK§R¡ÈìyC Lü'  ÓWµL ÄM¤yRZ¢H=éÐT®‰¦0Jù;ý‰Š{¾{?ör(0¥~œ_C’jFFÀ/Œ«[&ª¥*&°ßîË®âO›ÄŠG΃ÜÏr¾BŸªÑò x„Zf‰I6]†! ÓÏüYÜFîa:ï^©Q:ÕR§ªzýëæÒ½Æùœ‡ö%(=›Ù/=ÎKBë šêúÁi6“x¿†ç×k¬;"¶êß;v’^&.ð]Q×ÐKª§xrB–*Y×FŸ{Î ”ê½½Çßâ׃&Ñ œK'º’•>yîœ%8b À<£ûô©lGŸ Ç’u¾ÂZˆ§.“íñòÓúìùodô´e“éè{9âTÊQþ¢‰ÐàìÍlL1‰°5·Åskù[êþj‰íÌ[L)Àû×~û,„Î|D%øÒ a5Š@3LªEJ ß!èÔ²Õ`Ù‡‚ò†©\Ï/ ÂÁM!rÒ]äÀWÈsÏÒ‰9A¿v\PäLy¨&¨gèƒtq­Z ÔÄ%eošÒ‰÷ØDòÿ,´Y²¢ÂìDšì^(íÑ´Æi÷.zØ­³Bá # o^¨H®_ßÔí'vÌ> ì`ó4íµpù“ëörž¢Ÿú«¨bîžîà Jv5y›é×÷ašša óÕácæt 1¸ˆ@J–ÚBüõ͉•.2o²-3Õë¸Q™’Ñ1f}{ó¡.Yº9 ž—=%±ö£÷DZÝÏö¹ÍÜ–-æÇ1Gt–ˆF­4³}Xh%„I±š^ÓÀCmÓ©^¦ÉŽÍÃM3uXÞéŠç±}ÕË€‡‘CÏ™Jì›kÕnÊKÒÊË[)°Y’$TTH~ik÷ô0¶‘u×ÌMÞL-½öD’¸ùŸÓ}14Vx‰ÖÁfÛVÒ„XŒ_Ý^ëGÈöKÛÀ1–B‡02Ö÷ÉÖ³}ôÅÁ36 êQE÷®+å¬Bff°ˆ#é&ÎñÅõd§Ï½ÿ+©Û™_Â7!q#ø|£™¢:'÷¡¼nSê¼²”#€†ÛÅt¶QÖóWóBGö§ê¼Lô ½ê¤³ÿ¼ÉÅaû’Û@!Z|Y7tY7Ãø4Á¤[=¿åI’u×ê™õþ±4o†êÚ÷»@»å~Gc!(÷ôfžx26—®$uJ/"ÄKJ`—ŸèZÐÝ£™qß?+¢ ×FKãê%ÉK]>?FQ"¨W>Â<‚ÔV/Ç»6䵓páÒŠ)_×xÑ–+UßqR Ñ;Œœ1ìªÐbªhóŽEeÂðßž6þ[V9¤ûq!qyP €ý„J.³\}2úØ5‚¬y6£á0,¯@©©;ã¸Ieë…}jj ­^[¬­¡¸#€ºz1 yz|%jOˆ$z!Í'|Ô5’ìüŠh‰•µLz»*~Ø5ý¢\&ÜÒƒní±×ÅCwÖ4M‚‚Ó^ÇHœZð¬ùJ—Ë-Gþhþ :Ö¨:Å^0ç° #È{Þ¤×4!‡ûì)þØ‘lCÐmd»$”ΖE®ån…g[SæµÛø~"wWtrŒ]$E 'Éa>D&|EÖô€¶¦ÓP¨q!P²umÁaý§œ5q5ŒH:üüÖE5ÝÅ`”8Ç€£%«å‘ý—ˆpWø;eRh[{ÁœožDrté<ï1ß]8¾L)ÜØ€IŒwõ6ð%6Èè8ž·„hr‘Úù—­Ò¬M(JµøS8:Þf¾!oÇ EÑ÷¬nŽÑ”!øJׇ:Mªs5•´… ,åqÎür”E{èg U£-|Sj«ÅnKE?‹©£•ÿ8…­¥P)2ªÉJ/• ò2Qjv#Óƒ³L*â¨àYØ9·—uoŸ¼åì!ø±žÓ÷·ßQîB³“¹[´ fžû²Žì¦À”(™O'ûæt ˆ‘@É…WV´”Íxó8x²Åy={ýÆ$Ì^f#ß„^àFÞ>¶îÝ:ªo¡8Àïó/ÒÔ jmâaF¾ƒŽB¬À›Íítä¦;"j¦#5ùè—×Ò±{ÛÑÛð9:sÇÛàŒ¼3•ƒ¢Ò4$_¬§Ö²=imÞ“Æ­çÃÔ´Ìÿv€"ö¦@ yÌò«)Å14*Ä—4½®D¤:Lq€p‚¡<ÿUƒLu'™g,8®H¢ ƒ#Ž;dò‘ ­i(âÃQb½3á¬4 Qš<(xúƒ½0¨rÄÞe¼èwÁV‡m'§àŽTŒ€ +…­¡<…íüQýæ»ÛÀ!¢<ƒ2›¤lPpj³•²Ÿû§ÚÓüƒUÏPvvÑZÂA*YïãÑ•Út’FÀ&ÉßëL–.ŸžfG#_;¡KOò3…·clx"ØB‘À\°>–[î‰Zxüê' èâOMh^TómŠ'¤DdBJkÌ'~œaâpP³‰^ƒ[b¤Å•Aá¯*<ú{ô ŸrAJ‰-xˆÏt¹s7Y¡̇Ûèrþ©‚‹¥W0½VÜ&Ò§V€Ð5¼¯˜µŽ8…É#K'Θ 2z”À ³ŠÐÞø­R)™8A¾2‡=(ÎÿdùÊ¿²oAŽz¿QhçÓóþZÃoWý°°åX¿ˆ™[Ùû êý#¢O“ ÿZ&Û÷H¥’8êáN“™©A`¹a°JxÇ•ùÈÊõ¸À›r·ÃWwî^çøm„‘~ü Ænh{D3ù°{d;:K›<®;7WxôžaÉÇúJ’ÉÚ…`2™~þ„LhžÂE…<âyþ,0¯¢9sEà]ñºïSÉB‡ü£³9 Ïþ!…¬Û~14ö›ì“©õ0SäI)d<ÝgÈEÎÁ´n/4)o²©w§ ð JÐRѶ9^>ŸŽ *Ôöl"pØ1vŸìwe¦H¿ªæI)k³Q¼)øà…0#o!a}Ãæõ;ÐGÈ_ûI¯%ïÞ=˜µêF`q%'ݲö%¹))f¿Lhrc`9Û§½;Re\º#*£ù}Žf lÛÇËŸ#¬µ»3Ûª"é,ELË@ëÿEÿwþa}ghr¢³Uhç^✑X[HPiªÿ5ZŽïh+;uàåi틤+ chÚªüy‘~MŠ­&håÃ(ÃÕ¹d¬ä |“«D_ÇÄíR›ÅGu¨£ÀÔ˜ª%EÏ6]ÕvÒÄüSRòõBø[²ì_ˆ£õsææÔÞr›¤›VóÐpfç⳪g¬·$_wôýªÿzA˜á|yVs|“Ž—² ñkŒÇS_ý³íQÒÚóVÚ4£±écˆ‘˜K€|¤[¬ÿ{‰–øSøÍ<öÌH±Y¸¨Á î^piZôáÌ1p”ùïRa_fˆ†ÔvÈ4ýÞÀ†ú÷|l.-Æ¥d7Kì+0¬èN<Â)|ô†’TK^YÓìH_:µÎmb³jýx¥`RÅ+á²þQ¸/Ó¤7òÖ‚ÙJ1/Ó0OÆ#‚©«-}¹o<6¯IøâyÉ™ïç 5-»Ë 3»qÜDªì¦|ÕcOûû®FܲTÁWŸYŸlùé0ý™Ü}¾XIöÖÕÕe€¥³åw>~hM±3X7Â9ày\»²Äýlîô.;©`#ÝÂ8‘ÆÁii?™¼z’ÓlFjXCC8º©¤¥’±èÛMºˆJ‚aÉ¥o×£í¸ºIÅF ÄãAaNZˆ~­ÎE³ñƒc;p"bý2ÑÆMü{[8MuãpmtþúœÆ½öö[PªA" [¯QUž¥¢Ä?PhðSyFD³¸Í§w~^šÿáõ`-‡óÑD‡T~ñÒýÍÆ­n2@LÊg<g¢Lî®W9,!ÎêKCÐ*5f* ´!Ï™AF¥U1,n+_%&\; ø`Ox››·Ó_ qþa÷E÷ õ×;î®Dî;ûŽ8Ýù7Í™*Hg°$¸Ú3ä’YÌ PôùïNp+eöLœE”T6N/Äi–`y+çé˜EÐöá ý³|FˆOøM÷ íHšEŠ*—ø\ôJ¦­6Æ®SÓÇs4Šù2ŠU"•‚Ƈ+Ï0ZðuÅŠ?Ò˜kZOëì¼Ó£“ôJ‘,ùZ™M,üÐð{S¾Þw®ÁÈ´d´þ(Ôxþ!bpXxõÆÍ*9Ïç€AK+G9àK–F§ýg½Õ„Ïd2D>ý1ØA‡hÛ×óØŸäQ@¤ Eà d2Áÿ!÷ð&A9;Þ“c`ƒ¢ºW»9ÀÛì Bë«5uÌâ23»“U)…˜‚š­ƒ<ò¡½õ·Þô}B2ŠÇ/‚¯½°‘aZ¤vÀ§"^¦„‚¢ë8GÝGŠ#½œ2%w rC§Š÷„ˆÞý?Ü|;ßeõP© ëpǼB:ª”‡²g®¼%¼'g¦m\Ó²â]¡¢‘KƒÍû_ø.Ë/&dÇ@Ü9»˜‰íÖ¯1Ó_-¹´R%±‡W¥Äp r8°Wfv£Âê0ãß‹äÒ5¤ßI½‰îïàI—ú$°ÈJ5él uìn æ5¸ÛÅ×"=GITGxŽè’+•eçµÀrØb0õÔÃìÄãô›g¢ü_O¸h DØP‘ʘâ/]Ô* ï€Â¿1±'úøt3÷ó‚x.ÌUÐan‚ß>=`­Æô×RÜôF·§ , ån4aîÔr·1Ì –\ #ªë g8;º½= ëwøWGð®nOh¢±¯YšZöZ–g‰Ú³°Ï™ü»ªš{îmÄ~“VëQ ø’ŒùkU‡é”Á•§Jd¹s:ü5iöD—u„¤Ð9S`c¶e À¦ƒ¾3QrçÉ.!¯kŸ»:Ü¥EXJÈ©ÄÊHÙ"é†%iæ`C½*™¦ ;¼•Ô‹ jªe‡Ós*aXU³alÃ_øQ•u Ìo¡…*ã½p.]OÕÚ\³ñˆ«eñ{A¼}øMÛ£U ÇíG.,ð­»r€—KÝ Ëb•n@Ú !ä„s B‹AÙ ÎGŒPÿÙih32L‘‡‡Žz€yz}~€„Ž™‡††‡‰Œ“ ¯’ŽŒŠŒ‘¦¡•‡‚€€‚€‚‡‰“˜”Š€}||}}~…ŒŸž–‹‰‰ŠŒŽ‘˜©Ÿ”‘•˜›§•Œ‡„ƒ„‹„…‘žŒ£ Šƒ€€€ƒŠ˜£«”Ž‹Œ’”‘“œ¯©™–ŸŸ”•¢¤“Œ‰‡†pˆ”“‰š››—Œ„ƒ‡„‚ƒ…ˆŽ•¥ ”𢗖›©« œ¥ ˜®Ÿ’ŽŠ‰Š’š•ž˜Šƒ„ŽŸ•Ї–‡……†‰Œ“£ª˜““™©Ÿ›¡°¼«¤±¦£«­œ•–œŽ”¦° …}€‡Ÿ–Ž–•Š€ˆŠ‘˜©¦š—™¤©¢¤¯Á³±º¯¬¾² ›¤Ÿ’‘”¡¯µŸ‘‹|ƒˆ”¤Ÿ ’ŒŠŠ’˜©± ž¤·°ª²¾ÅÇÊÀ»¾­¤¦¨›––›ª­œ—˜˜|„ˆ¤½¥–Ž•Ÿ••˜Ÿ°®¬£¦µ½´¿ÆÛìéØÑ¸¯¸¨œ ®¦›”Šˆ}ƒ—𣝝£•‘‘–¦ ™š¤²Ä³©®²ÃÄÆ×êûøöêÔÃÁ·¨¥«­­ž“‹ˆ„}‚‹‘“Ÿ¯¨™•”—¡ªžž¦°Â½±»»Ä×ÓáöýõøúæÖʺ´¯¿µ¡˜“‹ˆ…~„ˆ‹—œª©ž˜™ž«¬¥¦«¶Ç½¾ËÊ׿ñýýâäýöáÎÉ»¾¾¯¢™—˜‘‰†€‚…‡Š‘—§´¥  ¡¯½®¯¶¶ÆÑÈÕÜäñüôÓi‹íûïáÓÍɶ«¤¡¦¢“‹Šƒ„†ˆ‹Ž‘–œ©³°¨¥«½ºµÁ¿ÆÙÚãðöüÿëU¦üûòæàÏ´µ®¡—’ŽŒˆˆŠ“˜•—œ¨½Á®¯³ºÈ¿ÄÑÏÛí÷úýþüìL §ûûýûøéÐ͍ž˜––œ™ŽŒ•¥¡›ž¨³Ãº¸À¿ÓÏÌÙßéøöÏÝß›ˆLk“«ó÷ôõàÆ·©©¡¦¦«¥—’‘”œ©¦¤§®ºÉÃÍÌÕÜÜáðöþøŒA^ %–z òêλµ¼²®¤™ ©Ÿ™—𣶳¯»½ÎØÞáãíëñøþúï …&Œúï×ËÀ»®ž˜’’©ª ¢¤°¿º¾ÎÖíø÷÷úûýþÿÚn#‡#˜ù÷ÝŶª¤›–’”Ÿ¬´®ª²¼ÍÊÔèúúþþúýÿÿü¾/Š"3¬ïäʺ«¤žœ‘”š¨½½´¿ÁÑÛáòþúßÞÛËéýõoŠ! ‰ôåÎÀº¶ª¨¢ž¡Ÿ¥°ÁÅÈÒ׿òüÿü¢?<+U½à2‹!‡ôäÐÀµ­¡›•–¡®²ºÅÖ×äéôýþþÔM+‹™öã;±¥Ÿš•–žª¾ÍÛéò÷ûþþò×’&‹'ÐöÞʼ±ª«ž›¦®¶Íí÷øïþýýôª+‚Š¡úôßÑĽ¾·«­¦®¶Íí÷øïþýýô«,‚Š¡úôßÑĽ¾·«­–žª¾ÌÛéò÷ûþþòØ’'‹!&ÏöÞʼ±ªªž›–¡®±ºÅÖ×äéôýþþÕM,ž‹!™öã;±¥Ÿš• ¡Ÿ¥°ÁÄÈÒ׿òüÿü£?=+V¾à2‹"ˆõäÐÀµ­¡›•‘”š¨½½´ÀÁÑÛáòýúßßÜËêýõoŠ" ˆôåÎÀº¶ª¨¢”Ÿ¬´®ª±¼ÍÊÔèúúþþúýÿÿü¿/Š$3­ðä˺«¤žœ’©ª ¢¤°¿º¾ÎÖíø÷÷úûýþÿÚo$‡&™ù÷ÝÆ¶ª¤›–’ ©Ÿ˜—𣶳¯»½ÏØÞáãìëñøþúïŽ …‹úï×ËÀ»®ž˜’¥—’‘”œ©¦¤§®ºÉÃÍÌÕÜÜáðöþøB_ %—{¡òêλµ¼²®¤™™ŽŒ•¥¡›ž¨³Ãº·À¿ÓÏÌÙßéøöÏÞàœˆMl•«ó÷ôõàÆ·©¨¡¦¦«ŒˆˆŠ“˜•—œ¨½Á®¯³ºÈ¿ÄÑÏÛí÷úýþüìL ¦ûûýûøèÐÄ·¨ž˜––œƒ„†ˆ‹Ž‘–©³°¨¥«½º´Á¿ÇÙÚãðöüÿëU¦üûòæàÏ´µ®¡—’Ž€‚…‡Š‘—§´¥  ¡¯½®¯¶¶ÆÑÈÕÜäñüôÓjŒíûïáÓÌɶ«¤¡¦¢“‹‰~„ˆ‹—œª©ž˜™ž«¬¥¦«¶Æ½¾ËÊ׿ñüýãäýöáÎÉ»¾¾¯¢™—˜‘‰†}‚‹‘“Ÿ°§™•”—¡ªžž¦°Â½±»»Ä×ÔâöýõøúæÖʺ´¯¿µ¡˜“‹ˆ…}ƒ—𣝝¢•‘‘–¦ ™š¤²Ä³©­²ÃÄÆ×ëûøöêÔÂvÁ·¨¥«­­ž“‹ˆ„|„‰¤½¥–”Ÿ••˜Ÿ°®¬£¦µ½´¿ÆÛìèØÐ¸¯¸¨œ ®¦›”Šˆ|ƒˆ•¤ŸŸ’ŒŠŠ’˜©± ž¤·¯ª²¿ÅÇÊÀ»¾­¤¦¨›––›ª­œ—˜˜}€‡Ÿ–Ž–•Š€ˆŠ‘˜©¦š—™¤¨¢¤¯Á³±º¯¬¾² š¤Ÿ’‘”¡¯µŸ‘Š‚„ŽŸ•Ї–‡……†‰Œ“£ª˜““™¨Ÿ›¡°¼«¤±¦£«­œ•–œŽ”¦¯ †‘›—„ƒ‡„‚ƒ…ˆŽ•¥ ”𢗖›©« œ¥ ˜®Ÿ’ŽŠ‰Š’š•hž˜‰Œ£ Šƒ€€€ƒŠ˜£«”Ž‹Œ’“‘“œ¯©™–ŸŸ”•¢¤“Œ‰‡†ˆ”“‰š›’˜“Š€}||}}~…ŒŸž–‹‰‰ŠŒŽ‘˜©Ÿ”‘•˜›§•Œ‡„ƒ„‹„…œ‡‡€{€z&{|}€„šˆ……ˆŠŒ“ ®œ’Œ‹Š‹‘¦¢•ˆ‚ƒ€‡‹‘‡‡Žz€yz}~€„Ž™‡††‡‰Œ“ ¯’ŽŒŠŒ‘¦¡•‡‚€€‚€‚‡‰“˜”Š€}||}}~…ŒŸž–‹‰‰ŠŒŽ‘˜©Ÿ”‘•˜›§•Œ‡„ƒ„‹„…‘žŒ£ Šƒ€€€ƒŠ˜£«”Ž‹Œ’”‘“œ¯©™–ŸŸ”•¢¤“Œ‰‡†pˆ”“‰š››—Œ„ƒ‡„‚ƒ…ˆŽ•¥ ”𢗖›©« œ¥ ˜®Ÿ’ŽŠ‰Š’š•ž˜Šƒ„ŽŸ•Ї–‡……†‰Œ“£ª˜““™©Ÿ›¡°¼«¤±¦£«­œ•–œŽ”¦° …}€‡Ÿ–Ž–•Š€ˆŠ‘˜©¦š—™¤©¢¤¯Á³±º¯¬¾² ›¤Ÿ’‘”¡¯µŸ‘‹|ƒˆ”¤Ÿ ’ŒŠŠ’˜©± ž¤·°ª²¾ÅÇÊÀ»¾­¤¦¨›––›ª­œ—˜˜|„ˆ¤½¥–Ž•Ÿ••˜Ÿ°®¬£¦µ½´¿ÆÛëèØÑ¸¯¸¨œ ®¦›”Šˆ}ƒ—𣝝£•‘‘–¦ ™š¤²Ä³©®²ÃÄÆ×êõîõéÔÃÁ·¨¥«­­ž“‹ˆ„}‚‹‘“Ÿ¯¨™•”—¡ªžž¦°Â½±»»Ä×ÓáöùÜâòæÖʺ´¯¿µ¡˜“‹ˆ…~„ˆ‹—œª©ž˜™ž«¬¥¦«¶Ç½¾ËÊ׿ñûù½½ûöáÎÉ»¾¾¯¢™—˜‘‰†€‚…‡Š‘—§´¥  ¡¯½®¯¶¶ÆÑÈÕÜäñûÝ©CbÐõïáÓÍɶ«¤¡¦¢“‹Šƒ„†ˆ‹Ž‘–œ©³°¨¥«½ºµÁ¿ÆÙÚãðöüþÔ4zöûòæàÏ´µ®¡—’ŽŒˆˆŠ“˜•—œ¨½Á®o¯³ºÈ¿ÄÑÏÛíôõùüøÜ4ˆøöüûôçÐ͍ž˜––œ™ŽŒ•¥¡›ž¨³Ãº¸À¿ÓÏÌÙßéøã•ÂÌ{n+ M{ˆéíÞçàÆ·©©¡¦¦«¥—’‘”œ©¦¤§®ºÉÃÍÌÕÜÜáðöýíb*A €*z[rÙêλµ¼²®¤™ ©Ÿ™—𣶳¯»½ÎØÞáãíëñøþóàk…& nòï×ËÀ»®ž˜’’©ª ¢¤°¿º¾ÎÖíö÷÷úûýþþ¿J‡# €õõÝŶª¤›–’”Ÿ¬´®ª²¼ÍÊÔèøéûýìøþþù¢Š"#ŒÛäʺ«¤žœ‘”š¨½½´¿ÁÑÛáòýç°¿°¢ÎùïQŠ!pêåÎÀº¶ª¨¢ž¡Ÿ¥°ÁÅÈÒ׿òüþôr$#5£Ï#‹!nìäÐÀµ­¡›•–¡®²ºÅÖ×äéôûùû±._ ‹‚òã;±¥Ÿš•–žª¾ÍÛéò÷ûþüÕ²b ‹ÁõÞʼ±ª«ž›¦®¶Íì÷óåùõòÖwƒŠ—øôßÑĽ¾·«­¦®¶Íì÷óåùõóÖxƒŠ–øôßÑĽ¾·«­–žª¾ÌÛéò÷ûþüÕ³b ‹!ÁõÞʼ±ªªž›–¡®±ºÅÖ×äéôûùú±.` ‹!‚òã;±¥Ÿš• ¡Ÿ¥°ÁÄÈÒ׿òüþôs%$6£Ï#‹"oìäÐÀµ­¡›•‘”š¨½½´ÀÁÑÛáòýç°À±£ÏùïQŠ"oêåÎÀº¶ª¨¢”Ÿ¬´®ª±¼ÍÊÔèøéûýìøþþú¢Š$$Üä˺«¤žœ’©ª ¢¤°¿º¾ÎÖíö÷÷úûýþþ¿K‡& õõÝÆ¶ª¤›–’ ©Ÿ˜—𣶳¯»½ÏØÞáãìëñøþóàk…) nòï×ËÀ»®ž˜’¥—’‘”œ©¦¤§®ºÉÃÍÌÕÜÜáðöýíb*B €{[rÙêλµ¼²®¤™™ŽŒ•¥¡›ž¨³Ãº·À¿ÓÏÌÙßéøã–ÃÌ|o+ N}ˆéíÞèàÆ·©¨¡¦¦«ŒˆˆŠ“˜•—œ¨½Á®¯³ºÈ¿ÄÑÏÛíôõùüøÜ4ˆøöüúôçÐÄ·¨ž˜––œƒ„†ˆ‹Ž‘–©³°¨¥«½º´Á¿ÇÙÚãðöüþÔ5zöûòæàÏ´µ®¡—’Ž€‚…‡Š‘—§´¥  ¡¯½®¯¶¶ÆÑÈÕÜäñûÞªDcÐõîáÓÌɶ«¤¡¦¢“‹‰~„ˆ‹—œª©ž˜™ž«¬¥¦«¶Æ½¾ËÊ׿ñûù½¾ûöáÎÉ»¾¾¯¢™—˜‘‰†}‚‹‘“Ÿ°§™•”—¡ªžž¦°Â½±»»Ä×ÔâõùÜâòæÖʺ´¯¿µ¡˜“‹ˆ…}ƒ—𣝝¢•‘‘–¦ ™š¤²Ä³©­²ÃÄÆ×êõîõéÔÂÁ·¨¥«­­ž“‹ˆ„|„‰¤½¥–”Ÿ••˜Ÿ°®¬£¦µ½´¿ÆÛëèØIи¯¸¨œ ®¦›”Šˆ|ƒˆ•¤ŸŸ’ŒŠŠ’˜©± ž¤·¯ª²¿ÅÇÊÀ»¾­¤¦¨›––›ª­œ—˜˜}€‡Ÿ–Ž–•Š€ˆŠ‘˜©¦š—™¤¨¢¤¯Á³±º¯¬¾² š¤Ÿ’‘”¡¯µŸ‘Š‚„ŽŸ•Ї–‡……†‰Œ“£ª˜““™¨Ÿ›¡°¼«¤±¦£«­œ•–œŽ”¦¯ †‘›—„ƒ‡„‚ƒ…ˆŽ•¥ ”𢗖›©« œ¥ ˜®Ÿ’ŽŠ‰Š’š•hž˜‰Œ£ Šƒ€€€ƒŠ˜£«”Ž‹Œ’“‘“œ¯©™–ŸŸ”•¢¤“Œ‰‡†ˆ”“‰š›’˜“Š€}||}}~…ŒŸž–‹‰‰ŠŒŽ‘˜©Ÿ”‘•˜›§•Œ‡„ƒ„‹„…œ‡‡€{€z&{|}€„šˆ……ˆŠŒ“ ®œ’Œ‹Š‹‘¦¢•ˆ‚ƒ€‡‹€þýˆþý‡þý…þý‰þüýþ‰ÿþþ†ÿþ„ÿþþ‡ÿýþˆÿ€þ†ÿþþ„ÿþ‡ÿþýþÿþŠÿþþÿþÿþƒÿþ‡ÿþÿÿþ‰ÿþþÿþ€ÿþþÿÿþÿÿþþ€ÿþÿ€þÿþþ€ÿþ‰ÿþþ…ÿ þÿþþÿÿýþÿÿþÿþþýþÿþþÿþÿþ†ÿþþÿþ€ÿ‚þÿþ…ÿþþ€ÿþþÿþýþ‚ÿþÿþÿþ€ÿþÿþþüáíý€þÿþÿþþÿþþ‚ÿ€þÿþ‚ÿýþ€ÿ þþÿýù²çïýþþÿþþ‚ÿþþƒÿþþ‚ÿþÿþþ€ÿþýþýö¾\r±ûýþÿþÿýþƒÿþþ„ÿþþÿþþÿþÿÿ€þ üúà§MK¸óýþþÿ€þƒÿþþ„ÿþþ‚ÿþÿÿþÿþýÿþþýúå‡C(/dÌúý€þÿþþÿÿþþ†ÿþþ€ÿþÿÿþÿÿýþýú÷íÏo" =±íùýýþþÿþþÿþþ†ÿþþÿþÿÿ€þúâÉÇ \6¸ßìØí€þ‚ÿþþÿþ‚ÿþÿÿþÿýþÿþýýñ“M[`=$ 4IŸq®úþþ€ÿþþýý‚ÿþÿ†þúùâ5 ,-4‡÷þÿÿ„þ‚ÿþÿÿþÿþý ûýû÷åµl'… 7µøýþÿÿþþÿþþÿþÿÿþþð×ðôîïìåÉm*‡7¥ãýþ‚ÿþþÿÿþþÿ€þ üÚv²Â—®ÅÄ¢I‰B¡ûþ‚ÿþþ€ÿþþÿþÿþýýùØlGT;Kf‰n(Š8ºûþÿ€þÿ‚þ ýùìÉy/#;/‹5ÃüþþÿþþÿþÿþþýþüüøÞ¯’?‹JÛýþ‚ÿþþÿÿþþýøòóîß²Q<#‹Šñýþ€ÿþÿ€þ ÿüëÛµ¦•‰T4‚ŠQËøý‚þÿ€þ ÿüëܶ¦•‰U4‚ŠQËøý‚þÿþþÿÿþþýøóóîß²Q<#‹Šñýÿþÿþþÿþÿþþýþüüøß¯’@‹JÛýþ‚ÿþþÿ‚þ üùìÉy/$;/‹5Ãüþþÿþþ€ÿþþÿþÿþýýùØlGT;LgŠn(Š8ºûþÿ€þÿÿþþÿ€þ üÚv²Ã˜¯ÅÄ¢I‰B¡ûþ‚ÿþþÿþþÿþÿÿþþðØðõîïìåÉm*‡7¦ãýþ‚ÿ€þ‚ÿþÿÿþÿþý ûüû÷åµl'… 7µø‚þÿÿþý‚ÿþÿƒþýþþúùâ5 ,.4‡÷þÿÿƒþÿþ‚ÿþÿÿþÿýþÿþýýñ“M\`>%5I q¯úþþÿ€þ†ÿþýÿþÿÿ€þúâÉÇ¡\6¹àìÙíþþƒÿþþ†ÿþþ€ÿþÿÿþÿÿýþýú÷íÎo# =±íùýýþþÿÿþÿþþ„ÿþþ‚ÿþÿÿþÿþýÿþþýúå‡D(/dÌúý€þÿþþÿÿþþ„ÿþþÿþþÿþÿÿ€þ üúà¨NK¹óýþþÿ€þƒÿþþƒÿþþ‚ÿþÿþþ€ÿ þýþýö¾\r²úýþ€ÿýþƒÿþþÿþÿþÿþýþ€ÿ þþÿýù²žèïý€þ€ÿþþ‚ÿþþÿþýþ‚ÿþÿ þÿþÿÿþþÿþþüáíý€þÿþÿþþÿþþÿþÿþ†ÿþþÿþ€ÿ‚þÿþ…ÿþþ€ÿþþ€ÿþ‰ÿþþ…ÿ þÿþþÿÿýþÿÿþÿ þþýþÿþþÿÿþ‰ÿþþÿþ€ÿþþÿÿþÿÿþþ€ÿþÿ€þÿþþÿþŠÿþþÿþÿþƒÿþ‡ÿƒþˆÿ€þ†ÿþþ„ÿþ‡ÿ€þýþ‰ÿþþ†ÿþ„ÿþþ‡ÿýÿŒþý‡þý…þý‡þÿþil32 ‰|z{|}‹˜’‰†‰Œ•¦›ŒŽ šŠƒ‚†‚„•ˆ€~€€„‘¤šŒ‹‘‘•§¢••—¤’‰†‡“ŠšŒ”–‡…Ž…ƒ†š¤”‘œ™§¬ ¦¤£“‘‹‹–œ€‡–•–‰‡ˆŒ”¥ —§¡­»¯µ«¶£›Ÿ’’¡²›Œ}‚‹Ÿ¦—‹‘’”¢¬¢ °±³ÃÏ몪Ÿ˜ž©ž”’~‰“Ÿ±¢“š ˜ ´µ©±ÁÃ×óóå̽³¥§¬‘‹†~‡Ž’ ©œ–𧡤³À¶¿ÊÙêûóøæÎ¼´»¦—’Œ†„ˆ”£­Ÿžª´¬³ÂÉÎÚëùàÛõàÎÆµ¦ Ÿ‘‰q…†Š“›¬´©¬½¹ÂÈÚæóûû‚ }úöêÛ¶©š’‘’‹ž¬¾¶»ÃÍÎÛêöÜâµe _³ãôñ׺¨¡¡¤¡˜“š¨©«¹ÉÎÔßáîúöu@SlÜãĺ´¦šš¥£ ¨¹¹ÆÚîñõøüùª3‚4ßîη¨š“‘›®´°¼ÍÕïû÷öõýåF„ ëи«¢ ›žª½ÂÌÙìûù›mf·µ†fîÕ¿²£›š¨·ÈÛåðûúÐ- W…yïÒ»© ˜¤°Ðìòùýø£E†,ÐîÒ¿¸°¦¤°Ðìòùýø¤E†,ÐîÒ¿¸°¦š¨·ÈÛåðûúÐ. X…yîÒ»© ˜›žª½ÂÌÙìûùœng·µ†fîÕ¾²£›‘›®´°¼ÎÕïû÷öõýåF„ ëи«¢ š¥¢ ¨¹¹ÆÚîñõøüù«3‚+4ßîη©š“¡˜“š¨©«¹ÉÎÓßáîúöu@TmÜãÄ»´§š’‹Ž€¬¿¶»ÃÍÎÛêöÜâµf _´ãôñ׺¨¡¡¤…†Š“›¬´©¬½¹ÂÈÚæóûû‚ }úöêÛ¶©š’‘„ˆ”£­Ÿžª´¬³ÂÉÎÚëùáÜõàÎÆµ¦ Ÿ‘‰~‡’¡©œ–𧡤³À¶¿ÊÙêûóøåμ´»¦—’Œ†~‰“Ÿ±¢“š ˜ ´µ©±ÁÃ×óóå̽³¥§¬‘‹†}‚‹Ÿ¦—Œ‹‘’”¢¬¢ °±³ÃÏ몪Ÿ˜ž©ž”’€‡–––‰‡ˆŒ”¥ —¦¡­»¯µ«¶£›Ÿ’’¡²›ŒŒ”–‡…Ž…ƒ†š¤”‘œ™§¬ ¦¤£’‘‹‹–œŒ”ˆ€~€9€„‘¤šŒ‹‘‘•§¢••—¤’‰†‡“Šš‘Œˆ|z{|}‹˜’‰†‰Œ•¦›ŒŽ šŠƒ‚†‚„މ|z{|}‹˜’‰†‰Œ•¦›ŒŽ šŠƒ‚†‚„•ˆ€~€€„‘¤šŒ‹‘‘•§¢••—¤’‰†‡“ŠšŒ”–‡…Ž…ƒ†š¤”‘œ™§¬ ¦¤£“‘‹‹–œ€‡–•–‰‡ˆŒ”¥ —§¡­»¯µ«¶£›Ÿ’’¡²›Œ}‚‹Ÿ¦—‹‘’”¢¬¢ °±³ÃÏ몪Ÿ˜ž©ž”’~‰“Ÿ±¢“š ˜ ´µ©±ÁÃ×ðîä̽³¥§¬‘‹†~‡Ž’ ©œ–𧡤³À¶¿ÊÙêø×íåμ´»¦—’Œ†„ˆ”£­Ÿžª´¬³ÂÉÎÚëõÆiÂòàÎÆµ¦ Ÿ‘‰p…†Š“›¬´©¬½¹ÂÈÚæóûöeaôöêÚ¶©š’‘’‹ž¬¾¶»ÃÍÎÛêë»Ò¡LG Õéã׺¨¡¡¤¡˜“š¨©«¹ÉÎÔßáîùìV-  AQÂãĺ´¦šš¥£ ¨¹¹ÆÚíñõøüó$ƒ'Òìη¨š“‘›®´°¼ÍÕïîèåçûÙ2…gßи«¢ ›žª½ÂÌÙìúîrNH ¢ †UèÕ¿²£›š¨·ÈÛåðúï³2…iëÒ»© ˜¤°Ðìîõøæ|,€†'ÉîÒ¿¸°¦¤°Ðìîõøæ}-€†'ÉîÒ¿¸°¦š¨·ÈÛåðùð³3…iëÒ»© ˜›žª½ÂÌÙìúîsOI¡£ †UèÕ¾²£›‘›®´°¼ÎÕîîèæèûÚ3…gßи«¢ š¥¢ ¨¹¹ÆÚìñõøüó%ƒ+'Óìη©š“¡˜“š¨©«¹ÉÎÓÞáîùìV.  BRÂãÄ»´§š’‹Ž€¬¿¶»ÃÍÎÛêë»Ó¢LG¡Õêã׺¨¡¡¤…†Š“›¬´©¬½¹ÂÈÚæóûöebôöêÚ¶©š’‘„ˆ”£­Ÿžª´¬³ÂÉÎÚëõÆjÃòàÎÆµ¦ Ÿ‘‰~‡’¡©œ–𧡤³À¶¿ÊÙêø×íåμ´»¦—’Œ†~‰“Ÿ±¢“š ˜ ´µ©±ÁÃ×ðîä̽³¥§¬‘‹†}‚‹Ÿ¦—Œ‹‘’”¢¬¢ °±³ÃÏ몪Ÿ˜ž©ž”’€‡–––‰‡ˆŒ”¥ —¦¡­»¯µ«¶£›Ÿ’’¡²›ŒŒ”–‡…Ž…ƒ†š¤”‘œ™§¬ ¦¤£’‘‹‹–œŒ”ˆ€~€9€„‘¤šŒ‹‘‘•§¢••—¤’‰†‡“Šš‘Œˆ|z{|}‹˜’‰†‰Œ•¦›ŒŽ šŠƒ‚†‚„Žûšþÿ€þ…ÿþ‰ÿþ„ÿþþÿþ…ÿþƒÿþ‡ÿþŽÿþÿþÿþ‚ÿþýÿþþÿÿþþ„ÿþ‚ÿþúûþþÿþ€ÿþÿÿþþÿÿþþ„ÿ þþÿÿþþýÑÅïýþ€ÿþ€ÿþþ€ÿþþ„ÿ þÿþþýúÇc£øþþÿþÿþþ‚ÿþ€ÿþÿÿþû×p2mßýþþ‚ÿþþƒÿþÿÿþÿþÿýùîä¬32¶î÷ø€þÿÿþþƒÿþÿþýû¿rzOR‘¨®úþÿÿþýþ„ÿ€þýýûì,)|ö„þ€ÿ þÿþüæòòðëºL‚‰ìþ€ÿþþÿþþÿÿþþõ•–Œ™²}„5Âþ€ÿþþÿÿ€þ ýúæŒ3#&G5†-Ðýþþÿþþÿþþüû÷Ù’J …Eäþ€ÿ þþÿùéÁ¹¯}6€†—ö€þ ÿþþÿùéÁ¹¯}6€†—÷€þÿþþÿþþüû÷Ú’J …Eäþ€ÿþþÿÿ€þ ýúæŒ3#&G5†-Ðýþþÿþþÿþþÿÿþþõ•—™²}„6Âþ€ÿ€þ€ÿ þÿþüæóòðëºL‚‰ìþ€ÿþþ„ÿ€þýýûì,)|öƒþƒÿþÿ‚þ ûÀr{PR‘¨¯úþ€ÿþþƒÿþÿÿþÿþÿýùïä¬32¶ï÷ø€þÿÿþþ‚ÿþ€ÿþÿÿþû×q3nßýþþ‚ÿþþ€ÿþþ„ÿ þÿþþýúÇc£øþþÿþÿþþÿÿþþ„ÿ þþÿÿþþýÑÅïýþ€ÿþ€ÿþþÿÿþþ„ÿþ‚ÿþúûþþÿþ€ÿþÿÿþþŽÿþÿþÿþƒÿýÿþþÿþ…ÿþƒÿþ‡ÿ‚þ…ÿþƒÿþ‚ÿþ„ÿý›þýûis32Ñh”…}~‰™‹Žœ›”š‘†ŠŒ‘‡‹œ˜ž¥®ª¦˜Ÿ–ƒ—¡–¬¬»Õؽ©¢ŽƒŸ ¢ª¹ÄÛæÑàÃ¯šŒŠ‘œ°´ÂÎåßšMÏâÂ¥šœž¬¼×åðØI$—ײ›±ÁÚðº½y€ JÖµ¡¨Íéô¨€ aÛ¸¥¨Íéô¨€ aÛ¸¥›±ÀÚðº¾y€cJÖµ¡œž«¼ÖåðÙI$—ײžŠ‘œ°´ÁÎäßšMÏâÂ¥šƒŸ £ª¹ÄÛæÑàÃ¯šŒƒ—¡–¬¬»Õؽ©¢ŽŒ‘‡‹œ˜ž¥®ª¦˜Ÿ–“…}~‰˜‹Žœ›”š‘†Šh”…}~‰™‹Žœ›”š‘†ŠŒ‘‡‹œ˜ž¥®ª¦˜Ÿ–ƒ—¡–¬¬»ÔÖ½©¢ŽƒŸ ¢ª¹ÄÛݼÞÃ¯šŒŠ‘œ°´ÂÎáÔŠ=ÄÛÂ¥šœž¬¼ÖåðÍ: …Õ²›±ÀÚ褮k€ @ѵ¡¨Íçì’€ [Ù¸¥¨Íçì’€ [Ù¸¥›±ÀÚ襮k€c@ѵ¡œž«¼ÖåðÍ: †Ô²žŠ‘œ°´ÁÎáÔŠ=ÅÛÂ¥šƒŸ £ª¹ÄÛݼÞÃ¯šŒƒ—¡–¬¬»ÔÖ½©¢ŽŒ‘‡‹œ˜ž¥®ª¦˜Ÿ–“…}~‰˜‹Žœ›”š‘†Šý‹þÿþ…ÿþ‚ÿþþÿþ‚ÿþñçý€ÿþþ‚ÿ þþû»yìþþÿþþÿþþè¬S!—ÍúÿþþÿÿþõñïžYî‚þû¼em8€)Û€þöݼQ Dì€þöݼR Dì‚þû¼em8€*Û€þ ÿÿþõñïžYî€þÿ þþè­S!˜Îúÿþþ‚ÿ þþû»yíþþÿþþÿþ‚ÿþñçý€ÿþþ…ÿþ‚ÿŽþich8 ÿÿTTTTTT~TTTTTTTTTTTTTTTTT*TTTTTTTT*TTTTTTTTTTÿÿÿTTT~~~T~T~~~TTTTTTT~TTTTTTTTTTTTTTTTTT~T~TT~TTÿTTTT~TT~T~T~TTTTTTT~TTTTTTT*TTTTTTTTTT~TT~TT~TTTTTTTTT~TT~TT~TTTTTTTTTTTTTTTTTTTTTTTTTT~TTTTTTTTTTTTT~TTTTT~TTTTT*TTTTTTTT***T*TT*TTTTTTTTTT*TTTT~TTTTTT~TT~T~TTTTTTTTT*TTT**T**T**TTTTTTTTT*TTTT~T~TTTTTTT~TTTTTTTTTTT*TT***T**T*TTT*TTTTT*TTTTT~TTTT*TTTTTTTTTTT*T*TT***T*õõõõ***T*TTTTTTTTTTTT~TTTT*TTTTTTTTTTT**T*T*****õõõ****TT*T*TTTT~TT~TTTTT*TTTTTTTTTTT**T*T***õõ õ****T*TTTTTTTTT~TT~TTTTTTTTT*T*T********õõõ.3õ***T**TTTTTT~TTT~TTTTTT*TTTTT*T*TT*****õõ4ˆ^ õõ*****TTTTTTTT~TT~TTTTT*T*T***T*****õõ ˆêþXõõ***T*TTTTTTTT~TTTTTTT***TT*******õõ ¬àà^õ****TTTTTTTTTTTTTTT**T*******õõ4--^^­àþ‰XX **TTTTTT*TTTTTTT*TT*T******õ*õ^¬ƒþàÿêôàþþ^‚^õ****T*TTT*TTTTT*T*T****õ*õõ ^ÿàÿÿÿÿÿÿÿÿàþ^õ***T*TTTTTTTTTTT*****õõõõ-‚ßÿÿÿÿÿÿÿÿÿÿÿþ^***TTTTTTTT**T******õ4ýÿÿÿÿÿÿÿÿÿÿÿÿÿ­Wõ**TTTT*TTTT*T*T***õõ 4-4-ˆàÿÿÿÿÿÿÿÿÿÿÿÿÿê^öõ*****TTTTTT******õõ^¬­ýˆ4.­ÿÿÿÿÿÿÿÿÿÿÿÿÿÿà^õ**TTTTTTT*TT***õõõ4ˆàÿÿàý_þÿÿÿÿÿÿÿÿÿÿÿÿÿÿê]****TTTTTT***õõõõõ .^àÿÿàÿÿýàÿÿÿÿÿÿÿÿÿÿÿÿÿÿý-õ***TT*TT*TT*õõ :ýþÿÿÿÿÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿßWõ*****T**T**õ  ^ýßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþXõõ***T*T*TTT***õõõõõ .^àÿÿÿÿÿýàÿÿÿÿÿÿÿÿÿÿÿÿÿÿý,õ**N*TTTTTT*T****õõ4‰ôÿÿÿý_ßôÿÿÿÿÿÿÿÿÿÿÿÿÿàXõõ**0TTTT*TTTT*****õõ^²­ýˆ4 ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿô^õ**N*TTTTTTT******õ*3- 4 '‚àÿÿÿÿÿÿÿÿÿÿÿÿÿà^$**0T0N0TTTT*TTT****õõ4ýÿÿÿÿÿÿÿÿÿÿÿÿÿýX**N*TTTTTTT*TTT**N***õõõõõ-ˆýàÿÿÿÿÿÿÿÿÿÿàXõ***TTTTT*TTTTTTN0T***õ*õõõõ ^àÿÿÿÿÿÿÿÿÿàô^*****TTTTTTTTT0T0TN0*****õ*õõõ^­ˆàÿÿÿÿÿÿþ^‚^õ**T*TTT*TTTTTNTTT*T**T*******õ4--^^‰ÿß‚^X ***T*TTT*TTT~TTTTTT**TT*******õõõ­ôþXõ**0TTTTTTT~TTTTTTTT*T*TTT*T***õ*õõõ-ˆôß^õõ***N*TTTTTTTT~T~TTTT*TTTT**T*0N****õõõ.ˆ^ õ****TTTT0TTTT~TT~TTTTNTTTT0NTT0T******õõõ-.õõ**N0**TTTTTTTT~TTTTTT0TTTTTTTTT***T*T***õ õ***0N*TTTTTxZTT~TTTT*NTTTTT*TTTTT**T*T****õõõ***N0TN0NTTTTxTT~TTTT*TTTTZTTTTTT*TNTT**T***õõ***0N0TTTT0TTTT~TT~~TTTTTTTxTxTTTTT*TTTTT*T0******N*TTNTTTT0TTTTTT~TTTTTTTZxZTZTTTTTTTTT*TTN*T*T0T*TTT0TTTTTN*TTTTTTTTT~TTTZxT~TTN0TTTTTTT0T*TT*TTT0TTTTTTTTTTTTTTTTTT~TTT~TxZTTTTTTTTTTTTTNTTT*TTT*TTTTT~TTTTTTTTTTT~T~~T~T~T~TTNTZTTTTTTTT*TTTTTTTTT~TT~TTTTTTTÿTTT~T~T~T~T~TTTTTTxZxTTTT0TTTTTTTTTTTT~TxTZxZTÿÿÿTTTTTT~TTTTTTTTTTTTTTTTT*TTTTTTTT*TTTTZTTTTTÿÿicl8ÿTTTTTTTTTTTTTTTT*TTTTTTTTTTTTTÿ*T~T~~~~TTTTTTTTTTTTTTTTTTT~TTTTTTTT~TTTTTTTTTTTTTTT*TTTTTT~TTTTTTTTTT~T~TTTTTTTT**T*T*TTTTTT*TTT~TTTTTTTTTT*TT*T******T*TTTTTTTTTTTTTTTTTTTT*TT***öõ**TTT*TTTTT~TTT*TTTTTT******õ õ****TTTTTTT~TTTTTTT*TT****õ-^-õ****TTTTTTT~TTTT*T******õõ‚à^õõ**TTTTTTTTTTTT**T****õ -3ˆô‰3,õ*TTTTTTTTT*T****õ*õˆ¬àêÿêꈂ-****T*TTTTT****õõõõX­ÿÿÿÿÿÿÿ¬,õ**TTTTT**T***õ­ôàÿÿÿÿÿÿà^*NTT*TTT****õõ^‚ˆX4àÿÿÿÿÿÿÿÿÿ‚***TTT*T**õõ4ýàÿþ‰ôÿÿÿÿÿÿÿÿÿ‚õ*0TTTT**õ^­ÿÿÿÿþÿÿÿÿÿÿÿÿàý,õ***T**T*õ ^ˆÿàÿÿàÿÿÿÿÿÿÿÿÿ­,õ**N0NTT***õ3­ÿôþ‰ÿÿÿÿÿÿÿÿÿþ‚õ**TTTTT*****õ^‚ˆ44þÿÿÿÿÿÿÿÿÿ‚**0TNTTT*T***ö& ¬ÿÿÿÿÿÿÿÿà‚*N*TTTTTTT****õõõW­ÿÿÿÿÿÿÿýõ**TTT*TTTTTT****õ*õõ‚­àÿÿÿàˆƒ,ö***0TTTTTTT**T****õõ-4‚ÿ‰Wö*TTTNT~TTTTT*TT*0***õõõ^þ‚õõ*N*TTTTTTTTTTTTT*TNT****õõ-^-õ***TTTTTT~TTT*TTT0T*T*****õ õ**T*TTTTTTTTTTTTTTTTT*TTT***ö**TTT*TTTTT~TTTTTTTTTT0NT0N0*****T*TTTTTTTTTTTTTT~TxTTTTTTT*NT*TNTTTTTT*TTTTTZxTZxZTTTTTTTT0TT0TTTTTTTTTTTTTT~T~T~TTTTTTTTTTTTTTTTTT~T~TTTÿTTTTTTTTTTTTTTTT*NTTTTTTTTTTTTÿics8*TTTTTTTTTTTTTT*TT~TTTTT*T*TTTTTTTTTTTT***ö*TTTTTTTTTTT*õ+-ö**TTTTTT***õ,Wˆ,ö*TTTTT**õõ­êàßW**TT**õö3-‚ôôàÿü+0TT*öXþþþÿÿÿÿ‚öN***öXßþßÿÿÿÿ‚ö0NT0**3-‚ÿÿÿÿ¬ö*TTTN0*õõ,ˆþà­]öTTTTT*T**õ+X¬,ö*0TTTTTTN0**,ö*0TTTTTTTTNT**ö*NTTTTTTTTTTT0NTTTTTTNTZTTTTTT*TTTTT*icl4üÌÜÍÌÌÌÌÌÌÌÌÌÌÌ¿ÍÆÆÆÆÌlllÍÜlÆÆÝÌÌÝÌÜÍÌÜÌÌÍÌÌÆÌÌÆÆÍÝÆÝÜÜÜÌÌÍÌÌÝÜÌÍÌÍÆÌÌÍÌÜÌÌÌÜÜÌÜÝÝÌÌÜÝÍÌÌÌ ÌÌÍÍÜÍÍÌlÍÍÌÌÌÌ ÌÍÆÌÆÆÌÌÜÌÌÌÀ̼ ÌÌÌÜÍÌÌÜÜÌÌÀË«À ÌÆÌÌllÌÌÌÌ Ì»ûÜ ÌÌÌÌ`ÌÌÌÌ Úÿÿû¬ ÌÜÌÌÌÌÌ ¿ÿÿÿ¬ ÌÌÌÌÜÌ ÀÊÿÿÿÿûÀÌlÆÌÌÀ»¡¿ÿÿÿÿýÌÌÌÌÌÀ̯ÿ_ÿÿÿÿû ÌÌÌÀ ³ÿÿÿÿÿÿÿü ÌÌÌÀÀÁºÿÿÿÿÿÿÿü ÌÌÌÌÌÿÿ¿ÿÿÿÿý ÍÌÌÌÌÛ½¿ÿÿÿÿû ÌÌÝÌÌ ÌÀÊÿÿÿÿû ÍÌÌÍÌÌÀÁÿÿÿÿü ÌÍÆÍÌÌÀÀ ºÿÿú¼ÌÌÌÌÌÜÜÌÌ ÁÛúÌ ÌllllÌÌÌÌ ýÌÌÌÌÌÌÍÌÌÌÌ ÜÀ ÌÜlÆÝÜÌlÜÌÌÌ  ÌÍÌÌÍÌÌlÜÍÌÌÌÀ ÌÜÆÆÜlÌlÆÍÍÌÌÀÌÍÌÜÌÌÍÌÜÜÜÌÆÌÜÌÌÌÜlÌÜÍÝÝÜllÌÜÜÍÍÍÌÆÝÌÌlÝÝÜÌÆÍÍÆÌÜÖÍÌÜüÍÆÌlÜÌÝÌÌÆÌÌÆÍ¿ics4ˆÌÍÌÌÌÌÌÌÍÜlÝÌÜÆÌÍÍÌÌÌÌÌÌÍÜÜÌÌÌÍÌÍÌÌÌͬÌÌÆÌÌ ¿ÿÜÌÌÀÌÝÿÿÜÌÌ ÚÿÿÿÜÌÌ ÚÿÿÿÜÌÌ ÿÿ\ÌÌÌÀ ¯ÿÜÌÆÌÌÀͼ ÌÌÌÌÌ ÌÍÆÍÜÌÀÌÍÌÌÍÜlÌÌÆÌÍÆÌÌÜÜÌÌich#HÀ€®»nÛméYUYEKŠ¥JUQR*ª’J’ªÔ¨¨…DRµJ‚))J’D ”P’ˆD’ªT¥ ªJ‘ %Z””ƒUD)UF DQH€—¤*ÿô(*¢ ÿøB©ÿü @ ÿü(U#ÿþQwÿü$HAÿÿþ ÿÿüR ÿÿøÿÿø*¤ÿÿü$ÿÿþ IëÿþQ£ÿü!ÿþJ@ÿøU)üR ÿô(J€ —¡ )@'*UP€¤i$ L ADI*@UT@ JQR€!U(@AJTª  RJR…IUU@R•T‚ ¤ªªª°ˆ•IÒ’‚H¢«?ÿÿÿÿüÿÿÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ?ÿÿÿÿüICN#€?m­ºHªª¢ª©¨Jª"ª"‘ÒT¢@RHŠTˆ’D"þ’YÿÿÅÒÿÀ}ÿÊ€ÿŠÿÿ€P?ÿÊ@ÿÂTÿÈÿ‚JþT€ T %!’Q JU$I$HTJ¤Iªª•J5HY‰&’Eÿÿþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþics#H»Z$Jª¥@ôùGøù¡øò¨°TU JRR”ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿh8mk uÉßààààààààààààààààààààààààààààààààààààààààÝÄm töÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõjÈÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÚßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛÆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÁqöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóf qÆÝßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÞÜÁf l8mkJÃÞßßßßßßßßßßßßßßßßßßßßßßßßßßÝÀEÃÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾ÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÜßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÂÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¾HÂÞßßßßßßßßßßßßßßßßßßßßßßßßßßݾBs8mk£ÞßßßßßßßßßßßßÞ ÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßÿÿÿÿÿÿÿÿÿÿÿÿÿÿßÞÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞ¢ÞßßßßßßßßßßßßÞŸfractalnow-0.8.1/gui/icons/icon64x64.png0000664000175000017500000001534311764667445016427 0ustar mpegmpeg‰PNG  IHDR@@ªiqÞgAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAg@@êóø`ÃIDATxÚ­›i¬%ÇußÕ{÷ÝÞ2oæÍ —9Ü% iÊÅD I)±F1QäCüÁVâÈ€¤X1% 8"o±ƒ@¶…^"KI¬X ,SVbÓ$E2˜X–Èá2g{ëÝïí­*έM…làâ-·»ºêÔ9ÿó?K©O}ÊàûÜT–|Âq8ÛíšÍáP©Ù ´æ/Ç¥äã8òq]èt Õ2ôû ­Áó`>cêg›Ï¹.ø¾<—$†$Åt Y&ï7¦þØËu! áØ1C–Áx Ó)ŒÇŠ¢X¾ß¾Ok Pßw¾èº|Ö.x››æ¦¢à×'õnß­e)„å7´Ÿæÿ² ÚmHûCž«j!ö~+@;þt Æ(<ÏT÷Ú÷+%‚Ìs(KùÛ÷EYƒb6“ïíØVJAˆÀf3”1xJq2øXr»çñao0P?»ºjÞÝí&оØÖ\ü« ÂóäE ØÜ4 0ª%A6w¿)À¦fű¡,Y&{t:†Á@U‹ô<èvebe)ŸæøÍ‰"CCQ¨J€®‹êõ̃QÄG<­9[²sEQ«4Ô*h'wP#š&E¢ÂVµíýö§½‚@>Y¶<†ïËÿµp]yWÊ‚›ãú¾<;ª%3µcÜ0ϓ՞$cpÎzí¶9šeŠK—Ä~“¤¶]+q‰8βM7¥=Ÿ‹„=À†ò¢4•ÅÚò}èõ £Q½£JÉ}óymãvd¼Z\Wž÷}垦¹´+ 0”ÿDZhÙî®b6ã:oÜðm] ×ú}§Z|YÊZ79™Þ8Î2­·Wsó¼ƒh'¨µÜ0ªŠ$acC$oqÀî¶Eàõu™@–ÕBÔZÌÄÚ{Q(”R¬®jÒTÌ««…¨q¸‹ÉC™'øî—ÏsîÏc~ôvïlEGIÓC„aMÎö÷í¶¨ÿp¨TµóV£}_¼Êx,˜`çì$2/+»£‚À¦"EVXÖ®[-(ŠZÕ“DßàÆ†f4r0FẊ•y.Ž ž§ˆã!zü0Wþm.¿´Í¯~~Ì“Ï͹éÌSÜtf›öí?M»}E††ÁÀ¡ÕÍ‘<Ȳ:†Cp]Ãx¼Ìe”ï o‚[ógY h-(,ôT—e5ÃËsC§S“ž(’‰Xr]E§ ¾¸×-A9$I†çe(µ›äì Kþù§wyìòEÀð3Ÿ.ù…GÜû¦D¯×a:õ1ÆDzpÇl˜LDàQ$æ1™¨…×ó²8ç U\&5®Ë’7°7k]ÓÒ#G4Ó©Q¯Zë놲”8 (ÓGáÚšþÐÒ„aŠç΀ ¥&À¨ ;}xa0@›€ïm ¢Â¸Dlà8+D‘[aãøìíÉ&D‘àÂpXSz»FkŽ^·k˜ÏŦ›7ôz"•4­}»UUß§5;x»-¾ÜšÍÊŠ0@­Å ó2´ZàyŠ••Îü[èþeÒ´Otü6²É.éè¢ÞEnzËUÎ÷ùÊÓ`xÓ±ÓoÙe>zU\¤H¯¡µy7¾ßÆè}ÂüI¼õ¥,W ‰öF#¸e„6¨²ØÐj<+©ƒ!®èÂP\LÓçËï²³í¶YPgáþy.ˆ¿ºª±õ²Tt»zÁø Nð þÏçž ¸&çÆ³Éî Û|þW® Ã!/^0Bàh£Žà“?ÿ"G|…“!'O]ÏÙõÉö]”»ÅäüS´n¹žNçŒFN•\ú,,r:•÷».fÁb•×nS¿üG%Y™‘/lþծ”åŒßû³Ëœÿgc.ìgø*äÞ_º—ðð¤SU¹½NGè°ç™Å†:Ö¨4•Mö¶·Å?·Z5#´1u“͵ÛâJ„-ª*ˆ)KEº]³ðç¦2£(Ò…" ‹E0”á8CÊôÿòÒc_Gçßæ™ó[¸À¤˜òƒ\Úh¿8$p~êïv¸ñ§Á;‚ïë*70)ØßwTXLÂ2WcÀ¤°X]U –ãê4UL&†^O"¬²)¯¯›*ä][ù.®›aÔI0³Ž“J ó™û?ÍŸ~é)>÷¥çøËËûlMÇ?ÐâëËëŒg.M¹|i›C§Ÿ%ð|‚à»»N奄æ×Y®æåYbŒØ|«%É»pK1Er†ÕU!:Z+À°ºªétJ<ž¡Üÿ:þᬀÉ(OදCyGóÍ@]e<ºH»w…ï]¼ŽÅ[þä©ÿõs¢‡}n¸ùDG?JGd™Y¸ÈšàL®zM??› ºolˆJïîŠ;9­¾¯évå^I *‚PtªØ{†lð9üd•àH‡ñ¹?Æ9r+­Íëq’c(/®pþÑs|æ? ¹2y}‹·Wf ~ù÷/RŒ#~öSà-"Y«î’7˜ÏŽc*Ð÷¢Hiæì-zÚ¸[) :ŠB‘¦I¢Y]5‹”SŽçÎPÞ&ѵ·ñWÿå›<ü°Ï»>ò½§2¾óÜ£¼ãŽÇ9õÀIŽ¿õZoÄwÎ]æüVmôë[yãê&ðÁŸ:Éêí÷0{D‘YÌQ`Y ¶åyi ^’x幪bf)7 £[_ºÇ‚ÂívIjÂpŽR{ wQAÎÞ à3_¾Âüšak6cZæ¬|%æÞ/Møè¿ºÀ=ïòèSvÒÙ¶x€ÝqÁŸ}õ·Ù¡ ²L‚žÉD¼Wš Ø*’M®x“‰¸¾8+K!2q\'!m¢²ÓÑ€ {5QxežRôìžþêcüÁMÙ ¸0¬Q}”Nùݧú\øä~íù9Ï~·DÊtoÜŠo;Žß=Åt![qé¢ò¶Út°°ãcIް¤^¯Fö0¬ ¬ô"‡Ÿáºc”>O~å·p»!Nñ,>¼Ïo|këU\ZÉ_œ¿Ì§áÎÞÛo^×lÄœ¼å øÇ(GBÀ|_ò–û×9ŽFZÜ}_b~c ¢Ý®!IRâx ˆ120—Á}†¼‘/ÿâ.;{þäÑ‚Iñê‹3ÆðµÉœóšõZ¯ÐsøGú!nzëýeLž+²LUªßÌMxžä ´^ü½¶&¡m§#’éõ Göétöð¼!޹ċçþ#'o" <Êùœ¨M¾ó=Ò—Îó§ñ/s›ç÷wˆ‚þ†ÅfÛÓ-?ÐÕûéÓ|øÄ ®AÏGrÿ««ßWU–Ê÷Å HRT‚º¥$wmjñ±5þ®’â6”²ß¨æ#ýõZï{×Áþæ ^)¸ÔkðÀ=dUÆ2ó33ž|As~'}à Ã;ïjsêŽ{ÈôÆbÇeá²`ùÙäZƒgSÙYV×èšµôÁ@T¥×3ôû®[gxáaØÅá*NœróÙ?öì7ùÂã]nèuؚ͘9«A̽§ñÑOv¹ãÁ§þ| 5æä³ÌðÜw/’ŸÅ o‘/ÒúZ«*T6^i xÓ©ÔݬŸ´6ß>¨…f°mÁ÷5ã±Ã|îÐëÅDáJ­c2µ®ÇϽ¶A…#î»CqÃ7pìžkp¼?|×·ùÿÙg'}ãøÀzÛãíï=F´qˆ|,è/ü¿î=’ËTx>_N‚j-j††Ý]g‘ôßéºÐíjŒ©sñ®ëáù1^y…ù÷¿Ã‰÷ÜÅgWw9züyÏæ"ŠVÁЭw\æ¦Ã;ì½4}ÃâѾðÏsòØ£x'ï"M=ö÷ãqíj-ŒÐV£hÁm…'Ž ²LŠŠ–?K_8Bž«E²S-ÊÖ†,õq]oí4þáaÃáöÇqÛׇnüá;øÄO¾ÀG>3äÒxøº8ùÐ5üý^Ì1Ú’;ñõ³™ªº^Äþë¼€g{î‚@R]Ž#»{°Ù(Šd°ý} ®Ê8€Â_=»z‚¢8ÆN÷Ì"!¢&@@»sœñ`“[6G”—5W_GX¬P¼çÍ=~üŸÜÃïü”ù­ììÌf²ð4]îw´…RûñlËYKþ¯™³¦ÑnKÊl4TchwWÇ¢Ey3Q¸\xˆ¢€¢p Ã|‘‹püÓüí;Ã}gK¾ø»ø÷Ÿw¸4ùÿÑ…ïœ:š°yt8EV\Gž«EF˜ÅGæìû¦röò66lõDh¥u°íEº1Eu‚@\£-p¦©hM§cdO峉ùÏ?-7¾ÿFv/ìЯPú¾iÀÓßQ<¾;Bë’;×:Ür«âèæ'7BNœ<Á™yÛïuqÜ«ŒŸy §ó&fc—ÉĆøRĵi°Fa„NG’;žmyi–eRÖ$¤]Nš%ÖÖÌ‚WKÊ9LÅEÂ΢¢n¶ZªPÊÃu»D›÷sÏÇoCg}¢c·‘Úå_ü‡ç »¹úä#üäO\&»’†N>ý©ë8~÷}P¡Ì®çn‚µF÷iÝx’iùfF#gá÷Õ‚ÊÛŽš.•Æl³bsñ–5ó„PÇ&‚ ‹†C†CU¹R¥¤o'Ïë¦féû“|Cúý6I뽄+)¡;ǘ” 5!hýO?ùO^|P:w9åé§qÃ;ïõŒÙ ÏW( —²Ü$-o¡ß÷ dS\×,’¹uvû`_qš*<ÛkgÚt6…lhöô^½êT Ëlj6â8Â+¤•ELJb ‘èlæÐë*PÉ¢<Þ/aZZ“+=¶§cÀpËá:Ì1YÁ1²LÊ㓉ZøwSu€f™˜Ÿ˜UKœ­Z!³h”lv†7;>›?]WÐé-%9jËæÖÎ}_š“ÒT’¦ ÊYuŒŠ1F´Ak×…<H$YEOõ\~å߬ó«¿òijs>û¯rÓ™Cèrƒ2ï0ä¹0ÔÙŒÊ5Ûä4­›©mØx\÷8Ø(Ñ;¸Ð—¹›F÷¸Õi„Xn‘±]e“Iý½h‡ª8¸®a{[\£t†ËáŠ0 ÃlÖ!n½‹Í[3ßæcñ79÷È”Û|3ɉ§,ïd<ð«˜DÛF#»ãR­¶Xd«BÍü`³Uîe’O‚Ho®ª*¬ÛÛªjm=xÂ’#kFV@b6âNÇcyÞ÷¥×V˜âذ¿ïÇ¥Öˆ¢{@µ¹ùG.rtýüÄÁè æóµJ«ä„ˆôǵ®¬HâVx@Ýš#ýÁªRÿJìÂm_ßÁ69){ òoo«ªé¡ œ®Ë¢7Àö × ÖBD I"•&ÙP£HžÏë û¾G´PÅ„éÖ:‹ÑeºÃxì²»k»Àlëž©€Ö÷®k( gi#š¸©õU0$`±Ü(ÙÌKÙLJdEƒ¬Ùï-A²ßÙ– ¢¥6+#€¤ª,Ôx\7e ˆ*âÄ'(¶ðº·án|˜<ï0û ØL§A -ùÃa]¡(„xIçš$F^íª`é¬íä C™ø‰Ò*»µ¥^ÖqiM%`v„ÛÓlønš|eÍnñ¦]ïî:U½"Zuø°f_UîØV‡«`¨Ùg;Áâ¸>Z"ýwõÄž'lšƒPë%ÆãeRG™õ «šÖ]JØ-åº$õ¶Z(]à†,sªsMÒo,­±Kà^ݶßëA»­é÷¥gÐÆ?žuw¢®uvx_U­ñö´HÓ‡6MÀ¶ÉZtµÈ¯µœâhÆÖ<¬«j™‰"¡Éáª09Ë(Œç‰ú»n}¨Ëö [,šNÕÒ»,Àözš0”L—M‰xqŒ)KT}ö†ÊÖ»fKæ`íiYÍÅ[Shµê³–4Õ­ù¦š„ L$7©ªŽ4»0 µëˆÕf¨…4Õ%}ÉY.ŸI°sCÃÕ«ªÊlAå­J¯Ý6Fk¥lt4¨¥ 4%iÙ^s±M¨[OêxÀªcó؈Z6Ç/ §Åd1vaŽ# Ñv´¼€h¼E3ë“nv^vsú}U¥ú{½ê ¥öÆcu±×3×nnŠ;šNëlI“ðØ3}¯tpꃓžkkõXvâMдBnŽa³´¶óÔjMQÔ*íXရ>k ÍùœŸH›ít aÈÇqøCÏÃØôqDšœ¹YMiž¼°ÏçjÑg¨–\åÁñÒTPýàxÖ­Ù9XU¶fdÿgó|–`5½Xs>M¬jV„æsf¥({=¾àõz泌Óûûê~9rÒÌ£¿úáéƒ^À®\‘,ÿ?xxº‰Íì³=cdMÐ.ºß_æy.Z`ݬçæqûÛ׌]Ê=ªÿ>òYïêUuÞóø§eÉÇóœt»æ˜ë*§y¸ðàb¦Ìí mçùtjϨ—qï¦×°ÏÛ£ó6wgﱋjFžöJSX_{^œ_:©Þ4]¥Ð‹µhàBšòûyÎ/)Å¥ÿ>˜;–D&p%tEXtdate:create2012-05-27T10:48:29+02:00Ó+b%tEXtdate:modify2012-05-27T10:48:29+02:00qŽ“ÞIEND®B`‚fractalnow-0.8.1/gui/icons/icon72x72.png0000664000175000017500000002015211764667445016417 0ustar mpegmpeg‰PNG  IHDRHHUí³GgAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAgHHÎyðJIDATxÚÍœiÌmgußÏÏ|ÞéŽö<Ýë)°lfÙLNh$B$T |(ˆˆJUÚmÜ ÒªR…"Em\QiBT'Ä@B(nÀŒ¦ØÆxº£¯ïô¾ï™§==ý°ÎÚ{Ÿs_›ÉHÝÒÖ¹÷¼ûìóìõ¬õ_ÿ5óÑZ¬¥‘¦üºµüzµÊ-ahÃímC’@–±ãaÌâé8Ű¾n‰"Ã` w]˜ÍÀÚËïSþ¬çA³i©T`eè÷ Ó)ùztMå{éwT*pÅ–(‚~âz=CÉõzêgô>Ö’Ãоã8|Âþ§µL¼+¯´õ~Ÿ»‡CóAk k5Ëdb¿ÓM—T^¨µ0›ªU’ïƒãX’Ħ; Yka2‘Íñ}K–‰`vf–‘ßÏ®çÉFôz"Ô8–ë–×àûrN&`-Ð2†;ÃÛ\—£ÖòïüyóÞvÛ~`cÆq,E; gyçw”žq, šáÉïù\Z¨§µÅû®hdyŽ#Z6™&“â^¢u"Ô(’5$Iñ,eAéõµÚâÆ¾O½Ý¶ C~àÅ1ïžNMåÀËt çÎ-.~'¡<Ÿ©…!4×Í©×-gÏ:dÙ¢pô³Ë_¾O@µ q,¡×xž<Ül&,¯ÍuE8ú]Ë0°¼nÏ-*›i@ÐŒcþ™†Ü⺖NGS¯[âXv{ƒæÒ%Ž/·=³ âØe¢æŠI³™ü=M5¡^·8ŒF"½OšŠ6‡¡%Må>*Œ ÏêZ+ïÕë–4•{ÅñâÚÔ–¡@ŸÉÚB3Ã:Cq½†¶2™Æc¨Õ Zµ´Û"¤á°x ÝíZÍ2 XRšŠM{žØódáÆÀx,¸ ÷“5ùƒEQ!8kåóúðj¶YVEw\µªÙ,´Gï_Î2þÉwVº®lFÂt*Eìõ:“/*ËDš++°µU¨dY@•ŠÜ Ëž[‹ô3 ¦Õjñ°®»¨AI"¯µš%ËLþ¹0”SÖc™LǬ•kÕã¹.s' ÷Ì‚9#›>™˜/ZÜÊ ¤©§Û…ÁÀ¨b¸ž‚˜µê ½ž, ÷ª¸P¹4¨|dL§†nW©RöJ ×Ôj–Ù¬RÅ‚JE>7;xžü­^—õŽÇòZ¯[j5Ùu¼ž•JWe rÝâyÂöïO9yÒe:5‹Ay…µ¢Âáp›ÖÜ%Šé-/BϲZ«€âX4ÎX]•ñ¼ÅϨéT«ò]jB³™j„! Ñá(¨V«òpž'kõ}†ëÊ{A ˜RÖ^Å2×%XYm¼pA¤†Å3x*Qu­ ´Ã¡¡Ñ°¬¯ æ¨O&Ï zeµ. J5§Z•ÏëBËšg­amÍ2 RJXšM››N¥£e:5T«‚oã±`£Þ? -^^Ÿ`—ae%c84lm9ùó×ë6ß`OñeÙ4f3C«e©Tdq£Q¡Â*Ô2XV*„êùÊœh00xž¥V¯äû…—”•ƒ‚ÿ4›B4­…µ5‹µ† 08ŽÍ?ïûº;Â,ÓŒn×ä&¥BªT,ƈlmH± xeÁ,sš$é_w]B·ëÐë8°ìêÕe#ÂÐÝPLÑžFCþ†6wÇŽ#Ô`<†VKÏBt¤X¡*W>‡CÃö¶hE£ai4Ä+©y¨P5DÓ(@SwF4Òàû–VËæ±˜âr±ÙÌau5£Z…F#£RcL˜àÕ+ô=‡¿à­Þ‚ïg´ÛÉœ Œ1ù½”75›09sçcóõª"(-P0W!y;¼²ÊY+;­Üb84ìÞmIËö¶É™ñr4ÞlŠé(+U\SÐNSC­&i4¬h·…1+— |¨Õc|?Æ5§Hz_ÁõãûŸ~˜û>Wã½k]í;±mÂðf‚ J½.ÑØÚ24Q$m6[ÔlÅ‚@p«Ó1 ê-«Öó JÀ\¢~e¨åðA¡D0 ’†‚=Ó©|QÚíŒFC‚ZÏ“÷WWÅ7Ù<#â{ç™=óçœýòý\ê¸çÏ">ÿp‡ëŽÅ´Vþ„`ý)jG÷S¯ï#Ë\ªUK·ëP­ À§)ôûâÕ´”›)6M&å8ÑZðʪö£ÒY&$Nv@È*ypÍ#%‰0à ›²Ær®+lÜuU‹2ÒÔæØÖngd™Cµšâû ®;3 ØUåLÇáCëñÈæY2›ò;ŸL¸xþ ¿ù»}Œé†«8NÀxìÍ£ry€n×äN¢ßü©Tl® ‹!U™{Ëù”e€^fÅÊOÆcÌ®]CÍf‹!„&­Z­ÌãØÐlZâX´$Š qì°¶–¡Q}&x~ŒcbŒc`›,Ž9} Nö¶É¬sgzž¼¸So]\÷ŽYÁ˜aIâÌ™¸8—ííB“AªéÔäô¢ü¬y¾¨Ñ]NkJìSü­üa߯ ñUF¯çä¦$©æŸö¬÷Q—­ZÕhØ<$¨×ÆxæŽ7 < ͽ€Å¦ÏbœMÜæy®{Å€õO;ô·e­×㆗¤Ô÷n?$›Å¸‡ ÃAˆµ)6zŒŠ 6Ì7)£ß7yJ¶üÌ J‘e…éyõz—IŸ’ÇF£p•åe™¼×í:ÔjÂZ£H­¸lÍÖ‰)v».i*‚k4,ž'‚l·³y€x‰Éñ{8÷­ÓTª]ö¾ávŒ_åO=B­¾Ig:`rú·­´9;HˆÒ G[x½ù_âÀá³Dç]v]{×ÞñZ Œ3btæ/ñ7^Ïúú?!M}F#Ñ\õp•"„á‹•T*–z<+ Ëæ6îx8,4I#í,ûu]‰Šûý‚¹6šß)Qžgç÷6¬¯'ı7ÀÇgLš¤<þ÷xðTÄÑo?Àk~qȽŸ™òôÙMéLf$6#±)ÆZ~пć>¡7äèž³¸TøWìpø¶gBáNÓ:à»Ï»zWZF#¡êÞeÝ–Z EØñ§ÓO“EQdòôD™(i$_¯£z.õ^Ê{ÖÖÄt4ÑE‚hµâr­uæD.Mr&À„úáÝŒ÷º|ü¿gãAÃMáów'ô¦àòÊAœÊbgQÌ·ÎŒð—ßûƒ)½Îþæ8q&åýoÜÃ;>”âz>•ŠxÆ$1s/šR©dôûÃ!&Ž1JO‡¯pݚϷÏos¼g±6åÇ=’,å»g¶ø—ÿyÊ0‰õ õkï u›¹ãYYɨՊº_›yÍÌc´‚,{Ý®x–f³HXëÊ Y…ÐjdÌ_½ÿo»á®W%ðoÖÉS« °RöäåÃ}ãï¾»u«mj‚ÞÚ"»§Ûh§NA0gu5£Ų̀ÖΓnÞƒ&¸A Ç☠dƒ0þãX`4?»XÎ0Ü~„í§åÏþ¾ÇÖtð3 G­aL89¼¾7x˜Jû©{ˆ4±9–j¡\–.Çg )WñLâ‰öìÉæœ@$ÛlŠV© ®¯gL§i*A©1†0LpÌ„h¸M·ñnm ëd ºÚ±—⯚¯fŠžàKŸ~š}jB'úÙ5gñ°Ü÷à6O}ø>úþxåQ;Oö¦Ó‚=@Àt*Øêy¶5ÊìWµÈóĵÛÂa4y¥EEk 㱓ƒtµji4RllÄìßw‰0ìã8]³É©ïÝG}­ÅÆ•W“ôžÆñ}Œç09ý}â çøú}†}¡Ã÷/œ¤6ˆ’é|k-ÝîùŸ‹p*žá·Þuÿö#o¥±qŒ,FãºRB ÃŒÁÀÌû˜g,Žƒë úþRÒ^½üŽ!¯4Süþo3ÿ·1zÕü½ÿk-v‡ö8»£?0;¾ïmoËÃı˜X³iÙÜô±v?ÕêþÜÄÜr5ÆXêxë…‰UÞNõܹؓ÷ üë®å›Ç*c?xèýAü¤ú°‡~ÿYöšÙ4±üá§ž…è¯øØÇRß8 O§R7›NÉÉ¢B'oÔV ÷®»î¾„1kKHóéYôȲu¢¨M’Ô0¦A–µqœ Ƭ@fIúrýUÞø+.GötøòWΞ_@ 7àVïgâ-²Ÿ jÿq œ>ÝåŇ®¾ù%¤v=ÏKÄ^¤x¤§Q”e6Ó"&xp–«ŸÝ®É“ÚZHœÍœÒ5þÜÍ»ø~Ç\¿÷.œj Ì V®º×]?áì`Ä¥çôd.ÿøæU~íÊ“|çK†^ô‚Ë€Ký˜ï|ãÞðöÇñ«W’މcñØPc© ¥è,÷­o½ûníKŽ"“W-ÇÇ&¯lj®ÄóÈKÂQä⺮×Ä Ž€iaSƒßœpÛÏҤʷÎÁ,Fªn•;ŽäßÄeïKfÜûEîäGƒúO«E-?à¥×¬°~äVF£ƒ™§:Š–í5X®Ñ{Ò$)H3…aȼÎ-ÕÉÍMÉÂ5›’æPI×ëB&ƒõºïqެ½œæ‘Ó´ÖÎòâÝ»¹óšï<3åt?âæõ7]½Ê;ÞßàÆ7W¹øô®Û·ÉÉ­?/6}øPÀî# XÉ`VBƒY‘ì¢Öñ´ÙA5'VµËBS¨Òç# ëv[2›¹ZÊM´Û `sÓ›‡ŽÓÆu»dã‹Ä[îzq·¼¥Íõ¯Oyü¯·yìä!^u{LåºÃ¬Ýx˜€æ®ÇxÝ­ñà«ô“ñ .ß8¬µ}•=8.cɬÉ{ ´»DõMÓÈy°š$1Ò?&‰`&É$%`stK­–1:óƒ1.¾ïã:ѹoâ­_íÿâÈ<Ý‘rðæû8öö—â¯Z·L «1ŽœæÈz‡‡/N_ðˆ¾êûüÍ—¼úðý¼òŸßŽå ¢Hb1Iœi[LQÙð<-dÚ"¤åájUú¥cËäá¿/ê¨ Ò%!®Úó,Õªe6sñý*n} wõ•8áKcG4oYÇ©ĸ»æß˜`ü”»Þs 3<Ë?Þ`kÖÿé$±ãaxóË×øð‡oæÀ¾¬u±–y€]Œ9Èèƒ`‘˜X©i]cÅžVK*ŽjV ùÙyKIKIÈIÜ# 4Ë ðkÿë^C’¬Ì…oqš‡k5åš$õuž>±CkSœnÆ¥ å plo7¿åj^ô¦·âº72ÝÀô’´ŽFfžæ˜×ü¨‹<Ñ IÚg™ôG'‰x,KȤOÞS¯Ë¶¶œ\%·Ý}þ~|?#޼Ó" CÒÔÅ÷“y† ƘC†[½š_üåó¼å#þÇg>ù׆gGC~ÐöLÀË®iòŠ;wẇɸž(n6oÛ‹"á=ÚÝ¡Mk‘„™öèh_r–QÓý¾p#iÅ•öåGŽ“q颃ïC­æÌË>†j5#M¦S‡FÃ%MÂЧR±¸ÎÕݯæ%ïÚöò+Óûù__sn,µ°Ÿ¤ì£ÇžJAó™;Üù'çyÏÑ ØÀe2qæ˜jó±Ùd)y©ת1àµÛ¢5³™É“Øe¡èTŒ1–K—“ÛÒ¶" |2´ÖܳÌä¥hו­ð g^8Œ‰¢ ž=p'd“Ç8õd§:1W¯´¸i_ÀßïÓ}ŽÂáeZ㸼èÊ~û] ¾øœ8’tgŒžø?„×ßI–µIÓ µËCû³[-›³jÍÍ{Ý.¹j-OÜ#%ä0d¡ô¬nÑqD“ÂÐæcš&˜LäKÄ,-á3O'˜R“¥G­–áÔ«¸nÑ©‹ÔÎgüök¯âèK^ýK#þÃÝ-þá‘—†S:Ói–Ùk3<ÇñPñŽî­àÚ ¿óÁ+xÓná5ßaí pš,óÈ’$/2¸n1@3 –ö?›7ª# î)‹,ׄ4‹¨“8:±W.‡hyY‹ÛÛr´ oLÑ£‹©V3¶¶¼¼ûu:­Q«Öp=—cwìáEÕ{ßpÆ«ñ¶_{„wÿæ%º“Ó3Ïð§Ÿ ù‹Ó[Äé„Z»øÀÛRvß²‡+ï!:ç°ëš›ñk¯åÐ!˜£'?‹¿ñ:Æñ•$‰——MžbÕSú%¸µy¡Õo4"woË S… ¼|ÞÊqtl²hNeYè.O5›²H5ÅnWz=wá÷qäª>éðNeÆX^óÇ0Î%påŸIøFçQ,í÷7‰šWñæßz1&|YÔÀ8‡XBl–Q9Ð`]Íö¦Ïd"`,Á¸É»â´ÁT«òj˜N-ž¦Ë Tz¡²ìrYH›È'1•NÇÉ“Þ:«•Ý<1%%˜:j$¥#É…·Zvž8¯Q¯_OHŒWÁÄ`Foð,é`“'¾Ö`kX¨ú4Mxì!—ñùuꇎâ°Ù ³YcÎk iúšsº] º=OF¾døÎ,L8j ¦‚óTsÊ]ñ*¤²'+Oôi«¿µpñ¢J^Û_t¤ß¡8Žà™h¬™wÀZ|?c{ۙdž•—, ¨V!nc¦8¾ÏÁCp¸½Î#›S2R¶V¹vw@6+¤é.â8`ͦ¥×s±Öe.®ëÑh€ï5‰6§XËø£Óæž?­ò¹ïwøý÷îã®wÔqœ6Ö®2›U \²LèÇx,ë”B¨“ϱê:Ò´˜ò¼"¬*Oxåîòçêt],´qšN+€ë5 ü“IazÒ#mò¹t–š< CñvŽ™àIõ3Ž]`/áþ·sðW÷rÄ{ŒÀùZ-^ñ†6«/ÿUlv q¼Îhä2™yÓ¨e84ó »ÚPžÍ¤µGâK›Ó==û<ô¢Ìƒ‡ ™‰PÛ-l³crÎt”ó+ÚÑæº6aÒp§×܈cá$Q³™O«åàÔáµ*`ró»§ìj]/>Ár³Y@I1šyºÂækµ¤+¥ß/²‡Š;ªée[˜ÕÐCÊåN×ò°«v)Ú/s'éƒÂs•‡î´ñ*ŽMÞd^©3jªòa(caŽã`Lz½!$Ni߸Ÿ¤áT"­ßF¯ç1™HÒ` Âöý¢Õ×i¸˜ÍœÜi¨–,Oû”!&Ÿs]ÑŽò0‹N+ð¶Z¦U=Ëí"zM­¦;¿(¼JÅÎGÆ…mn:¹}¿è”ŽÁÁ/›³õ4«`GÏÐv‹½Ü¤QŸñ8d4’T±ïË=”‹)ÏqÃÅ‹ÎÿdxFzµ a,Ÿ0× }Cí¯<U¯3€‹…‰ê¯”¥]5P`ÖŠ¥Vm“D@^:M ¬R“Рq:-L¯ZÕ_Rp©TR¿ÏÚõ¿Db^ÇdÔÌÇ¡¦Sòqí°×Æ0-jC{«%]¶Ã!—ý¨À²£Ê5HÞ4‚ךuÀž=2P§®³œ»-ã•ïkKÿ⯨kH"¦SPõ®ÕȧÓ”¼X*c<*/'aƒ­6ý¾C’Ƚ··eQfd¥u§Vaë5ú¬âeE«”³9N1R^¦: ´¬b2dg9sÆÍ3mª¶eVÌ‚/OÓÈl©iÕáMBÆc9µ¡»×3óFtË™gVÃÛpÝ}ÙTñz6/8”îåIB™¡KSyN^9ayúÀÛɵsëÂrG#¹(Ša×2@« ”Œ•=šz®fSÊÚݮɩAYˆ’ƒÑÔÙVcDCäm>Ô«½L:ó>Êgµž†²Á³™Yâ$1s80ìÙ#C½*hEÐç\H¹–½M£!¤?“£‚óý–MLwhÙ– ¬)L®LPE e¼JMA‰kµ*_2iÐ$G »že°{·h`9àLSiÛ‘q¨ÂsJaç˜ûöeL&†~ßä³´I²4í#‰.KS2º#ÚÛ'ZdvPYHeêØT§cæ;X¡`Õš")òã:×!øPŒCèÜüügmð¼B3'òïPÁÊ”óâ„!w”…¡eÿþŒ“']ýIŠœàzžW< h^Ú²¹)³©e© ë\4«ÈeÙT+›ÿPR™”½ŸŒS± =2¹(&$³úEÓºÎÌêõBEëË £ìËä¯|ކ>õ”››¤†C@æ­®Z;#øº‹¿á£7•¦èá[LyÎJµ©r”ËÓÖYVp¾j‹ü„6<©†Iœ®#Š4¦[ö´eÖ¿¬ñÆ0g×ÅLI«eÕ“¦ÞlfÆÕª­¨xM¢•¹ŽÄM‹ÙDzÖ(‡ÒÒ€³hÏphÒ z=H„_þUœ´O}@ýƒr¨ã8ò=*ð†å5kJF#ƒÙÌäÃüw=FÞlÆ÷|ß¼re¥ðXjÃË7ÞÉŽ—£Áaªí¶Ô˶·…†€òõ•›ÙËcJ·ig˜j²®MµNlX_—)Gíï.Og?צ–©ª×Ð^]µ$ ßô|Ÿ?®TìK¶·©*I,cLyñ;}AùPÓHS3X惿vÞ qù6©)-+XjVS½’~Ž”/³`åUå‚[a/_¯$Rï£)›(¢S©ðß¼}ûì÷z\Õé˜YK¥Ù/VÞ¥e-*Ûð²€ôT: #à‹Ck;áÀ¢Ë/åò”³}Ý®¹L@Ó©¼¯¥,ý®2-)o²x¼Ë qL¯Û5ÿ1Mù¬wæŒg¿—eIÒ%tEXtdate:create2012-05-27T10:48:29+02:00Ó+b%tEXtdate:modify2012-05-27T10:48:29+02:00qŽ“ÞIEND®B`‚fractalnow-0.8.1/gui/icons/icon96x96.png0000664000175000017500000003154111764667445016437 0ustar mpegmpeg‰PNG  IHDR``â˜w8gAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAg``xÛÙô2AIDATxÚͽi°$×ußù»7·Ú«ÞÒýè@ƒ@€°™E D‰”d‰¤-k£,qb¶&<ü0£{8!K†C²ãðmË£PŒ)dNŒåEåwŠi’H€¢±6ºû­µ/Y™×NžÌ¬zÕ RädDE¿~/+—sÏú?Ë5¿ñ –¦üðsÆpo«å¶¬ÅìïÇàœ|^í0fñ£¿³¶øx4›ŽV  “‰\WÏ‹cHÓ£×-_K¯¯×«V¡ÕrX Ž#I ;;†Ù ¦S˜Ïåšiºøå÷)_3 VƒÓ§S&ÃÞžœÇÐíÊu—¯µêÈþ–scxÞ>c ¿g ³_ýUƒùgÿÌEníðÐüJó7œ£†òBƒa8”Л]_þ” Z…vÛ1Â``pN^ý¾É_nÕ,_ÓóÀ÷…hž'ϰ¿/„šÏ!IŽ>¿1¬¼çL²¾Ý.ŒÇòL³ŒÇr½òw—¯†Å}—iäy\´–éyü#çèûý>•Z_©×Ýÿ2™/I ^wÌçrÃ2ôçËgùÜåsôˆcùÔëò ÆÈ=û}ƒµ…D\N –;Må:ú³JIYjÒ´øçÉ‚M&‹D²Vˆ§ :Áph˜Nå<=·|ïågóÇ2ñõúQ$pÎ1Á|nTï«ß)K\™ zŸ pÌffáÝ^M:õ»¾/÷*¿‡Þ/“²+ÇcþªÜ«å ¢‚ ]\æÊeÑÓÅy- ßwxžÃ9èõÀó a(›$—”異]¯;’D¸¼¼ñLfli Ó©É¿«*Èó ŠŠë{^ñ³- a42 …j[ÅXËô(;úNzø¾Ø¾0B]ºd0ÆÝá7›œð}ÇdbØÞãEò…$‘Šã—k¡ZuL§&7t—[uÐë™\Ôã<Ïå4 ÉÝ*ãX©È9ûû…a-_?ŽU½Éóë}ÊÏ¢Fv29ÊXQäh4dö÷í²´½ššN µšËŸA%¯Ù”ßíì˜Ìþ˜«|cœLF HSùr»íå˽ÞjÏ$Š ÑPé9ê%­ROeÎcñ‚66ä~ó¹pÞòbëËO§†JÅQ¯‹ª\6ŠÊ•qLÎDA ÒÇ!ä9L®"ô΂ÀeÌ ŒU¶Ke®WOh™!õoâÙ‰úŠ"a2¡¥Hh’’„ãþá¡Y ŽZ ÙÆ\¼hVF58Q$¾ö*;ñjž‘Æ ÷ß/^´Ìç…ÊX¾Žª‘Z­ðÐôP ã+ ÕhHlÐïߢ➺¾_¨‰ óG#“{Tú¼¢Z„£Ñ¢_–v1æ0Š·pé’xUeóUÇ•ÅÊ÷…ûÓ´°Ö.ª!%ÈŠ/?À*U´|Ljû©/§®Û²‡¡ <Úm1æ*¡ú÷(’çõ<ètR‚À°·gsâZ+o6!Ži*D®V…Cõž³Ù¢¨‹Ðn‹{ªäòûxž”âåmm%ôû6S›æˆ–ð•3tµQŸNõ†ŽN§š”3Åš»œÀeN¹Ü¬ŠÒÔàû½JÔ ÅÖ¼ü}ý}¹ÜëßâX‰JEˆèy&çp%®]çLn@$¦ÓqÊÏ zº,­­–Ë]èò;ëÃj¬±¶–fªÌ®T™~™`Î 7O&ŃÎf°¶& …Ç£0™,añ—oª¿+G§ã±¨½µ5GKR’Ê:~21Ôëâ,¨ÚÔsÄKQ¯VÉ9»Zé ÃE¯j>—‡Õä0ÆòÞå€. EêVª¦²´´Z.†Ÿ~Ú'I$¶:‰ RxäÈèG =ö÷åžç2|Åä/¯Æíµ¨ ËRâḜ(/Úü÷«^R °¶&ÏSÖ×úÙÌÐlŠÁžLL8êuY¤JE>áú}Ëh$ÒŸ¦‹.j­&ï:™˜#R_þ¿ªžvÛqá‚É¡k…Ðj—Ô†ù¼Ê‘¦" ¢'acD¤›MÇpÈ]¹ÊÕÀgU¥?kô­®m›#pƒÞ# Egw:Žý}“ëÝ (¾ ÂekÇ`(ÏŸ$â™]®¶ôz½žÉ¥[?¾ïòŸXV·ªâ”ûAü|ýûlV车¨@÷ê P>¦SÃhäØÚQê÷êB%Ò²gÂáÓiá–ÿž$¢‚ÂP<ªZ\ÿV«´©×!‹,úy8„f³P;žG1 U ª¸ ž0¹î¯Td!Œo©ß—ëW*ŽáPƒRY´ý}›pÚUçrfS/J~—»œ8'L1ª-5ŬBËzW0"Ãúz‚ïC¿ï-6ª×VE‡ž'ØÊpèrôsÕ}˶@$ÌP«‰a.Tú<³™\¹Z=˜FÃå†T@¯”µöãxæRNÑh¼‘Ñȧ×Õ¢ÛÕŒÇ& %0›Ïe¡<Ï,¼_àkµÈƒ¬áP˜b63”aðUÿúe• b¬*C]7ßÑŠ"¸tÉ#Š\î3‡¡üÜíš•„µ²pã±`iêPÂe¸Z¤ 66\æÍASYת72›‰á><,À5cÈy ·aãÏ`½6Íæ/›D‘èìÁ@lZµš2Ê{T*²¸Æˆê™Í ã­F]¡±Â(¢ëM¨•ó«>~Y‡¡©F£ðz n3”ahX_wD‘c0£,žËÄUï*ŠXðÊ8SI߇F#ÅØÞöscâ~zžxbÌäçVKTp'Šb<;úà¦xõ ¶æ1xæ"Çßw/&úp!AÐn˵÷ö,Óiáyž¨YÕ•Ì«Úß÷˜Läÿ*Á—sdÊîv™ÞGÜÐ2³J—M&! kkŽõu—G Ë`ZùAlk6]îõ”Ç2ê¨G½.ÒPŒ:î÷Mîı¥ÕšÓl¦$‰O¤ø^Ø^"ƒþÃ_âëäáUÛtvö‰NŽÀôÃ:iÚb8ô‰"8ÁP¯§¹‹†j'½žÉÓ• è»–O0*—¹Íæ`é/súªHvyô"ÊÁó9?î8809Þ²œ¸)ÇÖÂúº¼ÄtZ¨õ¨’Ää7˜Ü “ÀÐd³HsE„)¹akÕêÏáÒsÌ.ý Iÿ1ª[=žûø>ôoo܈øÍ[_bëä#$½±Õ·ãû7ÓhX¬ìfm-Íñ’ÄgP¨ºìù•ii-yN ŽÉµÂ2}ýe•‰ö­åÄ$ƒU« ·êJGQ$•9\ ¨n¬F®ahhµ\îG—3n›› “‰%I$‚ô<¹G»-¶@‚½°xžÁófs‰éöaï¡q᱄7ã#õyt÷EÆq‡G?ÛâÒàØž ¨_Eš®1›…¬­¥¤©¨•ÀVK¤ßJKÎAT®ª§$Ñ€PHrõ¹ŠÆþ²È\n!.—\Q•£âY«%ͦäe+üsû$J\[0l9«AH0¤±D­ær”6Š$òl4æD‘XªÕkS|ŠaL‰®ð"Æx¤ñs¸y¯zž]<<ÏÇp@šü7¢æÀ Y ”’$Ãt»ÂõZ ´œM[,«ò+•ÅJ„åZåHEü&“Å=g>7Ìç¢6öö<66$ŠNc‚z½ðÆítÆc/Ov¤©¼ŒBi*>~­–`­Å÷lòuOü6“!ôŸ?àØí5‚Î}@Ä…ÇåñÏìrÛ;8¿=§Êyî^òÃk§xððÓiŸ ¨ð¶ö•ÜÕÙå©ÏOSNßò$³f\xn“Ûßÿ‚úõ@€ÁáÒmçþ3µ“#š­³$IH¯'8Òxlu¥£¨Hì—ý¾/t¨×¾VB¨ï¾*€šN ý¾¸ŽA †G£B]¬ù\8[ÕÌá!4›&7¨bˆ‡¯Tä|Uo¢ïeq¥nHž ívJ[ŒQµ3ÆóF/$µ_ýÝKôošŸ§rñÓ¼áÇ¥ÇÎóO>l¸ãÁ=:çØÎŒç '“dÏíx´À~gFã÷-àÞw÷Kœß Ùjõ¸å=>A}ÌôÒ.óiLíÊã Ï´Ï6# o'Mmf¨”ZTu /P#ùf—$΃™Ï1£ø†«¬çWiZÜn T¬ùáUiFżVN’âÁ¤"e0°¹1}ÂÐå ŠÕ ¤0#M=æs?×¹Æ qé|Ÿ“·ïðáQá¥Ïõ¹÷¦süâs{|ä?F<öÊ€Oœ2Og$î(83›MÙc S`0Ä`xê?U‰ágïòÅ'Üõ¾m¾úÀ'>7~ÿœh'Å âØ»î$Šn¥V¸b8¤Õ!Š(k~"=vf00š<åékDê\åL§«Ó€ZXÕhH4Ç‚Ë^^T*«ZÒ$‹¦Çc“#‰Iâr/Ib—¹q& x$ã€Z-& AcÍÜŒ¡ý¦kxôc—8·û,]:Ç¥Á&?Qá3—.2M&yöZ‡c0ð‘¯Ìùúßù;OnóÛ|þ™.§þx“¿÷ã\÷†uLp6)옇Z<.ËY;lVä+x•ç9£ÅÉi þÎŽ¸Vkk²ª^.Wï¢xN§ãhµ$ÄVUËÚËÕ ÍfÊdbsQT¨e)b”Ò S—|C­æ˜ÏmVÙ` ÃCŒ±@ØÁ° ̸æ¶ÞrvÎ3û5¶Ç‡¼<‚ôˆ·óúŽq2å+çwøå¾Ánܧ7Ò‰6×·¨^w6<…™¤xž—#¥•J‘•Ó r<tYó ª†Ëý ~¯''­¯kÂÚå6¡\’½ Xj4„KUíÙ!ñ‡%>0 ͦxRªb@€4ßB™÷äy’:¬Tb’$ gÙ½Sp{¸ôeæƒGéž{„ÖÙ—8÷ͪ±#°ãÙèÛ"ü‚D8dzÃ=Œ5\YëðÞ·w8u×Uïj0~ÎLµš_¢fËxLfóÄîù¾Ë¯Æå~_Wm<–«×]^ï3ì2ñ§S“qÖºý;_æ‰/pò/ò{ÀOï0OƯŸÊßzp)´¹7æô>øêuËlæqx(žÐhTä$7P.Ö…]¼ƒ¯V+’Äpì˜ËŠ£\aUkeU$ÅZ’Ò\ªÀ ÂÙͦd¨*‘–FíÖ}üëÓ8"$xò0&Ƙç,ÆøàÆ`b$ª=Ìô~¿“Pi ø¿v‰'ÿ¿Câ$þs"~±Ou÷¹ÿÖƒéy~æo?ƒF˜dkoŘ*PTlkЩjf¹Sf™™}ÅÿÕÉêG‘”áiÝŒ¦aT“” ¨/ßwÙÍM^µ¶–fz2Åóñî§ÁûÁúObhƒ³`„Èéø&< Þ˜4û[ Ì€}`GŸ[~àeÞúŸ'|éÅ)Óä;§v^m~¡Ë‹çžçÒW?IóŠ'Hj×ýDÑÕT*ùAÑ—¦ù„UÅzX›¡¡eÜ_ÚqL˜‰*±V"Rí:ÑD·¢˜ZÉpüxJ¿o™Í$ÈpN°œZ-!ЦÀ¤·‡‰öaý p BâîcŒŸ|€æíïï& Àb\*Rbz¤³gùÔï?ÍÇþ àãOî3M&ßâgMÌ|´ÏÇzœŸÛ+¼ã‡¯¦~ý ÷äf3Çcò®åüFŽÿdŒ%0._ë¼_‚¡õõkm.R=Àl&.¨JŽ6É &«“Lñ<X €ŒÁkl1{þsL/ý{ŒÑæ:áɳ>Íð™mÆÉClÞy‘x?%:v‚5p€ëaüméK|êñ._Ü•…ù®ŽÇwºœI³Ê:7¼¼N–„7¹+®6/ ÉœŽ¢šÐÚ¢X“8¾B©Ë¢¢ Óx –ZM2^*Zql²úw1šÓ©¡ÛõX_ÄR¦Ùœ)ÖÄ@ˆì.¼Ê>»˜/|ä$Í«¾Ém?õÕöˆ¾ixàßôùŸ~ézçšœ|ÿy'®Æú-0c†{/ð§ŸKØŽÀ½†Ì÷wø°~ñ]-~þ×n¦±õC$I c\nï¤ÀËæžˆ›-ù— íÔ†úí¶ËŠr™¹äY r×Ö½^Qf' .+„Är63llÌIS›ðÀï‹1¦Í+ð6Bx®ÇÇ?¶Ãi³? xä|Ê—÷¿Î¥5Æó„ùæ6w½ï×þXŒÇ´û_ÿF̳ýîwø±Kyq'eÚ½@¥ú2ÔnL®jÊÂɤ(f›Ï `²ìŠ& øó¹p²d}ÈÒÊÚoDzzžÖŒ‚Ëüûç Ib©×癯<bñdض1n·ÛgÒ3¼Ð»À¯nÈ`: v1¸”ÿëk{XkùÂùãüÐSÇù ;àÆ;dïÜŒG^ HÝìÏJÃoóp|òË>ò¾Ì_ýßw©^k™Ï…éz=‰tÕ”]Q%¸º£e·Ô…Û«U *ÂPK0„Ëëu—u'Ê´Z.¯{,ÐLq7k5—ë9ÏOñ½Œé‚“Ä·›ŸcøôGÙyi—§>ðbŠKSöG»K/:'Ià›Ýó¼ôÅCójþ)=·\èůfßÑÃpÏíU~èßDõÔ$I»›p´oMíi9ðZ>|(ª “D1éÐBQ/ y›k&_¬v{Îdâ&K’€ç 0îY’îŸàµN1ÿÂú.Ÿü7 ¿õ`̳½óß6˜ÌüáÃÏq÷?lre<¡?ùn¸—#?xi@gí~íÉTòг™—Wj• ¨ ÃrR93˜¦K…Yš,?ü… 7{×3™ù{¶jÀÞw%õ+ïĹ&ÓiçD-“ãÿ hªß/Ú¢¨™Rï/7¨ÉB¦SI°;&®f­æòÒŒju*‰oc1ÆÃ˜¹|ˆ%zu`CÂÓm^üÈWÙ¹à1ÎÙ&|þ}¦óáëzùçÜ„ù1Î#né÷à¸ûÆMÞö#÷PÛ¼‘$ 0FÍ™ˆ:_¬.TF*¸‹S©+ÍR’³™ÉÊí„ØAà²4!ÔjŠ%T*s|еÏbÜ×Á¾ h yØ.sànú5Œ@òâãœûR•ý‡)ÛÃ]®oœâ™#:ÿ[óùˆíK_Ä}ÜO€O·ùÛº—kî¸\›4˜Nm†˜<ͨ¼¢ GÜtir4yJ²Œ¿Ó‘ÚNc¤ÙÁZ—gú·¶¦ln^$ö±f ìa̘áÅ/ñÅ?þ4wýÅ·Po_I2¾È¼û"Ag Œ%í½ÌÁ£Oã§)ÿq“ð_SÙyŠysa¼Ïk(9:r8ç˜L¾=˜ùÏrX ï¼³Âý¿uo½ï0›ˆéL ÔZMGZM×ëÙ¼ÀXºoÀ÷“<~Ò”e’ˆi_Ûc˜#“GmZ¹›}²ßkä¿Öe‘öŸ…ìÿÿ8œ÷çtû‡‡ä*È9QAZ‚wñbÄ|~†Zí4Q”R©ÄxÞ”ÚÖ5Ü÷ 7e*¨ŽŒñZª‚blý"¢‚îyãg1iÈáÞÀ˃‹ÜÐ8Åö{/¾®5ÆU<¦“9¯#Ñõm)Ž}eÌËí+|øŸà¾Ÿ<æ`™Í¤©O>â9jæO-QAR.Ùë ‚»9¼w¿ûþû ?V;úŠbTk]Öœf˜Í|’$Ęu0×âÜ&ε6°‰¡¦40þ•`›Pëážç¾›-ï½£Â_¾þ€‡ž2¼0x}Ñl48µu'Ýþ˯+Õø:v{S.žÛçmw´Y;y=ÐÀ9?w5'“UŒ˜|¶F¥7 djfF:åµ ÄÍ4¦èÁÝÝ5™“é!•Š¡Õ (wC«U­LKñ¼1Öàª@—ÙK]®x×UœêÔ0éFßñý_©óÅÝúëò„ÎÚˆ›wf<ÿ=ò€¾øä.úÑϲuõíT7¯È“-âž»¬ŽILçÌB$ÜëIŸB90›Ï—ú„¥zÙÑéÈ—ö÷M–ÃuðêphˆãbÌŒïÃdâ†ÕªÃó*RÌä6Nü¼æ•` ðÁÆG¹îT™æqÎu_zM±@%lðÁ»NÄßàÁ/ùŒâï't8ŽùÔ§¶ù‘÷}™Ú±·E  Kšz å÷R˜àònÈŽ(º%ó =OÕª¬b¯W@Z`›¦:£!e8´ÙH©èv}âØduùAÖEÓÀ÷Ïâµ~]Ü|F<:Æ}¿¸Ã•ë>ÿà¯åÓ¯§L|“´Ž?¤ C‡QH§,R¥Rrž—2ùHÇa(œé€‹>Î\ÙlQmF\Ó¾‚ÞÑd’ððyÇ—÷xïÕ&I•wÝ]á®÷úœýÑ“`}6Î>ígf|m;ü!¢†ûîlðS:Iuë¸4«zª^wt»h¨¥”¢jÈïv Ž/÷ÁJíŽËçÞÔjB| (j5²²q›]ÐdÑsJ¯ç1Ÿ›bÄØ¼Eà‡à&¤ým’½)?vv“Ÿ½ÏrÛOO¨¶¦<òoÀ˜S™Æ(&Ș‚¢`¹˜}Ttý@Æ)Ñõ_­xÖ}é‚$ç‰~3 HŸspé’¬œÄ&pä,ÖFø^¿¹Þ:p#˜¬,‡ß^§që)ðOë@Š!+Kq3pžåÞŸÛçŽ[¾ÉüoÕyüÒà»T–>?óc-þ‡¿y='H÷œkfžŽËN©äëÔIµeÿ¿Ö‘å”Êùͦ¬ÎÁ[çuj¥[yÌ£&e†CòÂ,-?ô<)N­VÁ ,^ûà_OšžÊ¸ß‰‡dÖ±ÕÓ8g?Ë¢ùòwMa×äkŸ9ÉCÏoÓ +TKw6øsçþ;®nsÕÙ«8vóâ…7â¶Ö˜Ä[ùÐÙ^¯hÐ(gÉ–[}—Ó’¾¬^׾آàV{‚µÜ¼Üé(ÅVb ƒbœŒï ñçsé¡R›2<{ß¿›hi¢É›­ƒ ÄZqAµ WÉJ ˜ 0#îzLG þÊ÷ãÔOøwdø£o$ŽÕq†ÚëÜÿ?×xçß8… ®®ÅÙ+HÓ0'°–Ÿh¾;bè]"Nc<ÏÏÄüÛÏc9[[g'óʨËù¬Ï_yÛ œýç1þ-¹JV$Ô“O„)5¹lŠ{Ѭ¸ãùˆÓMnlWùô¥]¦ó×× Q>ª^ÄM';üêÏ~ûu>÷ŒG«ÒfwÏ1~úT¯¿çÎäVÞ­ˆ€¥ACgJH| èç#ú¿ß/Úk–gÛ”‰¯C§[- ®´Þ˜¢;F%¼NFÑèäj_@§»,§*éP5lõº#b&$±T«QTÇÚ1¤ŽîÏrÌnó†cëT<Ã=7UøÀû÷øÈÜâ_bÀÎxHœ¬nQZ¡l¨ûUæÎðÓwtøÿæoyï&ǯòä'áÆ·Í /MéŸ; rö)‚lê4E­ÿ×|€LrqYߜ˧«¨ÖPúúƒAÁõ«&ß–g<´Û.7\žYÆ<Ô;Ò™=Ú;+Í d³€dB®v×W* £‘—Ïé×¢_p AÖ¤'àŸïŒ©KYxš°ýÈqÞÿ&Ç›~bNåÌ®}ûYœÿ2?µÉgwyèÇîpÊp4¢? 9dÌd2$ #š¶N͟Ѩ×hÞ÷VËù€ã­cü…w_O¥s·þø.7ÿpLõŠ—>þyZ7|?×0H2¦ÛÍj<}—A ]©™Y“Îé.³ª«XEùPî"™6«œ»ªMUÇ«¤´Ûb|ú}›ÇA 7Щ³š‡(¿Ðà®Ñs»]ñ–šÍ”ùÜ1Vi4 ^2Ã& ·þµ zϰyÛiZ7Þ T8vó£üòw¸õüäöœšyî'|~ów×xð`’é`Ã÷5:ü_èqü]uFãSœ¾eƒÙó.<·‰ß|p=ѱiÔx™ÚÛøõ³ÌÜÍÌf67´ý~±Éƒ&[t2Xù£1€Â<õ:øJŒUÛmhÃô;­nÔ#\®÷76R*ØÙ±y¨öe0(fM«Ú:8ðòó ±k<6Ya°áðÐÏÂÃø7Ñxó/Ó kß÷<.I€«”7oq⦰C6n<Ïü0á_ü?üÉþ L³Fí8žð¹Ã—yhÿþÖÝ':wמ±œü~iÔÆu‡1êgßËÜÜA¯qx(º]ô|á4àRƒ­MÊÀáÁ ã[&¾I"*gÕ¨•µ Ú$&‡.´F[žt²¹"¬ òi¿òlF¾xY2úøþ1ªÕ^2Ç«_›*pÀc×À.qᑟþˆÁlÑMÎgüéç?ó™×¾ç4Î]‹ 6 hã\›4­àRG<1¦ÍÜ]Åp0êö&2ÔCÕ³µäê¶¼˹cŠóürsݪùê-/[5¤U&†u)],‡à:ÊEÝ1Ï#_••¸½=“××€ÉÇ 6›Š›2†T«>adÓ Ï Ðèb Ò~•35‹µ>iZ†± ÍŠ¥ZÁU1¬ƒÛÂÇuÆc¹Ödb°Æ2™šëRõ©]ò¢¦]–,ˆ¸jqYãøËã ŽxK¾ùÜåÈX‡*õz&'¶Ú—òË`k1Z‡‡Åœ é.w #‚uÛ“fS¦(xc8´v•Òïû€Íüu¤xÌÌÁLq©cóÆ µ W·Nð|w›ÔͱÖã†+¸åŠãíÉ`€×l‘¦uf³ZæúJ-¬T;ج۱pBÔcSU©`¥héîKeÂ/ö̧§¯"|™à«Iaiß/ª¥UÇëôG],­DoJàWè˜Lm MƒÒÔíò`NE¤cßg2;1ëÜ ™–hˆ˜m¿ÄáÃ]~üŽ9o¿£Á¿ð&~ÿ‰¸¾Ýáï Å]ï3Ùn€]êÄqÄ`àeíU:O$ºÝNó•ÂùÒ§ˆAŒ§•æ:°ér‹°Ð#¶Šð¯v”GMnnŠ.×F„òÖReÕ¦ ®]•åÆÙL°–·¢ÒŸ÷÷½¼Ú¬\ ßíñÄtêEbÄ“$ÄóŽ^ùlÞS¡sÛcTwY¯^à©S¼a#äû~  }÷}4Øð:â¸Åtê1Ÿ§ôz6ï[îõldÙ|,=h@zª+¯EºÚCìû2_Œ(¢,eN_&þ²ñ-ûþ¾/°rúrL± 9h¹‹Š§.€ôQÞ‘ŽÊñ}i‚V½©*LÕAItéy2)1MƒA…ZÍ# În½‡ðÄm¤ñS\ýÎñ[ÃC¼š¥sÛàV¼æ8w‚ùÄg0°¹ì÷m6ªuhŸtš…w-\õzthŸµESûÂ\Nõ,]?•ŠôÄ1ùó4äSŠNcŠ2k+l’.í*T^0 ÏÄi6NGWêsK¶Ó‘É*£‘—€cZ>’Oð í·ô¸1ù(“{„›·UpMf³&Ó©ÅóR¦SáÐd¨°Í»eà¬0Z»]Àð:¨J¥aYïë».ïè—/À²aUOd•ç#‰Ë‡^KæKg<áåE,_q¤eÀoy?/ÙÑB~§Ò¥‡Ž”ñ6òíð?<´H2(e0ð¨V-¶^dzM0!ÉpL:Jh¼ñ½G£ru‡pëâØ£×ó˜Íd†´ö:F&w™‹ý_áÝØHHýý£PÎ*ì%º< ) ‹¹È«Fët­cÇdXÇ… &¯…\µÁå"–ärUSÞöª¼Á™Ö¥ª.W¦ àû.XvÂ0e4²y…Æ``²Z§4Ë;ø$ÃçÙûÚi]û&*W½‡dÔƒÙs$ñœñX ¼LQ7yUˆTžçw¾ð!I¼ìù]ÞµÜ𲌯-ÛФƒ¨W ïVî‡b·" ¬<¯,Q?jtëuÍ%/ïÖsud¦P‚1’CÐüªªn·˜B¥sH¼ K¬›fv%ÂÒxŸÔ6 ¯øIoÁT+$ÁÁð8£Q±Íp¨ÅjÅn|jHS‰UhsÎeÓ{Ý‘¹q—s` $êÑèì%¬–JÞÀå»]“oʦs$–}Ürçyd(ç¢Téè@(ÅI4à*o€¢vÊN€ {u™š*ž' Ý®Ív¯K íâ‡=¶n½¼•ñx“ñØc>ß`0PM‹td¦ìMPì"Rît\L™R°2é+ò#ËösÙÛ–$K³£Ë…¥Údž"†Â=‹ª@·Ôò»Uþî*Liù¡U÷;'DÕEYõ‚¤•›¡ËL¤®i½î²ê‹"‚Uu§Ž…¢°¾åùê&—9]P¹Œ›iQŽg ö}á|Í5s^yÅãüy›/ºÚÍ$)MO/‡ÿ:ÃSv»‹I½©Šî²ójGy1t;ke¬Y¹²l/GÓ²ãébt\ÞÈM%@6š+<4%H“Ë{⤮“|ËÝKs9—ÑíʴȲí+åÑojûö÷mN'ß_”*Y|‘w ß:Že_ŠÑ-`/sq/èt¬ËgÖVý_¡‹fSô¯º…Ë‹©^ƒB’/8šFUÛT©Hâ_J_äõ(”ºZñé¥ËÝ÷ÉÞÛåSV5RPP<ûò¤á^ð °ðÙg=j5Í©»¼Š$;¿Óqn:5F§'Jw¼Ë6*(^`•‹)¸ü"õZ8¿LTeÕýe.)Ÿ[ÞÁI¢ÓE׊´Å˜ªåÎUպػµø<ͦ´œöûG!d5ÊˈoYJU…J 0ù~;µ€¸ÉY\ûΙ´VsVLÍm*ÀT¾Ù²~×mÁU\Wá«’8ú ‚bëUs—‹'ÖU$µ\<¦(Ç,EeÂÑsõ9–íLÃI4O¡×^Õãµ|¨zÓ LQP­ôX_—vðû}·¡¹ºÓ‘15‚>¥—ÙôÁʰò«Š=À”“¥Ð‹V.¿åÐmv5Q¿jc-Ã&./ª>“T-·™j¢\¡f- [^àUîvyQ|TÁ²äõûbÈeÃOƒ1îœ|Ö9®vNDW»;TôÊúoÕMW©eÜ£øž¶é˜|ÀŸl”Ypé²[Y¾Vy¢å¼´^¿œ0Š"—srÙ kAír¦¾ëlF>t\Z-/ªy™QÕn–é'ÅhºÓ¶c4⓾µüAòãÕ*k¯¼R$›Ë™ý2G®&ìQv•ÁÕª1uug3ÙöU¥£ìý,߯ ”?Ë×Ñ—z×e&Ò먭Xþ[yú$\|‘UÏ·LUo«ì„njǼT©ðû6Mùx£áþU·Krx(Eºi*†x«)¯æåú^_íAËßÑ ƒ½=“ƒYåÎÌåë®Jp¬b »\žÛSþ®Únw±“½üwEG—·ãZ^ˆUÏ){©±_—¯ 0™˜ÉÎŽùÇÕªû‚ßl2Ïù­¬Æÿ—œ££íEaXTü^Îø,Be5t9‰Ð~…n…KLžØXåÎ^. SŽÓ9<åé…—#”rá*ø\M[OãXâ ÐÆãËK©JbyBbù;ÃùÙŒd-¿ýÔSVºÆ~ýׯPMSÞ¼ßÞÞj¹“Öâíï‹‹z9Ë¿|ƒeõ°œÄW̧Ւ¨W;Gô¼r„¹|ݲšÐóÈkµ4‘#ÖÎŽ)áVG%v™påkªËxú´ìœ´·W$¦º]³2ù´â˜g³@l çŒá“Æð{À’_û5ÃãŸÊ?úÿÜÕ%tEXtdate:create2012-05-27T10:48:29+02:00Ó+b%tEXtdate:modify2012-05-27T10:48:29+02:00qŽ“ÞIEND®B`‚fractalnow-0.8.1/gui/icons/icon48x48.png0000664000175000017500000001044511764667445016431 0ustar mpegmpeg‰PNG  IHDR00Wù‡gAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAg00ÎîŒWIDAThÞš{¬eW]Ç?kïµßç}çN{;Ì£(µ-Å©@ £i$bˆXäªø‡ $FHMHÀ¿4‚ÕTÅø‡¤(*J¤˜˜Rùƒ6•W¡fh§3Ü™;÷ÞsîyïçòßY{Ÿ;Å@g%'çÜsÖZû÷üþ^W=ôPÕÝÛSüN±5¡òŒ¡^Jã4ïZC’@’&…Ö°X@UÉ~Çi^At:†ý}ÅlEÑì­*¹×÷áèQCQÀx¬aÇ‘ÏUE¥ç<‡´æ3:MÕ‡ú}ó‘¢PÁ|~xó:W¾Ê<Ãb¡HÓ—îu!p±€(j˜r]aÌua>—½q,çÇcÅbq˜¥ ÕÆ—K¥8•$|¬Û5F§)÷õûUe˜Í®+‡íA¥f,Q¾/Ò÷<C˜Í„»ß÷e_Y6{ı!MJ‰A¤,š2TU£¥äœ¥CkyYÁű‰Š‚û´Ö\·»«HC§#Ä,rÐó„k–²„ÅBQUà8†vÛŠ<—‡G„¡˜—F–)\׆B´ç5ïž'>8P#Ïð&¢HB”ë6¶éºBк6@l:M… »:C(²¬1½ ƒã¨•™¡–a‘¼ì],mh-Z®*¸pÁ¡(Äœ‚ô:Òd™0tòdÅö¶ª/±„…¡Hh>WµÉÌçŠ ª*A%‹@í¶ü$òÀÍÍŠAÿQUªvè¢gùýÈCžËoIR tŸòâÃèÙSô{o£ÜxŽ£˜N…ÐVK,a0¨˜Ï;;‡ãÌúr,Ë¥po¹LSØÝ L-×m˜oð|2QD‘hÓuÅ—|_aŒbc£¢×+ ‚÷ðûÌÐIH·» I ZC¯'wöz" åRÊâXL«þΟõ%¸Ýh¦ÓiNXÝ®@šãˆSU•ØåÑ£³™C |†¡!I ÕÚeùÂçyþñ¯ñžçÆS÷_ó’7ètî@)1]­%¥ØÝU…½_ 5ÏÅ,j Uö‹+²XÝéÊRT\–˜1ò}šª%@ÕDG´Û¾_ g‡Åü"ûäYþù[/²ñxÈñ­„÷>pvçF\7Fk—,S ‡+Œi×x¬˜ÏWð©åù:Ž©#¨åÔFAˈ1“Z._Vµ³—¥¢Ó1µiõûf%1Å`P’„ÛhçÇ8®JLy¯5$×K %³4ÃàEå!I|3qÜ¡Hwˆ‚#(5Àu “‰Κ®ç MaºÕ2L§6- –vQˆãX̟ͽ´ÛÂ\‰É´Z6=P«h+hÒj-)w¾Äwÿå+ôîà&ÿùÅ2œoc®ãÓ }{ì{“ÏqM²É¯½ÿíøþ€jï ZÑ[è÷ß½‚ë&JS‰Ja<¥ÛmQÉ:<ÍçŠv»‰ŒU%>±XˆÝ§©\fŒÀc«%Ÿ}ºÝß7øþ˜¢exäñKüû§¿Í©ëJ¾ô1“4¥Â†íYÆgþu†÷o—9±³;}‘s?‚.÷~p‹¸_ž'‚ CA¥<‡Åµ·§ÐY&Ñq6‰¯rn²Là¯(Dºí¶+D²‚W‰ªQTaŒÅüŠÀß'Ÿ~›tönkÊ7ŸÛãÑgr /]†Ü”œÙðGö, ‡ßñ+î$Ïœ•o™U!ÄÛ€–ç ÇcqÊv[b>WµÙ¤©@aš6°Š£›#âè"8Çëf€Âq ”JAçÜ“ÿÁ§?õ_~b›E•†Ÿ¶&yN'ðèQ="bßß"Ï…®éTk­ÂÐE!øï8â››‚*ÖaŠB±¹)ðåû\ZÉŒÿÝ3ÊÝ ~·u JoSžáü¹3ü×·.ræòä§¾¾Æi΃ÿð ƒèAN¿{IýZ7‰ÍÇl6PÃh– ¾öû6QJ·Û”â¸B{PVKžÿògpû]Šƒ³?êrÃkOпõ&²ùy~ø OmO_ñv=õü˜çÎ-xGïóLP' Ý®À÷tÚø­îtÄŽmnqp uA¯gp]ê™$ÐnDÑ ¥Æè^—Ǿ¾ÍßþÓ÷1NÆî¸ä¶Oóûþ¯|Í”o|wCyU TÆ œ ¥#Lê ”YE{År)™ªÍôr)A¨Û5h-¯µ`º ŒY•%QxU} œyúkñ…¯îóØó—jBŸÞòôG‡|è­š —fWE<tw{›8ÞµT•© §úÔö«l´(ÄÖ{=C§£èvÝnAghW¡½×£Ì÷˜=ûlŸÝå«oóÕ§®”²á©øäÃ×1Zޝš“[mî:ýV*÷ZòÜV~â¾//[zê~_$†Ð땜:5$‰¨²°=C²¹…Yîcª)ËóóåϾÈÇ?ûÓ¬$7ùKn0üpySU/—n®é»üé§¹í—N3_z(eCEž›:åISV¾ip=üÒ)l:Ü$HÕÏJÍU,ƒÅu:lÕø“–û¶·=ð@ž«GŠùzá±gSfùÕ¡Ðd–sÛq‡×½ñ-,²>‹«RRš Ë¥8tžƒ¶½–ƒ…ç \†!ìï þÛb»,]LûQÔÃå 7Ÿ¾È½¿ºÏxª0nÎåqÁkNôø½oqÓíSþòÑŠKg÷¯Šª‚ƒƒ=ªü"Žsã*e‘xE‡3e=«ºs†§E!ÕU’HTî÷ ó9书ßoÑJÚ”£îzÓo~ç«)F?fÿ Ë ¯=Iÿçn"›¿Èoÿ ÿ{öàªb£¦T˜bRU@«,”²”ú=ÏAÛÆ‘À“Y I%ÊR‘$r`oO>CèƒrBNÝóA”–Tâúä(Ê¿¨ðã3¼ç=Ïòßß¼Ä÷¶^6·]ßåU'c²ÑªÈ¶|¤á›¦Mµ m™$0._nÊ5ßoŠiö÷|ï(që”åuPjÜö­”(œJ’9åjŽ¿‰Ó?–EYqfgÊÏ’ÌtßýíWñ®?¸Ÿ¼x»ÛV˜‡;Y&ŒéNG õtÚu›¶âd"ªj·¥=¾±aعÜÅ÷»ké´¿–N>œ¸ó×ùÄC†ãŸz„?yð–Uöÿ¤ÓÍj{T£ËUôXdGɲ¦1ìû¬´°Vû¾˜‡-h¬?ø¾äݶR3FŠœ,ƒÉÄ4Ò…HSµb@ÑíºTÕQë5¨âYÊÉ7øÅW8u¬âKÿsÀx­ ‘¥ð‡ƒ˜Ü‚s?Rl2?ÿ$Eÿnæs—ÑHÐ1 Mæ,ÒÖÔ“ u¡l==Ž Ë¥rݦ•E†ÑH­òq))ðb:U乤ãUåǮۡœ*~å®á7?p NâóË_ü!ÃÙ6>2â+ß³ùüÆé6·Üq””÷½ßß ß¾Šù\×IÛdÂ*ˆ);ŽbZ.²°Õ˜-rÖ›ºIb0FêgÇx C‘Â|.擦bŠEZ‡$ƒwsûû_ãnÁ}·Ÿerþýú#UÆhYq×]·rï‡ÞKUÜî«©hãè7p0>ÂpèPU¥$. Ê3@HÛ ‰­Âl°¦òûl&¨d“+;ä˜LXUlbŠAIR±·ç2‹ŽÑioI[Å]à¸mŠéxEˆƒK+(÷]ÈOa¼×3ŸÅL§.YÖe8„ñض5¥Fɲ¦”¬*¡µ†QKè•yG’Z-M˜•R¢-Ë 1âøéfs©£³Ô! =ÚmM«u”0Þâ|Gô¹ñTÄ=ï»…²z“qk5Su—[´+>VUó¶J´¥¥þI‰’…PÏ“Ú`6kð×öë‹Â°¿o3Ã&f(;—º8›):™äÀZ'ßÇ-'oàãƒÏ¡ÈéÜz/‹å«U &\ Qd¥¶^·5qÍ€RMC šéâ` míÑHÕ8l›_ÆPìYi¥KÉ—$âða(6¼·ç¬FJG ôQú×wÐþ&ÅlÉhÖ¾c5eŠÁ " …¡ª²uKÓ<Ä€.H hÆAYFÝJl´#ó;¸°³2Ç‘ïmÿ^kanwW²]­ ³™Æ‡¸ý»©¢wq0öØßSìï[¢Œ±³ã µY¡›ªiX_uE&­mVN(ݹímI_­ãJèn:ÙÆÈßÖ©.]Ô°L‹ãQ7†CÙï¨;eÀ±Óc¹”à4›I½Çv Ïð<ç0l¦9¶¤TjmBcýÀ÷åý…ÀÔÒ·Ör)ê…fnǂˣ‘HÞBœãˆ™ CâÔ;;—wOâ:’ …hf>—zW¦;"q‹8¶[räˆaoO­Æ\2¬ÛëZËCãØpp ŽÇÍÞ2¸ÞCuÖê¹Ù¬17ëCã±:4űPk!³™ª‡|žgjfe˜×ðÒà±c—.9ŒÇ²W{ž0¢¥òiÒ @«Chû.£O‘þpØÀ¬Mül3@)S—K9»X4é8¬Ú˜Â¸ïʲùŽÇj•N«Õ]Š<Çèv› p’DšY¶úi2¿æ’õ€çºÍÄRL¡qô °ÍàFC2¶’§ K„9 œb"Ò²—{‹ùì<`:•BKb“¡(T©‹‚ ×^kŽ—%ìï7f`Ïv6µ.}›µÛòy_Ç2iýäÊZ#Ëä7;j€˜Nm j ÓÆ¨¦!-ËÄŸ66Ì Nð÷Ó)ËÉDÕ³Üõ—ÍÅ׃G–‰ýÚ$ëÊs¶{fÏYÓ˜ÏU­©Ù¬I[l½»îWV€öÕhKîžÏÕLkþZùó½=òï6ǵÞù²’_¿ØÖ v°·>G°ÐÆ[ÇzÞáñ¨õ«µù\†ƒNóëtL§` ¦ª0JñülÆ_¥©ú›ÿÖŽˆQZØ%tEXtdate:create2012-05-27T10:48:29+02:00Ó+b%tEXtdate:modify2012-05-27T10:48:29+02:00qŽ“ÞIEND®B`‚fractalnow-0.8.1/gui/icons/icon22x22.png0000664000175000017500000000265511764667445016415 0ustar mpegmpeg‰PNG  IHDRÄ´l;gAMA± üasRGB®Îé cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDùC» pHYs  šœ vpAgÜÅéXIDAT8Ë…•]ˆUUÇûœ}Ï=ÞϹsï8㈄¦)D•’& RâS=E$VôÒCö¢åSHÐCVE%ùPö”HAfŸÂ(3£3:sïÌ;÷û|ïÖ11èÀfoöÙë¿öZë¿þ[8‘|Ùï«ý­©$¥À¶¡P€\Z-ˆã[{® ËË` Xd³†ÅE…ïC*qLËñµNõŒë’ò}M1pƒë*’ÒiùŸNòyµ  ÛÇ5kÀqp¢ˆzi §P€RI@{=™“ÂPQ,Ê^.'Àù¼Œ(c Æ­3Å¢Áq VS®6FBÍç –Q¤°,¹¡1j:­Ðr9C¡Ægðü,7çJ(%éJ§‹‹† -KÂnµ¥’¡P߇lV€m[Q(@1< cc1C©ó„Á$î¦CLOÐÂÐP«IÚ¢´RâÁ² Óp×U¤Rr[ËRäóP,&TFbJ¹ >>ú ÓSUÞ<¾“›¶S«ÂŠlVRÇ óyYärnYŠJÅ`ŒäÎq C%E%{™ù˧¹4Sg.1;ßãþS'xdÇc¹q‚‘ÝxžE }òdb¢H*[, eFF årH&«q]C.Û¥våS^yéç.Öh÷ÀIÛ<¸µÈûÇ^¥¼å-&'5†ayY¡{=Åð°Áu!V”ˆµ£ ë†Îtj˜žFg\>úð ΜŸ'Zá"ÐõcÎÿ¹Ä?]àÙm5”'Žå’:–ðK%(AyFGç¨_ý™7^ûŒ™…ýûÆøþ‡ÉÛ@W¾(«ÓËX–FkI§1 ]FGc¶l®“ÏÌÉ´™ýõ4GÞýŽÏÏÞ L.ü]'ŒïÈ®±Øõä.°…z®k„²+ j°Rw+þçûŸöÞ½‡‡¡EdéyãÄæ.Æ6ßÇÃø,LLQ.fxù…MÌÞì0W÷ï#C9³s÷ÓÔYšME· ZšÁÐh@¯§ˆ“u¬[ÿœ¼‡ÄØd+.Õúq~¿òËyNÙ°yãIEÂc¥@g2†NGÑï ݪUE’X„ÁîUºEªË‹çøã·kœ»X£Õo£Ûã;Â×:ÕÇ ÝlªV@£!bÔnC«å DE1T*P}‚cG[\¯NóÞ±o™ïñÎÛûؾcZ¯çzÝ¢Õ‚~_á8 ÛmÐ:é>cD_ÚŠe)ÂзQÙö:w?4Áô_3LMUyêÀ!šþvæ«°° šìyHŽ‘nK§E½Z-9σç) ‰ Ý¶¤c[yîàó„­I–û÷2=­h6!Š Ý®Âó @'‰¡P0#hY⤰KK"›IAhcÆÅ3{¸9™§Ñc®+7Öz n¶ í¶H^°:‹ÐíªU¡÷ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file color_button.h * \brief Header file introducing ColorButton class. * * \author Marc Pegon */ #ifndef _COLOR_BUTTON__H__ #define _COLOR_BUTTON__H__ #include #include class ColorButton : public QPushButton { Q_OBJECT public: ColorButton(QWidget *parent = 0); const QColor ¤tColor() const; private: QColor color; QColorDialog *colorDialog; void updateIcon(); public slots: void setCurrentColor(const QColor &color); private slots: void openColorDialog(); signals: void currentColorChanged(const QColor &color); }; #endif fractalnow-0.8.1/gui/include/shade_widget.h0000664000175000017500000000305411777303657017355 0ustar mpegmpeg/**************************************************************************** ** ** This file is based on some files of the demonstration applications of the ** Qt Toolkit. ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Modified to be used as a part of FractalNow: ** Copyright (c) 2012 Marc Pegon ** ** This file can be distributed and/or modified under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation. ** You should have received a copy of the GNU General Public License ** along with this file; if not, write to the Free Software Foundation, Inc., ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ****************************************************************************/ #ifndef __SHADE_WIDGET_H__ #define __SHADE_WIDGET_H__ #include "hoverpoints.h" class ShadeWidget : public QWidget { Q_OBJECT public: enum ShadeType { RedShade, GreenShade, BlueShade, ARGBShade }; ShadeWidget(ShadeType type, QWidget *parent = 0); void setGradientStops(const QGradientStops &stops); void paintEvent(QPaintEvent *e); QSize sizeHint() const { return QSize(150, 40); } QPolygonF points() const; HoverPoints *hoverPoints() const { return m_hoverPoints; } uint colorAt(int x); signals: void colorsChanged(); private: void generateShade(); ShadeType m_shade_type; HoverPoints *m_hoverPoints; QLinearGradient m_alpha_gradient; QImage m_shade; }; #endif fractalnow-0.8.1/gui/include/main_window.h0000664000175000017500000000671011754747533017243 0ustar mpegmpeg/* * main_window.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file main_window.h * \brief Header file introducing MainWindow class. * * \author Marc Pegon */ #ifndef __MAIN_WINDOW_H__ #define __MAIN_WINDOW_H__ #include "command_line.h" #include "export_fractal_image_dialog.h" #include "fractal_config_widget.h" #include "fractal_explorer.h" #include "fractal_rendering_widget.h" #include "fractalnow.h" #include #include #include #include #include #include #include #define DEFAULT_EXPLORER_WIDTH (uint)(640) #define DEFAULT_EXPLORER_HEIGHT (uint)(512) class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(int argc, char *argv[]); ~MainWindow(); private: enum FileType { UNKNOWN_FILE=0, CONFIG_FILE, FRACTAL_FILE, RENDER_FILE, GRADIENT_FILE }; ExportFractalImageDialog *exportFractalImageDialog; QDockWidget *fractalDock, *renderDock, *otherDock; QToolBar *toolBar; FractalExplorer *fractalExplorer; FractalConfigWidget *fractalConfigWidget; FractalRenderingWidget *fractalRenderingWidget; QSpinBox *preferredImageWidthSpinBox; QSpinBox *preferredImageHeightSpinBox; QCheckBox *solidGuessingCheckBox; QCheckBox *useCacheCheckBox; QSpinBox *cacheSizeSpinBox; QComboBox *floatTypeComboBox; QSpinBox *MPFloatPrecisionSpinBox; QWidget *editMPFloatPrecisionWidget; QAction *adaptExplorerToWindowAction; uint_fast32_t fractalExplorerNbThreads; uint_fast32_t exportImageNbThreads; bool adaptExplorerSize; uint lastPreferredExplorerWidth, lastPreferredExplorerHeight; uint lastWindowWidth, lastWindowHeight; QString imageDir; QString configDir; QString gradientDir; bool useCache; int cacheSize; bool solidGuessing; QAction *switchFullScreenAction; enum FileType getFileType(const char *fileName); void saveSettings(); void loadSettings(); void loadFile(const char *fileName); void loadConfigFile(const char *fileName); void loadFractalFile(const char *fileName); void loadRenderingFile(const char *fileName); void loadGradientFile(const char *fileName); void openFile(QString fileName); void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); private slots: void delayedInit(); void aboutQt(); void aboutQFractalNow(); void adaptExplorerToWindow(bool checked); void exportImage(); void openConfigFile(); void saveConfigFile(); void openGradientFile(); void saveGradientFile(); void onPreferredImageWidthChanged(); void onPreferredImageHeightChanged(); void onCacheSizeChanged(); void onFloatTypeChanged(int index); void editMPFloatPrecision(); void switchFullScreenMode(bool checked); void escapeFullScreen(); }; #endif fractalnow-0.8.1/gui/include/gradient_box.h0000664000175000017500000000316111754747533017372 0ustar mpegmpeg/* * gradient_box.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file gradient_box.h * \brief Header file introducing MainWindow class. * * \author Marc Pegon */ #ifndef __GRADIENT_BOX_H__ #define __GRADIENT_BOX_H__ #include "gradient_label.h" #include "fractalnow.h" #include class GradientBox : public QWidget { Q_OBJECT public: GradientBox(const QGradientStops &gradientStops, QWidget *parent = 0); GradientBox(const Gradient &gradient, QWidget *parent = 0); public slots: void setGradient(const Gradient &gradient); void setGradientStops(const QGradientStops &gradientStops); void openGradientDialog(); private: void initGradientBox(const QGradientStops &gradientStops); GradientLabel *gradientLabel; QGradientStops gradientStops; signals: void gradientStopsChanged(const QGradientStops &gradientStops); }; #endif fractalnow-0.8.1/gui/include/help.h0000664000175000017500000000237111754747533015657 0ustar mpegmpeg/* * help.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file help.h * \brief Header file introducing Help class. * * \author Marc Pegon */ #ifndef __HELP_H__ #define __HELP_H__ #include "fractalnow.h" #include //! To print help on the command line. class Help { public: //! Print program help. static void Print(); }; #define invalid_use_error(...) \ FractalNow_message(stderr, T_QUIET, __VA_ARGS__);\ Help::Print(); \ exit(EXIT_FAILURE) #endif fractalnow-0.8.1/gui/include/fractal_rendering_widget.h0000664000175000017500000000363011754747533021742 0ustar mpegmpeg/* * fractal_rendering_widget.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_config_widget.h * \brief Header file introducing FractalRenderingWidget class. * * \author Marc Pegon */ #ifndef __FRACTAL_RENDERING_WIDGET_H__ #define __FRACTAL_RENDERING_WIDGET_H__ #include "fractal_rendering_parameters.h" #include "color_button.h" #include "gradient_box.h" #include #include #include class FractalRenderingWidget : public QWidget { Q_OBJECT public: FractalRenderingWidget(const RenderingParameters &render); QComboBox *iterationCountComboBox; QComboBox *coloringMethodComboBox; QComboBox *addendFunctionComboBox; QSpinBox *stripeDensitySpinBox; QComboBox *interpolationMethodComboBox; QComboBox *transferFunctionComboBox; QDoubleSpinBox *colorScalingSpinBox; QDoubleSpinBox *colorOffsetSpinBox; ColorButton *spaceColorButton; GradientBox *gradientBox; public slots: void updateBoxesValues(const RenderingParameters &render); void updateBoxesEnabledValue(); void updateColorScalingSingleStep(); void editGradient(); private: void blockBoxesSignals(bool block); }; #endif fractalnow-0.8.1/gui/include/fractal_config_widget.h0000664000175000017500000000354211754747533021234 0ustar mpegmpeg/* * fractal_config_widget.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_config_widget.h * \brief Header file introducing FractalConfigWidget class. * * \author Marc Pegon */ #ifndef __FRACTAL_CONFIG_WIDGET_H__ #define __FRACTAL_CONFIG_WIDGET_H__ #include "mpfr_spin_box.h" #include "fractalnow.h" #include #include #include class FractalConfigWidget : public QWidget { Q_OBJECT public: FractalConfigWidget(const Fractal &fractal); QComboBox *fractalFormulaComboBox; MPFRSpinBox *pParamReSpinBox; MPFRSpinBox *pParamImSpinBox; MPFRSpinBox *cParamReSpinBox; MPFRSpinBox *cParamImSpinBox; MPFRSpinBox *centerXSpinBox; MPFRSpinBox *centerYSpinBox; MPFRSpinBox *spanXSpinBox; QDoubleSpinBox *bailoutRadiusSpinBox; QSpinBox *maxIterationsSpinBox; private: void blockBoxesSignals(bool block); public slots: void updateBoxesValues(const Fractal &fractal); private slots: void updateSpaceBoxesSingleSteps(); void updateCParamReSingleStep(); void updateCParamImSingleStep(); void updateBoxesEnabledValue(); }; #endif fractalnow-0.8.1/gui/include/main.h0000664000175000017500000000315711754747533015656 0ustar mpegmpeg/* * main.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file main.h * \brief Header file related to QFractalNow program. * \author Marc Pegon */ #ifndef __MAIN_H__ #define __MAIN_H__ #include /* Fractal is anti-aliased iteratively from "minimum anti-aliasing size" * to "maximum anti-aliasing size" by steps of "anti-aliasing size iteration". */ //! Default minimum anti-aliasing size. #define DEFAULT_MIN_ANTIALIASING_SIZE (uint_fast32_t)(3) //! Default maximum anti-aliasing size. #define DEFAULT_MAX_ANTIALIASING_SIZE (uint_fast32_t)(3) //! Default anti-aliasing size iteration. #define DEFAULT_ANTIALIASING_SIZE_ITERATION (uint_fast32_t)(2) //! Default number of decimals. #define DEFAULT_DECIMALS_NUMBER (int)(20) //! Minimum SingleStep for double & mpfr spin boxes. #define MIN_SINGLE_STEP (double)(pow(10, -DBL_DIG)) #endif fractalnow-0.8.1/gui/include/command_line.h0000664000175000017500000000473511754747533017362 0ustar mpegmpeg/* * command_line.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file command_line.h * \brief Header file related to command line parsing. * \author Marc Pegon */ #ifndef __COMMAND_LINE_H__ #define __COMMAND_LINE_H__ #include "main.h" #include "fractalnow.h" #include //! For storing command lines arguments. /* This structure is to store the arguments given on the command line. */ class CommandLineArguments { public: //!brief Parse arguments given on command line. /* * \param dst Pointer to the (already allocated) structure in which to store the arguments. * \param argc Argc of the main function * \param argv Argv of the main function */ CommandLineArguments(int argc, char *argv[]); //! Config file name. char *fractalConfigFileName; //! Fractal file name. char *fractalFileName; //! Rendering file name. char *renderingFileName; //! Rendering file name. char *gradientFileName; //! Width of output float table/image. uint_fast32_t width; //! Height of output float table/image. uint_fast32_t height; //! Minimum size for anti-aliasing. uint_fast32_t minAntiAliasingSize; //! Maximum size for anti-aliasing. uint_fast32_t maxAntiAliasingSize; //! Anti-aliasing size iteration. uint_fast32_t antiAliasingSizeIteration; //! Force number of threads used for drawing fractals. int nbThreads; //! Quad interpolation size. uint_fast32_t quadInterpolationSize; //! Adaptive anti-aliasing threshold. double adaptiveAAMThreshold; //! Color dissimilarity threshold. double colorDissimilarityThreshold; //! Float precision for computing fractal. FloatPrecision floatPrecision; //! Precision (value) of Multiple Precision floats. mpfr_prec_t MPFloatPrecision; }; #endif fractalnow-0.8.1/gui/include/gradient_label.h0000664000175000017500000000244411754747533017664 0ustar mpegmpeg/* * gradient_label.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file gradient_label.h * \brief Header file introducing ColorButton class. * * \author Marc Pegon */ #ifndef _GRADIENT_LABEL__H__ #define _GRADIENT_LABEL__H__ #include #include class GradientLabel : public QLabel { public: GradientLabel(QWidget *parent = 0); private: void paintEvent(QPaintEvent *event); QGradientStops gradientStops; public slots: void setGradientStops(const QGradientStops &gradientStops); }; #endif fractalnow-0.8.1/gui/include/gradient_editor.h0000664000175000017500000000264611777303657020077 0ustar mpegmpeg/**************************************************************************** ** ** This file is based on some files of the demonstration applications of the ** Qt Toolkit. ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Modified to be used as a part of FractalNow: ** Copyright (c) 2012 Marc Pegon ** ** This file can be distributed and/or modified under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation. ** You should have received a copy of the GNU General Public License ** along with this file; if not, write to the Free Software Foundation, Inc., ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ****************************************************************************/ #ifndef __GRADIENT_EDITOR_H__ #define __GRADIENT_EDITOR_H__ #include "gradient_label.h" #include "shade_widget.h" class GradientEditor : public QWidget { Q_OBJECT public: GradientEditor(QWidget *parent = 0); void setGradientStops(const QGradientStops &stops); QSize sizeHint() const { return QSize(480,320); } public slots: void pointsUpdated(); signals: void gradientStopsChanged(const QGradientStops &stops); private: GradientLabel *m_gradient_label; ShadeWidget *m_red_shade; ShadeWidget *m_green_shade; ShadeWidget *m_blue_shade; }; #endif fractalnow-0.8.1/gui/include/gradient_dialog.h0000664000175000017500000000275111754747533020045 0ustar mpegmpeg/* * gradient_dialog.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file gradient_dialog.h * \brief Header file introducing ColorButton class. * * \author Marc Pegon */ #ifndef _GRADIENT_DIALOG__H__ #define _GRADIENT_DIALOG__H__ #include "gradient_editor.h" #include #include class GradientDialog : public QDialog { Q_OBJECT public: GradientDialog(const QGradientStops &gradientStops, QWidget *parent = 0, Qt::WindowFlags f = 0); const QGradientStops ¤tGradientStops() const; private: GradientEditor *gradientEditor; QGradientStops gradientStops; private slots: void initGradientEditor(); void onGradientStopsChanged(const QGradientStops &gradientStops); }; #endif fractalnow-0.8.1/gui/include/task_progress_dialog.h0000664000175000017500000000236411754747533021136 0ustar mpegmpeg/* * task_progress_dialog.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file task_progress_dialog.h * \brief Header file introducing TaskProgressDialog class. * * \author Marc Pegon */ #ifndef __ACTION_PROGRESS_DIALOG_H__ #define __ACTION_PROGRESS_DIALOG_H__ #include "fractalnow.h" #include #include class TaskProgressDialog { public: static int progress(Task *task, QString labelText, QString cancelButtonText, QWidget *parent=0); }; #endif fractalnow-0.8.1/gui/include/hoverpoints.h0000664000175000017500000000665211777303657017315 0ustar mpegmpeg/**************************************************************************** ** ** This file is based on some files of the demonstration applications of the ** Qt Toolkit. ** ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Modified to be used as a part of FractalNow: ** Copyright (c) 2012 Marc Pegon ** ** This file can be distributed and/or modified under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation. ** You should have received a copy of the GNU General Public License ** along with this file; if not, write to the Free Software Foundation, Inc., ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ** ****************************************************************************/ #ifndef __HOVERPOINTS_H__ #define __HOVERPOINTS_H__ #include QT_FORWARD_DECLARE_CLASS(QBypassWidget) class HoverPoints : public QObject { Q_OBJECT public: enum PointShape { CircleShape, RectangleShape }; enum LockType { LockToLeft = 0x01, LockToRight = 0x02, LockToTop = 0x04, LockToBottom = 0x08 }; enum SortType { NoSort, XSort, YSort }; enum ConnectionType { NoConnection, LineConnection, CurveConnection }; HoverPoints(QWidget *widget, PointShape shape); bool eventFilter(QObject *object, QEvent *event); void paintPoints(); inline QRectF boundingRect() const; void setBoundingRect(const QRectF &boundingRect) { m_bounds = boundingRect; } QPolygonF points() const { return m_points; } void setPoints(const QPolygonF &points); QSizeF pointSize() const { return m_pointSize; } void setPointSize(const QSizeF &size) { m_pointSize = size; } SortType sortType() const { return m_sortType; } void setSortType(SortType sortType) { m_sortType = sortType; } ConnectionType connectionType() const { return m_connectionType; } void setConnectionType(ConnectionType connectionType) { m_connectionType = connectionType; } void setConnectionPen(const QPen &pen) { m_connectionPen = pen; } void setShapePen(const QPen &pen) { m_pointPen = pen; } void setShapeBrush(const QBrush &brush) { m_pointBrush = brush; } void setPointLock(int pos, LockType lock) { m_locks[pos] = lock; } void setEditable(bool editable) { m_editable = editable; } bool editable() const { return m_editable; } public slots: void setEnabled(bool enabled); void setDisabled(bool disabled) { setEnabled(!disabled); } signals: void pointsChanged(const QPolygonF &points); public: void firePointChange(); private: inline QRectF pointBoundingRect(int i) const; void movePoint(int i, const QPointF &newPos, bool emitChange = true); QWidget *m_widget; QPolygonF m_points; QRectF m_bounds; PointShape m_shape; SortType m_sortType; ConnectionType m_connectionType; QVector m_locks; QSizeF m_pointSize; int m_currentIndex; bool m_editable; bool m_enabled; QHash m_fingerPointMapping; QPen m_pointPen; QBrush m_pointBrush; QPen m_connectionPen; }; inline QRectF HoverPoints::pointBoundingRect(int i) const { QPointF p = m_points.at(i); qreal w = m_pointSize.width(); qreal h = m_pointSize.height(); qreal x = p.x() - w / 2; qreal y = p.y() - h / 2; return QRectF(x, y, w, h); } inline QRectF HoverPoints::boundingRect() const { if (m_bounds.isEmpty()) { return m_widget->rect(); } else { return m_bounds; } } #endif fractalnow-0.8.1/gui/include/fractal_explorer.h0000664000175000017500000001316611754747533020267 0ustar mpegmpeg/* * fractal_explorer.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_explorer.h * \brief Header file introducing FractalExplorer class. * * \author Marc Pegon */ #ifndef _FRACTAL_EXPLORER__H__ #define _FRACTAL_EXPLORER__H__ #include "main.h" #include "fractalnow.h" #include #include #include #include #include class FractalExplorer : public QLabel { Q_OBJECT public: FractalExplorer(const FractalConfig &fractalConfig, uint_fast32_t width, uint_fast32_t height, uint_fast32_t minAntiAliasingSize, uint_fast32_t maxAntiAliasingSize, uint_fast32_t antiAliasingSizeIteration, uint_fast32_t quadInterpolationSize, double colorDissimilarityThreshold, double adaptiveAAMThreshold, uint_fast32_t nbThreads, QWidget *parent = 0, Qt::WindowFlags f = 0); const FractalConfig &getFractalConfig() const; const Fractal &getFractal() const; const RenderingParameters &getRender() const; bool getFractalCacheEnabled() const; int getFractalCacheSize() const; bool getSolidGuessingEnabled() const; void launchFractalDrawing(); void launchFractalAntiAliasing(); void resizeImage(uint_fast32_t width, uint_fast32_t height); QSize sizeHint() const; ~FractalExplorer(); QAction *restoreInitialStateAction; QAction *stopDrawingAction; QAction *refreshAction; QAction *zoomInAction; QAction *zoomOutAction; QAction *moveLeftAction; QAction *moveRightAction; QAction *moveUpAction; QAction *moveDownAction; public slots: void restoreInitialState(); void refresh(); int stopDrawing(); // return 1 if drawing was not active anyway void pauseDrawing(); void resumeDrawing(); void zoomInFractal(); void zoomOutFractal(); void moveUpFractal(); void moveDownFractal(); void moveLeftFractal(); void moveRightFractal(); void useFractalCache(bool enabled); void resizeFractalCache(int size); void setSolidGuessingEnabled(bool enabled); void setFractalFormula(int index); void setPParam(const mpc_t *value); void setPParamRe(const mpfr_t *value); void setPParamIm(const mpfr_t *value); void setCParamRe(const mpfr_t *value); void setCParamIm(const mpfr_t *value); void setCenterX(const mpfr_t *value); void setCenterY(const mpfr_t *value); void setSpanX(const mpfr_t *value); void setBailoutRadius(double value); void setMaxIterations(int value); void setAddendFunction(int index); void setStripeDensity(int value); void setColoringMethod(int index); void setIterationCount(int index); void setInterpolationMethod(int index); void setTransferFunction(int index); void setColorScaling(double value); void setColorOffset(double value); void setSpaceColor(const QColor &color); void setGradient(const QGradientStops &gradientStops); void setFractalConfig(const FractalConfig &fractalConfig); void setFractal(const Fractal &fractal); void setRenderingParameters(const RenderingParameters &render); void setGradient(const Gradient &gradient); void setFloatPrecision(int index); private: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent * event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void wheelEvent(QWheelEvent *event); void contextMenuEvent(QContextMenuEvent *event); int cancelActionIfNotFinished(); void adjustSpan(); void reInitFractal(); void reInitRenderingParameters(); void moveFractal(const mpfr_t dx, const mpfr_t dy, bool emitFractalChanged = false); void zoomInFractal(const mpfr_t newSpanX, const mpfr_t zoomCenterX, const mpfr_t zoomCenterY, bool emitFractalChanged = false); void zoomOutFractal(const mpfr_t newSpanX, const mpfr_t zoomCenterX, const mpfr_t zoomCenterY, bool emitFractalChanged = false); enum ActionType { A_FractalDrawing = 0, A_FractalAntiAliasing }; enum ActionType lastActionType; bool drawingPaused; bool redrawFractal; double currentAntiAliasingSize; bool movingFractalDeferred; bool movingFractalRealTime; bool fractalMoved; mpfr_t fractalCenterXOnPress, fractalCenterYOnPress; QPointF prevMousePos; QPointF mousePosOnPress; QImage imageCopyOnPress; uint_fast32_t initialWidth, initialHeight; FractalConfig fractalConfig, initialFractalConfig; Fractal &fractal; RenderingParameters &render; uint_fast32_t quadInterpolationSize; double colorDissimilarityThreshold; double adaptiveAAMThreshold; FloatPrecision floatPrecision; bool solidGuessing; FractalCache cache; FractalCache *pCache; uint_fast32_t minAntiAliasingSize; uint_fast32_t maxAntiAliasingSize; uint_fast32_t antiAliasingSizeIteration; Threads *threads; QImage *fractalQImage; Image fractalImage; Task *task; QTimer *timer; private slots: void onTimeout(); signals: void wakeUpSignal(); void fractalChanged(const Fractal &); void renderingParametersChanged(const RenderingParameters &); void fractalCacheSizeChanged(int size); }; #endif fractalnow-0.8.1/gui/include/mpfr_spin_box.h0000664000175000017500000000522711754747533017577 0ustar mpegmpeg/* * mpfr_spin_box.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file mpfr_spin_box.h * \brief Header file introducing MPFRSpinBox class. * * \author Marc Pegon */ #ifndef __MPFR_SPIN_BOX_H__ #define __MPFR_SPIN_BOX_H__ #include #include class MPFRSpinBox : public QAbstractSpinBox { Q_OBJECT public: MPFRSpinBox(QWidget * parent = 0); ~MPFRSpinBox(); enum Notation { ClassicNotation = 0, ScientificNotation }; void fixup ( QString & input ) const; void stepBy(int step); const mpfr_t *value(); long double value_d(); void setMaximum ( const mpfr_t * max ); void setMinimum ( const mpfr_t * min ); void setRange ( const mpfr_t * min, const mpfr_t * max); void setMaximum ( long double max ); void setMinimum ( long double min ); void setRange ( long double min, long double max); void setSingleStep ( const mpfr_t * val ); void setSingleStep ( long double val ); void setNotation ( Notation notation ); void setDecimals ( int prec ); /* Checks that the str can be converted to a long */ QValidator::State validate ( QString & input, int & pos ) const; protected: QAbstractSpinBox::StepEnabled stepEnabled() const; virtual mpfr_t *valueFromText(const QString &text) const; virtual QString textFromValue(const mpfr_t *val) const; protected: mpfr_t m_value; mpfr_t m_singleStep; mpfr_t m_minimum; mpfr_t m_maximum; Notation m_notation; int m_decimals; private: void updateText(); inline bool isInRange(const mpfr_t val) const; void aux_setValue(const mpfr_t *val); void setValue(const mpfr_t *val, bool updateText); void aux_setValue(long double val); void aux_setMinimum(); void aux_setMaximum(); public slots: void setValue(const mpfr_t *val); void setValue(long double val); private slots: void onTextEdited(const QString & text); void onEditingFinished(); signals: void valueChanged ( const mpfr_t *val ); }; #endif fractalnow-0.8.1/gui/include/export_fractal_image_dialog.h0000664000175000017500000000522611754747533022427 0ustar mpegmpeg/* * export_fractal_image_dialog.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file export_fractal_image_dialog.h * \brief Header file introducing ExportFractalImageDialog class. * * \author Marc Pegon */ #ifndef __EXPORT_FRACTAL_IMAGE_DIALOG_H__ #define __EXPORT_FRACTAL_IMAGE_DIALOG_H__ #include #include #include #include #include #include #include #include "fractalnow.h" class ExportFractalImageDialog : public QDialog { Q_OBJECT public: ExportFractalImageDialog(const FractalConfig &config, uint_fast32_t nbThreads, QString imageDir = QString(), QWidget *parent = 0, Qt::WindowFlags f = 0); void resetFractalConfig(const FractalConfig &config); void setFloatPrecision(FloatPrecision floatPrecision); QString exportedFile(); ~ExportFractalImageDialog(); private: void TaskProgressBar(Task *task, QString labelText, QString cancelButtonText); enum AntiAliasingMethod { AAM_NONE = 0, AAM_GAUSSIANBLUR, AAM_OVERSAMPLING, AAM_ADAPTIVE }; AntiAliasingMethod getAntiAliasingMethod() const; QString m_exportedFile; QString imageDir; FractalConfig config; Fractal &fractal; RenderingParameters &render; Threads *threads; FloatPrecision floatPrecision; QComboBox *colorDepthBox; QLineEdit *outputFileEdit; QRadioButton *noAAMButton; QRadioButton *gaussianBlurAAMButton; QDoubleSpinBox *blurRadiusBox; QRadioButton *adaptiveAAMButton; QSpinBox *adaptiveSizeBox; QRadioButton *oversamplingAAMButton; QDoubleSpinBox *oversamplingSizeBox; QSpinBox *imageWidthBox; QSpinBox *imageHeightBox; QDialogButtonBox *dialogButtonBox; QPushButton *exportButton; QPushButton *cancelButton; private slots: void onAAMNoneToggled(bool); void onAAMBlurToggled(bool); void onAAMAdaptiveToggled(bool); void onAAMOversamplingToggled(bool); void exportImage(); }; #endif fractalnow-0.8.1/gui/objs/0000775000175000017500000000000011754777452014070 5ustar mpegmpegfractalnow-0.8.1/gui/qfractalnow.desktop0000664000175000017500000000032711754747533017046 0ustar mpegmpeg[Desktop Entry] Version=1.0 Type=Application Name=QFractalNow GenericName=Fractal Generator Comment=Fractal images generator Icon=qfractalnow Exec=qfractalnow -q Categories=Qt;Education;Science;Math; Terminal=false fractalnow-0.8.1/gui/mocs/0000775000175000017500000000000011754777452014074 5ustar mpegmpegfractalnow-0.8.1/gui/bin/0000775000175000017500000000000011754777453013704 5ustar mpegmpegfractalnow-0.8.1/gui/rcc/0000775000175000017500000000000011754777452013702 5ustar mpegmpegfractalnow-0.8.1/COPYING.LESSER0000664000175000017500000001674311754747533014406 0ustar mpegmpeg GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. fractalnow-0.8.1/lib/0000775000175000017500000000000011777336375013115 5ustar mpegmpegfractalnow-0.8.1/lib/Makefile.configure0000664000175000017500000000365411754776133016540 0ustar mpegmpegSRCDIR = src INCLUDEDIR= include OBJDIR = objs BINDIR = bin TARGET = ${BINDIR}/${TARGET_NAME} DEPENDENCY_FILE=${OBJDIR}/makefile.dep CC = gcc AR = ar ARFLAGS = -r -c -s CFLAGS = -std=c99 -pedantic -Wall -Wextra -D${SPINLOCK_DEFINE} ifdef VERSION_NUMBER CFLAGS += -DVERSION_NUMBER=${VERSION_NUMBER} endif ifdef DEBUG CFLAGS += -O0 -g -DDEBUG else CFLAGS += -O2 -ffast-math endif CFLAGS += -I${INCLUDEDIR} OBJECTS = \ $(OBJDIR)/float_precision.o \ $(OBJDIR)/fractal_addend_function.o \ $(OBJDIR)/fractal_cache.o \ $(OBJDIR)/fractal_coloring.o \ $(OBJDIR)/fractal_compute_engine.o \ $(OBJDIR)/fractal_config.o \ $(OBJDIR)/fractal_iteration_count.o \ $(OBJDIR)/fractal_formula.o \ $(OBJDIR)/error.o \ $(OBJDIR)/fractal_rendering_parameters.o \ $(OBJDIR)/fractal_transfer_function.o \ $(OBJDIR)/color.o \ $(OBJDIR)/file_io.o \ $(OBJDIR)/filter.o \ $(OBJDIR)/fractalnow.o \ $(OBJDIR)/fractal.o \ $(OBJDIR)/gradient.o \ $(OBJDIR)/image.o \ $(OBJDIR)/misc.o \ $(OBJDIR)/ppm.o \ $(OBJDIR)/uirectangle.o \ $(OBJDIR)/task.o \ $(OBJDIR)/thread.o all : $(OBJDIR) $(BINDIR) ${DEPENDENCY_FILE} $(TARGET) ${DEPENDENCY_FILE}: $(OBJDIR) ${SRCDIR}/*.c ${INCLUDEDIR}/*.h $(call quiet-command,for i in ${SRCDIR}/*.c; do ${CC} ${CFLAGS} -MM "$${i}"; done | sed "s/\(^.*:\)/${OBJDIR}\/\1/" > $@," BUILDING DEPENDENCY DATABASE"); -include ${DEPENDENCY_FILE} $(TARGET): $(OBJECTS) $(call quiet-command, $(AR) $(ARFLAGS) $@ $^, " AR $@") $(OBJDIR): $(call quiet-command, mkdir -p $(OBJDIR),) $(BINDIR): $(call quiet-command, mkdir -p $(BINDIR),) $(OBJDIR)/%.o:${SRCDIR}/%.c ${CC} ${CFLAGS} -c $< -o $@ clean: $(call quiet-command, rm -f ${DEPENDENCY_FILE}, " CLEAN (DEPENDENCY DATABASE)") $(call quiet-command, rm -f $(OBJECTS) , " CLEAN (OBJECTS)") distclean: clean $(call quiet-command, rm -rf $(OBJDIR), " CLEAN (OBJDIR)") $(call quiet-command, rm -rf $(BINDIR), " CLEAN (BINDIR)") fractalnow-0.8.1/lib/src/0000775000175000017500000000000011777336364013702 5ustar mpegmpegfractalnow-0.8.1/lib/src/ppm.c0000664000175000017500000000475411754747533014653 0ustar mpegmpeg/* * ppm.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ppm.h" #include "error.h" #include int aux_ExportPPM8(const char *fileName, const Image *image) { FILE *file; int res = 0; file = fopen(fileName,"wb"); if (!file) { FractalNow_open_werror(fileName); } fprintf(file,"P6\n%"PRIuFAST32" %"PRIuFAST32"\n%"PRIu8"\n", image->width, image->height, (uint8_t)UINT8_MAX); if (image->width != 0 && image->height != 0) { uint8_t *bytes = ImageToBytesArray(image); fwrite(bytes, 3, image->width*image->height, file); free(bytes); } end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } return res; } int aux_ExportPPM16(const char *fileName, const Image *image) { FILE *file; int res = 0; file = fopen(fileName,"wb"); if (!file) { FractalNow_open_werror(fileName); } fprintf(file,"P6\n%"PRIuFAST32" %"PRIuFAST32"\n%"PRIu16"\n", image->width, image->height, (uint16_t)UINT16_MAX); if (image->width != 0 && image->height != 0) { uint8_t *bytes = ImageToBytesArray(image); fwrite(bytes, 6, image->width*image->height, file); free(bytes); } end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } return res; } int ExportPPM(const char *fileName, const Image *image) { int res = 0; FractalNow_message(stdout, T_NORMAL, "Exporting PPM \'%s\'...\n", fileName); switch (image->bytesPerComponent) { case 1: res = aux_ExportPPM8(fileName, image); break; case 2: res = aux_ExportPPM16(fileName, image); break; default: FractalNow_error("Invalid image bytes per component.\n"); break; } FractalNow_message(stdout, T_NORMAL, "Exporting PPM \'%s\' : %s.\n", fileName, (res == 0) ? "DONE" : "FAILED"); return res; } fractalnow-0.8.1/lib/src/file_io.c0000664000175000017500000000544211755140374015447 0ustar mpegmpeg/* * file_io.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "file_io.h" #include "error.h" #include #include int readString(FILE *file, char *dst) { return fscanf(file, "%s", dst); } int readUint32(FILE *file, uint32_t *dst) { int res; int64_t read; if ((res = fscanf(file,"%"SCNd64,&read)) < 1) { return res; } if (read < 0) { return 0; } *dst = (uint32_t)read; return res; } int readDouble(FILE *file, double *dst) { return fscanf(file,"%lf",dst); } int readMPFR(FILE *file, mpfr_t dst) { return (mpfr_inp_str(dst, file, 10, MPFR_RNDN) == 0) ? -1 : 1; } int readColor(FILE *file, int_fast8_t bytesPerComponent, Color *dst) { uint32_t color32; uint64_t color64; int res; switch (bytesPerComponent) { case 1: if ((res = fscanf(file,"%"SCNx32,&color32)) < 1) { break; } *dst = ColorFromUint32(color32); break; case 2: if ((res = fscanf(file,"%"SCNx64,&color64)) < 1) { break; } *dst = ColorFromUint64((uint64_t)color64); break; default: FractalNow_error("Invalid bytes per component.\n"); break; } return res; } int writeString(FILE *file, const char *src, const char *suffix) { return fprintf(file, "%s%s", src, suffix); } int writeUint32(FILE *file, uint32_t src, const char *suffix) { return fprintf(file, "%"PRIu32"%s", src, suffix); } int writeDouble(FILE *file, double src, const char *suffix) { return fprintf(file, "%.*lG%s", DBL_DIG, src, suffix); } int writeMPFR(FILE *file, const mpfr_t src, const char *suffix) { return mpfr_fprintf(file, "%RE%s", src, suffix); } int writeColor(FILE *file, Color src, const char *suffix) { uint32_t color32; uint64_t color64; int res; switch (src.bytesPerComponent) { case 1: color32 = ARGB8_TO_UINT32(0, src.r, src.g, src.b); res = fprintf(file, "0x%"PRIx32"%s", color32, suffix); break; case 2: color64 = ARGB16_TO_UINT64(0, src.r, src.g, src.b); res = fprintf(file, "0x%"PRIx64"%s", color64, suffix); break; default: FractalNow_error("Invalid bytes per component.\n"); break; } return res; } fractalnow-0.8.1/lib/src/fractal_config.c0000664000175000017500000001760211754747533017014 0ustar mpegmpeg/* * fractal_config.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal_config.h" #include "file_io.h" #include "fractal.h" #include "fractal_rendering_parameters.h" #include "misc.h" #include const char *fractalConfigFormatStr[] = { (const char *)"c075" }; const uint_fast32_t nbFractalConfigFormats = sizeof(fractalConfigFormatStr) / sizeof(const char *); int ReadFractalConfigFileV075(FractalConfig *fractalConfig, const char *fileName, FILE *file); typedef int (*ReadFractalConfigFileFunction)(FractalConfig *fractalConfig, const char *fileName, FILE *file); const ReadFractalConfigFileFunction readFractalConfigFileFunction[] = { ReadFractalConfigFileV075 }; int WriteFractalConfigFileV075(const FractalConfig *fractalConfig, const char *fileName, FILE *file); typedef int (*WriteFractalConfigFileFunction)(const FractalConfig *fractalConfig, const char *fileName, FILE *file); const WriteFractalConfigFileFunction writeFractalConfigFileFunction[] = { WriteFractalConfigFileV075 }; inline void InitFractalConfig(FractalConfig *config, Fractal fractal, RenderingParameters render) { config->fractal = fractal; config->render = render; } FractalConfig CopyFractalConfig(const FractalConfig *config) { FractalConfig res; InitFractalConfig(&res, CopyFractal(&config->fractal), CopyRenderingParameters(&config->render)); return res; } void ResetFractal(FractalConfig *config, Fractal fractal) { FreeFractal(config->fractal); config->fractal = CopyFractal(&fractal); } void ResetRenderingParameters(FractalConfig *config, RenderingParameters param) { FreeRenderingParameters(config->render); config->render = CopyRenderingParameters(¶m); } int ReadFractalConfigFileV075(FractalConfig *fractalConfig, const char *fileName, FILE *file) { int res = 0; const char fractalFormat[] = "f075"; const char renderingFormat[] = "r075"; res |= ReadFractalFileBody(&fractalConfig->fractal, fileName, file, fractalFormat); if (res) { FractalNow_werror("Failed to read fractal from fractal configuration file.\n"); } res |= ReadRenderingFileBody(&fractalConfig->render, fileName, file, renderingFormat); if (res) { FractalNow_werror("Failed to read rendering parameters from fractal \ configuration file.\n"); } end: return res; } ReadFractalConfigFileFunction GetReadFractalConfigFileFunction(const char *format) { if (strlen(format) != 4) { return NULL; } ReadFractalConfigFileFunction readFractalConfigFile = NULL; char formatStr[5]; strcpy(formatStr, format); toLowerCase(formatStr); uint_fast32_t i; for (i = 0; i < nbFractalConfigFormats; ++i) { if (strcmp(formatStr, fractalConfigFormatStr[i]) == 0) { readFractalConfigFile = readFractalConfigFileFunction[i]; break; } } return readFractalConfigFile; } int isSupportedFractalConfigFile(const char *fileName) { int res = 0; FILE *file; file=fopen(fileName,"r"); if (!file) { FractalNow_open_werror(fileName); } char formatStr[256]; if (readString(file, formatStr) < 1) { res = 1; } else { ReadFractalConfigFileFunction readFractalConfigFileFunction; readFractalConfigFileFunction = GetReadFractalConfigFileFunction(formatStr); res = (readFractalConfigFileFunction == NULL); } end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } return !res; } int ReadFractalConfigFileBody(FractalConfig *fractalConfig, const char *fileName, FILE *file, const char *format) { FractalNow_message(stdout, T_VERBOSE, "Reading fractal config file body...\n"); int res = 0; ReadFractalConfigFileFunction readFractalConfigFile; readFractalConfigFile = GetReadFractalConfigFileFunction(format); if (readFractalConfigFile == NULL) { FractalNow_werror("Unsupported fractal config format '%s'.\n", format); } res |= readFractalConfigFile(fractalConfig, fileName, file); end: FractalNow_message(stdout, T_VERBOSE, "Reading fractal config file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int ReadFractalConfigFile(FractalConfig *fractalConfig, const char *fileName) { FractalNow_message(stdout, T_NORMAL, "Reading fractal configuration file...\n"); int res = 0; FILE *file; file=fopen(fileName,"r"); if (!file) { FractalNow_open_werror(fileName); } char formatStr[256]; if (readString(file, formatStr) < 1) { FractalNow_read_werror(fileName); } res = ReadFractalConfigFileBody(fractalConfig, fileName, file, formatStr); end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } FractalNow_message(stdout, T_NORMAL, "Reading fractal configuration file : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int WriteFractalConfigFileV075(const FractalConfig *fractalConfig, const char *fileName, FILE *file) { int res = 0; const char fractalFormat[] = "f075"; const char renderingFormat[] = "r075"; res |= WriteFractalFileBody(&fractalConfig->fractal, fileName, file, fractalFormat); if (res) { FractalNow_werror("Failed to write fractal file.\n"); } res |= WriteRenderingFileBody(&fractalConfig->render, fileName, file, renderingFormat); if (res) { FractalNow_werror("Failed to read rendering file.\n"); } end: return res; } WriteFractalConfigFileFunction GetWriteFractalConfigFileFunction(const char *format) { if (strlen(format) != 4) { return NULL; } WriteFractalConfigFileFunction writeFractalConfigFile = NULL; char formatStr[5]; strcpy(formatStr, format); toLowerCase(formatStr); uint_fast32_t i; for (i = 0; i < nbFractalConfigFormats; ++i) { if (strcmp(formatStr, fractalConfigFormatStr[i]) == 0) { writeFractalConfigFile = writeFractalConfigFileFunction[i]; break; } } return writeFractalConfigFile; } int WriteFractalConfigFileBody(const FractalConfig *fractalConfig, const char *fileName, FILE *file, const char *format) { FractalNow_message(stdout, T_VERBOSE, "Writing fractal config file body...\n"); int res = 0; WriteFractalConfigFileFunction writeFractalConfigFile; writeFractalConfigFile = GetWriteFractalConfigFileFunction(format); if (writeFractalConfigFile == NULL) { FractalNow_werror("Unsupported fractal config format '%s'.\n", format); } res |= writeFractalConfigFile(fractalConfig, fileName, file); end: FractalNow_message(stdout, T_VERBOSE, "Writing fractal config file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int WriteFractalConfigFile(const FractalConfig *fractalConfig, const char *fileName) { FractalNow_message(stdout, T_NORMAL, "Writing fractal configuration file...\n"); int res = 0; FILE *file; file=fopen(fileName,"w"); if (!file) { FractalNow_open_werror(fileName); } const char *format = fractalConfigFormatStr[nbFractalConfigFormats-1]; if (writeString(file, format, "\n") < 0) { FractalNow_write_werror(fileName); } res = WriteFractalConfigFileBody(fractalConfig, fileName, file, format); end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } FractalNow_message(stdout, T_NORMAL, "Writing fractal configuration file : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } void FreeFractalConfig(FractalConfig fractalConfig) { FreeFractal(fractalConfig.fractal); FreeRenderingParameters(fractalConfig.render); } fractalnow-0.8.1/lib/src/fractal_formula.c0000664000175000017500000000436611754747533017217 0ustar mpegmpeg/* * fractal_formula.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal_formula.h" #include "error.h" #include "misc.h" #include const char *fractalFormulaStr[] = { (const char *)"mandelbrot", (const char *)"mandelbrotp", (const char *)"julia", (const char *)"juliap", (const char *)"burningship", (const char *)"juliaburningship", (const char *)"mandelbar", (const char *)"juliabar", (const char *)"rudy" }; const char *fractalFormulaDescStr[] = { (const char *)"Mandelbrot (z^2+c)", (const char *)"Multibrot (z^p+c))", (const char *)"Julia (z^2+c)", (const char *)"Multi Julia (z^p+c)", (const char *)"Burning ship ((|Re(z)|+|Im(z)|)^p+c)", (const char *)"Julia B.ship ((|Re(z)|+|Im(z)|)^p+c)", (const char *)"Mandelbar (conjugate(z)^p+c)", (const char *)"Juliabar (conjugate(z)^p+c)", (const char *)"Rudy (z^p + c*z + d)" }; const uint_fast32_t nbFractalFormulas = sizeof(fractalFormulaStr) / sizeof(const char *); int GetFractalFormula(FractalFormula *fractalFormula, const char *str) { int res = 0; size_t len = strlen(str); if (len > 255) { FractalNow_werror("Unknown fractal formula \'%s\'.\n", str); } char FFStr[256]; strcpy(FFStr, str); toLowerCase(FFStr); uint_fast32_t i; for (i = 0; i < nbFractalFormulas; ++i) { if (strcmp(FFStr, fractalFormulaStr[i]) == 0) { *fractalFormula = (FractalFormula)i; break; } } if (i == nbFractalFormulas) { FractalNow_werror("Unknown fractal formula \'%s\'.\n", str); } end: return res; } fractalnow-0.8.1/lib/src/uirectangle.c0000664000175000017500000000741011754776720016351 0ustar mpegmpeg/* * rectangle.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "uirectangle.h" #include "misc.h" #include inline void InitUIRectangle(UIRectangle *rectangle, uint_fast32_t x1, uint_fast32_t y1, uint_fast32_t x2, uint_fast32_t y2) { rectangle->x1 = x1; rectangle->y1 = y1; rectangle->x2 = x2; rectangle->y2 = y2; } UIRectangle CopyUIRectangle(const UIRectangle *rectangle) { UIRectangle res; InitUIRectangle(&res, rectangle->x1, rectangle->y1, rectangle->x2, rectangle->y2); return res; } void CutUIRectangleMaxSize(UIRectangle src, uint_fast32_t size, UIRectangle **out, uint_fast32_t *out_size) { uint_fast32_t width = src.x2 - src.x1 + 1; uint_fast32_t height = src.y2 - src.y1 + 1; uint_fast32_t nb_x = width / size; uint_fast32_t nb_y = height / size; if (width % size > 0) { nb_x++; } if (height % size > 0) { nb_y++; } *out_size = nb_x*nb_y; *out = (UIRectangle *)safeMalloc("rectangles", (*out_size)*sizeof(UIRectangle)); UIRectangle *p_out = *out; uint_fast32_t y1 = src.y1; uint_fast32_t y2 = src.y1+size-1; for (; y1 <= src.y2; y1+=size, y2+=size) { y2 = (y2 > src.y2) ? src.y2 : y2; uint_fast32_t x1 = src.x1; uint_fast32_t x2 = src.x1+size-1; for (; x1 <= src.x2; x1+=size, x2+=size) { x2 = (x2 > src.x2) ? src.x2 : x2; p_out->x1 = x1; p_out->x2 = x2; p_out->y1 = y1; p_out->y2 = y2; ++p_out; } } } int CutUIRectangleInHalf(UIRectangle rectangle, UIRectangle *out1, UIRectangle *out2) { uint_fast32_t width = rectangle.x2 - rectangle.x1; uint_fast32_t height = rectangle.y2 - rectangle.y1; if (width == 0 && height == 0) { return 1; } if (width >= height) { width /= 2; InitUIRectangle(out1, rectangle.x1, rectangle.y1, rectangle.x1 + width, rectangle.y2); InitUIRectangle(out2, rectangle.x1 + width + 1, rectangle.y1, rectangle.x2, rectangle.y2); } else { height /= 2; InitUIRectangle(out1, rectangle.x1, rectangle.y1, rectangle.x2, rectangle.y1 + height); InitUIRectangle(out2, rectangle.x1, rectangle.y1 + height + 1, rectangle.x2, rectangle.y2); } return 0; } int CutUIRectangleInN(UIRectangle rectangle, uint_fast32_t N, UIRectangle *out) { uint_fast32_t width = rectangle.x2 + 1 - rectangle.x1; uint_fast32_t height = rectangle.y2 + 1 - rectangle.y1; if (width*height < N) { return 1; } uint_fast32_t nbRectangles = 1; uint_fast32_t tmpNbRectangles; InitUIRectangle(&out[0], rectangle.x1, rectangle.y1, rectangle.x2, rectangle.y2); while (nbRectangles < N) { tmpNbRectangles = nbRectangles; for (uint_fast32_t i = 0; i < tmpNbRectangles; i++) { if (CutUIRectangleInHalf(out[i], &out[i], &out[nbRectangles])) { /* This particular rectangle could not be in half. * Assuming that the initial rectangle could be cut in N parts, * we know that there still exists a rectangle that can be cut * in half (until we have reached N rectangles). * Just skip this one and try the next. */ continue; } else { nbRectangles++; } if (nbRectangles == N) { break; } } } return 0; } fractalnow-0.8.1/lib/src/fractal_iteration_count.c0000664000175000017500000000353311754747533020753 0ustar mpegmpeg/* * fractal_iteration_count.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal.h" #include "fractal_iteration_count.h" #include "error.h" #include "misc.h" #include const char *iterationCountStr[] = { (const char *)"discrete", (const char *)"continuous", (const char *)"smooth" }; const char *iterationCountDescStr[] = { (const char *)"Discrete iteration", (const char *)"Continuous iteration", (const char *)"Smooth iteration" }; const uint_fast32_t nbIterationCounts = sizeof(iterationCountStr) / sizeof(const char *); int GetIterationCount(IterationCount *iterationCount, const char *str) { int res = 0; int len = strlen(str); if (len > 255) { FractalNow_werror("Unknown iteration count \'%s\'.\n", str); } char ICStr[256]; strcpy(ICStr, str); toLowerCase(ICStr); uint_fast32_t i; for (i = 0; i < nbIterationCounts; ++i) { if (strcmp(ICStr, iterationCountStr[i]) == 0) { *(iterationCount) = (IterationCount)i; break; } } if (i == nbIterationCounts) { FractalNow_werror("Unknown iteration count \'%s\'.\n", str); } end: return res; } fractalnow-0.8.1/lib/src/fractal_addend_function.c0000664000175000017500000000347111754747533020672 0ustar mpegmpeg/* * fractal_addend_function.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal.h" #include "fractal_addend_function.h" #include "misc.h" #include const char *addendFunctionStr[] = { (const char *)"triangleinequality", (const char *)"curvature", (const char *)"stripe" }; const char *addendFunctionDescStr[] = { (const char *)"Triangle inequality", (const char *)"Curvature", (const char *)"Stripe" }; const uint_fast32_t nbAddendFunctions = sizeof(addendFunctionStr) / sizeof(const char *); int GetAddendFunction(AddendFunction *addendFunction, const char *str) { int res = 0; int len = strlen(str); if (len > 255) { FractalNow_werror("Unknown addend function \'%s\'.\n", str); } char AFStr[256]; strcpy(AFStr, str); toLowerCase(AFStr); uint_fast32_t i; for (i = 0; i < nbAddendFunctions; ++i) { if (strcmp(AFStr, addendFunctionStr[i]) == 0) { *addendFunction = (AddendFunction)i; break; } } if (i == nbAddendFunctions) { FractalNow_werror("Unknown addend function \'%s\'.\n", str); } end: return res; } fractalnow-0.8.1/lib/src/fractal_coloring.c0000664000175000017500000000520711754747533017361 0ustar mpegmpeg/* * fractal_coloring.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal.h" #include "fractal_coloring.h" #include "misc.h" #include const char *coloringMethodStr[] = { (char *)"iterationcount", (char *)"averagecoloring" }; const char *coloringMethodDescStr[] = { (char *)"Iteration count", (char *)"Average coloring" }; const uint_fast32_t nbColoringMethods = sizeof(coloringMethodStr) / sizeof(char *); int GetColoringMethod(ColoringMethod *coloringMethod, const char *str) { int res = 0; int len = strlen(str); if (len > 255) { FractalNow_werror("Unknown coloring method \'%s\'.\n", str); } char CMStr[256]; strcpy(CMStr, str); toLowerCase(CMStr); uint_fast32_t i; for (i = 0; i < nbColoringMethods; ++i) { if (strcmp(CMStr, coloringMethodStr[i]) == 0) { *coloringMethod = (ColoringMethod)i; break; } } if (i == nbColoringMethods) { FractalNow_werror("Unknown coloring method \'%s\'.\n", str); } end: return res; } const char *interpolationMethodStr[] = { (const char *)"none", (const char *)"linear", (const char *)"spline" }; const char *interpolationMethodDescStr[] = { (const char *)"None", (const char *)"Linear", (const char *)"Spline" }; const uint_fast32_t nbInterpolationMethods = sizeof(interpolationMethodStr) / sizeof(const char *); int GetInterpolationMethod(InterpolationMethod *interpolationMethod, const char *str) { int res = 0; int len = strlen(str); if (len > 255) { FractalNow_werror("Unknown interpolation method \'%s\'.\n", str); } char IMStr[256]; strcpy(IMStr, str); toLowerCase(IMStr); uint_fast32_t i; for (i = 0; i < nbInterpolationMethods; ++i) { if (strcmp(IMStr, interpolationMethodStr[i]) == 0) { *interpolationMethod = (InterpolationMethod)i; break; } } if (i == nbInterpolationMethods) { FractalNow_werror("Unknown interpolation method \'%s\'.\n", str); } end: return res; } fractalnow-0.8.1/lib/src/misc.c0000664000175000017500000000501511754747533015001 0ustar mpegmpeg/* * misc.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "misc.h" #include "error.h" #include #include void toLowerCase(char *str) { for (; *str != '\0'; ++str) { *str = tolower(*str); } } void *safeMalloc(const char *name, uint_least64_t size) { if (size > SIZE_MAX) { FractalNow_alloc_error(name); } void *res = malloc((size_t)size); if (size > 0 && res == NULL) { FractalNow_alloc_error(name); } return res; } void *safeRealloc(const char *name, void *ptr, uint_least64_t size) { if (size > SIZE_MAX) { FractalNow_alloc_error(name); } void *res = realloc(ptr, (size_t)size); if (size > 0 && res == NULL) { FractalNow_alloc_error(name); } return res; } void *safeCalloc(const char *name, uint_least64_t nmemb, uint_least64_t size) { if (nmemb > SIZE_MAX || size > SIZE_MAX) { FractalNow_alloc_error(name); } void *res = calloc((size_t)nmemb, (size_t)size); if (size > 0 && res == NULL) { FractalNow_alloc_error(name); } return res; } int mpcIsInteger(const mpc_t x) { if (mpfr_cmp_ui(mpc_imagref(x), 0) != 0) { return 0; } else { return mpfr_integer_p(mpc_realref(x)); } } int complexIsInteger(long double complex x) { if (cimagl(x) != 0) { return 0; } else { long double fptr, iptr; fptr = modfl(creall(x), &iptr); return (fptr == 0); } } #define BUILD_cipow(ftype, suffix) \ /* Function assumes that y >= 1 and computes x^y. */\ ftype complex cipow##suffix(ftype complex x, uint_fast32_t y)\ {\ ftype complex res;\ \ if (y == 0) {\ res = 1;\ }\ \ ftype complex rem;\ rem = 1;\ res = x;\ while (y > 1) {\ if (y % 2) {\ rem *= res;\ --y;\ }\ y >>= 1;\ res *= res;\ }\ \ res *= rem;\ \ return res;\ } BUILD_cipow(float, f) BUILD_cipow(double, ) BUILD_cipow(long double, l) fractalnow-0.8.1/lib/src/float_precision.c0000664000175000017500000000350411754747533017227 0ustar mpegmpeg/* * float_precision.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "error.h" #include "float_precision.h" #include "misc.h" #include const char *floatPrecisionStr[] = { (const char *)"single", (const char *)"double", (const char *)"ldouble", (const char *)"mp" }; const char *floatPrecisionDescStr[] = { (const char *)"Single", (const char *)"Double", (const char *)"Long double", (const char *)"Multiple" }; const uint_fast32_t nbFloatPrecisions = sizeof(floatPrecisionStr) / sizeof(const char *); int GetFloatPrecision(FloatPrecision *floatPrecision, const char *str) { int res = 0; size_t len = strlen(str); if (len > 255) { FractalNow_werror("Unknown float precision \'%s\'.\n", str); } char FPStr[256]; strcpy(FPStr, str); toLowerCase(FPStr); uint_fast32_t i; for (i = 0; i < nbFloatPrecisions; ++i) { if (strcmp(FPStr, floatPrecisionStr[i]) == 0) { *floatPrecision = (FloatPrecision)i; break; } } if (i == nbFloatPrecisions) { FractalNow_werror("Unknown float precision \'%s\'.\n", str); } end: return res; } fractalnow-0.8.1/lib/src/thread.c0000664000175000017500000001475711754747533015332 0ustar mpegmpeg/* * thread.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "thread.h" #include "error.h" #include "fractalnow.h" #include "misc.h" #include #include #include void *StartThreadRoutine(void *arg); Threads *CreateThreads(uint_fast32_t N) { Threads *res = (Threads *)safeMalloc("threads", sizeof(Threads)); res->thread = (pthread_t *)safeMalloc("pthreads", N*sizeof(pthread_t)); res->startThreadArg = (StartThreadArg *)safeMalloc("startThreadArgs", N*sizeof(StartThreadArg)); res->lastResult = (void **)safeMalloc("last results", N*sizeof(void *)); res->N = N; safePThreadMutexInit(&res->startThreadCondMutex, NULL); safePThreadCondInit(&res->startThreadCond, NULL); safePThreadMutexInit(&res->threadsMutex, NULL); safePThreadCondInit(&res->allThreadsReadyCond, NULL); safePThreadMutexLock(&res->threadsMutex); safePThreadCondInit(&res->allPausedCond, NULL); safePThreadCondInit(&res->allResumedCond, NULL); safePThreadCondInit(&res->resumeTaskCond, NULL); res->nbReady = 0; res->nbPaused = 0; for (uint_fast32_t i = 0; i < N; ++i) { res->startThreadArg[i].threadId = i; res->startThreadArg[i].threads = res; res->startThreadArg[i].message = NULL; res->startThreadArg[i].startRoutine = NULL; res->startThreadArg[i].arg = NULL; res->startThreadArg[i].result = &res->lastResult[i]; safePThreadCreate(&(res->thread[i]),NULL,StartThreadRoutine,&res->startThreadArg[i]); } /* Wait till all threads are ready before returning. */ safePThreadCondWait(&res->allThreadsReadyCond, &res->threadsMutex); safePThreadMutexUnlock(&res->threadsMutex); return res; } void *StartThreadRoutine(void *arg) { mpfr_set_default_prec(fractalnow_mpfr_precision); StartThreadArg *startThreadArg = (StartThreadArg *)arg; Threads *threads = startThreadArg->threads; do { safePThreadMutexLock(&threads->startThreadCondMutex); safePThreadMutexLock(&threads->threadsMutex); ++threads->nbReady; if (threads->nbReady+threads->nbPaused == threads->N) { safePThreadCondSignal(&threads->allPausedCond); } if (startThreadArg->message != NULL) { FractalNow_message(stdout, T_VERBOSE, "%s [%"PRIuFAST32"] : %s.\n", startThreadArg->message, startThreadArg->threadId, *startThreadArg->result == NULL ? "DONE" : "CANCELED"); } if (threads->nbReady == threads->N) { safePThreadCondSignal(&threads->allThreadsReadyCond); } safePThreadMutexUnlock(&threads->threadsMutex); safePThreadCondWait(&threads->startThreadCond, &threads->startThreadCondMutex); safePThreadMutexUnlock(&threads->startThreadCondMutex); if (startThreadArg->startRoutine == NULL) { break; } if (startThreadArg->message != NULL) { FractalNow_message(stdout, T_VERBOSE, "%s [%"PRIuFAST32"]...\n", startThreadArg->message, startThreadArg->threadId); } *(startThreadArg->result) = startThreadArg->startRoutine(startThreadArg->arg); } while (1); mpfr_free_cache(); return NULL; } void DestroyThreads(Threads *threads) { uint_fast32_t nbReady = 0; safePThreadMutexLock(&threads->threadsMutex); nbReady = threads->nbReady; if (nbReady < threads->N) { safePThreadCondWait(&threads->allThreadsReadyCond, &threads->threadsMutex); nbReady = threads->nbReady; } safePThreadMutexUnlock(&threads->threadsMutex); safePThreadMutexLock(&threads->startThreadCondMutex); for (uint_fast32_t i = 0; i < threads->N; ++i) { threads->startThreadArg[i].startRoutine = NULL; } safePThreadCondBroadcast(&threads->startThreadCond); safePThreadMutexUnlock(&threads->startThreadCondMutex); void *status; for (uint_fast32_t i = 0; i < threads->N; ++i) { safePThreadJoin(threads->thread[i], &status); if (status != NULL) { FractalNow_message(stderr, T_QUIET, "Thread return value is not as \ expected.\n"); } } safePThreadMutexDestroy(&threads->startThreadCondMutex); safePThreadMutexDestroy(&threads->threadsMutex); safePThreadCondDestroy(&threads->startThreadCond); safePThreadCondDestroy(&threads->allThreadsReadyCond); safePThreadCondDestroy(&threads->allPausedCond); safePThreadCondDestroy(&threads->allResumedCond); safePThreadCondDestroy(&threads->resumeTaskCond); free(threads->thread); free(threads->startThreadArg); free(threads->lastResult); free(threads); } ThreadArgHeader *GetThreadArgHeader(const void *arg) { return *((ThreadArgHeader **)arg); } void *GetThreadArgBody(const void *arg) { return *((void **)(((uint8_t *)arg)+sizeof(ThreadArgHeader *))); } static inline int ReadIntVarSafe(int *variable, pthread_spinlock_t *mutex) { int res; safePThreadSpinLock(mutex); res = *variable; safePThreadSpinUnlock(mutex); return res; } static inline void WriteIntVarSafe(int *variable, int value, pthread_spinlock_t *mutex) { safePThreadSpinLock(mutex); *variable = value; safePThreadSpinUnlock(mutex); } int CancelTaskRequested(ThreadArgHeader *threadArgHeader) { return ReadIntVarSafe(threadArgHeader->cancel, threadArgHeader->cancelMutex); } void SetThreadProgress(ThreadArgHeader *threadArgHeader, int progress) { WriteIntVarSafe(&threadArgHeader->progress, progress, &threadArgHeader->progressMutex); } void HandlePauseRequest(ThreadArgHeader *threadArgHeader) { int pause = ReadIntVarSafe(threadArgHeader->pause, threadArgHeader->pauseMutex); if (pause) { uint_fast32_t nbThreadsActive; Threads *threads = threadArgHeader->threads; safePThreadMutexLock(&threads->threadsMutex); ++threads->nbPaused; nbThreadsActive = threads->N-(*threadArgHeader->nbReady); if (threads->nbPaused == nbThreadsActive) { safePThreadCondSignal(&threads->allPausedCond); } safePThreadCondWait(&threads->resumeTaskCond, &threads->threadsMutex); --threads->nbPaused; if (threads->nbPaused == 0) { safePThreadCondSignal(&threads->allResumedCond); } safePThreadMutexUnlock(&threads->threadsMutex); } } fractalnow-0.8.1/lib/src/fractal_compute_engine.c0000664000175000017500000003163411754747533020551 0ustar mpegmpeg/* * fractal_compute_engine.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "float_precision.h" #include "fractal_compute_engine.h" #include "fractal_coloring.h" #include "fractal_formula.h" #include "fractal.h" #include "fractal_rendering_parameters.h" #include "macro_build_fractals.h" #include "misc.h" #include #define BUILD_FRACTAL_ENGINE(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) \ struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec {\ FLOATTYPE(FP_##fprec) centerX;\ FLOATTYPE(FP_##fprec) centerY;\ FLOATTYPE(FP_##fprec) spanX;\ FLOATTYPE(FP_##fprec) spanY;\ FLOATTYPE(FP_##fprec) x1;\ FLOATTYPE(FP_##fprec) y1;\ uint_fast32_t n;\ COMPLEX_FLOATTYPE(FP_##fprec) pixel;\ FLOATTYPE(FP_##fprec) rePixel;\ FLOATTYPE(FP_##fprec) imPixel;\ COMPLEX_FLOATTYPE(FP_##fprec) z;\ COMPLEX_FLOATTYPE(FP_##fprec) c;\ FLOATTYPE(FP_##fprec) res;\ FLOATTYPE(FP_##fprec) normZ;\ FLOATTYPE(FP_##fprec) escapeRadius;\ FLOATTYPE(FP_##fprec) escapeRadius2;\ COMPLEX_FLOATTYPE(FP_##fprec) fractalP;\ uint_fast32_t fractalP_INT;\ COMPLEX_FLOATTYPE(FP_##fprec) fractalC;\ ENGINE_DECL_VAR_FRAC_##formula(FP_##fprec)\ ENGINE_DECL_VAR_CM_##coloring(IC_##iterationcount,AF_##addend,IM_##interpolation,FP_##fprec)\ };\ \ CacheEntry FractalLoop##formula##ptype##coloring##iterationcount##addend##interpolation##fprec(\ void *engData, const Fractal *fractal, const RenderingParameters *render,\ uint_fast32_t x, uint_fast32_t y,\ uint_fast32_t width, uint_fast32_t height)\ {\ struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec *data =\ (struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec *)engData;\ UNUSED(render);\ \ CacheEntry dres;\ fromUiF(FP_##fprec, data->rePixel, x);\ add_dF(FP_##fprec, data->rePixel, data->rePixel, 0.5);\ mulF(FP_##fprec, data->rePixel, data->rePixel, data->spanX);\ div_uiF(FP_##fprec, data->rePixel, data->rePixel, width);\ addF(FP_##fprec, data->rePixel, data->rePixel, data->x1);\ \ fromUiF(FP_##fprec, data->imPixel, y);\ add_dF(FP_##fprec, data->imPixel, data->imPixel, 0.5);\ mulF(FP_##fprec, data->imPixel, data->imPixel, data->spanY);\ div_uiF(FP_##fprec, data->imPixel, data->imPixel, height);\ addF(FP_##fprec, data->imPixel, data->imPixel, data->y1);\ cfromReImF(FP_##fprec,data->pixel,data->rePixel,data->imPixel);\ cfromUiF(FP_##fprec,data->z, 0);\ cfromUiF(FP_##fprec,data->c, 0);\ fromUiF(FP_##fprec,data->res,0);\ fromUiF(FP_##fprec,data->normZ,0);\ LOOP_INIT_FRAC_##formula(FP_##fprec)\ LOOP_INIT_CM_##coloring(IC_##iterationcount,AF_##addend,IM_##interpolation,FP_##fprec)\ for (data->n=0; data->nmaxIter && \ cmpF(FP_##fprec,data->normZ,data->escapeRadius2) < 0; ++data->n) {\ LOOP_ITERATION_CM_##coloring(IC_##iterationcount,AF_##addend,IM_##interpolation,FP_##fprec)\ LOOP_ITERATION_FRAC_##formula(ptype,FP_##fprec)\ cnormF(FP_##fprec,data->normZ,data->z);\ }\ /* Color even the last iteration, when |z| becomes > escape radius */\ LOOP_ITERATION_CM_##coloring(IC_##iterationcount,AF_##addend,IM_##interpolation,FP_##fprec)\ dres.floatPrecision = FP_##fprec;\ initF(FP_##fprec, dres.x.val_FP_##fprec);\ initF(FP_##fprec, dres.y.val_FP_##fprec);\ crealF(FP_##fprec, dres.x.val_FP_##fprec, data->pixel);\ cimagF(FP_##fprec, dres.y.val_FP_##fprec, data->pixel);\ if (cmpF(FP_##fprec,data->normZ,data->escapeRadius2) < 0) {\ dres.value = -1;\ } else {\ LOOP_END_CM_##coloring(IC_##iterationcount,AF_##addend,IM_##interpolation,FP_##fprec)\ dres.value = toDoubleF(FP_##fprec,data->res);\ }\ return dres;\ }\ \ void FreeEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec(void *engData)\ {\ struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec *data =\ (struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec *)engData;\ UNUSED(data);\ \ clearF(FP_##fprec, data->centerX);\ clearF(FP_##fprec, data->centerY);\ clearF(FP_##fprec, data->spanX);\ clearF(FP_##fprec, data->spanY);\ clearF(FP_##fprec, data->x1);\ clearF(FP_##fprec, data->y1);\ cclearF(FP_##fprec, data->pixel);\ clearF(FP_##fprec, data->rePixel);\ clearF(FP_##fprec, data->imPixel);\ cclearF(FP_##fprec, data->z);\ cclearF(FP_##fprec, data->c);\ clearF(FP_##fprec, data->res);\ clearF(FP_##fprec, data->normZ);\ clearF(FP_##fprec, data->escapeRadius);\ clearF(FP_##fprec, data->escapeRadius2);\ cclearF(FP_##fprec, data->fractalP);\ cclearF(FP_##fprec, data->fractalC);\ ENGINE_CLEAR_VAR_FRAC_##formula(FP_##fprec)\ ENGINE_CLEAR_VAR_CM_##coloring(IC_##iterationcount,AF_##addend,IM_##interpolation,FP_##fprec)\ }\ \ void InitEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec(\ const Fractal *fractal, const RenderingParameters *render, FractalEngine *engine)\ {\ UNUSED(render);\ engine->fractalLoop = FractalLoop##formula##ptype##coloring##iterationcount##addend##interpolation##fprec;\ engine->freeEngineData = FreeEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec;\ engine->data = (struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec *)\ safeMalloc("fractal engine",\ sizeof(struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec));\ struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec *data =\ (struct FractalEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec *)engine->data;\ UNUSED(data);\ \ initF(FP_##fprec, data->centerX);\ initF(FP_##fprec, data->centerY);\ initF(FP_##fprec, data->spanX);\ initF(FP_##fprec, data->spanY);\ initF(FP_##fprec, data->x1);\ initF(FP_##fprec, data->y1);\ cinitF(FP_##fprec, data->pixel);\ initF(FP_##fprec, data->rePixel);\ initF(FP_##fprec, data->imPixel);\ cinitF(FP_##fprec, data->z);\ cinitF(FP_##fprec, data->c);\ initF(FP_##fprec, data->res);\ initF(FP_##fprec, data->normZ);\ initF(FP_##fprec, data->escapeRadius);\ initF(FP_##fprec, data->escapeRadius2);\ cinitF(FP_##fprec, data->fractalP);\ cinitF(FP_##fprec, data->fractalC);\ fromMPFRF(FP_##fprec, data->centerX, fractal->centerX);\ fromMPFRF(FP_##fprec, data->centerY, fractal->centerY);\ fromMPFRF(FP_##fprec, data->spanX, fractal->spanX);\ fromMPFRF(FP_##fprec, data->spanY, fractal->spanY);\ fromMPFRF(FP_##fprec, data->x1, fractal->x1);\ fromMPFRF(FP_##fprec, data->y1, fractal->y1);\ fromDoubleF(FP_##fprec, data->escapeRadius, fractal->escapeRadius);\ mulF(FP_##fprec, data->escapeRadius2, data->escapeRadius, data->escapeRadius);\ cfromMPCF(FP_##fprec, data->fractalP, fractal->p);\ cfromMPCF(FP_##fprec, data->fractalC, fractal->c);\ data->fractalP_INT = (uint_fast32_t)creal(ctoCDoubleF(FP_##fprec, data->fractalP));\ ENGINE_INIT_VAR_FRAC_##formula(FP_##fprec)\ ENGINE_INIT_VAR_CM_##coloring(IC_##iterationcount,AF_##addend,IM_##interpolation,FP_##fprec)\ } #undef MACRO_BUILD_FRACTAL /* All this crap to avoid creating duplicates of fractal engines: Indeed, with CM_ITERATIONCOUNT coloring method, addend function and interpolation methods are not used : we generate only one fractal engine for all interpolation methods and addend functions (for AF_TRIANGLEINEQUALITY and IM_NONE). The same thing applies with CM_AVERAGECOLORING color methods, where iteration count is not used : we generate only one fractal engine for all iteration counts. It is necessary to reduce executable size... When we are able to compile loops at runtime we won't need all these macros.*/ #define BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT_AF_TRIANGLEINEQUALITY_IM_NONE(formula,ptype,iterationcount,fprec) \ BUILD_FRACTAL_ENGINE(formula,ptype,ITERATIONCOUNT,iterationcount,TRIANGLEINEQUALITY,NONE,fprec) #define BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT_AF_TRIANGLEINEQUALITY_IM_LINEAR(formula,ptype,iterationcount,fprec) #define BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT_AF_TRIANGLEINEQUALITY_IM_SPLINE(formula,ptype,iterationcount,fprec) #define BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT_AF_TRIANGLEINEQUALITY(formula,ptype,iterationcount,interpolation,fprec) \ BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT_AF_TRIANGLEINEQUALITY_IM_##interpolation(\ formula,ptype,iterationcount,fprec) #define BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT_AF_CURVATURE(formula,ptype,iterationcount,interpolation,fprec) #define BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT_AF_STRIPE(formula,ptype,iterationcount,interpolation,fprec) #define BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) \ BUILD_FRACTAL_ENGINE_CM_ITERATIONCOUNT_AF_##addend(formula,ptype,iterationcount,interpolation,fprec) #define BUILD_FRACTAL_ENGINE_CM_AVERAGECOLORING_IC_DISCRETE(formula,ptype,addend,interpolation,fprec) \ BUILD_FRACTAL_ENGINE(formula,ptype,AVERAGECOLORING,DISCRETE,addend,interpolation,fprec) #define BUILD_FRACTAL_ENGINE_CM_AVERAGECOLORING_IC_CONTINUOUS(formula,ptype,addend,interpolation,fprec) #define BUILD_FRACTAL_ENGINE_CM_AVERAGECOLORING_IC_SMOOTH(formula,ptype,addend,interpolation,fprec) #define BUILD_FRACTAL_ENGINE_CM_AVERAGECOLORING(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) \ BUILD_FRACTAL_ENGINE_CM_AVERAGECOLORING_IC_##iterationcount(formula,ptype,addend,interpolation,fprec) #define MACRO_BUILD_FRACTAL(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) \ BUILD_FRACTAL_ENGINE_CM_##coloring(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) MACRO_BUILD_FRACTALS /* Build CreateEngine function. */ #define VAL_PINT 1 #define VAL_PFLOATT 0 /*#define BUILD_InitEngine(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) \ if (fractal->fractalFormula == FRAC_##formula && mpcIsInteger(fractal->p) == VAL_##ptype && \ render->coloringMethod == CM_##coloring && render->iterationCount == IC_##iterationcount && \ render->addendFunction == AF_##addend && render->interpolationMethod == IM_##interpolation && \ floatPrecision == FP_##fprec) {\ \ InitEngine##formula##ptype##coloring##iterationcount##addend##interpolation##fprec(\ fractal,render,engine);\ return;\ }*/ #define BUILD_InitEngine_CM_ITERATIONCOUNT(formula,ptype,iterationcount,addend,interpolation,fprec)\ if (render->coloringMethod == CM_ITERATIONCOUNT && fractal->fractalFormula == FRAC_##formula && \ mpcIsInteger(fractal->p) == VAL_##ptype && render->iterationCount == IC_##iterationcount && \ floatPrecision == FP_##fprec) {\ \ InitEngine##formula##ptype##ITERATIONCOUNT##iterationcount##TRIANGLEINEQUALITY##NONE##fprec(\ fractal,render,engine);\ return;\ } #define BUILD_InitEngine_CM_AVERAGECOLORING(formula,ptype,iterationcount,addend,interpolation,fprec)\ if (render->coloringMethod == CM_AVERAGECOLORING && fractal->fractalFormula == FRAC_##formula && \ mpcIsInteger(fractal->p) == VAL_##ptype && render->addendFunction == AF_##addend && \ render->interpolationMethod == IM_##interpolation && floatPrecision == FP_##fprec) {\ \ InitEngine##formula##ptype##AVERAGECOLORING##DISCRETE##addend##interpolation##fprec(\ fractal,render,engine);\ return;\ } #define BUILD_InitEngine(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) \ BUILD_InitEngine_CM_##coloring(formula,ptype,iterationcount,addend,interpolation,fprec) #undef MACRO_BUILD_FRACTAL #define MACRO_BUILD_FRACTAL(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) \ BUILD_InitEngine(formula,ptype,coloring,iterationcount,addend,interpolation,fprec) void CreateFractalEngine(FractalEngine *engine, const Fractal *fractal, const RenderingParameters *render, FloatPrecision floatPrecision) { MACRO_BUILD_FRACTALS /* This should never happen, because fractal engine is built by macros for all possible * values of each parameter. */ FractalNow_error("Could not create fractal compute engine for given parameters.\n"); } void FreeFractalEngine(FractalEngine *engine) { engine->freeEngineData(engine->data); free(engine->data); } CacheEntry RunFractalEngine(const FractalEngine *engine, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t x, uint_fast32_t y, uint_fast32_t width, uint_fast32_t height) { return engine->fractalLoop(engine->data, fractal, render, x, y, width, height); } fractalnow-0.8.1/lib/src/fractal_transfer_function.c0000664000175000017500000000520211754747533021271 0ustar mpegmpeg/* * fractal_transfer_function.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal_transfer_function.h" #include "error.h" #include "misc.h" #include #include double logp1logp1(double x) { return log(log(1+x)+1); } double logp1(double x) { return log(1+x); } double cubert(double x) { return pow(x, 1./3); } double identity(double x) { return x; } double square(double x) { return x*x; } double cube(double x) { return x*x*x; } const TransferFunctionPtr transferFunctionsArray[] = { logp1logp1, logp1, cubert, sqrt, identity, square, cube, exp }; const char *transferFunctionStr[] = { (const char *)"loglog", (const char *)"log", (const char *)"cuberoot", (const char *)"squareroot", (const char *)"identity", (const char *)"square", (const char *)"cube", (const char *)"exp" }; const char *transferFunctionDescStr[] = { (const char *)"Log log", (const char *)"Logarithm", (const char *)"Cube root", (const char *)"Square root", (const char *)"Identity", (const char *)"Square", (const char *)"Cube", (const char *)"Exponential" }; const uint_fast32_t nbTransferFunctions = sizeof(transferFunctionStr) / sizeof(const char *); int GetTransferFunction(TransferFunction *transferFunction, const char *str) { int res = 0; size_t len = strlen(str); if (len > 255) { FractalNow_werror("Unknown transfer function \'%s\'.\n", str); } char TFStr[256]; strcpy(TFStr, str); toLowerCase(TFStr); uint_fast32_t i; for (i = 0; i < nbTransferFunctions; ++i) { if (strcmp(TFStr, transferFunctionStr[i]) == 0) { *(transferFunction) = (TransferFunction)i; break; } } if (i == nbTransferFunctions) { FractalNow_werror("Unknown transfer function \'%s\'.\n", str); } end: return res; } TransferFunctionPtr GetTransferFunctionPtr(TransferFunction transferFunction) { return transferFunctionsArray[(int)transferFunction]; } fractalnow-0.8.1/lib/src/fractalnow.c0000664000175000017500000000205311754747533016205 0ustar mpegmpeg/* * fractalnow.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractalnow.h" #define STR_EXPAND(tok) #tok #define STR(tok) STR_EXPAND(tok) mpfr_prec_t fractalnow_mpfr_precision = DEFAULT_MPFR_PRECISION; const char *FractalNow_VersionNumber() { return STR(VERSION_NUMBER); } fractalnow-0.8.1/lib/src/filter.c0000664000175000017500000002240711754776133015335 0ustar mpegmpeg/* * filter.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "filter.h" #include "misc.h" #include "uirectangle.h" #include #include #define HandleRequests(max_counter) \ if (counter == max_counter) {\ HandlePauseRequest(threadArgHeader);\ cancelRequested =\ CancelTaskRequested(threadArgHeader);\ counter = 0;\ } else {\ ++counter;\ } typedef struct s_ApplyFilterArguments { uint_fast32_t threadId; Image *dst; uint_fast32_t nbRectangles; UIRectangle *rectangles; const Image *src; Filter *filter; } ApplyFilterArguments; void FreeApplyFilterArguments(void *arg) { ApplyFilterArguments *c_arg = (ApplyFilterArguments *)arg; if (c_arg->threadId == 0) { free(c_arg->rectangles); FreeFilter(*c_arg->filter); free(c_arg->filter); } } void InitFilter(Filter *filter, uint_fast32_t sx, uint_fast32_t sy, uint_fast32_t cx, uint_fast32_t cy, double *data) { filter->sx = sx; filter->sy = sy; filter->cx = cx; filter->cy = cy; filter->data = data; } void InitFilter2(Filter *filter, uint_fast32_t sx, uint_fast32_t sy, double *data) { filter->sx = sx; filter->sy = sy; filter->cx = (sx-1) / 2; filter->cy = (sy-1) / 2; filter->data = data; } Filter CopyFilter(const Filter *filter) { Filter res; double *data = (double *)safeMalloc("filter data", filter->sx*filter->sy*sizeof(double)); memcpy(data, filter->data, filter->sx*filter->sy*sizeof(double)); InitFilter(&res, filter->sx, filter->sy, filter->cx, filter->cy, data); return res; } void CreateHorizontalGaussianFilter(Filter *filter, double sigma) { if (sigma <= 0) { FractalNow_error("Sigma must be > 0.\n"); } uint_fast32_t radius = floor(3. * sigma); filter->sx = radius*2+1; filter->sy = 1; filter->cx = radius; filter->cy = 0; filter->data = (double *)safeMalloc("filter", filter->sx*filter->sy*sizeof(double)); double sigma2_x_2 = sigma*sigma*2; double *value = filter->data; int_fast64_t size = (int_fast64_t)filter->cx; double sum = 0; for (int_fast64_t i = -size; i <= size; ++i) { *value = exp(-i*i/sigma2_x_2); sum += *(value++); } if (sum != 0.) { MultiplyFilterByScalar(filter, 1./sum); } } inline void CreateHorizontalGaussianFilter2(Filter *filter, double radius) { if (radius <= 0) { FractalNow_error("Radius must be > 0.\n"); } CreateHorizontalGaussianFilter(filter, radius / 3.); } void CreateVerticalGaussianFilter(Filter *filter, double sigma) { if (sigma <= 0) { FractalNow_error("Sigma must be > 0.\n"); } uint_fast32_t radius = floor(3. * sigma); filter->sx = 1; filter->sy = radius*2+1; filter->cx = 0; filter->cy = radius; filter->data = (double *)safeMalloc("filter", filter->sx*filter->sy*sizeof(double)); double sigma2_x_2 = sigma*sigma*2; double *value = filter->data; int_fast64_t size = (int_fast64_t)filter->cy; double sum = 0; for (int_fast64_t i = -size; i <= size; ++i) { *value = exp(-i*i/sigma2_x_2); sum += *(value++); } if (sum != 0.) { MultiplyFilterByScalar(filter, 1./sum); } } inline void CreateVerticalGaussianFilter2(Filter *filter, double radius) { if (radius <= 0) { FractalNow_error("Radius must be > 0.\n"); } CreateVerticalGaussianFilter(filter, radius / 3.); } void CreateGaussianFilter(Filter *filter, double sigma) { if (sigma <= 0) { FractalNow_error("Sigma must be > 0.\n"); } uint_fast32_t radius = floor(3. * sigma); filter->sx = radius*2+1; filter->sy = radius*2+1; filter->cx = radius; filter->cy = radius; filter->data = (double *)safeMalloc("filter", filter->sx*filter->sy*sizeof(double)); double sigma2_x_2 = sigma*sigma*2; double *value = filter->data; int_fast64_t size = (int_fast64_t)filter->cx; double sum = 0; for (int_fast64_t i = -size; i <= size; ++i) { for (int_fast64_t j = -size; j <= size; ++j) { *value = exp(-(i*i+j*j)/sigma2_x_2); sum += *(value++); } } if (sum != 0.) { MultiplyFilterByScalar(filter, 1./sum); } } void CreateGaussianFilter2(Filter *filter, double radius) { if (radius <= 0) { FractalNow_error("Radius must be > 0.\n"); } CreateGaussianFilter(filter, radius / 3.); } inline double GetFilterValueUnsafe(const Filter *filter, uint_fast32_t x, uint_fast32_t y) { return filter->data[x+y*filter->sx]; } void MultiplyFilterByScalar(Filter *filter, double scalar) { double *value = filter->data; for (uint_fast32_t i = 0; i < filter->sx; ++i) { for (uint_fast32_t j = 0; j < filter->sy; ++j) { *(value++) *= scalar; } } } int NormalizeFilter(Filter *filter) { double *value = filter->data; double sum = 0; for (uint_fast32_t i = 0; i < filter->sx; ++i) { for (uint_fast32_t j = 0; j < filter->sy; ++j) { sum += *(value++); } } if (sum != 0.) { // Otherwize do nothing : can't be normalized anyway MultiplyFilterByScalar(filter, 1./sum); return 0; } else { return 1; } } Color ApplyFilterOnSinglePixel(const Image *src, uint_fast32_t x, uint_fast32_t y, const Filter *filter) { double value; Color color; double r, g, b; r = 0; g = 0; b = 0; for (uint_fast32_t i = 0; i < filter->sx; ++i) { for (uint_fast32_t j = 0; j < filter->sy; ++j) { color = iGetPixel(src, x-filter->cx+i, y-filter->cy+j); value = GetFilterValueUnsafe(filter, i, j); r += color.r * value; g += color.g * value; b += color.b * value; } } color.bytesPerComponent = src->bytesPerComponent; color.r = r; color.g = g; color.b = b; return color; } void *ApplyFilterThreadRoutine(void *arg) { ThreadArgHeader *threadArgHeader = GetThreadArgHeader(arg); ApplyFilterArguments *c_arg = (ApplyFilterArguments *)GetThreadArgBody(arg); Image *dst = c_arg->dst; const Image *src = c_arg->src; Filter *filter = c_arg->filter; uint_fast32_t nbRectangles = c_arg->nbRectangles; UIRectangle *dstRect; uint_fast32_t rectHeight; uint_fast32_t counter = 0; int cancelRequested = CancelTaskRequested(threadArgHeader); for (uint_fast32_t i = 0; i < nbRectangles && !cancelRequested; ++i) { dstRect = &c_arg->rectangles[i]; rectHeight = dstRect->y2+1 - dstRect->y1; for (uint_fast32_t j = dstRect->y1; j <= dstRect->y2 && !cancelRequested; ++j) { SetThreadProgress(threadArgHeader, 100 * (i * rectHeight + (j-dstRect->y1)) / (rectHeight * nbRectangles)); for (uint_fast32_t k = dstRect->x1; k <= dstRect->x2 && !cancelRequested; ++k) { HandleRequests(32); PutPixelUnsafe(dst, k, j, ApplyFilterOnSinglePixel(src, k, j, filter)); } } } SetThreadProgress(threadArgHeader, 100); int canceled = CancelTaskRequested(threadArgHeader); return (canceled ? PTHREAD_CANCELED : NULL); } char applyFilterMessage[] = "Applying filter"; Task *CreateApplyFilterTask(Image *dst, const Image *src, const Filter *filter, uint_fast32_t nbThreads) { if (src->width == 0 || src->height == 0) { return DoNothingTask(); } uint_fast32_t nbPixels = src->width*src->height; uint_fast32_t nbThreadsNeeded = nbThreads; uint_fast32_t rectanglesPerThread = DEFAULT_RECTANGLES_PER_THREAD; if (nbPixels <= nbThreadsNeeded) { nbThreadsNeeded = nbPixels; rectanglesPerThread = 1; } else if (nbPixels < nbThreadsNeeded*rectanglesPerThread) { rectanglesPerThread = nbPixels / nbThreadsNeeded; } uint_fast32_t nbRectangles = nbThreadsNeeded*rectanglesPerThread; UIRectangle *rectangle; rectangle = (UIRectangle *)safeMalloc("rectangles", nbRectangles * sizeof(UIRectangle)); InitUIRectangle(&rectangle[0], 0, 0, dst->width-1, dst->height-1); if (CutUIRectangleInN(rectangle[0], nbRectangles, rectangle)) { FractalNow_error("Could not cut rectangle ((%"PRIuFAST32",%"PRIuFAST32"),\ (%"PRIuFAST32",%"PRIuFAST32") in %"PRIuFAST32" parts.\n", rectangle[0].x1, rectangle[0].y1, rectangle[0].x2, rectangle[0].y2, nbRectangles); } ApplyFilterArguments *arg; arg = (ApplyFilterArguments *)safeMalloc("arguments", nbThreadsNeeded * sizeof(ApplyFilterArguments)); Filter *copyFilter = (Filter *)safeMalloc("copy filter", sizeof(Filter)); *copyFilter = CopyFilter(filter); for (uint_fast32_t i = 0; i < nbThreadsNeeded; ++i) { arg[i].threadId = i; arg[i].dst = dst; arg[i].nbRectangles = rectanglesPerThread; arg[i].rectangles = &rectangle[i*rectanglesPerThread]; arg[i].src = src; arg[i].filter = copyFilter; } Task *res = CreateTask(applyFilterMessage, nbThreadsNeeded, arg, sizeof(ApplyFilterArguments), ApplyFilterThreadRoutine, FreeApplyFilterArguments); free(arg); return res; } void ApplyFilter(Image *dst, const Image *src, const Filter *filter, Threads *threads) { Task *task = CreateApplyFilterTask(dst, src, filter, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } void FreeFilter(Filter filter) { free(filter.data); } fractalnow-0.8.1/lib/src/gradient.c0000664000175000017500000003013511754747533015644 0ustar mpegmpeg/* * gradient.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gradient.h" #include "error.h" #include "file_io.h" #include "misc.h" #include const char *gradientFormatStr[] = { (const char *)"g073" }; const uint_fast32_t nbGradientFormats = sizeof(gradientFormatStr) / sizeof(const char *); int ReadGradientFileV073(Gradient *gradient, uint_fast8_t bytesPerComponent, const char *fileName, FILE *file); typedef int (*ReadGradientFileFunction)(Gradient *gradient, uint_fast8_t bytesPerComponent, const char *fileName, FILE *file); const ReadGradientFileFunction readGradientFileFunction[] = { ReadGradientFileV073 }; int WriteGradientFileV073(const Gradient *gradient, const char *fileName, FILE *file); typedef int (*WriteGradientFileFunction)(const Gradient *gradient, const char *fileName, FILE *file); const WriteGradientFileFunction writeGradientFileFunction[] = { WriteGradientFileV073 }; void aux_GenerateGradient(Gradient *gradient, uint_fast64_t begin_ind_tab, uint_fast64_t end_ind_tab, Color C1, Color C2) { uint_fast64_t N = end_ind_tab - begin_ind_tab; Color *pixel = gradient->data+begin_ind_tab; if (N == 0) { *pixel = C2; } else { for (uint_fast64_t i=0;i<=N;i++) { pixel->bytesPerComponent = C1.bytesPerComponent; pixel->r = (C1.r*(N-i) + C2.r*i) / N; pixel->g = (C1.g*(N-i) + C2.g*i) / N; pixel->b = (C1.b*(N-i) + C2.b*i) / N; ++pixel; } } } void GenerateGradient(Gradient *gradient, uint_fast32_t nbStops, double *positionStop, Color *colorStop, uint_fast32_t size) { FractalNow_message(stdout, T_NORMAL,"Generating gradient...\n"); if (nbStops < 2) { FractalNow_error("Gradient number of stops must be >= 2.\n"); } if (size == 0) { FractalNow_error("Gradient size must be > 0.\n"); } gradient->positionStop = (double *)safeMalloc("position stops copy", nbStops*sizeof(double)); memcpy(gradient->positionStop, positionStop, nbStops*sizeof(double)); gradient->colorStop = (Color *)safeMalloc("color stops copy", nbStops*sizeof(Color)); memcpy(gradient->colorStop, colorStop, nbStops*sizeof(Color)); gradient->nbStops = nbStops; gradient->bytesPerComponent = colorStop[0].bytesPerComponent; gradient->size = size; gradient->data = (Color *)safeMalloc("gradient data", size*sizeof(Color)); for (uint_fast32_t i=0; i 1) { FractalNow_error("Gradient position stops must be between 0 and 1.\n"); } else if (i != 0 && positionStop[i] <= positionStop[i-1]) { FractalNow_error("Gradient position stops should be (stricly) increasing.\n"); } aux_GenerateGradient(gradient, positionStop[i]*(size-1), positionStop[i+1]*(size-1), colorStop[i], colorStop[i+1]); } FractalNow_message(stdout, T_NORMAL,"Generating gradient : DONE.\n"); } void GenerateGradient2(Gradient *gradient, uint_fast32_t nbStops, Color *colorStop, uint_fast32_t nbTransitions) { if (nbTransitions == 0) { FractalNow_error("Gradient number of transitions must be > 0.\n"); } double *positionStop = (double *)malloc(nbStops * sizeof(double)); for (uint_fast32_t i = 0; i < nbStops; ++i) { positionStop[i] = i / (double)(nbStops-1); } uint_fast64_t size = (nbStops-1) * nbTransitions; GenerateGradient(gradient, nbStops, positionStop, colorStop, size); free(positionStop); } Gradient CopyGradient(const Gradient *gradient) { Gradient res; res.bytesPerComponent = gradient->bytesPerComponent; res.size = gradient->size; res.data = (Color *)safeMalloc("gradient copy data", gradient->size*sizeof(Color)); memcpy(res.data, gradient->data, gradient->size*sizeof(Color)); res.nbStops = gradient->nbStops; res.positionStop = (double *)safeMalloc("gradient position stop copy", gradient->nbStops*sizeof(double)); memcpy(res.positionStop, gradient->positionStop, gradient->nbStops*sizeof(double)); res.colorStop = (Color *)safeMalloc("gradient color stop copy", gradient->nbStops*sizeof(Color)); memcpy(res.colorStop, gradient->colorStop, gradient->nbStops*sizeof(Color)); return res; } Gradient Gradient16(const Gradient *gradient) { Gradient res; if (gradient->bytesPerComponent == 2) { res = CopyGradient(gradient); } else { Color *tmp = (Color *)safeMalloc("16 bits gradient color stops copy", gradient->nbStops*sizeof(Color)); for (uint_fast32_t i = 0; i < gradient->nbStops; ++i) { tmp[i] = Color16(gradient->colorStop[i]); } GenerateGradient(&res, gradient->nbStops, gradient->positionStop, tmp, gradient->size); free(tmp); } return res; } Gradient Gradient8(const Gradient *gradient) { Gradient res; if (gradient->bytesPerComponent == 1) { res = CopyGradient(gradient); } else { Color *tmp = (Color *)safeMalloc("8 bits gradient color stops copy", gradient->nbStops*sizeof(Color)); for (uint_fast32_t i = 0; i < gradient->nbStops; ++i) { tmp[i] = Color8(gradient->colorStop[i]); } GenerateGradient(&res, gradient->nbStops, gradient->positionStop, tmp, gradient->size); free(tmp); } return res; } inline Color GetGradientColor(const Gradient *gradient, uint_fast64_t index) { return gradient->data[index % gradient->size]; } void FreeGradient(Gradient gradient) { free(gradient.data); free(gradient.positionStop); free(gradient.colorStop); } int ReadGradientFileV073(Gradient *gradient, uint_fast8_t bytesPerComponent, const char *fileName, FILE *file) { int res = 0; double positionStop[257]; Color colorStop[257]; uint_fast32_t nbStops=0; int readRes; while (1) { readRes = readDouble(file, &positionStop[nbStops]); if (readRes == EOF) { break; } else if (readRes != 1) { FractalNow_read_werror(fileName); } readRes = readColor(file, bytesPerComponent, &colorStop[nbStops]); if (readRes == EOF) { FractalNow_werror("Missing gradient color stop.\n"); } else if (readRes != 1) { FractalNow_read_werror(fileName); } if (nbStops > 255) { break; } nbStops++; } if (nbStops < 2 || nbStops > 255) { FractalNow_werror("Gradient number of stops must be between 2 and 255.\n"); } /* Check stops are well-formed (pos0 = 0 <= pos1 <= ... <= posN = 1) */ if (positionStop[0] != 0) { FractalNow_werror("First gradient stop position should be 0.\n"); } if (positionStop[nbStops-1] != 1) { FractalNow_werror("Last gradient stop position should be 1.\n"); } for (uint_fast32_t i = 1; i < nbStops; ++i) { if (positionStop[i] <= positionStop[i-1]) { FractalNow_werror("Gradient stop positions should be (stricly) increasing.\n"); } } GenerateGradient(gradient, nbStops, positionStop, colorStop, DEFAULT_GRADIENT_SIZE); end: return res; } ReadGradientFileFunction GetReadGradientFileFunction(const char *format) { if (strlen(format) != 4) { return NULL; } ReadGradientFileFunction readGradientFile = NULL; char formatStr[5]; strcpy(formatStr, format); toLowerCase(formatStr); uint_fast32_t i; for (i = 0; i < nbGradientFormats; ++i) { if (strcmp(formatStr, gradientFormatStr[i]) == 0) { readGradientFile = readGradientFileFunction[i]; break; } } return readGradientFile; } int isSupportedGradientFile(const char *fileName) { int res = 0; FILE *file; file=fopen(fileName,"r"); if (!file) { FractalNow_open_werror(fileName); } char formatStr[256]; if (readString(file, formatStr) < 1) { res = 1; } else { ReadGradientFileFunction readGradientFileFunction; readGradientFileFunction = GetReadGradientFileFunction(formatStr); res = (readGradientFileFunction == NULL); } end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } return !res; } int ReadGradientFileBody(Gradient *gradient, uint_fast8_t bytesPerComponent, const char *fileName, FILE *file, const char *format) { FractalNow_message(stdout, T_VERBOSE, "Reading gradient file body...\n"); int res = 0; ReadGradientFileFunction readGradientFile; readGradientFile = GetReadGradientFileFunction(format); if (readGradientFile == NULL) { FractalNow_werror("Unsupported gradient format '%s'.\n", format); } res |= readGradientFile(gradient, bytesPerComponent, fileName, file); end: FractalNow_message(stdout, T_VERBOSE, "Reading gradient file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int ReadGradientFile(Gradient *gradient, const char *fileName) { FractalNow_message(stdout, T_NORMAL, "Reading gradient file...\n"); int res = 0; FILE *file; file=fopen(fileName,"r"); if (!file) { FractalNow_open_werror(fileName); } char formatStr[256]; if (readString(file, formatStr) < 1) { FractalNow_read_werror(fileName); } uint_fast8_t bytesPerComponent; uint32_t bytesPerComponent32; if (readUint32(file, &bytesPerComponent32) < 1) { FractalNow_read_werror(fileName); } if (bytesPerComponent32 == 1 || bytesPerComponent32 == 2) { bytesPerComponent = (uint_fast8_t)bytesPerComponent32; } else { FractalNow_werror("Invalid gradient file : bytes per components must be 1 or 2.\n"); } res = ReadGradientFileBody(gradient, bytesPerComponent, fileName, file, formatStr); end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } FractalNow_message(stdout, T_NORMAL, "Reading gradient file : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int WriteGradientFileV073(const Gradient *gradient, const char *fileName, FILE *file) { int res = 0; const char *suffix = " "; for (uint_fast32_t i = 0; i < gradient->nbStops; ++i) { if (writeDouble(file, gradient->positionStop[i], " ") < 0) { FractalNow_write_werror(fileName); } if (i == gradient->nbStops-1) { suffix = "\n"; } if (writeColor(file, gradient->colorStop[i], suffix) < 0) { FractalNow_write_werror(fileName); } } end: return res; } WriteGradientFileFunction GetWriteGradientFileFunction(const char *format) { if (strlen(format) != 4) { return NULL; } WriteGradientFileFunction writeGradientFile = NULL; char formatStr[5]; strcpy(formatStr, format); toLowerCase(formatStr); uint_fast32_t i; for (i = 0; i < nbGradientFormats; ++i) { if (strcmp(formatStr, gradientFormatStr[i]) == 0) { writeGradientFile = writeGradientFileFunction[i]; break; } } return writeGradientFile; } int WriteGradientFileBody(const Gradient *gradient, const char *fileName, FILE *file, const char *format) { FractalNow_message(stdout, T_VERBOSE, "Writing gradient file body...\n"); int res = 0; WriteGradientFileFunction writeGradientFile; writeGradientFile = GetWriteGradientFileFunction(format); if (writeGradientFile == NULL) { FractalNow_werror("Unsupported gradient format '%s'.\n", format); } res |= writeGradientFile(gradient, fileName, file); end: FractalNow_message(stdout, T_VERBOSE, "Writing gradient file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int WriteGradientFile(const Gradient *gradient, const char *fileName) { FractalNow_message(stdout, T_NORMAL, "Writing gradient file...\n"); int res = 0; FILE *file; file=fopen(fileName,"w"); if (!file) { FractalNow_open_werror(fileName); } const char *format = gradientFormatStr[nbGradientFormats-1]; if (writeString(file, format, "\n") < 0) { FractalNow_write_werror(fileName); } if (writeUint32(file, gradient->bytesPerComponent, "\n") < 0) { FractalNow_write_werror(fileName); } res |= WriteGradientFileBody(gradient, fileName, file, format); end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } FractalNow_message(stdout, T_VERBOSE, "Writing gradient file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } fractalnow-0.8.1/lib/src/task.c0000664000175000017500000003526011754747533015015 0ustar mpegmpeg/* * task.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "task.h" #include "error.h" #include "misc.h" #include #define ARG_SIZE (size_t)(sizeof(ThreadArgHeader *)+sizeof(void *)) static inline int ReadIntVarSafe(int *variable, pthread_spinlock_t *mutex) { int res; safePThreadSpinLock(mutex); res = *variable; safePThreadSpinUnlock(mutex); return res; } static inline void WriteIntVarSafe(int *variable, int value, pthread_spinlock_t *mutex) { safePThreadSpinLock(mutex); *variable = value; safePThreadSpinUnlock(mutex); } void *DoNothingThreadRoutine(void *arg) { ThreadArgHeader *c_arg = GetThreadArgHeader(arg); HandlePauseRequest(c_arg); return (CancelTaskRequested(c_arg) ? PTHREAD_CANCELED : NULL); } void FreeArgDoNothing(void *arg) { UNUSED(arg); } #ifdef DEBUG char DoNothingMessage[] = "Doing nothing"; #else char *DoNothingMessage = NULL; #endif Task *DoNothingTask() { return CreateTask(DoNothingMessage, 0, NULL, 0, DoNothingThreadRoutine, FreeArgDoNothing); } static inline Task *aux_CreateTask(const char message[], uint_fast32_t nbThreadsNeeded, size_t s_elem, void *(*routine)(void *), void (*freeArg)(void *)) { Task *res = (Task *)safeMalloc("task", sizeof(Task)); res->launchPrepared = 0; res->hasBeenLaunched = 0; res->done = 0; res->returnValue = -1; res->nbThreadsNeeded = nbThreadsNeeded; res->initialArgs = NULL; safePThreadSpinInit(&res->cancelMutex, SPIN_INIT_ATTR); WriteIntVarSafe(&res->cancel, 0, &res->cancelMutex); safePThreadSpinInit(&res->pauseMutex, SPIN_INIT_ATTR); WriteIntVarSafe(&res->pause, 0, &res->pauseMutex); res->isComposite = 0; res->compositeTaskArguments.thisTask = NULL; res->nbSubTasks = 0; res->subTasks = NULL; res->compositeTaskNbReady = 0; res->stopLaunchingSubTasks = 0; safePThreadCondInit(&res->compositeTaskAllThreadsReadyCond, NULL); res->s_elem = s_elem; if (freeArg == NULL) { res->freeArg = FreeArgDoNothing; } else { res->freeArg = freeArg; } if (message == NULL) { res->message = NULL; } else { res->message = (char *)safeMalloc("message", (strlen(message)+1)*sizeof(char)); strcpy(res->message, message); } res->threadsRoutine = routine; return res; } inline Task *CreateTask(const char message[], uint_fast32_t nbThreadsNeeded, const void *args, size_t s_elem, void *(*routine)(void *), void (*freeArg)(void *)) { Task *res = aux_CreateTask(message, nbThreadsNeeded, s_elem, routine, freeArg); if (res->s_elem > 0) { res->initialArgs = safeMalloc("thread args", nbThreadsNeeded * s_elem); memcpy(res->initialArgs, args, nbThreadsNeeded * s_elem); } return res; } void *CompositeTaskRoutine(void *arg); Task *CreateCompositeTask(const char message[], uint_fast32_t nbSubTasks, Task *subTasks[]) { if (nbSubTasks == 0) { FractalNow_error("Number of subtasks must be > 0 when creating composite task.\n"); } uint_fast32_t nbThreadsNeeded = subTasks[0]->nbThreadsNeeded; for (uint_fast32_t i = 1; i < nbSubTasks; ++i) { if (subTasks[i]->nbThreadsNeeded > nbThreadsNeeded) { nbThreadsNeeded = subTasks[i]->nbThreadsNeeded; } } Task *res = aux_CreateTask(message, nbThreadsNeeded, sizeof(CompositeTaskArguments), CompositeTaskRoutine, NULL); res->isComposite = 1; res->compositeTaskArguments.thisTask = res; res->nbSubTasks = nbSubTasks; res->subTasks = (Task **)safeMalloc("copy subtasks", nbSubTasks*sizeof(Task *)); memcpy(res->subTasks, subTasks, nbSubTasks*sizeof(Task *)); return res; } /* nbReady override for tasks that are subtasks. */ static void PrepareLaunchTask(Task *task, Threads *threads, uint_fast32_t *nbReadyOverride) { task->threads = threads; task->threadArgsHeaders = (ThreadArgHeader *)safeMalloc("thread arg headers", threads->N * sizeof(ThreadArgHeader)); task->args = (void *)safeMalloc("thread args", threads->N * ARG_SIZE); uint8_t *task_args = (uint8_t *)task->args; uint8_t *c_args = (uint8_t *)task->initialArgs; ThreadArgHeader *threadArgHeader = task->threadArgsHeaders; for (uint_fast32_t i = 0; i < threads->N; ++i) { threadArgHeader->threadId = i; threadArgHeader->threads = threads; if (nbReadyOverride != NULL) { threadArgHeader->nbReady = nbReadyOverride; } else { threadArgHeader->nbReady = &threads->nbReady; } threadArgHeader->cancel = &task->cancel; threadArgHeader->cancelMutex = &task->cancelMutex; threadArgHeader->pause = &task->pause; threadArgHeader->pauseMutex = &task->pauseMutex; threadArgHeader->progress = 0; safePThreadSpinInit(&threadArgHeader->progressMutex, SPIN_INIT_ATTR); *((ThreadArgHeader **)task_args) = threadArgHeader; if (task->isComposite) { *((void **)(task_args + sizeof(ThreadArgHeader *))) = &task->compositeTaskArguments; } else { if (i < task->nbThreadsNeeded) { *((void **)(task_args + sizeof(ThreadArgHeader *))) = c_args; c_args += task->s_elem; } else { *((void **)(task_args + sizeof(ThreadArgHeader *))) = NULL; } } task_args += ARG_SIZE; ++threadArgHeader; } if (task->isComposite) { for (uint_fast32_t i = 0; i < task->nbSubTasks; ++i) { PrepareLaunchTask(task->subTasks[i], threads, &task->compositeTaskNbReady); } } task->launchPrepared = 1; } void LaunchTask(Task *task, Threads *threads) { if (task->hasBeenLaunched) { FractalNow_error("Trying to launch task that has already been launched.\n"); } safePThreadMutexLock(&threads->threadsMutex); if (threads->nbReady < threads->N) { FractalNow_error("Trying to launch task while threads are still busy.\n"); } safePThreadMutexUnlock(&threads->threadsMutex); PrepareLaunchTask(task, threads, NULL); uint8_t *task_args = (uint8_t *)task->args; safePThreadMutexLock(&threads->startThreadCondMutex); for (uint_fast32_t i = 0; i < threads->N; ++i) { threads->startThreadArg[i].message = task->message; if (task->isComposite || i < task->nbThreadsNeeded) { threads->startThreadArg[i].startRoutine = task->threadsRoutine; } else { threads->startThreadArg[i].startRoutine = DoNothingThreadRoutine; } threads->startThreadArg[i].arg = task_args; task_args += ARG_SIZE; } /* Reinit nbReady counter. */ threads->nbReady = 0; threads->nbPaused = 0; task->hasBeenLaunched = 1; if (task->message != NULL) { FractalNow_message(stdout, T_NORMAL, "%s...\n", task->message); } safePThreadCondBroadcast(&threads->startThreadCond); safePThreadMutexUnlock(&threads->startThreadCondMutex); } void CancelTask(Task *task) { if (task->isComposite) { for (uint_fast32_t i = 0; i < task->nbSubTasks; ++i) { CancelTask(task->subTasks[i]); } } WriteIntVarSafe(&task->cancel, 1, &task->cancelMutex); } static inline void aux_PauseTask(Task *task) { if (task->isComposite) { WriteIntVarSafe(&task->pause, 1, &task->pauseMutex); for (uint_fast32_t i = 0; i < task->nbSubTasks; ++i) { aux_PauseTask(task->subTasks[i]); } } else { WriteIntVarSafe(&task->pause, 1, &task->pauseMutex); } } void PauseTask(Task *task) { if (!task->hasBeenLaunched || task->done) { return; } int pause = ReadIntVarSafe(&task->pause, &task->pauseMutex); if (pause) { return; } Threads *threads = task->threads; safePThreadMutexLock(&threads->threadsMutex); if (threads->nbReady < threads->N) { threads->nbPaused = 0; aux_PauseTask(task); safePThreadCondWait(&threads->allPausedCond, &threads->threadsMutex); } safePThreadMutexUnlock(&threads->threadsMutex); } static inline void aux_ResumeTask(Task *task) { if (task->isComposite) { for (uint_fast32_t i = 0; i < task->nbSubTasks; ++i) { aux_ResumeTask(task->subTasks[i]); } WriteIntVarSafe(&task->pause, 0, &task->pauseMutex); } else { WriteIntVarSafe(&task->pause, 0, &task->pauseMutex); } } void ResumeTask(Task *task) { if (!task->hasBeenLaunched || task->done) { return; } Threads *threads = task->threads; safePThreadMutexLock(&task->threads->threadsMutex); aux_ResumeTask(task); if (threads->nbPaused > 0) { safePThreadCondBroadcast(&threads->resumeTaskCond); safePThreadCondWait(&threads->allResumedCond, &threads->threadsMutex); } safePThreadMutexUnlock(&threads->threadsMutex); } void onTaskFinished(Task *task) { void *status; for (uint_fast32_t i = 0; i < task->threads->N; ++i) { status = task->threads->lastResult[i]; if (status != NULL && status != PTHREAD_CANCELED) { FractalNow_message(stderr, T_QUIET, "Thread ended because of an error.\n"); } } task->done = 1; task->returnValue = ReadIntVarSafe(&task->cancel, &task->cancelMutex); if (task->message != NULL) { FractalNow_message(stdout, T_NORMAL, "%s : %s.\n", task->message, (task->returnValue == 0) ? "DONE" : "CANCELED"); } } int TaskIsFinished(Task *task) { if (task->done) { return 1; } if (!task->hasBeenLaunched) { return 0; } uint_fast32_t nbReady = 0; safePThreadMutexLock(&task->threads->threadsMutex); nbReady = task->threads->nbReady; safePThreadMutexUnlock(&task->threads->threadsMutex); int res = 0; if (nbReady == task->threads->N) { onTaskFinished(task); res = 1; } return res; } inline int GetTaskResult(Task *task) { if (task->done) { return task->returnValue; } if (!task->hasBeenLaunched) { FractalNow_error("Cannot get result of not-yet-launched task.\n"); } uint_fast32_t nbReady = 0; safePThreadMutexLock(&task->threads->threadsMutex); nbReady = task->threads->nbReady; if (nbReady < task->threads->N) { safePThreadCondWait(&task->threads->allThreadsReadyCond, &task->threads->threadsMutex); nbReady = task->threads->nbReady; } safePThreadMutexUnlock(&task->threads->threadsMutex); onTaskFinished(task); return task->returnValue; } int ExecuteTaskBlocking(Task *task, Threads *threads) { LaunchTask(task, threads); int res = GetTaskResult(task); FreeTask(task); return res; } double GetTaskProgress(const Task *task) { double res; if (!task->hasBeenLaunched) { res = 0; } else if (task->done) { res = 1; } else if (!task->isComposite) { res = 0; for (uint_fast32_t i = 0; i < task->nbThreadsNeeded; ++i) { res += ReadIntVarSafe(&task->threadArgsHeaders[i].progress, &task->threadArgsHeaders[i].progressMutex); } res /= 100 * task->nbThreadsNeeded; } else { res = 0; for (uint_fast32_t i = 0; i < task->nbSubTasks; ++i) { res += GetTaskProgress(task->subTasks[i]); } res /= task->nbSubTasks; } return res; } inline void FreeTask(Task *task) { if (task->hasBeenLaunched && !task->done) { FractalNow_error("Trying to free non-finished task.\n"); } uint8_t *c_arg = (uint8_t *)task->initialArgs; for (uint_fast32_t i = 0; i < task->nbThreadsNeeded; ++i) { task->freeArg(c_arg); c_arg += task->s_elem; } if (task->initialArgs != NULL) { free(task->initialArgs); } if (task->launchPrepared) { Threads *threads = task->threads; for (uint_fast32_t i = 0; i < threads->N; ++i) { safePThreadSpinDestroy(&task->threadArgsHeaders[i].progressMutex); } free(task->threadArgsHeaders); free(task->args); } if (task->message != NULL) { free(task->message); } if (task->isComposite) { for (uint_fast32_t i = 0; i < task->nbSubTasks; ++i) { FreeTask(task->subTasks[i]); } free(task->subTasks); } safePThreadSpinDestroy(&task->cancelMutex); safePThreadSpinDestroy(&task->pauseMutex); safePThreadCondDestroy(&task->compositeTaskAllThreadsReadyCond); free(task); } static inline void CompositeTaskRendezVous(ThreadArgHeader *threadArgHeader, Task *thisTask, Task *finishedTask, Task *newTask, uint_fast32_t i) { Threads *threads = threadArgHeader->threads; safePThreadMutexLock(&threads->threadsMutex); ++thisTask->compositeTaskNbReady; if (threads->nbPaused > 0 && thisTask->compositeTaskNbReady+threads->nbPaused == threads->N) { safePThreadCondSignal(&threads->allPausedCond); } if (finishedTask != NULL && finishedTask->message != NULL) { FractalNow_message(stdout, T_VERBOSE, "%s [%"PRIuFAST32"] : %s.\n", finishedTask->message, threadArgHeader->threadId, threads->lastResult[threadArgHeader->threadId] == NULL ? "DONE" : "CANCELED"); } if (thisTask->compositeTaskNbReady == threads->N) { if (finishedTask != NULL) { onTaskFinished(finishedTask); } if (newTask != NULL) { if (CancelTaskRequested(threadArgHeader)) { thisTask->stopLaunchingSubTasks = 1; } else { threadArgHeader->progress = 100 * i / thisTask->nbSubTasks; thisTask->compositeTaskNbReady = 0; newTask->hasBeenLaunched = 1; if (newTask->message != NULL) { FractalNow_message(stdout, T_NORMAL, "%s...\n", newTask->message); } } } else { threadArgHeader->progress = 100; } safePThreadCondBroadcast(&thisTask->compositeTaskAllThreadsReadyCond); } else { safePThreadCondWait(&thisTask->compositeTaskAllThreadsReadyCond, &threads->threadsMutex); } safePThreadMutexUnlock(&threads->threadsMutex); } void *CompositeTaskRoutine(void *arg) { ThreadArgHeader *threadArgHeader = GetThreadArgHeader(arg); CompositeTaskArguments *c_arg = (CompositeTaskArguments *)GetThreadArgBody(arg); Task *thisTask = c_arg->thisTask; Task *currentTask = NULL; Task *previousTask = NULL; void *result; int canceled = 0; uint_fast32_t i; for (i = 0; i < thisTask->nbSubTasks; ++i) { previousTask = currentTask; currentTask = thisTask->subTasks[i]; CompositeTaskRendezVous(threadArgHeader, thisTask, previousTask, currentTask, i); if (thisTask->stopLaunchingSubTasks) { canceled = 1; break; } else { if (currentTask->message != NULL) { FractalNow_message(stdout, T_VERBOSE, "%s [%"PRIuFAST32"]...\n", currentTask->message, threadArgHeader->threadId); } if (currentTask->isComposite || threadArgHeader->threadId < currentTask->nbThreadsNeeded) { result = currentTask->threadsRoutine(((uint8_t *)currentTask->args)+ threadArgHeader->threadId*ARG_SIZE); } else { result = DoNothingThreadRoutine(((uint8_t *)currentTask->args)+ threadArgHeader->threadId*ARG_SIZE); } currentTask->threads->lastResult[threadArgHeader->threadId] = result; } } if (!canceled) { CompositeTaskRendezVous(threadArgHeader, thisTask, currentTask, NULL, i); } return (CancelTaskRequested(threadArgHeader) ? PTHREAD_CANCELED : NULL); } fractalnow-0.8.1/lib/src/fractal_rendering_parameters.c0000664000175000017500000002777411754747533021762 0ustar mpegmpeg/* * fractal_rendering_parameters.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal_rendering_parameters.h" #include "error.h" #include "file_io.h" #include "misc.h" #include #include #include const char *renderingFileFormatStr[] = { (const char *)"r075" }; const uint_fast32_t nbRenderingFileFormats = sizeof(renderingFileFormatStr) / sizeof(const char *); int ReadRenderingFileV075(RenderingParameters *param, const char *fileName, FILE *file); typedef int (*ReadRenderingFileFunction)(RenderingParameters *param, const char *fileName, FILE *file); const ReadRenderingFileFunction readRenderingFileFunction[] = { ReadRenderingFileV075 }; int WriteRenderingFileV075(const RenderingParameters *param, const char *fileName, FILE *file); typedef int (*WriteRenderingFileFunction)(const RenderingParameters *param, const char *fileName, FILE *file); const WriteRenderingFileFunction writeRenderingFileFunction[] = { WriteRenderingFileV075 }; inline void InitRenderingParameters(RenderingParameters *param, uint_fast8_t bytesPerComponent, Color spaceColor, IterationCount iterationCount, ColoringMethod coloringMethod, AddendFunction addendFunction, uint_fast32_t stripeDensity, InterpolationMethod interpolationMethod, TransferFunction transferFunction, double multiplier, double offset, Gradient gradient) { param->bytesPerComponent = bytesPerComponent; param->spaceColor = spaceColor; param->iterationCount = iterationCount; param->coloringMethod = coloringMethod; param->addendFunction = addendFunction; param->stripeDensity = stripeDensity; param->interpolationMethod = interpolationMethod; param->transferFunction = transferFunction; param->transferFunctionPtr = GetTransferFunctionPtr(transferFunction); param->multiplier = multiplier; param->realMultiplier = multiplier*gradient.size; param->offset = offset; param->realOffset = offset*gradient.size; param->gradient = gradient; } RenderingParameters CopyRenderingParameters(const RenderingParameters *param) { Gradient copyGradient = CopyGradient(¶m->gradient); RenderingParameters res; InitRenderingParameters(&res, param->bytesPerComponent, param->spaceColor, param->iterationCount, param->coloringMethod, param->addendFunction, param->stripeDensity, param->interpolationMethod, param->transferFunction, param->multiplier, param->offset, copyGradient); return res; } void ResetGradient(RenderingParameters *param, Gradient gradient) { FreeGradient(param->gradient); param->gradient = CopyGradient(&gradient); param->bytesPerComponent = gradient.bytesPerComponent; param->realMultiplier = param->multiplier*gradient.size; param->realOffset = param->offset*gradient.size; } int ReadRenderingFileV075(RenderingParameters *param, const char *fileName, FILE *file) { int res = 0; uint_fast8_t bytesPerComponent; Color spaceColor; IterationCount iterationCount; ColoringMethod coloringMethod; AddendFunction addendFunction; uint32_t stripeDensity; InterpolationMethod interpolationMethod; TransferFunction transferFunction; double multiplier; double offset; Gradient gradient; char str[256]; uint32_t bytesPerComponent32; if (readUint32(file, &bytesPerComponent32) < 1) { FractalNow_read_werror(fileName); } if (bytesPerComponent32 == 1 || bytesPerComponent32 == 2) { bytesPerComponent = (uint_fast8_t)bytesPerComponent32; } else { FractalNow_werror("Invalid rendering file : bytes per components must be 1 or 2.\n"); } if (readColor(file, bytesPerComponent, &spaceColor) < 1) { FractalNow_read_werror(fileName); } if (readString(file, str) < 1) { FractalNow_read_werror(fileName); } if (GetColoringMethod(&coloringMethod, str)) { FractalNow_werror("Invalid rendering file : could not get coloring method.\n"); } /* Just to be sure these are initialized, because they are always needed (and thus read). */ iterationCount = IC_SMOOTH; interpolationMethod = IM_NONE; addendFunction = AF_TRIANGLEINEQUALITY; stripeDensity = 1; switch (coloringMethod) { case CM_ITERATIONCOUNT: if (readString(file, str) < 1) { FractalNow_read_werror(fileName); } if (GetIterationCount(&iterationCount, str)) { FractalNow_werror("Invalid rendering file : could not get counting function.\n"); } break; case CM_AVERAGECOLORING: if (readString(file, str) < 1) { FractalNow_read_werror(fileName); } if (GetAddendFunction(&addendFunction, str)) { FractalNow_werror("Invalid rendering file : could not get addend function.\n"); } if (addendFunction == AF_STRIPE) { if (readUint32(file, &stripeDensity) < 1) { FractalNow_read_werror(fileName); } } if (readString(file, str) < 1) { FractalNow_read_werror(fileName); } if (GetInterpolationMethod(&interpolationMethod, str)) { FractalNow_werror("Invalid rendering file : could not get interpolation method.\n"); } break; default: FractalNow_werror("Unknown coloring method.\n"); break; } if (readString(file, str) < 1) { FractalNow_read_werror(fileName); } if (GetTransferFunction(&transferFunction, str)) { FractalNow_werror("Invalid rendering file : could not get transfer function.\n"); } if (readDouble(file, &multiplier) < 1) { FractalNow_read_werror(fileName); } if (readDouble(file, &offset) < 1) { FractalNow_read_werror(fileName); } if (ReadGradientFileBody(&gradient, bytesPerComponent, fileName, file, "g073")) { FractalNow_werror("Invalid rendering file : failed to read gradient.\n"); } InitRenderingParameters(param, bytesPerComponent, spaceColor, iterationCount, coloringMethod, addendFunction, stripeDensity, interpolationMethod, transferFunction, multiplier, offset, gradient); end: return res; } ReadRenderingFileFunction GetReadRenderingFileFunction(const char *format) { if (strlen(format) != 4) { return NULL; } ReadRenderingFileFunction readRenderingFile = NULL; char formatStr[5]; strcpy(formatStr, format); toLowerCase(formatStr); uint_fast32_t i; for (i = 0; i < nbRenderingFileFormats; ++i) { if (strcmp(formatStr, renderingFileFormatStr[i]) == 0) { readRenderingFile = readRenderingFileFunction[i]; break; } } return readRenderingFile; } int isSupportedRenderingFile(const char *fileName) { int res = 0; FILE *file; file=fopen(fileName,"r"); if (!file) { FractalNow_open_werror(fileName); } char formatStr[256]; if (readString(file, formatStr) < 1) { res = 1; } else { ReadRenderingFileFunction readRenderingFileFunction; readRenderingFileFunction = GetReadRenderingFileFunction(formatStr); res = (readRenderingFileFunction == NULL); } end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } return !res; } int ReadRenderingFileBody(RenderingParameters *param, const char *fileName, FILE *file, const char *format) { FractalNow_message(stdout, T_VERBOSE, "Reading rendering file body...\n"); int res = 0; ReadRenderingFileFunction readRenderingFile; readRenderingFile = GetReadRenderingFileFunction(format); if (readRenderingFile == NULL) { FractalNow_werror("Unsupported rendering file format '%s'.\n", format); } res |= readRenderingFile(param, fileName, file); end: FractalNow_message(stdout, T_VERBOSE, "Reading rendering file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int ReadRenderingFile(RenderingParameters *param, const char *fileName) { FractalNow_message(stdout, T_NORMAL, "Reading rendering file...\n"); int res = 0; FILE *file; file=fopen(fileName,"r"); if (!file) { FractalNow_open_werror(fileName); } char formatStr[256]; if (readString(file, formatStr) < 1) { FractalNow_read_werror(fileName); } res = ReadRenderingFileBody(param, fileName, file, formatStr); end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } FractalNow_message(stdout, T_NORMAL, "Reading rendering file : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int WriteRenderingFileV075(const RenderingParameters *param, const char *fileName, FILE *file) { int res = 0; if (writeUint32(file, param->bytesPerComponent, "\n") < 0) { FractalNow_write_werror(fileName); } if (writeColor(file, param->spaceColor, "\n") < 0) { FractalNow_write_werror(fileName); } if (writeString(file, coloringMethodStr[(int)param->coloringMethod], "\n") < 0) { FractalNow_write_werror(fileName); } switch (param->coloringMethod) { case CM_ITERATIONCOUNT: if (writeString(file, iterationCountStr[(int)param->iterationCount], "\n") < 0) { FractalNow_write_werror(fileName); } break; case CM_AVERAGECOLORING: if (writeString(file, addendFunctionStr[(int)param->addendFunction], " ") < 0) { FractalNow_write_werror(fileName); } if (param->addendFunction == AF_STRIPE) { if (writeUint32(file, param->stripeDensity, " ") < 0) { FractalNow_write_werror(fileName); } } if (writeString(file, interpolationMethodStr[(int)param->interpolationMethod], "\n") < 0) { FractalNow_write_werror(fileName); } break; default: FractalNow_werror("Unknown coloring method.\n"); break; } if (writeString(file, transferFunctionStr[(int)param->transferFunction], "\n") < 0) { FractalNow_write_werror(fileName); } if (writeDouble(file, param->multiplier, " ") < 0) { FractalNow_write_werror(fileName); } if (writeDouble(file, param->offset, "\n") < 0) { FractalNow_write_werror(fileName); } if (WriteGradientFileBody(¶m->gradient, fileName, file, "g073")) { FractalNow_werror("Failed to write gradient.\n"); } end: return res; } WriteRenderingFileFunction GetWriteRenderingFileFunction(const char *format) { if (strlen(format) != 4) { return NULL; } WriteRenderingFileFunction writeRenderingFile = NULL; char formatStr[5]; strcpy(formatStr, format); toLowerCase(formatStr); uint_fast32_t i; for (i = 0; i < nbRenderingFileFormats; ++i) { if (strcmp(formatStr, renderingFileFormatStr[i]) == 0) { writeRenderingFile = writeRenderingFileFunction[i]; break; } } return writeRenderingFile; } int WriteRenderingFileBody(const RenderingParameters *param, const char *fileName, FILE *file, const char *format) { FractalNow_message(stdout, T_VERBOSE, "Writing rendering file body...\n"); int res = 0; WriteRenderingFileFunction writeRenderingFile; writeRenderingFile = GetWriteRenderingFileFunction(format); if (writeRenderingFile == NULL) { FractalNow_werror("Unsupported rendering file format '%s'.\n", format); } res |= writeRenderingFile(param, fileName, file); end: FractalNow_message(stdout, T_VERBOSE, "Writing rendering file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int WriteRenderingFile(const RenderingParameters *param, const char *fileName) { FractalNow_message(stdout, T_NORMAL, "Writing rendering file...\n"); int res = 0; FILE *file; file=fopen(fileName,"w"); if (!file) { FractalNow_open_werror(fileName); } const char *format = renderingFileFormatStr[nbRenderingFileFormats-1]; if (writeString(file, format, "\n") < 0) { FractalNow_write_werror(fileName); } res = WriteRenderingFileBody(param, fileName, file, format); end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } FractalNow_message(stdout, T_NORMAL, "Writing rendering file : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } void FreeRenderingParameters(RenderingParameters param) { FreeGradient(param.gradient); } fractalnow-0.8.1/lib/src/fractal_cache.c0000664000175000017500000006725311754776133016617 0ustar mpegmpeg/* * fractal_cache.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "float_precision.h" #include "fractal_cache.h" #include "fractal.h" #include "macro_build_floats.h" #include "misc.h" #include "uirectangle.h" #include "thread.h" #define HandleRequests(max_counter) \ if (counter == max_counter) {\ HandlePauseRequest(threadArgHeader);\ cancelRequested =\ CancelTaskRequested(threadArgHeader);\ counter = 0;\ } else {\ ++counter;\ } inline void FreeCacheEntry(CacheEntry entry) { switch (entry.floatPrecision) { case FP_SINGLE: clearF(FP_SINGLE, entry.x.val_FP_SINGLE); clearF(FP_SINGLE, entry.y.val_FP_SINGLE); break; case FP_DOUBLE: clearF(FP_DOUBLE, entry.x.val_FP_DOUBLE); clearF(FP_DOUBLE, entry.y.val_FP_DOUBLE); break; case FP_LDOUBLE: clearF(FP_LDOUBLE, entry.x.val_FP_LDOUBLE); clearF(FP_LDOUBLE, entry.y.val_FP_LDOUBLE); break; case FP_MP: clearF(FP_MP, entry.x.val_FP_MP); clearF(FP_MP, entry.y.val_FP_MP); break; default: FractalNow_error("Unknown float precision.\n"); break; } } int CreateFractalCache(FractalCache *cache, uint_least64_t size) { int res = 0; cache->firstUse = 1; cache->fractal = (Fractal *)safeMalloc("fractal", sizeof(Fractal)); cache->render = (RenderingParameters *)safeMalloc("rendering parameters", sizeof(RenderingParameters)); cache->currentState = 0; cache->nbInitialized = 0; cache->size = size; cache->entry = (CacheEntry *)malloc(size*sizeof(CacheEntry)); if (cache->entry == NULL) { res = 1; cache->size = 0; } cache->currentIndex = 0; cache->arrayWidth = 0; cache->arrayHeight = 0; cache->array = NULL; safePThreadSpinInit(&cache->arrayMutex, SPIN_INIT_ATTR); safePThreadSpinInit(&cache->entryMutex, SPIN_INIT_ATTR); return res; } int ResizeCacheThreadSafe(FractalCache *cache, uint_least64_t size) { if (size == cache->size) { return 0; } int res = 1; safePThreadSpinLock(&cache->entryMutex); if (size < cache->size) { for (uint_fast32_t i = size; i < cache->size; ++i) { FreeCacheEntry(cache->entry[i]); } } void *newEntry = (CacheEntry *)realloc(cache->entry, size*sizeof(CacheEntry)); if (size == 0 || newEntry != NULL) { res = 0; cache->entry = newEntry; cache->size = size; if (cache->nbInitialized > size) { cache->nbInitialized = size; } if (cache->currentIndex >= size) { cache->currentIndex = 0; } } safePThreadSpinUnlock(&cache->entryMutex); return res; } inline void AddToCache(FractalCache *cache, CacheEntry entry) { if (cache->size == 0) { return; } if (cache->nbInitialized < cache->size) { ++cache->nbInitialized; } else { FreeCacheEntry(cache->entry[cache->currentIndex]); } cache->entry[cache->currentIndex++] = entry; if (cache->currentIndex >= cache->size) { cache->currentIndex = 0; } } void AddToCacheThreadSafe(FractalCache *cache, CacheEntry entry) { safePThreadSpinLock(&cache->entryMutex); AddToCache(cache, entry); safePThreadSpinUnlock(&cache->entryMutex); } static inline CacheEntry GetCacheEntry(FractalCache *cache, uint_least64_t index) { return cache->entry[index]; } static inline CacheEntry GetCacheEntryThreadSafe(FractalCache *cache, uint_least64_t index) { CacheEntry res; safePThreadSpinLock(&cache->entryMutex); res = GetCacheEntry(cache, index); safePThreadSpinUnlock(&cache->entryMutex); return res; } typedef struct ClearCacheArrayArguments { uint_fast32_t threadId; FractalCache *cache; uint_fast32_t nbRectangles; UIRectangle *rectangles; } ClearCacheArrayArguments; void FreeClearCacheArrayArguments(void *arg) { ClearCacheArrayArguments *c_arg = (ClearCacheArrayArguments *)arg; if (c_arg->threadId == 0) { free(c_arg->rectangles); } } void *ClearCacheArrayThreadRoutine(void *arg) { ThreadArgHeader *threadArgHeader = GetThreadArgHeader(arg); ClearCacheArrayArguments *c_arg = (ClearCacheArrayArguments *)GetThreadArgBody(arg); FractalCache *cache = c_arg->cache; uint_fast32_t nbRectangles = c_arg->nbRectangles; UIRectangle *currentRect; uint_fast32_t rectHeight; ArrayValue *aVal; uint_fast32_t counter = 0; for (uint_fast32_t i = 0; i < nbRectangles; ++i) { currentRect = &c_arg->rectangles[i]; rectHeight = currentRect->y2+1-currentRect->y1; for (uint_fast32_t j = currentRect->y1; j <= currentRect->y2; ++j) { SetThreadProgress(threadArgHeader, 100 * (i*rectHeight+j) / (nbRectangles*rectHeight)); /* Handling pause & cancelation requests after each * scanline should be good enough since operations * on each pixel are trivial */ for (uint_fast32_t k = currentRect->x1; k <= currentRect->x2; ++k) { if (counter == 256) { HandlePauseRequest(threadArgHeader); counter = 0; } else { ++counter; } aVal = &cache->array[j][k]; aVal->state = cache->currentState; aVal->totalWeight = 0; aVal->r = 0; aVal->g = 0; aVal->b = 0; } } } SetThreadProgress(threadArgHeader, 100); int canceled = CancelTaskRequested(threadArgHeader); return (canceled ? PTHREAD_CANCELED : NULL); } char clearCacheArrayMessage[] = "Clearing cache array"; Task *CreateClearCacheArrayTask(FractalCache *cache, uint_fast32_t width, uint_fast32_t height, uint_fast32_t nbThreads) { if (width == 0 || height == 0) { return DoNothingTask(); } uint_fast32_t nbPixels = width*height; uint_fast32_t nbThreadsNeeded = nbThreads; uint_fast32_t rectanglesPerThread = DEFAULT_RECTANGLES_PER_THREAD; if (nbPixels <= nbThreadsNeeded) { nbThreadsNeeded = nbPixels; rectanglesPerThread = 1; } else if (nbPixels < nbThreadsNeeded*rectanglesPerThread) { rectanglesPerThread = nbPixels / nbThreadsNeeded; } uint_fast32_t nbRectangles = nbThreadsNeeded*rectanglesPerThread; UIRectangle *rectangle; rectangle = (UIRectangle *)safeMalloc("rectangles", nbRectangles * sizeof(UIRectangle)); InitUIRectangle(&rectangle[0], 0, 0, width-1, height-1); if (CutUIRectangleInN(rectangle[0], nbRectangles, rectangle)) { FractalNow_error("Could not cut rectangle ((%"PRIuFAST32",%"PRIuFAST32"),\ (%"PRIuFAST32",%"PRIuFAST32") in %"PRIuFAST32" parts.\n", rectangle[0].x1, rectangle[0].y1, rectangle[0].x2, rectangle[0].y2, nbRectangles); } ClearCacheArrayArguments *arg; arg = (ClearCacheArrayArguments *)safeMalloc("arguments", nbThreadsNeeded * sizeof(ClearCacheArrayArguments)); for (uint_fast32_t i = 0; i < nbThreadsNeeded; ++i) { arg[i].threadId = i; arg[i].cache = cache; arg[i].nbRectangles = rectanglesPerThread; arg[i].rectangles = &rectangle[i*rectanglesPerThread]; } Task *task = CreateTask(clearCacheArrayMessage, nbThreadsNeeded, arg, sizeof(ClearCacheArrayArguments), ClearCacheArrayThreadRoutine, FreeClearCacheArrayArguments); free(arg); return task; } void ClearCacheArray(FractalCache *cache, Threads *threads) { Task *task = CreateClearCacheArrayTask(cache, cache->arrayWidth, cache->arrayHeight, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } static inline Color ColorFromValue(double value, const RenderingParameters *render) { Color res; if (value < 0) { res = render->spaceColor; } else { value = render->transferFunctionPtr(value)*render->realMultiplier+ render->realOffset; res = GetGradientColor(&render->gradient, (uint_fast64_t)(value)); } return res; } static inline ArrayValue aux_PutIntoArray(FractalCache *cache, uint_fast32_t x, uint_fast32_t y, double r, double g, double b, double weight) { ArrayValue *aVal = &cache->array[y][x]; if (aVal->state != cache->currentState) { aVal->r = 0; aVal->g = 0; aVal->b = 0; aVal->totalWeight = 0; aVal->state = cache->currentState; } aVal->r += r; aVal->g += g; aVal->b += b; aVal->totalWeight += weight; return *aVal; } static inline ArrayValue PutIntoArray(FractalCache *cache, const RenderingParameters *render, uint_fast32_t x, uint_fast32_t y, double value, double weight) { Color color = ColorFromValue(value, render); double r = color.r * weight; double g = color.g * weight; double b = color.b * weight; return aux_PutIntoArray(cache, x, y, r, g, b, weight); } static inline ArrayValue PutIntoArrayThreadSafe(FractalCache *cache, const RenderingParameters *render, uint_fast32_t x, uint_fast32_t y, double value, double weight) { Color color = ColorFromValue(value, render); double r = color.r * weight; double g = color.g * weight; double b = color.b * weight; safePThreadSpinLock(&cache->arrayMutex); ArrayValue res = aux_PutIntoArray(cache, x, y, r, g, b, weight); safePThreadSpinUnlock(&cache->arrayMutex); return res; } inline ArrayValue GetArrayValue(FractalCache *cache, uint_fast32_t x, uint_fast32_t y) { return cache->array[y][x]; } static inline ArrayValue GetArrayValueThreadSafe(FractalCache *cache, uint_fast32_t x, uint_fast32_t y) { safePThreadSpinLock(&cache->arrayMutex); ArrayValue aVal = GetArrayValue(cache, x, y); safePThreadSpinUnlock(&cache->arrayMutex); return aVal; } inline int isArrayValueValid(ArrayValue aVal, FractalCache *cache) { return (aVal.state == cache->currentState && aVal.totalWeight > DEFAULT_CACHE_WEIGHT_THRESHOLD); } inline Color GetColorFromAVal(ArrayValue aVal, const RenderingParameters *render) { Color res; res.bytesPerComponent = render->bytesPerComponent; res.r = aVal.r / aVal.totalWeight; res.g = aVal.g / aVal.totalWeight; res.b = aVal.b / aVal.totalWeight; return res; } static inline int isInsideArray(FLOATTYPE(FP_LDOUBLE) x, FLOATTYPE(FP_LDOUBLE) y, uint_fast32_t width, uint_fast32_t height) { return (x >= 0 && x <= width-1 && y <= height-1 && y >= 0); } typedef struct ResizeCacheArrayArguments { FractalCache *cache; uint_fast32_t width; uint_fast32_t height; } ResizeCacheArrayArguments; void FreeResizeCacheArrayArguments(void *arg) { UNUSED(arg); } void ResizeCacheArray(FractalCache *cache, uint_fast32_t width, uint_fast32_t height) { for (uint_fast32_t i = 0; i < cache->arrayHeight; ++i) { free(cache->array[i]); } cache->array = (ArrayValue **)safeRealloc("cache array", cache->array, height*sizeof(ArrayValue *)); for (uint_fast32_t i = 0; i < height; ++i) { cache->array[i] = (ArrayValue *)safeMalloc("cache array", width*sizeof(ArrayValue)); } cache->arrayWidth = width; cache->arrayHeight = height; } void *ResizeCacheArrayThreadRoutine(void *arg) { ResizeCacheArrayArguments *c_arg = (ResizeCacheArrayArguments *)GetThreadArgBody(arg); ResizeCacheArray(c_arg->cache, c_arg->width, c_arg->height); return NULL; } char resizeCacheArrayMessage[] = "Resizing cache array"; Task *CreateResizeCacheArrayTask(FractalCache *cache, uint_fast32_t width, uint_fast32_t height) { ResizeCacheArrayArguments arg; arg.cache = cache; arg.width = width; arg.height = height; Task *task = CreateTask(resizeCacheArrayMessage, 1, &arg, sizeof(ResizeCacheArrayArguments), ResizeCacheArrayThreadRoutine, FreeResizeCacheArrayArguments); return task; } int InvalidateCacheArray(FractalCache *cache) { int res = 0; if (cache->currentState == UINT_FAST32_MAX) { cache->currentState = 0; res = 1; } else { ++cache->currentState; } return res; } typedef struct FillCacheArrayArguments { uint_fast32_t threadId; uint_least64_t begin, end; Image *image; pthread_spinlock_t *imageMutex; const Fractal *fractal; const RenderingParameters *render; FractalCache *cache; DECL_MULTI_FLOAT(spanX); DECL_MULTI_FLOAT(spanY); DECL_MULTI_FLOAT(x1); DECL_MULTI_FLOAT(y1); } FillCacheArrayArguments; void FreeFillCacheArrayArguments(void *arg) { FillCacheArrayArguments *c_arg = (FillCacheArrayArguments *)arg; if (c_arg->threadId == 0) { safePThreadSpinDestroy(c_arg->imageMutex); free((void *)c_arg->imageMutex); } CLEAR_MULTI_FLOAT(c_arg->spanX); CLEAR_MULTI_FLOAT(c_arg->spanY); CLEAR_MULTI_FLOAT(c_arg->x1); CLEAR_MULTI_FLOAT(c_arg->y1); } #define BUILD_GetImageCoordFromCacheEntry(fprec) \ static void GetImageCoordFromCacheEntry_##fprec(CacheEntry *entry,\ double *outx, double *outy,\ FLOATTYPE(fprec) x, FLOATTYPE(fprec) y,\ uint_fast32_t width, uint_fast32_t height,\ FLOATTYPE(fprec) spanX, FLOATTYPE(fprec) spanY,\ FLOATTYPE(fprec) x1, FLOATTYPE(fprec) y1)\ {\ subF(fprec, x, FLOAT_VAR(fprec,entry->x.val), x1);\ mul_uiF(fprec, x, x, width);\ divF(fprec, x, x, spanX);\ sub_dF(fprec, x, x, 0.5);\ *outx = toDoubleF(fprec, x);\ \ subF(fprec, y, FLOAT_VAR(fprec,entry->y.val), y1);\ mul_uiF(fprec, y, y, height);\ divF(fprec, y, y, spanY);\ sub_dF(fprec, y, y, 0.5);\ *outy = toDoubleF(fprec, y);\ } #undef MACRO_BUILD_FLOAT #define MACRO_BUILD_FLOAT(fprec) BUILD_GetImageCoordFromCacheEntry(fprec) MACRO_BUILD_FLOATS #define BUILD_SwitchCacheEntry(fprec)\ case fprec:\ GetImageCoordFromCacheEntry_##fprec(&entry, &x, &y,\ FLOAT_VAR(fprec,multiX), FLOAT_VAR(fprec,multiY),\ cache->arrayWidth, cache->arrayHeight,\ FLOAT_VAR(fprec,c_arg->spanX), FLOAT_VAR(fprec,c_arg->spanY),\ FLOAT_VAR(fprec,c_arg->x1), FLOAT_VAR(fprec,c_arg->y1));\ break; #undef MACRO_BUILD_FLOAT #define MACRO_BUILD_FLOAT(fprec) BUILD_SwitchCacheEntry(fprec) void *FillCacheArrayThreadRoutine(void *arg) { ThreadArgHeader *threadArgHeader = GetThreadArgHeader(arg); FillCacheArrayArguments *c_arg = (FillCacheArrayArguments *)GetThreadArgBody(arg); FractalCache *cache = c_arg->cache; const Fractal *fractal = c_arg->fractal; const RenderingParameters *render = c_arg->render; Image *image = c_arg->image; pthread_spinlock_t *imageMutex = c_arg->imageMutex; CacheEntry entry; double x = 0, y = 0; uint_least64_t nbEntries = c_arg->end-c_arg->begin+1; uint_fast32_t counter = 0; int cancelRequested = CancelTaskRequested(threadArgHeader); double dx, dy; uint_fast32_t intX, intY; double sigma = 1./3; double sigma2_x_2 = sigma*sigma*2; double weight; DECL_MULTI_FLOAT(multiX); DECL_MULTI_FLOAT(multiY); INIT_MULTI_FLOAT(multiX); INIT_MULTI_FLOAT(multiY); ASSIGN_MULTI_FLOAT(multiX, fractal->centerX); ASSIGN_MULTI_FLOAT(multiY, fractal->centerY); ArrayValue aVal; Color color; for (uint_least64_t i = c_arg->begin; i <= c_arg->end && !cancelRequested; ++i) { SetThreadProgress(threadArgHeader, 100 * (i-c_arg->begin) / nbEntries); HandleRequests(128); entry = GetCacheEntry(cache, i); switch(entry.floatPrecision) { MACRO_BUILD_FLOATS default: FractalNow_error("Unknown float precision.\n"); break; } intX = roundl(x); intY = roundl(y); dx = x - intX; dy = y - intY; if (isInsideArray(intX, intY, cache->arrayWidth, cache->arrayHeight)) { weight = exp(-(dx*dx+dy*dy)/sigma2_x_2); if (image != NULL) { safePThreadSpinLock(imageMutex); aVal = PutIntoArray(cache, render, intX, intY, entry.value, weight); color = GetColorFromAVal(aVal, render); PutPixelUnsafe(image, intX, intY, color); safePThreadSpinUnlock(imageMutex); } else { aVal = PutIntoArrayThreadSafe(cache, render, intX, intY, entry.value, weight); } } } CLEAR_MULTI_FLOAT(multiX); CLEAR_MULTI_FLOAT(multiY); SetThreadProgress(threadArgHeader, 100); int canceled = CancelTaskRequested(threadArgHeader); return (canceled ? PTHREAD_CANCELED : NULL); } char fillCacheArrayMessage[] = "Filling cache array"; Task *CreateFillCacheArrayTask(FractalCache *cache, Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t nbThreads) { if (cache->size == 0 || cache->arrayWidth == 0 || cache->arrayHeight == 0 || cache->nbInitialized == 0) { return DoNothingTask(); } uint_fast32_t nbEntries = cache->nbInitialized; uint_fast32_t nbThreadsNeeded = nbThreads; if (nbEntries <= nbThreadsNeeded) { nbThreadsNeeded = nbEntries; } uint_fast32_t nbRectangles = nbThreadsNeeded; UIRectangle *rectangle; rectangle = (UIRectangle *)safeMalloc("rectangles", nbRectangles * sizeof(UIRectangle)); InitUIRectangle(&rectangle[0], 0, 0, nbEntries-1, 0); if (CutUIRectangleInN(rectangle[0], nbRectangles, rectangle)) { FractalNow_error("Could not cut rectangle ((%"PRIuFAST32",%"PRIuFAST32"),\ (%"PRIuFAST32",%"PRIuFAST32") in %"PRIuFAST32" parts.\n", rectangle[0].x1, rectangle[0].y1, rectangle[0].x2, rectangle[0].y2, nbRectangles); } pthread_spinlock_t *imageMutex; imageMutex = (pthread_spinlock_t *)safeMalloc("image mutex", sizeof(pthread_spinlock_t)); safePThreadSpinInit(imageMutex, SPIN_INIT_ATTR); FillCacheArrayArguments *arg; arg = (FillCacheArrayArguments *)safeMalloc("arguments", nbThreadsNeeded * sizeof(FillCacheArrayArguments)); for (uint_fast32_t i = 0; i < nbThreadsNeeded; ++i) { arg[i].threadId = i; arg[i].cache = cache; arg[i].image = image; arg[i].imageMutex = imageMutex; arg[i].fractal = fractal; arg[i].render = render; arg[i].begin = rectangle[i].x1; arg[i].end = rectangle[i].x2; INIT_MULTI_FLOAT(arg[i].spanX); INIT_MULTI_FLOAT(arg[i].spanY); INIT_MULTI_FLOAT(arg[i].x1); INIT_MULTI_FLOAT(arg[i].y1); ASSIGN_MULTI_FLOAT(arg[i].spanX, fractal->spanX); ASSIGN_MULTI_FLOAT(arg[i].spanY, fractal->spanY); ASSIGN_MULTI_FLOAT(arg[i].x1, fractal->x1); ASSIGN_MULTI_FLOAT(arg[i].y1, fractal->y1); } Task *task = CreateTask(fillCacheArrayMessage, nbThreadsNeeded, arg, sizeof(FillCacheArrayArguments), FillCacheArrayThreadRoutine, FreeFillCacheArrayArguments); free(arg); free(rectangle); return task; } void FillCacheArray(FractalCache *cache, Image *image, const Fractal *fractal, const RenderingParameters *render, Threads *threads) { Task *task = CreateFillCacheArrayTask(cache, image, fractal, render, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } typedef struct FillImageFromCacheArrayArguments { uint_fast32_t threadId; FractalCache *cache; Image *image; const RenderingParameters *render; uint_fast32_t nbRectangles; UIRectangle *rectangles; } FillImageFromCacheArrayArguments; void FreeFillImageFromCacheArrayArguments(void *arg) { FillImageFromCacheArrayArguments *c_arg = (FillImageFromCacheArrayArguments *)arg; if (c_arg->threadId == 0) { free(c_arg->rectangles); } } void *FillImageFromCacheArrayThreadRoutine(void *arg) { ThreadArgHeader *threadArgHeader = GetThreadArgHeader(arg); FillImageFromCacheArrayArguments *c_arg = (FillImageFromCacheArrayArguments *)GetThreadArgBody(arg); FractalCache *cache = c_arg->cache; Image *dst = c_arg->image; const RenderingParameters *render = c_arg->render; uint_fast32_t nbRectangles = c_arg->nbRectangles; UIRectangle *currentRect; uint_fast32_t rectHeight; ArrayValue aVal; uint_fast32_t counter = 0; int cancelRequested = CancelTaskRequested(threadArgHeader); Color color; for (uint_fast32_t i = 0; i < nbRectangles && !cancelRequested; ++i) { currentRect = &c_arg->rectangles[i]; rectHeight = currentRect->y2+1-currentRect->y1; for (uint_fast32_t j = currentRect->y1; j <= currentRect->y2 && !cancelRequested; ++j) { SetThreadProgress(threadArgHeader, 100 * (i*rectHeight+j) / (nbRectangles*rectHeight)); for (uint_fast32_t k = currentRect->x1; k <= currentRect->x2 && !cancelRequested; ++k) { HandleRequests(128); aVal = GetArrayValue(cache, k, j); if (isArrayValueValid(aVal, cache)) { color = GetColorFromAVal(aVal, render); PutPixelUnsafe(dst, k, j, color); } } } } SetThreadProgress(threadArgHeader, 100); int canceled = CancelTaskRequested(threadArgHeader); return (canceled ? PTHREAD_CANCELED : NULL); } char fillImageFromCacheArrayMessage[] = "Filling image from cache array"; Task *CreateFillImageFromCacheArrayTask(Image *dst, FractalCache *cache, const RenderingParameters *render, uint_fast32_t nbThreads) { if (dst->width == 0 || dst->height == 0) { return DoNothingTask(); } uint_fast32_t nbPixels = dst->width*dst->height; uint_fast32_t nbThreadsNeeded = nbThreads; uint_fast32_t rectanglesPerThread = DEFAULT_RECTANGLES_PER_THREAD; if (nbPixels <= nbThreadsNeeded) { nbThreadsNeeded = nbPixels; rectanglesPerThread = 1; } else if (nbPixels < nbThreadsNeeded*rectanglesPerThread) { rectanglesPerThread = nbPixels / nbThreadsNeeded; } uint_fast32_t nbRectangles = nbThreadsNeeded*rectanglesPerThread; UIRectangle *rectangle; rectangle = (UIRectangle *)safeMalloc("rectangles", nbRectangles * sizeof(UIRectangle)); InitUIRectangle(&rectangle[0], 0, 0, dst->width-1, dst->height-1); if (CutUIRectangleInN(rectangle[0], nbRectangles, rectangle)) { FractalNow_error("Could not cut rectangle ((%"PRIuFAST32",%"PRIuFAST32"),\ (%"PRIuFAST32",%"PRIuFAST32") in %"PRIuFAST32" parts.\n", rectangle[0].x1, rectangle[0].y1, rectangle[0].x2, rectangle[0].y2, nbRectangles); } FillImageFromCacheArrayArguments *arg; arg = (FillImageFromCacheArrayArguments *)safeMalloc("arguments", nbThreadsNeeded * sizeof(FillImageFromCacheArrayArguments)); for (uint_fast32_t i = 0; i < nbThreadsNeeded; ++i) { arg[i].threadId = i; arg[i].cache = cache; arg[i].image = dst; arg[i].render = render; arg[i].nbRectangles = rectanglesPerThread; arg[i].rectangles = &rectangle[i*rectanglesPerThread]; } Task *task = CreateTask(fillImageFromCacheArrayMessage, nbThreadsNeeded, arg, sizeof(FillImageFromCacheArrayArguments), FillImageFromCacheArrayThreadRoutine, FreeFillImageFromCacheArrayArguments); free(arg); return task; } void FillImageFromCacheArray(Image *dst, FractalCache *cache, const RenderingParameters *render, Threads *threads) { Task *task = CreateFillImageFromCacheArrayTask(dst, cache, render, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } Task *CreateFillArrayAndImageFromCacheTask(FractalCache *cache, Image *image, const Fractal *fractal, const RenderingParameters *render, int fillImageOnTheFly, uint_fast32_t nbThreads) { Task *res; if (fillImageOnTheFly) { res = CreateFillCacheArrayTask(cache, image, fractal, render, nbThreads); } else { Task *subTasks[2]; subTasks[0] = CreateFillCacheArrayTask(cache, NULL, fractal, render, nbThreads); subTasks[1] = CreateFillImageFromCacheArrayTask(image, cache, render, nbThreads); res = CreateCompositeTask(NULL, 2, subTasks); } return res; } void FillArrayAndImageFromCache(FractalCache *cache, Image *image, const Fractal *fractal, const RenderingParameters *render, int fillImageOnTheFly, Threads *threads) { Task *task = CreateFillArrayAndImageFromCacheTask(cache, image, fractal, render, fillImageOnTheFly, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } void aux_CreateFractalCachePreviewTask(FractalCache *cache, const Fractal *fractal, const RenderingParameters *render) { safePThreadSpinLock(&cache->entryMutex); cache->nbInitialized = 0; cache->currentIndex = 0; safePThreadSpinUnlock(&cache->entryMutex); if (cache->firstUse) { cache->firstUse = 0; } else { FreeFractal(*cache->fractal); FreeRenderingParameters(*cache->render); } *cache->fractal = CopyFractal(fractal); *cache->render = CopyRenderingParameters(render); } enum TaskType { DO_NOTHING=0, RESIZE_CLEAR, RESIZE_CLEAR_FILL, CLEAR_FILL, FILL }; static inline int PartCompareFractals(const Fractal *fractal1, const Fractal *fractal2) { return (fractal1->fractalFormula != fractal2->fractalFormula || mpc_cmp(fractal1->p, fractal2->p) || mpc_cmp(fractal1->c, fractal2->c) || fractal1->escapeRadius != fractal2->escapeRadius || fractal1->maxIter != fractal2->maxIter); } static inline int PartCompareRenderingParameters(const RenderingParameters *param1, const RenderingParameters *param2) { return (param1->bytesPerComponent != param2->bytesPerComponent || CompareColors(param1->spaceColor, param2->spaceColor) || param1->iterationCount != param2->iterationCount || param1->coloringMethod != param2->coloringMethod || param1->addendFunction != param2->addendFunction || param1->stripeDensity != param2->stripeDensity || param1->interpolationMethod != param2->interpolationMethod); } char fractalCachePreviewMessage[] = "Creating fractal preview from cache"; Task *CreateFractalCachePreviewTask(Image *dst, FractalCache *cache, const Fractal *fractal, const RenderingParameters *render, int fillImageOnTheFly, uint_fast32_t nbThreads) { Task *res; Fractal *cacheFractal = cache->fractal; RenderingParameters *cacheRender = cache->render; enum TaskType taskType; if (cache->firstUse) { aux_CreateFractalCachePreviewTask(cache, fractal, render); taskType = RESIZE_CLEAR; } else if (PartCompareFractals(cacheFractal, fractal) || PartCompareRenderingParameters(cacheRender, render)) { aux_CreateFractalCachePreviewTask(cache, fractal, render); if (dst->width != cache->arrayWidth || dst->height != cache->arrayHeight) { taskType = RESIZE_CLEAR; } else { int unused = InvalidateCacheArray(cache); UNUSED(unused); taskType = DO_NOTHING; } } else if (dst->width != cache->arrayWidth || dst->height != cache->arrayHeight) { taskType = RESIZE_CLEAR_FILL; } else { if (InvalidateCacheArray(cache)) { taskType = CLEAR_FILL; } else { taskType = FILL; } } switch (taskType) { case DO_NOTHING: { Task *subTask = DoNothingTask(); res = CreateCompositeTask(fractalCachePreviewMessage, 1, &subTask); break; } case RESIZE_CLEAR: { Task *subTasks[2]; subTasks[0] = CreateResizeCacheArrayTask(cache, dst->width, dst->height); subTasks[1] = CreateClearCacheArrayTask(cache, dst->width, dst->height, nbThreads); res = CreateCompositeTask(fractalCachePreviewMessage, 2, subTasks); break; } case RESIZE_CLEAR_FILL: { Task *subTasks[3]; subTasks[0] = CreateResizeCacheArrayTask(cache, dst->width, dst->height); subTasks[1] = CreateClearCacheArrayTask(cache, dst->width, dst->height, nbThreads); subTasks[2] = CreateFillArrayAndImageFromCacheTask(cache, dst, fractal, render, fillImageOnTheFly, nbThreads); res = CreateCompositeTask(fractalCachePreviewMessage, 3, subTasks); break; } case CLEAR_FILL: { Task *subTasks[2]; subTasks[0] = CreateClearCacheArrayTask(cache, dst->width, dst->height, nbThreads); subTasks[1] = CreateFillArrayAndImageFromCacheTask(cache, dst, fractal, render, fillImageOnTheFly, nbThreads); res = CreateCompositeTask(fractalCachePreviewMessage, 2, subTasks); break; } case FILL: { Task *subTask = CreateFillArrayAndImageFromCacheTask(cache, dst, fractal, render, fillImageOnTheFly, nbThreads); res = CreateCompositeTask(fractalCachePreviewMessage, 1, &subTask); } break; } return res; } void FractalCachePreview(Image *dst, FractalCache *cache, const Fractal *fractal, const RenderingParameters *render, int fillImageOnTheFly, Threads *threads) { Task *task = CreateFractalCachePreviewTask(dst, cache, fractal, render, fillImageOnTheFly, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } void FreeFractalCache(FractalCache *cache) { for (uint_fast32_t i = 0; i < cache->nbInitialized; ++i) { FreeCacheEntry(cache->entry[i]); } free(cache->entry); for (uint_fast32_t i = 0; i < cache->arrayHeight; ++i) { free(cache->array[i]); } free(cache->array); if (!cache->firstUse) { FreeFractal(*cache->fractal); FreeRenderingParameters(*cache->render); } free(cache->fractal); free(cache->render); safePThreadSpinDestroy(&cache->entryMutex); safePThreadSpinDestroy(&cache->arrayMutex); } fractalnow-0.8.1/lib/src/image.c0000664000175000017500000003251311754776133015131 0ustar mpegmpeg/* * image.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "image.h" #include "filter.h" #include "misc.h" #include "uirectangle.h" #include #include #include #define HandleRequests(max_counter) \ if (counter == max_counter) {\ HandlePauseRequest(threadArgHeader);\ cancelRequested =\ CancelTaskRequested(threadArgHeader);\ counter = 0;\ } else {\ ++counter;\ } inline void CreateImage(Image *image, uint_fast32_t width, uint_fast32_t height, uint_fast8_t bytesPerComponent) { if (bytesPerComponent != 1 && bytesPerComponent != 2) { FractalNow_error("Invalid bytes per component. Only 1 and 2 are allowed.\n"); } image->data = (uint8_t *)safeCalloc("image data", width*height, 4*bytesPerComponent); image->data_is_external = 0; image->width = width; image->height = height; image->bytesPerComponent = bytesPerComponent; } void CreateImage2(Image *image, uint8_t *data, uint_fast32_t width, uint_fast32_t height, uint_fast8_t bytesPerComponent) { if (bytesPerComponent != 1 && bytesPerComponent != 2) { FractalNow_error("Invalid bytes per component. Only 1 and 2 are allowed.\n"); } image->data = data; image->data_is_external = 1; image->width = width; image->height = height; image->bytesPerComponent = bytesPerComponent; } Image CloneImage(const Image *image) { Image res; CreateImage(&res, image->width, image->height, image->bytesPerComponent); memcpy(res.data, image->data, image->width*image->height*4*image->bytesPerComponent); return res; } static inline uint8_t *ImageRGB8ToBytesArray(const Image *image) { if (image->width == 0 || image->height == 0) { return NULL; } uint8_t *res = (uint8_t *)safeCalloc("image bytes array", image->width*image->height, 3*image->bytesPerComponent); uint32_t *p_data32 = (uint32_t *)image->data; uint32_t data32; uint8_t *p_res = res; for (uint_fast32_t i = 0; i < image->height; ++i) { for (uint_fast32_t j = 0; j < image->width; ++j) { data32 = *p_data32; *(p_res++) = GET_R8(data32); *(p_res++) = GET_G8(data32); *(p_res++) = GET_B8(data32); ++p_data32; } } return res; } static inline uint8_t *ImageRGB16ToBytesArray(const Image *image) { if (image->width == 0 || image->height == 0) { return NULL; } uint8_t *res = (uint8_t *)safeCalloc("image bytes array", image->width*image->height, 3*image->bytesPerComponent); uint64_t *p_data64 = (uint64_t *)image->data; uint64_t data64; uint16_t r, g, b; uint8_t *p_res = res; for (uint_fast32_t i = 0; i < image->height; ++i) { for (uint_fast32_t j = 0; j < image->width; ++j) { data64 = *p_data64; /* We want the components in the order RGB, so we need to extract * them from uint64_t (the machine can be MSB first, or LSB first..) */ r = GET_R16(data64); g = GET_G16(data64); b = GET_B16(data64); /* Then we want for each component the most significant byte first.*/ *(p_res++) = r >> 8; *(p_res++) = r & 0xFF; *(p_res++) = g >> 8; *(p_res++) = g & 0xFF; *(p_res++) = b >> 8; *(p_res++) = b & 0xFF; ++p_data64; } } return res; } uint8_t *ImageToBytesArray(const Image *image) { uint8_t *res; switch(image->bytesPerComponent) { case 1: res = ImageRGB8ToBytesArray(image); break; case 2: res = ImageRGB16ToBytesArray(image); break; default: FractalNow_error("Invalid bytes per component (%"PRIuFAST8").\n", image->bytesPerComponent); break; } return res; } typedef enum { LEFT = 0, TOP, RIGHT, BOTTOM, TOPLEFT, TOPRIGHT, BOTTOMRIGHT, BOTTOMLEFT, CENTER } Region; inline Color iGetPixelUnsafe(const Image *image, uint_fast32_t x, uint_fast32_t y) { Color res; res.bytesPerComponent = image->bytesPerComponent; switch (res.bytesPerComponent) { case 1: { uint32_t data32 = *((uint32_t *)(image->data) + y*image->width+x); res.r = GET_R8(data32); res.g = GET_G8(data32); res.b = GET_B8(data32); break; } case 2: { uint64_t data64 = *((uint64_t *)(image->data) + y*image->width+x); res.r = GET_R16(data64); res.g = GET_G16(data64); res.b = GET_B16(data64); } break; default: FractalNow_error("Invalid bytes per component.\n"); break; } return res; } Region iGetImageRegion(const Image *image, int_fast64_t x, int_fast64_t y) { Region region; if (x < 0) { if (y < 0) { region = TOPLEFT; } else if ((uint_fast32_t)y >= image->height) { region = BOTTOMLEFT; } else { region = LEFT; } } else if ((uint_fast32_t)x >= image->width) { if (y < 0) { region = TOPRIGHT; } else if ((uint_fast32_t)y >= image->height) { region = BOTTOMRIGHT; } else { region = RIGHT; } } else { if (y < 0) { region = TOP; } else if ((uint_fast32_t)y >= image->height) { region = BOTTOM; } else { region = CENTER; } } return region; } Color blackColorRGB8 = {1, 0, 0, 0}; Color blackColorRGB16 = {2, 0, 0, 0}; Color iGetPixel(const Image *image, int_fast64_t x, int_fast64_t y) { if (image->width == 0 || image->height == 0) { if (image->bytesPerComponent == 1) { return blackColorRGB8; } else { return blackColorRGB16; } } Region region = iGetImageRegion(image, x, y); Color res; switch (region) { case TOPLEFT: res = iGetPixelUnsafe(image, 0, 0); break; case TOPRIGHT: res = iGetPixelUnsafe(image, image->width-1, 0); break; case BOTTOMLEFT: res = iGetPixelUnsafe(image, 0, image->height-1); break; case BOTTOMRIGHT: res = iGetPixelUnsafe(image, image->width-1, image->height-1); break; case TOP: res = iGetPixelUnsafe(image, x, 0); break; case LEFT: res = iGetPixelUnsafe(image, 0, y); break; case RIGHT: res = iGetPixelUnsafe(image, image->width-1, y); break; case BOTTOM: res = iGetPixelUnsafe(image, x, image->height-1); break; case CENTER: res = iGetPixelUnsafe(image, x, y); break; default: FractalNow_error("Unknown region.\n"); break; } return res; } inline void PutPixelUnsafe(Image *image, uint_fast32_t x, uint_fast32_t y, Color color) { switch (image->bytesPerComponent) { case 1: { uint32_t *data32 = (uint32_t *)(image->data) + y*image->width+x; *data32 = RGB8_TO_UINT32(color.r, color.g, color.b); break; } case 2: { uint64_t *data64 = (uint64_t *)(image->data) + y*image->width+x; *data64 = RGB16_TO_UINT64(color.r, color.g, color.b); } break; default: FractalNow_error("Invalid bytes per component.\n"); break; } } char applyGaussianBlurMessage[] = "Applying gaussian blur"; Task *CreateApplyGaussianBlurTask(Image *dst, Image *temp, const Image *src, double radius, uint_fast32_t nbThreads) { Filter horizontalGaussianFilter; Filter verticalGaussianFilter; CreateHorizontalGaussianFilter2(&horizontalGaussianFilter, radius); CreateVerticalGaussianFilter2(&verticalGaussianFilter, radius); Task *subTasks[2]; subTasks[0] = CreateApplyFilterTask(temp, src, &horizontalGaussianFilter, nbThreads); subTasks[1] = CreateApplyFilterTask(dst, temp, &verticalGaussianFilter, nbThreads); Task *res = CreateCompositeTask(applyGaussianBlurMessage, 2, subTasks); FreeFilter(horizontalGaussianFilter); FreeFilter(verticalGaussianFilter); return res; } void ApplyGaussianBlur(Image *dst, const Image *src, double radius, Threads *threads) { Image temp; CreateImage(&temp, src->width, src->height, src->bytesPerComponent); Task *task = CreateApplyGaussianBlurTask(dst, &temp, src, radius, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); FreeImage(temp); } typedef struct s_DownscaleImageArguments { uint_fast32_t threadId; Image *dst; uint_fast32_t nbRectangles; UIRectangle *rectangles; const Image *src; double invScaleX; double invScaleY; Filter *horizontalGaussianFilter; Filter *verticalGaussianFilter; } DownscaleImageArguments; void FreeDownscaleImageArguments(void *arg) { DownscaleImageArguments *c_arg = (DownscaleImageArguments *)arg; if (c_arg->threadId == 0) { free(c_arg->rectangles); FreeFilter(*c_arg->horizontalGaussianFilter); FreeFilter(*c_arg->verticalGaussianFilter); free(c_arg->horizontalGaussianFilter); free(c_arg->verticalGaussianFilter); } } void *DownscaleImageThreadRoutine(void *arg) { ThreadArgHeader *threadArgHeader = GetThreadArgHeader(arg); DownscaleImageArguments *c_arg = (DownscaleImageArguments *)GetThreadArgBody(arg); Image *dst = c_arg->dst; const Image *src = c_arg->src; double invScaleX = c_arg->invScaleX; double invScaleY = c_arg->invScaleY; Filter *horizontalGaussianFilter = c_arg->horizontalGaussianFilter; Filter *verticalGaussianFilter = c_arg->verticalGaussianFilter; Image tmpImage; CreateImage(&tmpImage, horizontalGaussianFilter->sx, 1, src->bytesPerComponent); uint_fast32_t nbRectangles = c_arg->nbRectangles; UIRectangle *dstRect; uint_fast32_t rectHeight; uint_fast32_t counter = 0; int cancelRequested = CancelTaskRequested(threadArgHeader); for (uint_fast32_t i = 0; i < nbRectangles && !cancelRequested; ++i) { dstRect = &c_arg->rectangles[i]; rectHeight = dstRect->y2+1 - dstRect->y1; for (uint_fast32_t j = dstRect->y1; j <= dstRect->y2 && !cancelRequested; ++j) { SetThreadProgress(threadArgHeader, 100 * (i * rectHeight + (j-dstRect->y1)) / (rectHeight * nbRectangles)); uint_fast32_t y = (j+0.5)*invScaleY; for (uint_fast32_t k = dstRect->x1; k <= dstRect->x2 && !cancelRequested; ++k) { HandleRequests(32); uint_fast32_t x = (k+0.5)*invScaleX; for (uint_fast32_t l = 0; l < horizontalGaussianFilter->sx; ++l) { PutPixelUnsafe(&tmpImage, l, 0, ApplyFilterOnSinglePixel(src, x-horizontalGaussianFilter->cx+l, y, verticalGaussianFilter)); } PutPixelUnsafe(dst, k, j, ApplyFilterOnSinglePixel(&tmpImage, horizontalGaussianFilter->cx, 0, horizontalGaussianFilter)); } } } SetThreadProgress(threadArgHeader, 100); FreeImage(tmpImage); int canceled = CancelTaskRequested(threadArgHeader); return (canceled ? PTHREAD_CANCELED : NULL); } char downscaleImageMessage[] = "Downscaling image"; Task *CreateDownscaleImageTask(Image *dst, const Image *src, uint_fast32_t nbThreads) { if (src->width == 0 || src->height == 0 || dst->width == 0 || dst->height == 0) { return DoNothingTask(); } if (dst->width > src->width || dst->height > src->height) { FractalNow_error("Downscaling to a bigger image makes no sense.\n"); } double invScaleX = src->width / (double)dst->width; double invScaleY = src->height / (double)dst->height; Filter *horizontalGaussianFilter = (Filter *)safeMalloc("horizontal gaussian filter", sizeof(Filter)); Filter *verticalGaussianFilter = (Filter *)safeMalloc("vertical gaussian filter", sizeof(Filter)); CreateHorizontalGaussianFilter2(horizontalGaussianFilter, invScaleX); CreateVerticalGaussianFilter2(verticalGaussianFilter, invScaleY); uint_fast32_t nbPixels = dst->width*dst->height; uint_fast32_t nbThreadsNeeded = nbThreads; uint_fast32_t rectanglesPerThread = DEFAULT_RECTANGLES_PER_THREAD; if (nbPixels <= nbThreadsNeeded) { nbThreadsNeeded = nbPixels; rectanglesPerThread = 1; } else if (nbPixels < nbThreadsNeeded*rectanglesPerThread) { rectanglesPerThread = nbPixels / nbThreadsNeeded; } uint_fast32_t nbRectangles = nbThreadsNeeded*rectanglesPerThread; UIRectangle *rectangle; rectangle = (UIRectangle *)safeMalloc("rectangles", nbRectangles * sizeof(UIRectangle)); InitUIRectangle(&rectangle[0], 0, 0, dst->width-1, dst->height-1); if (CutUIRectangleInN(rectangle[0], nbRectangles, rectangle)) { FractalNow_error("Could not cut rectangle ((%"PRIuFAST32",%"PRIuFAST32"),\ (%"PRIuFAST32",%"PRIuFAST32") in %"PRIuFAST32" parts.\n", rectangle[0].x1, rectangle[0].y1, rectangle[0].x2, rectangle[0].y2, nbRectangles); } DownscaleImageArguments *arg; arg = (DownscaleImageArguments *)safeMalloc("arguments", nbThreadsNeeded * sizeof(DownscaleImageArguments)); for (uint_fast32_t i = 0; i < nbThreadsNeeded; ++i) { arg[i].threadId = i; arg[i].dst = dst; arg[i].nbRectangles = rectanglesPerThread; arg[i].rectangles = &rectangle[i*rectanglesPerThread]; arg[i].src = src; arg[i].invScaleX = invScaleX; arg[i].invScaleY = invScaleY; /* Filters copied to avoid concurrent read. */ arg[i].horizontalGaussianFilter = horizontalGaussianFilter; arg[i].verticalGaussianFilter = verticalGaussianFilter; } Task *res = CreateTask(downscaleImageMessage, nbThreadsNeeded, arg, sizeof(DownscaleImageArguments), DownscaleImageThreadRoutine, FreeDownscaleImageArguments); free(arg); return res; } void DownscaleImage(Image *dst, const Image *src, Threads *threads) { Task *task = CreateDownscaleImageTask(dst, src, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } void FreeImage(Image image) { if (image.width != 0 && image.height != 0 && !image.data_is_external) { free(image.data); } } fractalnow-0.8.1/lib/src/error.c0000664000175000017500000000164011754747533015177 0ustar mpegmpeg/* * error.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "error.h" int FractalNow_debug = 0; TraceLevel FractalNow_traceLevel = T_NORMAL; fractalnow-0.8.1/lib/src/color.c0000664000175000017500000000737111777336364015174 0ustar mpegmpeg/* * color.c -- part of FractalNow * * Copyright (c) 2011-2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "color.h" #include "error.h" #include #include Color ColorFromRGB(uint8_t bytesPerComponent, uint16_t r, uint16_t g, uint16_t b) { if (bytesPerComponent != 1 && bytesPerComponent != 2) { FractalNow_error("Invalid bytes per component.\n"); } Color res; res.bytesPerComponent = bytesPerComponent; res.r = r; res.g = g; res.b = b; return res; } inline Color ColorFromUint32(uint32_t color) { Color res; res.r = GET_R8(color); res.g = GET_G8(color); res.b = GET_B8(color); res.bytesPerComponent = 1; return res; } inline Color ColorFromUint64(uint64_t color) { Color res; res.r = GET_R16(color); res.g = GET_G16(color); res.b = GET_B16(color); res.bytesPerComponent = 2; return res; } Color Color16(Color color) { Color res; if (color.bytesPerComponent == 2) { res = color; } else { res.bytesPerComponent = 2; res.r = round(color.r * UINT16_MAX / UINT8_MAX); res.g = round(color.g * UINT16_MAX / UINT8_MAX); res.b = round(color.b * UINT16_MAX / UINT8_MAX); } return res; } Color Color8(Color color) { Color res; if (color.bytesPerComponent == 1) { res = color; } else { res.bytesPerComponent = 1; res.r = round(color.r * UINT8_MAX / UINT16_MAX); res.g = round(color.g * UINT8_MAX / UINT16_MAX); res.b = round(color.b * UINT8_MAX / UINT16_MAX); } return res; } int CompareColors(const Color color1, const Color color2) { return (color1.bytesPerComponent != color2.bytesPerComponent || color1.r != color2.r || color1.g != color2.g || color1.b != color2.b); } Color MixColors(Color C1, double weight1, Color C2, double weight2) { Color res; res.bytesPerComponent = C1.bytesPerComponent; res.r = C1.r * weight1 + C2.r * weight2; res.g = C1.g * weight1 + C2.g * weight2; res.b = C1.b * weight1 + C2.b * weight2; return res; } inline double ColorManhattanDistance(Color C1, Color C2) { double res = 0; uint_fast32_t sum = (labs(C1.r-(long int)C2.r)+labs(C1.g-(long int)C2.g)+ labs(C1.b-(long int)C2.b)); switch (C1.bytesPerComponent) { case 1: res = sum / (double)(3*UINT8_MAX); break; case 2: res = sum / (double)(3*UINT16_MAX); break; default: FractalNow_error("Invalid bytes per component.\n"); break; } return res; } inline double QuadAvgDissimilarity(const Color C[4]) { Color avg; avg.r = (C[0].r + C[1].r + C[2].r + C[3].r) / 4; avg.g = (C[0].g + C[1].g + C[2].g + C[3].g) / 4; avg.b = (C[0].b + C[1].b + C[2].b + C[3].b) / 4; return (ColorManhattanDistance(C[0],avg)+ ColorManhattanDistance(C[1],avg)+ ColorManhattanDistance(C[2],avg)+ ColorManhattanDistance(C[3],avg)) / 4; } inline Color QuadLinearInterpolation(const Color C[4], double x, double y) { Color res; res.bytesPerComponent = C[0].bytesPerComponent; res.r = (C[0].r*(1.-x)+C[1].r*x)*(1.-y) + (C[2].r*(1.-x)+C[3].r*x)*y; res.g = (C[0].g*(1.-x)+C[1].g*x)*(1.-y) + (C[2].g*(1.-x)+C[3].g*x)*y; res.b = (C[0].b*(1.-x)+C[1].b*x)*(1.-y) + (C[2].b*(1.-x)+C[3].b*x)*y; return res; } fractalnow-0.8.1/lib/src/fractal.c0000664000175000017500000010072311754776133015462 0ustar mpegmpeg/* * fractal.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "fractal.h" #include "error.h" #include "file_io.h" #include "filter.h" #include "fractal_compute_engine.h" #include "misc.h" #include "uirectangle.h" #include "thread.h" #include #include #include #include #define HandleRequests(max_counter) \ if (counter == max_counter) {\ HandlePauseRequest(threadArgHeader);\ cancelRequested =\ CancelTaskRequested(threadArgHeader);\ counter = 0;\ } else {\ ++counter;\ } typedef struct s_DrawFractalArguments { uint_fast32_t threadId; FractalCache *cache; Image *image; Image *copyImage; const Fractal *fractal; const RenderingParameters *render; uint_fast32_t nbRectangles; UIRectangle *rectangles; uint_fast32_t size; double threshold; FloatPrecision floatPrecision; } DrawFractalArguments; void FreeDrawFractalArguments(void *arg) { DrawFractalArguments *c_arg = (DrawFractalArguments *)arg; if (c_arg->threadId == 0) { free(c_arg->rectangles); if (c_arg->copyImage != NULL) { FreeImage(*c_arg->copyImage); free(c_arg->copyImage); } } } const char *fractalFormatStr[] = { (const char *)"f075" }; const uint_fast32_t nbFractalFormats = sizeof(fractalFormatStr) / sizeof(const char *); int ReadFractalFileV075(Fractal *fractal, const char *fileName, FILE *file); typedef int (*ReadFractalFileFunction)(Fractal *fractal, const char *fileName, FILE *file); const ReadFractalFileFunction readFractalFileFunction[] = { ReadFractalFileV075 }; int WriteFractalFileV075(const Fractal *fractal, const char *fileName, FILE *file); typedef int (*WriteFractalFileFunction)(const Fractal *fractal, const char *fileName, FILE *file); const WriteFractalFileFunction writeFractalFileFunction[] = { WriteFractalFileV075 }; void InitFractal(Fractal *fractal, FractalFormula fractalFormula, const mpc_t p, const mpc_t c, const mpfr_t centerX, const mpfr_t centerY, const mpfr_t spanX, const mpfr_t spanY, double escapeRadius, uint_fast32_t maxIter) { cinitF(FP_MP, fractal->p); cinitF(FP_MP, fractal->c); initF(FP_MP, fractal->centerX); initF(FP_MP, fractal->centerY); initF(FP_MP, fractal->spanX); initF(FP_MP, fractal->spanY); initF(FP_MP, fractal->x1); initF(FP_MP, fractal->y1); fractal->fractalFormula = fractalFormula; if (fractalFormula == FRAC_MANDELBROT || fractalFormula == FRAC_JULIA) { cfromUiF(FP_MP, fractal->p, 2); } else { cassignF(FP_MP, fractal->p, p); } cassignF(FP_MP, fractal->c, c); fractal->escapeRadius = escapeRadius; fractal->maxIter = maxIter; assignF(FP_MP, fractal->centerX, centerX); assignF(FP_MP, fractal->centerY, centerY); assignF(FP_MP, fractal->spanX, spanX); assignF(FP_MP, fractal->spanY, spanY); mpfr_t tmp; initF(FP_MP, tmp); div_uiF(FP_MP, tmp, spanX, 2); subF(FP_MP, fractal->x1, centerX, tmp); div_uiF(FP_MP, tmp, spanY, 2); subF(FP_MP, fractal->y1, centerY, tmp); clearF(FP_MP, tmp); } void InitFractal2(Fractal *fractal, FractalFormula fractalFormula, long double complex p, long double complex c, long double centerX, long double centerY, long double spanX, long double spanY, double escapeRadius, uint_fast32_t maxIter) { cinitF(FP_MP, fractal->p); cinitF(FP_MP, fractal->c); initF(FP_MP, fractal->centerX); initF(FP_MP, fractal->centerY); initF(FP_MP, fractal->spanX); initF(FP_MP, fractal->spanY); initF(FP_MP, fractal->x1); initF(FP_MP, fractal->y1); fractal->fractalFormula = fractalFormula; if (fractalFormula == FRAC_MANDELBROT || fractalFormula == FRAC_JULIA) { p = 2; } cfromCDoubleF(FP_MP, fractal->p, p); cfromCDoubleF(FP_MP, fractal->c, c); fractal->escapeRadius = escapeRadius; fractal->maxIter = maxIter; fromDoubleF(FP_MP, fractal->centerX, centerX); fromDoubleF(FP_MP, fractal->centerY, centerY); fromDoubleF(FP_MP, fractal->spanX, spanX); fromDoubleF(FP_MP, fractal->spanY, spanY); fromDoubleF(FP_MP, fractal->x1, centerX - spanX/2); fromDoubleF(FP_MP, fractal->y1, centerY - spanY/2); } Fractal CopyFractal(const Fractal *fractal) { Fractal res; InitFractal(&res, fractal->fractalFormula, fractal->p, fractal->c, fractal->centerX, fractal->centerY, fractal->spanX, fractal->spanY, fractal->escapeRadius, fractal->maxIter); return res; } int ReadFractalFileV075(Fractal *fractal, const char *fileName, FILE *file) { int res = 0; char tmp[6][256]; mpc_t p; cinitF(FP_MP, p); mpc_t c; cinitF(FP_MP, c); mpfr_t centerX, centerY; initF(FP_MP, centerX); initF(FP_MP, centerY); mpfr_t spanX, spanY; initF(FP_MP, spanX); initF(FP_MP, spanY); FractalFormula fractalFormula; if (readString(file, tmp[0]) < 1) { FractalNow_read_werror(fileName); } if (GetFractalFormula(&fractalFormula, tmp[0])) { FractalNow_werror("Invalid fractal file : could not get fractal formula.\n"); } switch (fractalFormula) { case FRAC_MANDELBROT: case FRAC_JULIA: fromUiF(FP_MP, mpc_realref(p), 2); fromUiF(FP_MP, mpc_imagref(p), 0); break; case FRAC_MULTIBROT: case FRAC_MULTIJULIA: case FRAC_BURNINGSHIP: case FRAC_JULIABURNINGSHIP: case FRAC_MANDELBAR: case FRAC_JULIABAR: case FRAC_RUDY: if (readMPFR(file, mpc_realref(p)) < 1) { FractalNow_read_werror(fileName); } if (readMPFR(file, mpc_imagref(p)) < 1) { FractalNow_read_werror(fileName); } break; default: FractalNow_werror("Unknown fractal formula \'%s\'.\n", tmp[0]); break; } if (cmp_uiF(FP_MP, mpc_realref(p), 0) < 0 || cmp_uiF(FP_MP, mpc_realref(p), 100) > 0) { FractalNow_werror("Invalid fractal file : Re(p) must be between 0 and 100.\n"); } if (cmp_uiF(FP_MP, mpc_imagref(p), 0) < 0 || cmp_uiF(FP_MP, mpc_imagref(p), 100) > 0) { FractalNow_werror("Invalid fractal file : Im(p) must be between 0 and 100.\n"); } cfromCDoubleF(FP_MP, c, 0.5+I*0.5); switch (fractalFormula) { case FRAC_MANDELBROT: case FRAC_BURNINGSHIP: case FRAC_MANDELBAR: case FRAC_MULTIBROT: break; case FRAC_JULIA: case FRAC_MULTIJULIA: case FRAC_JULIABURNINGSHIP: case FRAC_JULIABAR: case FRAC_RUDY: if (readMPFR(file, mpc_realref(c)) < 1) { FractalNow_read_werror(fileName); } if (readMPFR(file, mpc_imagref(c)) < 1) { FractalNow_read_werror(fileName); } break; default: FractalNow_werror("Unknown fractal formula \'%s\'.\n", tmp[0]); break; } if (readMPFR(file, centerX) < 1) { FractalNow_read_werror(fileName); } if (readMPFR(file, centerY) < 1) { FractalNow_read_werror(fileName); } if (readMPFR(file, spanX) < 1) { FractalNow_read_werror(fileName); } if (cmp_uiF(FP_MP, spanX, 0) <= 0) { FractalNow_werror("Invalid fractal file : spanX must be > 0.\n"); } if (readMPFR(file, spanY) < 1) { FractalNow_read_werror(fileName); } if (cmp_uiF(FP_MP, spanY, 0) <= 0) { FractalNow_werror("Invalid fractal file : spanY must be > 0.\n"); } double escapeRadius; if (readDouble(file, &escapeRadius) < 1) { FractalNow_read_werror(fileName); } if (escapeRadius <= 1.) { FractalNow_werror("Invalid config file : escape radius must be > 1.\n"); } uint32_t nbIterMax; if (readUint32(file, &nbIterMax) < 1) { FractalNow_read_werror(fileName); } InitFractal(fractal, fractalFormula, p, c, centerX, centerY, spanX, spanY, escapeRadius, nbIterMax); end: cclearF(FP_MP, p); cclearF(FP_MP, c); clearF(FP_MP, centerX); clearF(FP_MP, centerY); clearF(FP_MP, spanX); clearF(FP_MP, spanY); return res; } ReadFractalFileFunction GetReadFractalFileFunction(const char *format) { if (strlen(format) != 4) { return NULL; } ReadFractalFileFunction readFractalFile = NULL; char formatStr[5]; strcpy(formatStr, format); toLowerCase(formatStr); uint_fast32_t i; for (i = 0; i < nbFractalFormats; ++i) { if (strcmp(formatStr, fractalFormatStr[i]) == 0) { readFractalFile = readFractalFileFunction[i]; break; } } return readFractalFile; } int isSupportedFractalFile(const char *fileName) { int res = 0; FILE *file; file=fopen(fileName,"r"); if (!file) { FractalNow_open_werror(fileName); } char formatStr[256]; if (readString(file, formatStr) < 1) { res = 1; } else { ReadFractalFileFunction readFractalFileFunction; readFractalFileFunction = GetReadFractalFileFunction(formatStr); res = (readFractalFileFunction == NULL); } end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } return !res; } int ReadFractalFileBody(Fractal *fractal, const char *fileName, FILE *file, const char *format) { FractalNow_message(stdout, T_VERBOSE, "Reading fractal file body...\n"); int res = 0; ReadFractalFileFunction readFractalFile = GetReadFractalFileFunction(format); if (readFractalFile == NULL) { FractalNow_werror("Unsupported fractal format '%s'.\n", format); } res |= readFractalFile(fractal, fileName, file); end: FractalNow_message(stdout, T_VERBOSE, "Reading fractal file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int ReadFractalFile(Fractal *fractal, const char *fileName) { FractalNow_message(stdout, T_NORMAL, "Reading fractal file...\n"); int res = 0; FILE *file; file=fopen(fileName,"r"); if (!file) { FractalNow_open_werror(fileName); } char formatStr[256]; if (readString(file, formatStr) < 1) { FractalNow_read_werror(fileName); } res = ReadFractalFileBody(fractal, fileName, file, formatStr); end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } FractalNow_message(stdout, T_NORMAL, "Reading fractal file : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } WriteFractalFileFunction GetWriteFractalFileFunction(const char *format) { if (strlen(format) != 4) { return NULL; } WriteFractalFileFunction writeFractalFile = NULL; char formatStr[5]; strcpy(formatStr, format); toLowerCase(formatStr); uint_fast32_t i; for (i = 0; i < nbFractalFormats; ++i) { if (strcmp(formatStr, fractalFormatStr[i]) == 0) { writeFractalFile = writeFractalFileFunction[i]; break; } } return writeFractalFile; } int WriteFractalFileV075(const Fractal *fractal, const char *fileName, FILE *file) { int res = 0; const char *fractalFormula = fractalFormulaStr[(int)fractal->fractalFormula]; if (writeString(file, fractalFormula, "\n") < 0) { FractalNow_write_werror(fileName); } switch (fractal->fractalFormula) { case FRAC_MANDELBROT: case FRAC_JULIA: break; case FRAC_MULTIBROT: case FRAC_MULTIJULIA: case FRAC_BURNINGSHIP: case FRAC_JULIABURNINGSHIP: case FRAC_MANDELBAR: case FRAC_JULIABAR: case FRAC_RUDY: if (writeMPFR(file, mpc_realref(fractal->p), " ") < 0) { FractalNow_write_werror(fileName); } if (writeMPFR(file, mpc_imagref(fractal->p), "\n") < 0) { FractalNow_write_werror(fileName); } break; default: FractalNow_werror("Unknown fractal formula value '%d'.\n", fractal->fractalFormula); break; } switch (fractal->fractalFormula) { case FRAC_MANDELBROT: case FRAC_MULTIBROT: case FRAC_BURNINGSHIP: case FRAC_MANDELBAR: break; case FRAC_JULIA: case FRAC_MULTIJULIA: case FRAC_JULIABURNINGSHIP: case FRAC_JULIABAR: case FRAC_RUDY: if (writeMPFR(file, mpc_realref(fractal->c), " ") < 0) { FractalNow_write_werror(fileName); } if (writeMPFR(file, mpc_imagref(fractal->c), "\n") < 0) { FractalNow_write_werror(fileName); } break; default: FractalNow_werror("Unknown fractal formula value '%d'.\n", fractal->fractalFormula); break; } if (writeMPFR(file, fractal->centerX, " ") < 0) { FractalNow_write_werror(fileName); } if (writeMPFR(file, fractal->centerY, " ") < 0) { FractalNow_write_werror(fileName); } if (writeMPFR(file, fractal->spanX, " ") < 0) { FractalNow_write_werror(fileName); } if (writeMPFR(file, fractal->spanY, "\n") < 0) { FractalNow_write_werror(fileName); } if (writeDouble(file, fractal->escapeRadius, " ") < 0) { FractalNow_write_werror(fileName); } if (writeUint32(file, fractal->maxIter, "\n") < 0) { FractalNow_write_werror(fileName); } end: return res; } int WriteFractalFileBody(const Fractal *fractal, const char *fileName, FILE *file, const char *format) { FractalNow_message(stdout, T_VERBOSE, "Writing fractal file body...\n"); int res = 0; WriteFractalFileFunction writeFractalFile = GetWriteFractalFileFunction(format); if (writeFractalFile == NULL) { FractalNow_werror("Unsupported fractal format '%s'.\n", format); } res |= writeFractalFile(fractal, fileName, file); end: FractalNow_message(stdout, T_VERBOSE, "Writing fractal file body : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } int WriteFractalFile(const Fractal *fractal, const char *fileName) { FractalNow_message(stdout, T_NORMAL, "Writing fractal file...\n"); int res = 0; FILE *file; file=fopen(fileName,"w"); if (!file) { FractalNow_open_werror(fileName); } const char *format = fractalFormatStr[nbFractalFormats-1]; fprintf(file, "%s\n", format); res = WriteFractalFileBody(fractal, fileName, file, format); end: if (file && fclose(file)) { FractalNow_close_errmsg(fileName); res = 1; } FractalNow_message(stdout, T_NORMAL, "Writing fractal file : %s.\n", (res == 0) ? "DONE" : "FAILED"); return res; } static inline Color aux_ComputeFractalColor(const Fractal *fractal, const RenderingParameters *render, const FractalEngine *engine, uint_fast32_t x, uint_fast32_t y, uint_fast32_t width, uint_fast32_t height, FractalCache *cache) { CacheEntry entry = RunFractalEngine(engine, fractal, render, x, y, width, height); double value = entry.value; Color res; if (cache != NULL) { AddToCacheThreadSafe(cache, entry); } else { FreeCacheEntry(entry); } if (value < 0) { res = render->spaceColor; } else { value = render->transferFunctionPtr(value)*render->realMultiplier+ render->realOffset; res = GetGradientColor(&render->gradient, (uint_fast64_t)(value)); } return res; } static inline Color aux_ComputeFractalImagePixel(const Fractal *fractal, const RenderingParameters *render, const FractalEngine *fractalEngine, uint_fast32_t x, uint_fast32_t y, uint_fast32_t width, uint_fast32_t height, FractalCache *cache) { /* We call auxiliary function because we don't need (and thus want) to * to re-get the FractalLoop to use for each pixel. It is already stored * in arg. */ return aux_ComputeFractalColor(fractal, render, fractalEngine, x, y, width, height, cache); } static inline Color ComputeFractalImagePixel(const DrawFractalArguments *arg, const FractalEngine *engine, uint_fast32_t width, uint_fast32_t height, uint_fast32_t x, uint_fast32_t y, int useCache, FractalCache *cache) { const Fractal *fractal = arg->fractal; const RenderingParameters *render = arg->render; Color res; if (useCache && cache != NULL) { ArrayValue aVal = GetArrayValue(cache, x, y); if (isArrayValueValid(aVal, cache)) { res = GetColorFromAVal(aVal, render); } else { res = aux_ComputeFractalImagePixel(fractal, render, engine, x, y, width, height, cache); } } else { res = aux_ComputeFractalImagePixel(fractal, render, engine, x, y, width, height, cache); } return res; } /* Compute (all) fractal values of given rectangle and render in image. */ static void aux1_DrawFractalThreadRoutine(ThreadArgHeader *threadArgHeader, const DrawFractalArguments *arg, const FractalEngine *engine) { Image *image = arg->image; uint_fast32_t nbRectangles = arg->nbRectangles; FractalCache *cache = arg->cache; UIRectangle *rectangle; uint_fast32_t rectHeight; int cancelRequested = CancelTaskRequested(threadArgHeader); uint_fast32_t counter = 0; for (uint_fast32_t i = 0; i < nbRectangles && !cancelRequested; ++i) { rectangle = &arg->rectangles[i]; rectHeight = rectangle->y2+1 - rectangle->y1; Color color; for (uint_fast32_t j=rectangle->y1; j<=rectangle->y2 && !cancelRequested; j++) { /* Updating progress after each line should be precise enough. */ SetThreadProgress(threadArgHeader, 100 * (i * rectHeight + (j-rectangle->y1)) / (rectHeight * nbRectangles)); for (uint_fast32_t k=rectangle->x1; k<=rectangle->x2 && !cancelRequested; k++) { HandleRequests(32); color = ComputeFractalImagePixel(arg, engine, image->width, image->height, k, j, 1, cache); PutPixelUnsafe(image,k,j,color); } } } SetThreadProgress(threadArgHeader, 100); } static inline int IsTooBigForInterpolation(const UIRectangle *rectangle, uint_fast32_t quadInterpolationSize) { return ((rectangle->x2-rectangle->x1+1 > quadInterpolationSize) || (rectangle->y2-rectangle->y1+1 > quadInterpolationSize)); } static inline int_fast8_t GetCornerIndex(const UIRectangle *rectangle, uint_fast32_t x, uint_fast32_t y) { if ((x == rectangle->x1 && y == rectangle->y1)) { return 0; } else if (x == rectangle->x2 && y == rectangle->y1) { return 1; } else if (x == rectangle->x1 && y == rectangle->y2) { return 2; } else if (x == rectangle->x2 && y == rectangle->y2) { return 3; } else { return -1; } } /* Compute fractal values of given rectangle into fractal_table, according to its dissimilarity and the given dissimilarity threshold (i.e. either computes it really, or interpolate linearly from the corners), and render in image. */ static inline void aux2_DrawFractalThreadRoutine(const DrawFractalArguments *arg, const FractalEngine *engine, const UIRectangle *rectangle) { Image *image = arg->image; uint_fast32_t width = image->width; uint_fast32_t height = image->height; double interpolationThreshold = arg->threshold; FractalCache *cache = arg->cache; Color corner[4]; if (rectangle->x1 == rectangle->x2 && rectangle->y1 == rectangle->y2) { /* Rectangle is just one pixel.*/ corner[0] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x1,rectangle->y1,1, cache); PutPixelUnsafe(image,rectangle->x1,rectangle->y1,corner[0]); return; } else if (rectangle->x1 == rectangle->x2) { /* Rectangle is a vertical line. There are only two "corners". */ corner[0] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x1,rectangle->y1,1, cache); corner[1] = corner[0]; corner[2] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x1,rectangle->y2,1, cache); corner[3] = corner[2]; /* Even for a line, we can still use quad interpolation.*/ } else if (rectangle->y1 == rectangle->y2) { /* Rectangle is a horizontal line. There are only two "corners". */ corner[0] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x1,rectangle->y1,1, cache); corner[1] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x2,rectangle->y1,1, cache); corner[2] = corner[0]; corner[3] = corner[1]; /* Even for a line, we can still use quad interpolation.*/ } else { /* "Real" rectangle. Compute four corners. */ corner[0] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x1,rectangle->y1,1, cache); corner[1] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x2,rectangle->y1,1, cache); corner[2] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x1,rectangle->y2,1, cache); corner[3] = ComputeFractalImagePixel(arg,engine,width,height,rectangle->x2,rectangle->y2,1 ,cache); } Color color; int_fast8_t index = -1; if (QuadAvgDissimilarity(corner) < interpolationThreshold) { /* Linear interpolation */ double sx = (double)rectangle->x2-rectangle->x1+1; double sy = (double)rectangle->y2-rectangle->y1+1; double x, y; for (uint_fast32_t i=rectangle->y1; i<=rectangle->y2; i++) { y = ((double)(i-rectangle->y1)) / sy; for (uint_fast32_t j=rectangle->x1; j<=rectangle->x2; j++) { index = GetCornerIndex(rectangle, j, i); if (index >= 0) { color = corner[index]; } else { x = ((double)(j-rectangle->x1)) / sx; color = QuadLinearInterpolation(corner,x,y); } PutPixelUnsafe(image,j,i,color); } } } else { /* Real computation */ for (uint_fast32_t i=rectangle->y1; i<=rectangle->y2; i++) { for (uint_fast32_t j=rectangle->x1; j<=rectangle->x2; j++) { index = GetCornerIndex(rectangle, j, i); if (index >= 0) { color = corner[index]; } else { color = ComputeFractalImagePixel(arg,engine,width,height,j,i,1, cache); } PutPixelUnsafe(image,j,i,color); } } } } void *DrawFractalThreadRoutine(void *arg) { ThreadArgHeader *threadArgHeader = GetThreadArgHeader(arg); DrawFractalArguments *c_arg = (DrawFractalArguments *)GetThreadArgBody(arg); FractalEngine engine; CreateFractalEngine(&engine, c_arg->fractal, c_arg->render, c_arg->floatPrecision); if (c_arg->size == 1) { aux1_DrawFractalThreadRoutine(threadArgHeader, c_arg, &engine); } else { UIRectangle *currentRect; int cancelRequested = CancelTaskRequested(threadArgHeader); uint_fast32_t counter = 0; for (uint_fast32_t i = 0; i < c_arg->nbRectangles && !cancelRequested; ++i) { currentRect = &c_arg->rectangles[i]; /* Cut rectangle into smaller rectangles, so that all rectangles are smaller than quadInterpolationSize. */ UIRectangle *rectangle; uint_fast32_t nbRectangles; CutUIRectangleMaxSize(*currentRect, c_arg->size, &rectangle, &nbRectangles); /* If the rectangle dissimilarity is greater that threshold, we compute the fractal colors, otherwise we interpolate them using the corner colors. Check for cancellation after each rectangle is drawn. There should be very small latency because rectangles are fairly small (default size is 5*5 pixels). If this results in too much latency when cancelling, we might want to make this check in aux2_DrawFractalThreadRoutine, after each scanline for example. */ for (uint_fast32_t j = 0; j < nbRectangles && !cancelRequested; ++j) { /* Updating after each rectangle should be precise enough. */ SetThreadProgress(threadArgHeader, 100 * (i * nbRectangles + j) / (nbRectangles * c_arg->nbRectangles)); HandleRequests(0); aux2_DrawFractalThreadRoutine(c_arg, &engine, &rectangle[j]); } free(rectangle); } SetThreadProgress(threadArgHeader, 100); } FreeFractalEngine(&engine); int canceled = CancelTaskRequested(threadArgHeader); return (canceled ? PTHREAD_CANCELED : NULL); } char drawFractalMessage[] = "Drawing fractal"; Task *aux_CreateDrawFractalTask(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t quadInterpolationSize, double interpolationThreshold, FloatPrecision floatPrecision, FractalCache *cache, uint_fast32_t nbThreads) { if (image->width < 2 || image->height < 2) { return DoNothingTask(); } if (quadInterpolationSize == 0) { quadInterpolationSize = 1; } uint_fast32_t nbPixels = image->width*image->height; uint_fast32_t nbThreadsNeeded = nbThreads; uint_fast32_t rectanglesPerThread = DEFAULT_RECTANGLES_PER_THREAD; if (nbPixels <= nbThreadsNeeded) { nbThreadsNeeded = nbPixels; rectanglesPerThread = 1; } else if (nbPixels < nbThreadsNeeded*rectanglesPerThread) { rectanglesPerThread = nbPixels / nbThreadsNeeded; } uint_fast32_t nbRectangles = nbThreadsNeeded*rectanglesPerThread; UIRectangle *rectangle; rectangle = (UIRectangle *)safeMalloc("rectangles", nbRectangles * sizeof(UIRectangle)); InitUIRectangle(&rectangle[0], 0, 0, image->width-1, image->height-1); if (CutUIRectangleInN(rectangle[0], nbRectangles, rectangle)) { FractalNow_error("Could not cut rectangle ((%"PRIuFAST32",%"PRIuFAST32"),\ (%"PRIuFAST32",%"PRIuFAST32") in %"PRIuFAST32" parts.\n", rectangle[0].x1, rectangle[0].y1, rectangle[0].x2, rectangle[0].y2, nbRectangles); } DrawFractalArguments *arg; arg = (DrawFractalArguments *)safeMalloc("arguments", nbThreadsNeeded * sizeof(DrawFractalArguments)); for (uint_fast32_t i = 0; i < nbThreadsNeeded; ++i) { arg[i].threadId = i; arg[i].cache = cache; arg[i].image = image; arg[i].copyImage = NULL; arg[i].fractal = fractal; arg[i].render = render; arg[i].floatPrecision = floatPrecision; arg[i].rectangles = &rectangle[i*rectanglesPerThread]; arg[i].nbRectangles = rectanglesPerThread; arg[i].size = quadInterpolationSize; arg[i].threshold = interpolationThreshold; } Task *task = CreateTask(drawFractalMessage, nbThreadsNeeded, arg, sizeof(DrawFractalArguments), DrawFractalThreadRoutine, FreeDrawFractalArguments); free(arg); return task; } inline Task *CreateDrawFractalTask(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t quadInterpolationSize, double interpolationThreshold, FloatPrecision floatPrecision, FractalCache *cache, uint_fast32_t nbThreads) { Task *res; if (cache == NULL) { res = aux_CreateDrawFractalTask(image, fractal, render, quadInterpolationSize, interpolationThreshold, floatPrecision, cache, nbThreads); } else { /* Create preview image from cache first. */ Task *subTasks[2]; subTasks[0] = CreateFractalCachePreviewTask(image, cache, fractal, render, 1, nbThreads); subTasks[1] = aux_CreateDrawFractalTask(image, fractal, render, quadInterpolationSize, interpolationThreshold, floatPrecision, cache, nbThreads); res = CreateCompositeTask(NULL, 2, subTasks); } return res; } void DrawFractal(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t quadInterpolationSize, double interpolationThreshold, FloatPrecision floatPrecision, FractalCache *cache, Threads *threads) { Task *task = CreateDrawFractalTask(image, fractal, render, quadInterpolationSize, interpolationThreshold, floatPrecision, cache, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } void *AntiAliaseFractalThreadRoutine(void *arg) { ThreadArgHeader *threadArgHeader = GetThreadArgHeader(arg); DrawFractalArguments *c_arg = (DrawFractalArguments *)GetThreadArgBody(arg); Image *image = c_arg->image; const Image *copyImage = c_arg->copyImage; uint_fast32_t antialiasingSize = c_arg->size; double threshold = c_arg->threshold; FractalCache *cache = c_arg->cache; uint_fast32_t width = image->width; uint_fast32_t height = image->height; FractalEngine engine; CreateFractalEngine(&engine, c_arg->fractal, c_arg->render, c_arg->floatPrecision); Image tmpImage1, tmpImage2; CreateImage(&tmpImage1, antialiasingSize, antialiasingSize, image->bytesPerComponent); CreateImage(&tmpImage2, 1, antialiasingSize, image->bytesPerComponent); Filter horizontalGaussianFilter; Filter verticalGaussianFilter; CreateHorizontalGaussianFilter2(&horizontalGaussianFilter, antialiasingSize); CreateVerticalGaussianFilter2(&verticalGaussianFilter, antialiasingSize); uint_fast32_t center = (antialiasingSize-1) / 2; uint_fast32_t bigWidth = width * antialiasingSize; uint_fast32_t bigHeight = height * antialiasingSize; Color C[9], c; double max = 0; UIRectangle *rectangle; uint_fast32_t counter = 0; int cancelRequested = CancelTaskRequested(threadArgHeader); for (uint_fast32_t i = 0; i < c_arg->nbRectangles && !cancelRequested; ++i) { rectangle = &c_arg->rectangles[i]; uint_fast32_t rectHeight = rectangle->y2+1 - rectangle->y1; uint_fast32_t y = rectangle->y1 * antialiasingSize; for (uint_fast32_t j = rectangle->y1; j <= rectangle->y2 && !cancelRequested; ++j, y+=antialiasingSize) { SetThreadProgress(threadArgHeader, 100 * (i * rectHeight + (j-rectangle->y1)) / (rectHeight * c_arg->nbRectangles)); uint_fast32_t x = rectangle->x1 * antialiasingSize; for (uint_fast32_t k = rectangle->x1; k <= rectangle->x2 && !cancelRequested; ++k, x+=antialiasingSize) { C[0] = iGetPixel(copyImage, k, j); C[1] = iGetPixel(copyImage, k-1, j-1); C[2] = iGetPixel(copyImage, k, j-1); C[3] = iGetPixel(copyImage, k+1, j-1); C[4] = iGetPixel(copyImage, k-1, j); C[5] = iGetPixel(copyImage, k+1, j); C[6] = iGetPixel(copyImage, k-1, j+1); C[7] = iGetPixel(copyImage, k, j+1); C[8] = iGetPixel(copyImage, k+1, j+1); max = 0; for (int_fast8_t l = 1; l < 9; ++l) { max = fmaxl(max, ColorManhattanDistance(C[0], C[l])); } if (max > threshold) { for (uint_fast32_t l=0; lwidth*antiAliasingSize < 2 || image->height*antiAliasingSize < 2) { return DoNothingTask(); } uint_fast32_t nbPixels = image->width*image->height; uint_fast32_t nbThreadsNeeded = nbThreads; uint_fast32_t rectanglesPerThread = DEFAULT_RECTANGLES_PER_THREAD; if (nbPixels <= nbThreadsNeeded) { nbThreadsNeeded = nbPixels; rectanglesPerThread = 1; } else if (nbPixels < nbThreadsNeeded*rectanglesPerThread) { rectanglesPerThread = nbPixels / nbThreadsNeeded; } uint_fast32_t nbRectangles = nbThreadsNeeded*rectanglesPerThread; UIRectangle *rectangle; rectangle = (UIRectangle *)safeMalloc("rectangles", nbRectangles * sizeof(UIRectangle)); InitUIRectangle(&rectangle[0], 0, 0, image->width-1, image->height-1); if (CutUIRectangleInN(rectangle[0], nbRectangles, rectangle)) { FractalNow_error("Could not cut rectangle ((%"PRIuFAST32",%"PRIuFAST32"),\ (%"PRIuFAST32",%"PRIuFAST32") in %"PRIuFAST32" parts.\n", rectangle[0].x1, rectangle[0].y1, rectangle[0].x2, rectangle[0].y2, nbRectangles); } DrawFractalArguments *arg; arg = (DrawFractalArguments *)safeMalloc("arguments", nbThreadsNeeded*sizeof(DrawFractalArguments)); Image *copyImage = (Image *)safeMalloc("copyImage", sizeof(Image)); *copyImage = CloneImage(image); for (uint_fast32_t i = 0; i < nbThreadsNeeded; ++i) { arg[i].threadId = i; /* No copy for image. * Concurrent read is OK. */ arg[i].image = image; arg[i].copyImage = copyImage; arg[i].cache = cache; /* Fractal is not copied because it is not modified.*/ arg[i].fractal = fractal; /* Rendering parameters are not modified.*/ arg[i].render = render; arg[i].floatPrecision = floatPrecision; arg[i].rectangles = &rectangle[i*rectanglesPerThread]; arg[i].nbRectangles = rectanglesPerThread; arg[i].size = antiAliasingSize; arg[i].threshold = threshold; } Task *res = CreateTask(antiAliaseFractalMessage, nbThreadsNeeded, arg, sizeof(DrawFractalArguments), AntiAliaseFractalThreadRoutine, FreeDrawFractalArguments); free(arg); return res; } void AntiAliaseFractal(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t antiAliasingSize, double threshold, FloatPrecision floatPrecision, FractalCache *cache, Threads *threads) { Task *task = CreateAntiAliaseFractalTask(image, fractal, render, antiAliasingSize, threshold, floatPrecision, cache, threads->N); int unused = ExecuteTaskBlocking(task, threads); UNUSED(unused); } void FreeFractal(Fractal fractal) { cclearF(FP_MP, fractal.p); cclearF(FP_MP, fractal.c); clearF(FP_MP, fractal.centerX); clearF(FP_MP, fractal.centerY); clearF(FP_MP, fractal.spanX); clearF(FP_MP, fractal.spanY); clearF(FP_MP, fractal.x1); clearF(FP_MP, fractal.y1); } fractalnow-0.8.1/lib/include/0000775000175000017500000000000011766115336014526 5ustar mpegmpegfractalnow-0.8.1/lib/include/fractalnow.h0000664000175000017500000000400611754776133017044 0ustar mpegmpeg/* * fractalnow.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractalnow.h * \brief Main FractalNow lib header file. * \author Marc Pegon */ #ifndef __FRACTALNOW_H__ #define __FRACTALNOW_H__ #include "color.h" #include "error.h" #include "file_io.h" #include "filter.h" #include "float_precision.h" #include "fractal_addend_function.h" #include "fractal_cache.h" #include "fractal_coloring.h" #include "fractal_compute_engine.h" #include "fractal_config.h" #include "fractal_formula.h" #include "fractal.h" #include "fractal_iteration_count.h" #include "fractal_rendering_parameters.h" #include "fractal_transfer_function.h" #include "gradient.h" #include "image.h" #include "misc.h" #include "ppm.h" #include "uirectangle.h" #include "task.h" #include "thread.h" #include #ifdef __cplusplus extern "C" { #endif #ifndef VERSION_NUMBER /** * \def VERSION_NUMBER * \brief FractalNow version number. */ #define VERSION_NUMBER ?.?.? #endif #define DEFAULT_MPFR_PRECISION (mpfr_prec_t)(128) extern mpfr_prec_t fractalnow_mpfr_precision; /** * \fn const char *FractalNow_VersionNumber() * \brief Get FractalNow lib version number. */ const char *FractalNow_VersionNumber(); void FractalNow_Init(); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/macro_build_floats.h0000664000175000017500000000254111754747533020540 0ustar mpegmpeg/* * macro_build_floats.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file macro_build_floats.h * \brief Header file related to macros for building functions operating on multiple float types. * * \author Marc Pegon */ #ifndef __MACRO_BUILD_FLOATS_H__ #define __MACRO_BUILD_FLOATS_H__ #ifdef __cplusplus extern "C" { #endif #define BUILD_FLOAT(fprec) MACRO_BUILD_FLOAT(fprec) #define BUILD_FLOATS \ BUILD_FLOAT(FP_SINGLE) \ BUILD_FLOAT(FP_DOUBLE) \ BUILD_FLOAT(FP_LDOUBLE) \ BUILD_FLOAT(FP_MP) #define MACRO_BUILD_FLOATS BUILD_FLOATS #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/color.h0000664000175000017500000001561611754747533016035 0ustar mpegmpeg/* * color.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file color.h * \brief Header file related to colors. * \author Marc Pegon */ #ifndef __COLOR_H__ #define __COLOR_H__ #include #ifdef __cplusplus extern "C" { #endif /** * \def GET_R8(x) * \brief Get red component of uint32_t color. */ #define GET_R8(x) ((x >> 16) & 0xFF) /** * \def GET_G8(x) * \brief Get green component of uint32_t color. */ #define GET_G8(x) ((x >> 8) & 0xFF) /** * \def GET_B8(x) * \brief Get blue component of uint32_t color. */ #define GET_B8(x) (x & 0xFF) /** * \def RGB8_TO_UINT32(r,g,b) * \brief Create uint32_t color from 8-bits red, green, and blue components. * * alpha is set to 0xFF by default. */ #define RGB8_TO_UINT32(r,g,b) (0xFF000000+((uint32_t)(r)<<16)+((uint32_t)(g)<<8)+(uint32_t)b) /** * \def ARGB8_TO_UINT32(a,r,g,b) * \brief Create uint32_t color from 8-bits alpha, red, green, and blue components. */ #define ARGB8_TO_UINT32(a,r,g,b) (((uint32_t)(a)<<24)+((uint32_t)(r)<<16)+((uint32_t)(g)<<8)+(uint32_t)b) /** * \def GET_R16(x) * \brief Get red component of uint64_t color. */ #define GET_R16(x) ((x >> 32) & 0xFFFF) /** * \def GET_G16(x) * \brief Get green component of uint64_t color. */ #define GET_G16(x) ((x >> 16) & 0xFFFF) /** * \def GET_B16(x) * \brief Get blue component of uint64_t color. */ #define GET_B16(x) (x & 0xFFFF) /** * \def RGB16_TO_UINT64(r,g,b) * \brief Create uint64_t color from 16-bits red, green, and blue components. * * alpha is set to 0xFFFF by default. */ #define RGB16_TO_UINT64(r,g,b) (0xFFFF000000000000+((uint64_t)(r)<<32)+((uint64_t)(g)<<16)+(uint64_t)b) /** * \def ARGB16_TO_UINT64(r,g,b) * \brief Create uint64_t color from 16-bits alpha, red, green, and blue components. */ #define ARGB16_TO_UINT64(a,r,g,b) (((uint64_t)(a)<<48)+((uint64_t)(r)<<32)+((uint64_t)(g)<<16)+(uint64_t)b) /** * \struct Color * \brief Simple RGB color structure. */ /** * \typedef Color * \brief Convenient typedef for struct Color. */ typedef struct Color { uint_fast8_t bytesPerComponent; /*!< Either 1 (RGB8) or 2 (RGB16).*/ uint_fast16_t r; /*!< Red component.*/ uint_fast16_t g; /*!< Green component.*/ uint_fast16_t b; /*!< Blue component.*/ } Color; /** * \fn Color ColorFromRGB(uint8_t bytesPerComponent, uint16_t r, uint16_t g, uint16_t b) * \brief Create color from RGB values. * * bytesPerComponent must be 1 or 2. * * \param bytesPerComponent Bytes per component. * \param r Red value. * \param g Green value. * \param b Blue value. * \return Corresponding color structure. */ Color ColorFromRGB(uint8_t bytesPerComponent, uint16_t r, uint16_t g, uint16_t b); /** * \fn Color ColorFromUint32(uint32_t color) * \brief Convert a uint32_t color to Color structure. * * Creates a RGB8 Color structure. * alpha component (most significant 8 bits) is ignored. * * \param color Color to convert. * \return Converted color. */ Color ColorFromUint32(uint32_t color); /** * \fn Color ColorFromUint64(uint64_t color) * \brief Convert a uint64_t color to Color structure. * * Creates a RGB16 Color structure. * alpha component (most significant 16 bits) is ignored. * * \param color Color to convert. * \return Converted color. */ Color ColorFromUint64(uint64_t color); /** * \fn Color Color16(Color color) * \brief Convert color to 16 bits color. * * Simple copy if color bytes per component is already 2. * * \param color Color to be converted. * \return 16 bits color. */ Color Color16(Color color); /** * \fn Color Color8(Color color) * \brief Convert color to 8 bits color. * * Simple copy if color bytes per component is already 1. * * \param color Color to be converted. * \return 8 bits color. */ Color Color8(Color color); /** * \fn int CompareColors(const Color color1, const Color color2) * \brief Compare two colors. * * \param color1 First color. * \param color2 Second color. * \return 0 if colors are the same, 1 otherwise. */ int CompareColors(const Color color1, const Color color2); /** * \fn Color MixColors(Color C1, double weight1, Color C2, double weight2) * \brief Mix two weighted colors. * * Both colors must have same number of bytes per component * (undefined behaviour otherwise). * * \param C1 First Color. * \param weight1 Weight given to first color for mixing. * \param C2 Second Color. * \param weight2 Weight given to second color for mixing. * \return Result of the mixing of colors C1 and C2 according to given weights. */ Color MixColors(Color C1, double weight1, Color C2, double weight2); /** * \fn double ColorManhattanDistance(Color C1, Color C2) * \brief Compute manhattan distance between two colors. * * Distance is normalized (i.e. between 0 and 1).\n * Both colors must have same number of bytes per component * (undefined behaviour otherwise). * * \param C1 First color. * \param C2 Second color. * \return Manhattan distance between colors C1 and C2. */ double ColorManhattanDistance(Color C1, Color C2); /** * \fn double QuadAvgDissimilarity(const Color C[4]) * \brief Compute average dissimilarity of a quadrilateral given its corner colors. * * Result is normalized (between 0 and 1).\n * Colors must have same number of bytes per component * (undefined behaviour otherwise). * * \param C Point to colors at the four corners. * \return Quadrilateral average anhattan dissimilarity. */ double QuadAvgDissimilarity(const Color C[4]); /** * \fn Color QuadLinearInterpolation(const Color C[4], double x, double y) * \brief Interpolate linearly some color of a quadrilateral. * * Interpolate color at point (x,y) according to its corner colors.\n * Coordinates x and y are relative (undefined behaviour otherwise) : * (0,0 is the top left corner, (1,0) the top right, etc...\n * Colors must have same number of bytes per component * (undefined behaviour otherwise). * * \param C Quadrilateral corner colors. * \param x X (relative) coordinate of quad point to interpolate. * \param y Y (relative) coordinate of quad point to interpolate. * \return Linearly interpolated color at point (x,y) of quadrilateral. */ Color QuadLinearInterpolation(const Color C[4], double x, double y); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/thread.h0000664000175000017500000002552411754747533016165 0ustar mpegmpeg/* * thread.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file thread.h * \brief Header file related to threads. * \author Marc Pegon */ #ifndef __THREAD_H__ #define __THREAD_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif /** * \def DEFAULT_NB_THREADS * \brief Default number of threads. */ #define DEFAULT_NB_THREADS (uint_fast32_t)(4) /** * \def DEFAULT_RECTANGLES_PER_THREAD * \brief Default number of rectangles per thread. * * Used for working on images. Each thread * may be assigned a number of rectangles * to draw. * This can be used to distribute homogeneously * the work between threads. * Although it can be disturbing if the user can * view the progress of the action in real-time * (small rectangles being drawn erratically), * which is why this is 1 by default. * * Not that a workaround to distribute the work * more homogeneously is simply to create more * threads than machine cores. */ #define DEFAULT_RECTANGLES_PER_THREAD (uint_fast32_t)(1) // thread related #define THREAD_CREATE_ERROR "Thread create error" #define THREAD_CANCEL_ERROR "Thread cancel error" #define THREAD_JOIN_ERROR "Thread join error" #define THREAD_MUTEX_INIT_ERROR "Thread mutex init error" #define THREAD_MUTEX_LOCK_ERROR "Thread mutex lock error" #define THREAD_MUTEX_UNLOCK_ERROR "Thread mutex unlock error" #define THREAD_MUTEX_DESTROY_ERROR "Thread mutex destroy error" #define THREAD_COND_INIT_ERROR "Thread cond init error" #define THREAD_COND_WAIT_ERROR "Thread cond wait error" #define THREAD_COND_SIGNAL_ERROR "Thread cond signal error" #define THREAD_COND_BROADCAST_ERROR "Thread cond broadcast error" #define THREAD_COND_DESTROY_ERROR "Thread cond destroy error" #define safePThreadCreate(thread,attributes,startRoutine,argument) {if((errno=pthread_create(thread,attributes,startRoutine,argument))!=0){perror(THREAD_CREATE_ERROR);exit(EXIT_FAILURE);}} #define safePThreadJoin(thread,status); {if((errno=pthread_join(thread,status))!=0){perror(THREAD_JOIN_ERROR);exit(EXIT_FAILURE);}} #define safePThreadMutexInit(mutex,attributes) {if((errno=pthread_mutex_init(mutex,attributes))!=0){perror(THREAD_MUTEX_INIT_ERROR);exit(EXIT_FAILURE);}} #define safePThreadMutexLock(mutex) {if((errno=pthread_mutex_lock(mutex))!=0){perror(THREAD_MUTEX_LOCK_ERROR);exit(EXIT_FAILURE);}} #define safePThreadMutexUnlock(mutex) {if((errno=pthread_mutex_unlock(mutex))!=0){perror(THREAD_MUTEX_UNLOCK_ERROR);perror(THREAD_MUTEX_UNLOCK_ERROR);exit(EXIT_FAILURE);}} #define safePThreadMutexDestroy(mutex) {if((errno=pthread_mutex_destroy(mutex))!=0){perror(THREAD_MUTEX_DESTROY_ERROR);exit(EXIT_FAILURE);}} #define safePThreadCondInit(cond,attributes) {if((errno=pthread_cond_init(cond,attributes))!=0){perror(THREAD_COND_INIT_ERROR);exit(EXIT_FAILURE);}} #define safePThreadCancel(thread) {if((errno=pthread_cancel(thread))!=0){perror(THREAD_CANCEL_ERROR);exit(EXIT_FAILURE);}} #define safePThreadCondWait(cond,mutex) {if((errno=pthread_cond_wait(cond,mutex))!=0){perror(THREAD_COND_WAIT_ERROR);exit(EXIT_FAILURE);}} #define safePThreadCondSignal(cond) {if((errno=pthread_cond_signal(cond))!=0){perror(THREAD_COND_SIGNAL_ERROR);exit(EXIT_FAILURE);}} #define safePThreadCondBroadcast(cond) {if((errno=pthread_cond_broadcast(cond))!=0){perror(THREAD_COND_BROADCAST_ERROR);exit(EXIT_FAILURE);}} #define safePThreadCondDestroy(cond) {if((errno=pthread_cond_destroy(cond))!=0){perror(THREAD_COND_DESTROY_ERROR);exit(EXIT_FAILURE);}} #ifdef NO_SPINLOCK #define THREAD_SPIN_INIT_ERROR THREAD_MUTEX_INIT_ERROR #define THREAD_SPIN_LOCK_ERROR THREAD_MUTEX_LOCK_ERROR #define THREAD_SPIN_UNLOCK_ERROR THREAD_MUTEX_UNLOCK_ERROR #define THREAD_SPIN_DESTROY_ERROR THREAD_MUTEX_DESTROY_ERROR #define safePThreadSpinInit(mutex,attributes) safePThreadMutexInit(mutex,attributes) #define safePThreadSpinLock(mutex) safePThreadMutexLock(mutex) #define safePThreadSpinUnlock(mutex) safePThreadMutexUnlock(mutex) #define safePThreadSpinDestroy(mutex) safePThreadMutexDestroy(mutex) #define pthread_spinlock_t pthread_mutex_t #define SPIN_INIT_ATTR NULL #else #define THREAD_SPIN_INIT_ERROR "Thread spin init error" #define THREAD_SPIN_LOCK_ERROR "Thread spin lock error" #define THREAD_SPIN_UNLOCK_ERROR "Thread spin unlock error" #define THREAD_SPIN_DESTROY_ERROR "Thread spin destroy error" #define safePThreadSpinInit(mutex,attributes) {if((errno=pthread_spin_init(mutex,attributes))!=0){perror(THREAD_SPIN_INIT_ERROR);exit(EXIT_FAILURE);}} #define safePThreadSpinLock(mutex) {if((errno=pthread_spin_lock(mutex))!=0){perror(THREAD_SPIN_LOCK_ERROR);exit(EXIT_FAILURE);}} #define safePThreadSpinUnlock(mutex) {if((errno=pthread_spin_unlock(mutex))!=0){perror(THREAD_SPIN_UNLOCK_ERROR);perror(THREAD_SPIN_UNLOCK_ERROR);exit(EXIT_FAILURE);}} #define safePThreadSpinDestroy(mutex) {if((errno=pthread_spin_destroy(mutex))!=0){perror(THREAD_SPIN_DESTROY_ERROR);exit(EXIT_FAILURE);}} #define SPIN_INIT_ATTR PTHREAD_PROCESS_PRIVATE #endif struct StartThreadArg; /** * \struct Threads * \brief Threads structure. * * Threads should be created on program startup, and destroyed * on exit.\n * Once created, threads can be used to launch actions, such * as drawing fractals, applying filters on images, etc.. */ /** * \typedef Threads * \brief Convenient typedef for struct Threads. */ typedef struct Threads { uint_fast32_t N; /*!< N Number of threads in this structure.*/ uint_fast32_t nbReady; /*!< Number of threads ready to launch a new task.*/ uint_fast32_t nbPaused; /*!< Number of threads currently paused (waiting resumeTaskCond to be signaled).*/ pthread_mutex_t startThreadCondMutex; /*!< Mutex for starting threads condition.*/ pthread_cond_t startThreadCond; /*!< Condition signaled when thread should start working on a new task.*/ pthread_mutex_t threadsMutex; /*!< Main threads mutex (multiple use).*/ pthread_cond_t allThreadsReadyCond; /*!< Condition signaled when all threads are ready to launch a new task.*/ pthread_cond_t allPausedCond; /*!< Condition signaled when all active threads have been paused.*/ pthread_cond_t allResumedCond; /*!< Condition signaled when all previously paused threads have resumed.*/ pthread_cond_t resumeTaskCond; /*!< Condition signaled when resume task is requested.*/ pthread_t *thread; /*!< Pthreads array.*/ struct StartThreadArg *startThreadArg; /*!< Start thread argument.*/ void **lastResult; /*!< Last result for each thread.*/ } Threads; /** * \struct ThreadArgHeader * \brief Thread argument header. */ /** * \typedef ThreadArgHeader * \brief Convenient typedef for struct ThreadArgHeader. */ typedef struct ThreadArgHeader { uint_fast32_t threadId; /*!< Id of thread working on this argument.*/ Threads *threads; /*!< Pointer to threads structure.*/ uint_fast32_t *nbReady; /*!< Number of threads ready for next task, OR subtask (for composite tasks). This does not necessarily points to threads->nbWaiting.*/ int *cancel; /*!< Used by thread to receive cancellation request.*/ pthread_spinlock_t *cancelMutex; /*!< Mutex for cancel variable.*/ int *pause; /*!< Used to pause thread.*/ pthread_spinlock_t *pauseMutex; /*!< Mutex for pause variable.*/ int progress; /*!< Should be kept up-to-date by thread to give an hint on its progress (value between 0 and 100).*/ pthread_spinlock_t progressMutex; /*!< Mutex for progress variable.*/ } ThreadArgHeader; /** * \struct StartThreadArg * \brief Structure used to start tasks (for internal use). */ /** * \typedef StartThreadArg * \brief Convenient typedef for struct StartThreadArg. */ typedef struct StartThreadArg { uint_fast32_t threadId; /*!< Thread id (between 0 and threads->N-1.*/ Threads *threads; /*!< Threads structure.*/ char *message; /*!< Pointer to threads structure (convenient to access threads common variables).*/ void *(*startRoutine)(void *arg); /*!< Routine to be launched by thread (task routine).*/ void *arg; /*!< Argument to be passed to thread routine.*/ void **result; /*!< Where to put startRoutine return value.*/ } StartThreadArg; /** * \fn Threads *CreateThreads(uint_fast32_t N) * \brief Create threads. * * \param N Number of threads to be created. * \return Newly-allocated threads structure. */ Threads *CreateThreads(uint_fast32_t N); /** * \fn void DestroyThreads(Threads *threads) * \brief Destroy threads. * * Threads should not be busy.\n * Function is blocking, i.e. will wait for threads to * finish before destroying them. * * \param threads Threads structure to destroy and free. */ void DestroyThreads(Threads *threads); /** * \fn ThreadArgHeader *GetThreadArgHeader(const void *arg) * \brief Get header part of thread argument. * * \param arg Argument passed to thread routine. * \return Header part of thread argument. */ ThreadArgHeader *GetThreadArgHeader(const void *arg); /** * \fn void *GetThreadArgBody(const void *arg) * \brief Get body (user) part of thread argument. * * \param arg Argument passed to thread routine. * \return Body part of thread argument (i.e. pointer to argument passed by user when launching action). */ void *GetThreadArgBody(const void *arg); /** * \fn int CancelTaskRequested(ThreadArgHeader *threadArgHeader) * \brief Query task cancelation request, through argument header. * * This function is thread-safe. * * \param threadArgHeader Thread argument header. * \return 1 if cancelation request has been made, 0 otherwise. */ int CancelTaskRequested(ThreadArgHeader *threadArgHeader); /** * \fn int SetThreadProgress(ThreadArgHeader *threadArgHeader, int progress) * \brief Set thread progress, through argument header. * * This function is thread-safe. * Progress should be a value between 0 and 100 (unspecified behaviour * otherwise). * * \param threadArgHeader Thread argument header. * \param progress Task progress. */ void SetThreadProgress(ThreadArgHeader *threadArgHeader, int progress); /** * \fn void HandlePauseRequest(ThreadArgHeader *threadArgHeader) * \brief Handle pause request. * * Blocks if task has been paused, until task is resumed. * \see task.c * * \param threadArgHeader Thread argument header. */ void HandlePauseRequest(ThreadArgHeader *threadArgHeader); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal.h0000664000175000017500000003526511754747533016335 0ustar mpegmpeg/* * fractal.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal.h * \brief Main header file related to fractals. * * A fractal point is computed and colored as follows : * - The fractal loop function is executed, and returns a floating point * value. * \see fractal_loop.h * - The transfer function is applied, as well as the multiplier, and the * offset is added. * - Finally, the value is mapped to a color using the gradient. * * Note that points that belong to the fractal set (radius <= escape radius * after the maximum number of iterations) do not go through all those * steps : the fractal loop gives a negative value, so that the color of * fractal space is returned. * * \author Marc Pegon */ #ifndef __FRACTAL_H__ #define __FRACTAL_H__ #include "float_precision.h" #include "gradient.h" #include "image.h" #include "fractal_cache.h" #include "fractal_formula.h" #include "fractal_rendering_parameters.h" #include "task.h" #include "thread.h" #include #include #ifdef __cplusplus extern "C" { #endif #ifndef complex #define complex _Complex #endif /** * \def DEFAULT_QUAD_INTERPOLATION_SIZE * \brief Default maximum size of quadrilaterals for interpolation. * * \see DrawFractalFast for more details. */ #define DEFAULT_QUAD_INTERPOLATION_SIZE (uint_fast32_t)(5) /** * \def DEFAULT_COLOR_DISSIMILARITY_THRESHOLD * \brief Default color dissimilarity threshold for quad interpolation. * * \see DrawFractalFast for more details. */ #define DEFAULT_COLOR_DISSIMILARITY_THRESHOLD (double)(3.5E-3) /** * \def DEFAULT_ADAPTIVE_AAM_THRESHOLD * \brief Default threshold for adaptive anti-aliasing. * * \see AntiAliaseFractal for more details. */ #define DEFAULT_ADAPTIVE_AAM_THRESHOLD (double)(5.05E-2) /** * \struct Fractal * \brief Description of a subset of some fractal set. */ /** * \typedef Fractal * \brief Convenient typedef for struct Fractal. */ typedef struct Fractal { FractalFormula fractalFormula; /*!< Fractal formula.*/ mpc_t p; /*!< Parameter for some fractals (main power in iteration z = z^p + ...).*/ mpc_t c; /*!< Parameter for Julia and Rudy fractal.*/ mpfr_t centerX; /*!< X coordinate of the center of the fractal subset.*/ mpfr_t centerY; /*!< Y coordinate of the center of the fractal subset.*/ mpfr_t spanX; /*!< X span of the fractal subset.*/ mpfr_t spanY; /*!< Y span of the fractal subset.*/ double escapeRadius; /*!< Escape radius for computing fractal.*/ uint_fast32_t maxIter; /*!< Maximum number of iterations for computing fractal.*/ /* Some parameters for internal use.*/ mpfr_t x1; /*!< X coordinate of the upper left point of the fractal subset.*/ mpfr_t y1; /*!< Y coordinate of the upper left point of the fractal subset.*/ } Fractal; /** * \fn void InitFractal(Fractal *fractal, FractalFormula fractalFormula, const mpc_t p, const mpc_t c, const mpfr_t centerX, const mpfr_t centerY, const mpfr_t spanX, const mpfr_t spanY, double escapeRadius, uint_fast32_t maxIter) * \brief Initialize fractal structure. * * \param fractal Pointer to fractal structure to initialize. * \param fractalFormula Fractal type. * \param p (main power in iteration) parameter for fractal. * \param c Parameter for Julia fractal (will be ignored for Mandelbrot fractal). * \param centerX X coordinate of the center of the fractal subset. * \param centerY Y coordinate of the center of the fractal subset. * \param spanX * \param spanY * \param escapeRadius Escape radius for computing fractal. * \param maxIter Maximum number of iterations for computing fractal. */ void InitFractal(Fractal *fractal, FractalFormula fractalFormula, const mpc_t p, const mpc_t c, const mpfr_t centerX, const mpfr_t centerY, const mpfr_t spanX, const mpfr_t spanY, double escapeRadius, uint_fast32_t maxIter); /** * \fn void InitFractal2(Fractal *fractal, FractalFormula fractalFormula, long double complex p, long double complex c, long double centerX, long double centerY, long double spanX, long double spanY, double escapeRadius, uint_fast32_t maxIter) * \brief Initialize fractal structure. * * \param fractal Pointer to fractal structure to initialize. * \param fractalFormula Fractal type. * \param p (main power in iteration) parameter for fractal. * \param c Parameter for Julia fractal (will be ignored for Mandelbrot fractal). * \param centerX X coordinate of the center of the fractal subset. * \param centerY Y coordinate of the center of the fractal subset. * \param spanX * \param spanY * \param escapeRadius Escape radius for computing fractal. * \param maxIter Maximum number of iterations for computing fractal. */ void InitFractal2(Fractal *fractal, FractalFormula fractalFormula, long double complex p, long double complex c, long double centerX, long double centerY, long double spanX, long double spanY, double escapeRadius, uint_fast32_t maxIter); /** * \fn Fractal CopyFractal(const Fractal *fractal) * \brief Copy fractal. * * \param fractal Pointer to fractal to copy. * \return Copy of fractal. */ Fractal CopyFractal(const Fractal *fractal); /** * \fn int isSupportedFractalFile(const char *fileName) * \brief Check whether a file is a supported fractal file. * * \param fileName File name. * \return 1 if file is a supported fractal file, 0 otherwise. */ int isSupportedFractalFile(const char *fileName); /** * \fn int ReadFractalFileBody(Fractal *fractal, const char *fileName, FILE *file, const char *format) * \brief Create fractal from fractal file body. * * The body of a fractal file is everything that comes after * the format version.\n * fileName is used only for error messages.\n * This function should only be used internally by the library. * * \param fractal Pointer to the fractal structure to create. * \param fileName Fractal file name. * \param file Pointer to opened file, positioned at the beginning of the body. * \param format Fractal file format. * \return 0 in case of success, 1 in case of failure. */ int ReadFractalFileBody(Fractal *fractal, const char *fileName, FILE *file, const char *format); /** * \fn int ReadFractalFile(Fractal *fractal, const char *fileName) * \brief Read and parse a fractal file, and create the according fractal. * * \param fractal Pointer to the fractal structure to create. * \param fileName Fractal file name. * \return 0 in case of success, 1 in case of failure. */ int ReadFractalFile(Fractal *fractal, const char *fileName); /** * \fn int WriteFractalFileBody(const Fractal *fractal, const char *fileName, FILE *file, const char *format) * \brief Write fractal file body. * * The body of a fractal file is everything that comes after * the format version.\n * fileName is used only for error messages.\n * This function should only be used internally by the library. * * \param fractal Fractal to write into file. * \param fileName Fractal file name. * \param file Pointer to opened file, positioned at the beginning of the body. * \param format Fractal file format. * \return 0 in case of success, 1 in case of failure. */ int WriteFractalFileBody(const Fractal *fractal, const char *fileName, FILE *file, const char *format); /** * \fn int WriteFractalFile(const Fractal *fractal, const char *fileName) * \brief Read and parse a fractal file, and create the according fractal. * * \param fractal Fractal to write into file. * \param fileName Fractal file name. * \return 0 in case of success, 1 in case of failure. */ int WriteFractalFile(const Fractal *fractal, const char *fileName); /** * \fn void DrawFractal(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t quadInterpolationSize, double interpolationThreshold, FloatPrecision floatPrecision, FractalCache *cache, Threads* threads) * \brief Draw fractal in a fast, approximate way. * * Image width and height must be >= 2 (does nothing otherwise).\n * Details on the algorithm : * The image is cut in quads (rectangles, actually) of size * quadInterpolationSize (meaning width AND height <= size).\n * Then for each quad, its corner colors are computed, and depending * on its dissimilarity (average difference of the corner colors to the * average color of the corners), the quad is either computed or linearly * interpolated.\n * Default values of quadInterpolationSize and interpolationThreshold * are good for no visible loss of quality.\n * Pointer to cache structure can be NULL if no cache is to be used.\n * If cache is not NULL, it must point to a created cache structure, * and it is used to generate a preview of the image, and speed-up * the task by using values computed by a previous fractal drawing * or anti-aliasing. * * \param image Image in which to draw fractal subset. * \param fractal Fractal subset to compute. * \param render Rendering parameters. * \param quadInterpolationSize Maximum quad size for interpolation. * \param interpolationThreshold Dissimilarity threshold for interpolation. * \param floatPrecision Float precision. * \param cache Cache structure to put computed values in. * \param threads Threads to be used for task. */ void DrawFractal(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t quadInterpolationSize, double interpolationThreshold, FloatPrecision floatPrecision, FractalCache *cache, Threads* threads); /** * \fn Task *CreateDrawFractalTask(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t quadInterpolationSize, double interpolationThreshold, FloatPrecision floatPrecision, FractalCache *cache, uint_fast32_t nbThreads) * \brief Create fractal drawing task. * * Create task and return immediately.\n * Task structure can be used to query progress, send * cancellation request, etc.\n * Image width and height must be >= 2 (does nothing otherwise).\n * When launching task, Threads structure should provide * enough threads (at least number specified here). * Pointer to cache structure can be NULL if no cache is to be used. * * \param image Image in which to draw fractal subset. * \param fractal Fractal subset to compute. * \param render Rendering parameters. * \param quadInterpolationSize Maximum quad size for interpolation. * \param interpolationThreshold Dissimilarity threshold for interpolation. * \param floatPrecision Float precision. * \param cache Cache structure to put computed values in. * \param nbThreads Number of threads that action will need to be launched. * \return Corresponding newly-allocated task. */ Task *CreateDrawFractalTask(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t quadInterpolationSize, double interpolationThreshold, FloatPrecision floatPrecision, FractalCache *cache, uint_fast32_t nbThreads); /** * \fn void AntiAliaseFractal(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t antiAliasingSize, double threshold, FloatPrecision floatPrecision, FractalCache *cache, Threads *threads) * \brief AntiAliase fractal image. * * Image width and height must be >= 2 (does nothing otherwise).\n * Anti-aliasing size must be >= 2 to have an effect (does nothing otherwise). * * Details on the algorithm : * Pixels that differ too much from neighbour pixels * (difference greater than threshold) are recomputed.\n * Several pixels (antiAliasingSize^2 to be precise) are computed * for each of these preselected pixels, and averaged (with gaussian * filter) to produce the new pixel value.\n * Default threshold value is good to obtain a result similar to * oversampling (computing a bigger image and downscaling it) with * the same size factor.\n * Pointer to cache structure can be NULL if no cache is to be used.\n * Note that for anti-aliasing, cache is not used to generate of preview * of the image and speed-up task: it is only filled with the values * computed when anti-aliasing. * * \param image Fractal image (already drawn) to anti-aliase. * \param fractal Fractal subset to compute. * \param render Rendering parameters. * \param antiAliasingSize Anti-aliasing size. * \param threshold Dissimilarity threshold to determine pixels to recompute. * \param floatPrecision Float precision. * \param cache Cache structure to put computed values in. * \param threads Threads to be used for task. */ void AntiAliaseFractal(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t antiAliasingSize, double threshold, FloatPrecision floatPrecision, FractalCache *cache, Threads *threads); /** * \fn Task *CreateAntiAliaseFractalTask(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t antiAliasingSize, double threshold, FloatPrecision floatPrecision, FractalCache *cache, uint_fast32_t nbThreads) * \brief Create task anti-aliasing fractal image * * Create task and return immediately.\n * Image width and height must be >= 2 (does nothing otherwise).\n * Anti-aliasing size must be >= 2 to have an effect (does nothing otherwise).\n * When launching task, Threads structure should provide * enough threads (at least number specified here). * * \param image Fractal image (already drawn) to anti-aliase. * \param fractal Fractal subset to compute. * \param render Rendering parameters. * \param antiAliasingSize Anti-aliasing size. * \param threshold Dissimilarity threshold to determine pixels to recompute. * \param floatPrecision Float precision. * \param cache Cache structure to put computed values in. * \param nbThreads Number of threads that action will need to be launched. * \return Corresponding newly-allocated task. */ Task *CreateAntiAliaseFractalTask(Image *image, const Fractal *fractal, const RenderingParameters *render, uint_fast32_t antiAliasingSize, double threshold, FloatPrecision floatPrecision, FractalCache *cache, uint_fast32_t nbThreads); /** * \fn void FreeFractal(Fractal fractal) * \brief Free a fractal structure. * * \param fractal Fractal structure to be freed. */ void FreeFractal(Fractal fractal); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal_transfer_function.h0000664000175000017500000000630411754747533022136 0ustar mpegmpeg/* * fractal_transfer_function.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_transfer_function.h * \brief Header file related to fractal transfer functions. * \author Marc Pegon */ #ifndef __FRACTAL_TRANSFER_FUNCTION_H__ #define __FRACTAL_TRANSFER_FUNCTION_H__ #include #ifdef __cplusplus extern "C" { #endif /** * \enum e_TransferFunction * \brief Possible transfer functions. * * Transfer function are used to map fractal values to colors correctly. */ /** * \typedef TransferFunction * \brief Convenient typedef for enum TransferFunction. */ typedef enum e_TransferFunction { TF_LOGLOG = 0, /* * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_addend_function.h * \brief Header file related to fractal addend functions. * \author Marc Pegon */ #ifndef __FRACTAL_ADDEND_FUNCTION_H__ #define __FRACTAL_ADDEND_FUNCTION_H__ #include "float_precision.h" #include #ifdef __cplusplus extern "C" { #endif /** * \enum e_AddendFunction * \brief Fractal addend function. * * Addend functions are used to compute values of fractal * in case of average coloring (CM_AVERAGECOLORING). * * Addend functions are described by a sequence of instructions * at the initialization of the fractal loop, for each iteration, * and at the end of the fractal loop.\n * They take for parameter 'size' the number of average sums to * be computed. Those sums SN[0], SN[1], ..., SN[size-1] *must* * be computed (at least initialized) by the addend function, * since they will be used by the interpolation method. * * Remark : in the fractal "literature", addend functions * are not exactly the functions *that compute* the average * sums, but functions *used* when computing those sums.\n * Remark 2 : some sums might not be computable if the number of * iterations (in orbit) is too small (N must be >= size). */ /** * \typedef AddendFunction * \brief Convenient typedef for enum AddendFunction. */ typedef enum e_AddendFunction { AF_TRIANGLEINEQUALITY = 0, AF_CURVATURE, AF_STRIPE } AddendFunction; /** * \var nbAddendFunctions * \brief Number of addend functions. */ extern const uint_fast32_t nbAddendFunctions; /** * \var addendFunctionStr * \brief Strings of addend function enum values. */ extern const char *addendFunctionStr[]; /** * \var addendFunctionDescStr * \brief More descriptive strings for addend functions. */ extern const char *addendFunctionDescStr[]; /** * \fn int GetAddendFunction(AddendFunction *addendFunction, const char *str) * \brief Get addend function from string. * * Function is case insensitive. * Possible strings are : * - "triangleinequality" for triangle inequality * - "curvature" for curvature * - "stripe" for stripe * * \param addendFunction AddendFunction destination. * \param str String specifying addend function. * \return 0 in case of success, 1 in case of failure. */ int GetAddendFunction(AddendFunction *addendFunction, const char *str); /******************AF_TRIANGLEINEQUALITY******************/ #define ENGINE_DECL_VAR_AF_TRIANGLEINEQUALITY(size,fprec) \ FLOATTYPE(fprec) shiftSN_AF[size];\ uint_fast32_t zeros_AF[size];\ uint_fast32_t shiftZeros_AF[size];\ COMPLEX_FLOATTYPE(fprec) prevZP_AF;\ FLOATTYPE(fprec) nPrevZP_AF;\ FLOATTYPE(fprec) mn_AF;\ FLOATTYPE(fprec) Mn_AF;\ FLOATTYPE(fprec) rn_AF;\ FLOATTYPE(fprec) diff_AF;\ FLOATTYPE(fprec) absC_AF;\ FLOATTYPE(fprec) tmp_AF;\ uint_fast32_t currentIndex_AF;\ uint_fast32_t previousIndex_AF; #define ENGINE_INIT_VAR_AF_TRIANGLEINEQUALITY(size,fprec) \ for (uint_fast32_t i = 0; i < size; ++i) {\ initF(fprec,data->shiftSN_AF[i]);\ }\ cinitF(fprec,data->prevZP_AF);\ initF(fprec,data->nPrevZP_AF);\ initF(fprec,data->mn_AF);\ initF(fprec,data->Mn_AF);\ initF(fprec,data->rn_AF);\ initF(fprec,data->diff_AF);\ initF(fprec,data->absC_AF);\ initF(fprec,data->tmp_AF); #define ENGINE_CLEAR_VAR_AF_TRIANGLEINEQUALITY(size,fprec) \ for (uint_fast32_t i = 0; i < size; ++i) {\ clearF(fprec,data->shiftSN_AF[i]);\ }\ cclearF(fprec,data->prevZP_AF);\ clearF(fprec,data->nPrevZP_AF);\ clearF(fprec,data->mn_AF);\ clearF(fprec,data->Mn_AF);\ clearF(fprec,data->rn_AF);\ clearF(fprec,data->diff_AF);\ clearF(fprec,data->absC_AF);\ clearF(fprec,data->tmp_AF); #define LOOP_INIT_AF_TRIANGLEINEQUALITY(size,fprec) \ cfromUiF(fprec, data->prevZP_AF, 0);\ fromUiF(fprec, data->nPrevZP_AF, 0);\ fromUiF(fprec, data->mn_AF, 0);\ fromUiF(fprec, data->Mn_AF, 0);\ fromUiF(fprec, data->rn_AF, 0);\ fromUiF(fprec, data->diff_AF, 0);\ cabsF(fprec,data->absC_AF,data->c);\ data->currentIndex_AF = 0;\ data->previousIndex_AF = size-1;\ for (uint_fast32_t i = 0; i < size; ++i) {\ fromUiF(fprec, data->SN_IM[i], 0);\ data->zeros_AF[i] = 0;\ } #define LOOP_ITERATION_AF_TRIANGLEINEQUALITY(size,fprec) \ {\ uint_fast32_t m = 1;\ if (data->n >= m) {\ csubF(fprec,data->prevZP_AF,data->z,data->c);\ cabsF(fprec,data->nPrevZP_AF,data->prevZP_AF);\ subF(fprec,data->mn_AF,data->nPrevZP_AF,data->absC_AF);\ fabsF(fprec,data->mn_AF,data->mn_AF);\ addF(fprec,data->Mn_AF,data->nPrevZP_AF,data->absC_AF);\ sqrtF(fprec,data->rn_AF,data->normZ);\ subF(fprec,data->diff_AF,data->Mn_AF,data->mn_AF);\ data->zeros_AF[data->currentIndex_AF] = data->zeros_AF[data->previousIndex_AF];\ if (!eq_uiF(fprec,data->diff_AF,0)) {\ /* Avoid division by zero. */\ subF(fprec,data->tmp_AF,data->rn_AF,data->mn_AF);\ divF(fprec,data->tmp_AF,data->tmp_AF,data->diff_AF);\ addF(fprec,data->SN_IM[data->currentIndex_AF],data->SN_IM[data->previousIndex_AF],data->tmp_AF);\ } else {\ assignF(fprec, data->SN_IM[data->currentIndex_AF], data->SN_IM[data->previousIndex_AF]);\ /* Counting zeros in order to divide by*/\ /* the exact number of terms added to SN.*/\ ++data->zeros_AF[data->currentIndex_AF];\ }\ data->previousIndex_AF = data->currentIndex_AF;\ data->currentIndex_AF = (data->currentIndex_AF + 1) % size;\ }\ } #define LOOP_END_AF_TRIANGLEINEQUALITY(size,fprec) \ {\ uint_fast32_t m = 1;\ if (data->n >= m+size-1) {\ for (uint_fast32_t i = 0; i < size; ++i) {\ assignF(fprec, data->shiftSN_AF[i], data->SN_IM[i]);\ data->shiftZeros_AF[i] = data->zeros_AF[i];\ }\ for (uint_fast32_t i = 0; i < size; ++i) {\ data->zeros_AF[i] = data->shiftZeros_AF[(data->previousIndex_AF+size-i) % size];\ if (data->zeros_AF[i] == data->n+1-m-i) {\ fromUiF(fprec, data->SN_IM[i], 0);\ } else {\ div_uiF(fprec, data->SN_IM[i], data->shiftSN_AF[(data->previousIndex_AF+size-i) %\ size], data->n+1-m-i-data->zeros_AF[i]);\ }\ }\ } else {\ /* Result undefined. 0 chosen. */\ for (uint_fast32_t i = 0; i < size; ++i) {\ fromUiF(fprec, data->SN_IM[i], 0);\ }\ }\ } /*********************************************************/ /***********************AF_CURVATURE**********************/ #define ENGINE_DECL_VAR_AF_CURVATURE(size,fprec) \ FLOATTYPE(fprec) shiftSN_AF[size];\ uint_fast32_t zeros_AF[size];\ uint_fast32_t shiftZeros_AF[size];\ COMPLEX_FLOATTYPE(fprec) znm1_AF;\ COMPLEX_FLOATTYPE(fprec) znm2_AF;\ COMPLEX_FLOATTYPE(fprec) diff_AF;\ COMPLEX_FLOATTYPE(fprec) ctmp_AF;\ FLOATTYPE(fprec) tmp_AF;\ uint_fast32_t currentIndex_AF;\ uint_fast32_t previousIndex_AF; #define ENGINE_INIT_VAR_AF_CURVATURE(size,fprec) \ for (uint_fast32_t i = 0; i < size; ++i) {\ initF(fprec, data->shiftSN_AF[i]);\ }\ cinitF(fprec, data->znm1_AF);\ cinitF(fprec, data->znm2_AF);\ cinitF(fprec, data->diff_AF);\ cinitF(fprec, data->ctmp_AF);\ initF(fprec, data->tmp_AF); #define ENGINE_CLEAR_VAR_AF_CURVATURE(size,fprec) \ cclearF(fprec, data->znm1_AF);\ cclearF(fprec, data->znm2_AF);\ cclearF(fprec, data->diff_AF);\ cclearF(fprec, data->ctmp_AF);\ clearF(fprec, data->tmp_AF);\ for (uint_fast32_t i = 0; i < size; ++i) {\ clearF(fprec, data->shiftSN_AF[i]);\ } #define LOOP_INIT_AF_CURVATURE(size,fprec) \ cfromUiF(fprec, data->znm1_AF, 0);\ cfromUiF(fprec, data->znm2_AF, 0);\ cfromUiF(fprec, data->diff_AF, 0);\ data->currentIndex_AF = 0;\ data->previousIndex_AF = size-1;\ for (uint_fast32_t i = 0; i < size; ++i) {\ fromUiF(fprec, data->SN_IM[i], 0);\ data->zeros_AF[i] = 0;\ } #define LOOP_ITERATION_AF_CURVATURE(size,fprec) \ {\ uint_fast32_t m = 1;\ if (data->n >= m+1) {\ csubF(fprec,data->diff_AF,data->znm1_AF,data->znm2_AF);\ data->zeros_AF[data->currentIndex_AF] = data->zeros_AF[data->previousIndex_AF];\ if (!ceq_siF(fprec,data->diff_AF,0)) {\ /* Avoid division by zero. */\ csubF(fprec,data->ctmp_AF,data->z,data->znm1_AF);\ cdivF(fprec,data->ctmp_AF,data->ctmp_AF,data->diff_AF);\ cargF(fprec,data->tmp_AF,data->ctmp_AF);\ fabsF(fprec,data->tmp_AF,data->tmp_AF);\ addF(fprec,data->SN_IM[data->currentIndex_AF],data->SN_IM[data->previousIndex_AF],data->tmp_AF);\ } else {\ assignF(fprec,data->SN_IM[data->currentIndex_AF],data->SN_IM[data->previousIndex_AF]);\ /* Counting zeros in order to divide by*/\ /* the exact number of terms added to SN.*/\ ++data->zeros_AF[data->currentIndex_AF];\ }\ data->previousIndex_AF = data->currentIndex_AF;\ data->currentIndex_AF = (data->currentIndex_AF + 1) % size;\ }\ cassignF(fprec, data->znm2_AF, data->znm1_AF);\ cassignF(fprec, data->znm1_AF, data->z);\ } #define LOOP_END_AF_CURVATURE(size,fprec) \ {\ uint_fast32_t m = 1;\ if (data->n >= m+size) {\ for (uint_fast32_t i = 0; i < size; ++i) {\ assignF(fprec, data->shiftSN_AF[i], data->SN_IM[i]);\ data->shiftZeros_AF[i] = data->zeros_AF[i];\ }\ for (uint_fast32_t i = 0; i < size; ++i) {\ data->zeros_AF[i] = data->shiftZeros_AF[(data->previousIndex_AF+size-i) % size];\ if (data->zeros_AF[i] == data->n-m-i) {\ fromUiF(fprec, data->SN_IM[i], 0);\ } else {\ div_uiF(fprec, data->SN_IM[i], data->shiftSN_AF[(data->previousIndex_AF+size-i) %\ size], data->n-m-i-data->zeros_AF[i]);\ }\ }\ } else {\ /* Result undefined. 0 chosen. */\ for (uint_fast32_t i = 0; i < size; ++i) {\ fromUiF(fprec, data->SN_IM[i], 0);\ }\ }\ } /*********************************************************/ /************************AF_STRIPE************************/ #define ENGINE_DECL_VAR_AF_STRIPE(size,fprec) \ uint_fast32_t currentIndex_AF ;\ uint_fast32_t previousIndex_AF;\ FLOATTYPE(fprec) tmp_AF ;\ FLOATTYPE(fprec) shiftSN_AF[size]; #define ENGINE_INIT_VAR_AF_STRIPE(size,fprec) \ initF(fprec, data->tmp_AF);\ for (uint_fast32_t i = 0; i < size; ++i) {\ initF(fprec, data->shiftSN_AF[i]);\ } #define ENGINE_CLEAR_VAR_AF_STRIPE(size,fprec) \ clearF(fprec,data->tmp_AF);\ for (uint_fast32_t i = 0; i < size; ++i) {\ clearF(fprec, data->shiftSN_AF[i]);\ } #define LOOP_INIT_AF_STRIPE(size,fprec) \ data->currentIndex_AF = 0;\ data->previousIndex_AF = size-1;\ for (uint_fast32_t i = 0; i < size; ++i) {\ fromUiF(fprec, data->SN_IM[i], 0);\ } #define LOOP_ITERATION_AF_STRIPE(size,fprec) \ {\ uint_fast32_t m = 1;\ if (data->n >= m) {\ cargF(fprec,data->tmp_AF,data->z);\ mul_dF(fprec,data->tmp_AF,data->tmp_AF,render->stripeDensity);\ sinF(fprec,data->tmp_AF,data->tmp_AF);\ add_uiF(fprec,data->tmp_AF,data->tmp_AF,1);\ addF(fprec,data->SN_IM[data->currentIndex_AF],data->SN_IM[data->previousIndex_AF],data->tmp_AF);\ data->previousIndex_AF = data->currentIndex_AF;\ data->currentIndex_AF = (data->currentIndex_AF + 1) % size;\ }\ } #define LOOP_END_AF_STRIPE(size,fprec) \ {\ uint_fast32_t m = 1;\ if (data->n >= m+size-1) {\ for (uint_fast32_t i = 0; i < size; ++i) {\ assignF(fprec, data->shiftSN_AF[i], data->SN_IM[i]);\ }\ for (uint_fast32_t i = 0; i < size; ++i) {\ div_uiF(fprec, data->SN_IM[i], data->shiftSN_AF[(data->previousIndex_AF+size-i) %\ size], 2*(data->n+1-m-i));\ }\ } else {\ /* Result undefined. 0 chosen. */\ for (uint_fast32_t i = 0; i < size; ++i) {\ fromUiF(fprec, data->SN_IM[i], 0);\ }\ }\ } /*********************************************************/ #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/float_precision.h0000664000175000017500000005561511754747533020102 0ustar mpegmpeg/* * float_precision.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file float_precision.h * \brief Header file related to floating point types for different precision. * * \author Marc Pegon */ #ifndef __FLOAT_PRECISION_H__ #define __FLOAT_PRECISION_H__ #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * \enum e_FloatPrecision * \brief Supported float precisions (types). */ /** * \typedef FloatPrecision * \brief Convenient typedef for enum e_FloatPrecision. */ typedef enum e_FloatPrecision { FP_SINGLE = 0, /*!< Single precision (float).*/ FP_DOUBLE, /*!< Double precision (double).*/ FP_LDOUBLE, /*!< Extended precision (long double).*/ FP_MP /* Multiple precision (mpfr_t and mpc_t).*/ } FloatPrecision; #define FLOATTYPE_FP_SINGLE float #define COMPLEX_FLOATTYPE_FP_SINGLE FLOATTYPE_FP_SINGLE complex #define FLOATTYPE_FP_DOUBLE double #define COMPLEX_FLOATTYPE_FP_DOUBLE FLOATTYPE_FP_DOUBLE complex #define FLOATTYPE_FP_LDOUBLE long double #define COMPLEX_FLOATTYPE_FP_LDOUBLE FLOATTYPE_FP_LDOUBLE complex #define FLOATTYPE_FP_MP mpfr_t #define COMPLEX_FLOATTYPE_FP_MP mpc_t #define FLOATTYPE(fprec) FLOATTYPE_##fprec #define COMPLEX_FLOATTYPE(fprec) COMPLEX_FLOATTYPE_##fprec /** * \union MultiFloat * \brief Union for different types of float. */ /** * \typedef MultiFloat * \brief Convenient typedef for union MultiFloat. */ typedef union MultiFloat { FLOATTYPE(FP_SINGLE) val_FP_SINGLE; /*!< float type value.*/ FLOATTYPE(FP_DOUBLE) val_FP_DOUBLE; /*!< double type value.*/ FLOATTYPE(FP_LDOUBLE) val_FP_LDOUBLE; /*!< long double type value.*/ FLOATTYPE(FP_MP) val_FP_MP; /*!< mpfr_t type value.*/ } MultiFloat; /** * \var nbFloatPrecisions * \brief Number of diffenret float precisions. */ extern const uint_fast32_t nbFloatPrecisions; /** * \var floatPrecisionStr * \brief Strings of float precisions. */ extern const char *floatPrecisionStr[]; /** * \var floatPrecisionDescStr * \brief More descriptive strings for float precisions. */ extern const char *floatPrecisionDescStr[]; /** * \fn int GetFloatPrecision(FloatPrecision *floatPrecision, const char *str) * \brief Get float precision from string. * * Function is case insensitive. * Possible strings are : * - "single" for FP_SINGLE * - "double" for FP_DOUBLE * - "ldouble" for FP_LDOUBLE * - "mp" for FP_MP * * \param floatPrecision Float precision destination. * \param str String specifying float precision. * \return 0 in case of success, 1 in case of failure. */ int GetFloatPrecision(FloatPrecision *floatPrecision, const char *str); /************************FP_SINGLE************************/ #define init_FP_SINGLE(x) (void)NULL #define clear_FP_SINGLE(x) (void)NULL #define cinit_FP_SINGLE(x) (void)NULL #define cclear_FP_SINGLE(x) (void)NULL #define assign_FP_SINGLE(dst,src) dst=src #define cassign_FP_SINGLE(dst,src) dst=src #define fromMPFR_FP_SINGLE(dst,src) dst=mpfr_get_flt(src,MPFR_RNDN) #define fromDouble_FP_SINGLE(dst,src) dst=(FLOATTYPE_FP_SINGLE)src #define fromUi_FP_SINGLE(dst,src) dst=(FLOATTYPE_FP_SINGLE)src #define fromSi_FP_SINGLE(dst,src) dst=(FLOATTYPE_FP_SINGLE)src #define toDouble_FP_SINGLE(src) (long double)src #define cfromMPC_FP_SINGLE(dst,src) dst=mpfr_get_flt(mpc_realref(src),MPFR_RNDN)+I*mpfr_get_flt(mpc_imagref(src),MPFR_RNDN) #define cfromUi_FP_SINGLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_SINGLE)src #define cfromSi_FP_SINGLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_SINGLE)src #define cfromReIm_FP_SINGLE(dst,re,im) dst=re+I*im #define cfromCDouble_FP_SINGLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_SINGLE)src #define ctoCDouble_FP_SINGLE(src) (complex long double)src #define cmp_FP_SINGLE(x,y) ((xy)?1:0)) #define cmp_ui_FP_SINGLE(x,y) ((xy)?1:0)) #define cmp_si_FP_SINGLE(x,y) ((xy)?1:0)) #define eq_ui_FP_SINGLE(x,y) (x==y) #define eq_si_FP_SINGLE(x,y) (x==y) #define ceq_si_FP_SINGLE(x,y) (x==y) #define add_FP_SINGLE(res,x,y) res=((x)+(y)) #define sub_FP_SINGLE(res,x,y) res=((x)-(y)) #define mul_FP_SINGLE(res,x,y) res=((x)*(y)) #define div_FP_SINGLE(res,x,y) res=((x)/(y)) #define add_d_FP_SINGLE(res,x,y) res=((x)+(y)) #define sub_d_FP_SINGLE(res,x,y) res=((x)-(y)) #define mul_d_FP_SINGLE(res,x,y) res=((x)*(y)) #define div_d_FP_SINGLE(res,x,y) res=((x)/(y)) #define add_ui_FP_SINGLE(res,x,y) res=((x)+(y)) #define sub_ui_FP_SINGLE(res,x,y) res=((x)-(y)) #define mul_ui_FP_SINGLE(res,x,y) res=((x)*(y)) #define div_ui_FP_SINGLE(res,x,y) res=((x)/(y)) #define add_si_FP_SINGLE(res,x,y) res=((x)+(y)) #define sub_si_FP_SINGLE(res,x,y) res=((x)-(y)) #define mul_si_FP_SINGLE(res,x,y) res=((x)*(y)) #define div_si_FP_SINGLE(res,x,y) res=((x)/(y)) #define cadd_FP_SINGLE(res,x,y) res=((x)+(y)) #define csub_FP_SINGLE(res,x,y) res=((x)-(y)) #define cmul_FP_SINGLE(res,x,y) res=((x)*(y)) #define cdiv_FP_SINGLE(res,x,y) res=((x)/(y)) #define sqr_FP_SINGLE(res,x) res=((x)*(x)) #define csqr_FP_SINGLE(res,x) res=((x)*(x)) #define fabs_FP_SINGLE(res,x) res=fabsf(x) #define cabs_FP_SINGLE(res,z) res=cabsf(z) #define cnorm_FP_SINGLE(res,z) res=(crealf(z)*crealf(z)+cimagf(z)*cimagf(z)) #define creal_FP_SINGLE(res,z) res=crealf(z) #define cimag_FP_SINGLE(res,z) res=cimagf(z) #define carg_FP_SINGLE(res,z) res=cargf(z) #define cpow_FP_SINGLE(res,z,y) res=cpowf(z,y) #define cipow_FP_SINGLE(res,z,y) res=cipowf(z,y) #define conj_FP_SINGLE(res,z) res=conjf(z) #define round_FP_SINGLE(res,x) res=roundf(x) #define floor_FP_SINGLE(res,x) res=floorf(x) #define pow_FP_SINGLE(res,x,y) res=powf(x,y) #define fmax_FP_SINGLE(res,x,y) res=fmaxf(x,y) #define modf_FP_SINGLE(ires,fres,x) fres=modff(x,&ires) #define exp_FP_SINGLE(res,x) res=expf(x) #define log_FP_SINGLE(res,x) res=logf(x) #define sqrt_FP_SINGLE(res,x) res=sqrtf(x) #define sin_FP_SINGLE(res,x) res=sinf(x) #define cos_FP_SINGLE(res,x) res=cosf(x) #define tan_FP_SINGLE(res,x) res=tanf(x) /*********************************************************/ /************************FP_DOUBLE************************/ #define init_FP_DOUBLE(x) (void)NULL #define clear_FP_DOUBLE(x) (void)NULL #define cinit_FP_DOUBLE(x) (void)NULL #define cclear_FP_DOUBLE(x) (void)NULL #define assign_FP_DOUBLE(dst,src) dst=src #define cassign_FP_DOUBLE(dst,src) dst=src #define fromMPFR_FP_DOUBLE(dst,src) dst=mpfr_get_d(src,MPFR_RNDN) #define fromDouble_FP_DOUBLE(dst,src) dst=(FLOATTYPE_FP_DOUBLE)src #define fromUi_FP_DOUBLE(dst,src) dst=(FLOATTYPE_FP_DOUBLE)src #define fromSi_FP_DOUBLE(dst,src) dst=(FLOATTYPE_FP_DOUBLE)src #define toDouble_FP_DOUBLE(src) (long double)src #define cfromMPC_FP_DOUBLE(dst,src) dst=mpfr_get_d(mpc_realref(src),MPFR_RNDN)+I*mpfr_get_d(mpc_imagref(src),MPFR_RNDN) #define cfromUi_FP_DOUBLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_DOUBLE)src #define cfromSi_FP_DOUBLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_DOUBLE)src #define cfromReIm_FP_DOUBLE(dst,re,im) dst=re+I*im #define cfromCDouble_FP_DOUBLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_DOUBLE)src #define ctoCDouble_FP_DOUBLE(src) (complex long double)src #define cmp_FP_DOUBLE(x,y) ((xy)?1:0)) #define cmp_ui_FP_DOUBLE(x,y) ((xy)?1:0)) #define cmp_si_FP_DOUBLE(x,y) ((xy)?1:0)) #define eq_ui_FP_DOUBLE(x,y) (x==y) #define eq_si_FP_DOUBLE(x,y) (x==y) #define ceq_si_FP_DOUBLE(x,y) (x==y) #define add_FP_DOUBLE(res,x,y) res=((x)+(y)) #define sub_FP_DOUBLE(res,x,y) res=((x)-(y)) #define mul_FP_DOUBLE(res,x,y) res=((x)*(y)) #define div_FP_DOUBLE(res,x,y) res=((x)/(y)) #define add_d_FP_DOUBLE(res,x,y) res=((x)+(y)) #define sub_d_FP_DOUBLE(res,x,y) res=((x)-(y)) #define mul_d_FP_DOUBLE(res,x,y) res=((x)*(y)) #define div_d_FP_DOUBLE(res,x,y) res=((x)/(y)) #define add_ui_FP_DOUBLE(res,x,y) res=((x)+(y)) #define sub_ui_FP_DOUBLE(res,x,y) res=((x)-(y)) #define mul_ui_FP_DOUBLE(res,x,y) res=((x)*(y)) #define div_ui_FP_DOUBLE(res,x,y) res=((x)/(y)) #define add_si_FP_DOUBLE(res,x,y) res=((x)+(y)) #define sub_si_FP_DOUBLE(res,x,y) res=((x)-(y)) #define mul_si_FP_DOUBLE(res,x,y) res=((x)*(y)) #define div_si_FP_DOUBLE(res,x,y) res=((x)/(y)) #define cadd_FP_DOUBLE(res,x,y) res=((x)+(y)) #define csub_FP_DOUBLE(res,x,y) res=((x)-(y)) #define cmul_FP_DOUBLE(res,x,y) res=((x)*(y)) #define cdiv_FP_DOUBLE(res,x,y) res=((x)/(y)) #define sqr_FP_DOUBLE(res,x) res=((x)*(x)) #define csqr_FP_DOUBLE(res,x) res=((x)*(x)) #define fabs_FP_DOUBLE(res,x) res=fabs(x) #define cabs_FP_DOUBLE(res,z) res=cabs(z) #define cnorm_FP_DOUBLE(res,z) res=(creal(z)*creal(z)+cimag(z)*cimag(z)) #define creal_FP_DOUBLE(res,z) res=creal(z) #define cimag_FP_DOUBLE(res,z) res=cimag(z) #define carg_FP_DOUBLE(res,z) res=carg(z) #define cpow_FP_DOUBLE(res,z,y) res=cpow(z,y) #define cipow_FP_DOUBLE(res,z,y) res=cipow(z,y) #define conj_FP_DOUBLE(res,z) res=conj(z) #define round_FP_DOUBLE(res,x) res=round(x) #define floor_FP_DOUBLE(res,x) res=floor(x) #define pow_FP_DOUBLE(res,x,y) res=pow(x,y) #define fmax_FP_DOUBLE(res,x,y) res=fmax(x,y) #define modf_FP_DOUBLE(ires,fres,x) fres=modf(x,&ires) #define exp_FP_DOUBLE(res,x) res=exp(x) #define log_FP_DOUBLE(res,x) res=log(x) #define sqrt_FP_DOUBLE(res,x) res=sqrt(x) #define sin_FP_DOUBLE(res,x) res=sin(x) #define cos_FP_DOUBLE(res,x) res=cos(x) #define tan_FP_DOUBLE(res,x) res=tan(x) /*********************************************************/ /************************FP_LDOUBLE***********************/ #define init_FP_LDOUBLE(x) (void)NULL #define clear_FP_LDOUBLE(x) (void)NULL #define cinit_FP_LDOUBLE(x) (void)NULL #define cclear_FP_LDOUBLE(x) (void)NULL #define assign_FP_LDOUBLE(dst,src) dst=src #define cassign_FP_LDOUBLE(dst,src) dst=src #define fromMPFR_FP_LDOUBLE(dst,src) dst=mpfr_get_ld(src,MPFR_RNDN) #define fromDouble_FP_LDOUBLE(dst,src) dst=(FLOATTYPE_FP_LDOUBLE)src #define fromUi_FP_LDOUBLE(dst,src) dst=(FLOATTYPE_FP_LDOUBLE)src #define fromSi_FP_LDOUBLE(dst,src) dst=(FLOATTYPE_FP_LDOUBLE)src #define toDouble_FP_LDOUBLE(src) (long double)src #define cfromMPC_FP_LDOUBLE(dst,src) dst=mpfr_get_ld(mpc_realref(src),MPFR_RNDN)+I*mpfr_get_ld(mpc_imagref(src),MPFR_RNDN) #define cfromUi_FP_LDOUBLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_LDOUBLE)src #define cfromSi_FP_LDOUBLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_LDOUBLE)src #define cfromReIm_FP_LDOUBLE(dst,re,im) dst=re+I*im #define cfromCDouble_FP_LDOUBLE(dst,src) dst=(COMPLEX_FLOATTYPE_FP_LDOUBLE)src #define ctoCDouble_FP_LDOUBLE(src) (complex long double)src #define cmp_FP_LDOUBLE(x,y) ((xy)?1:0)) #define cmp_ui_FP_LDOUBLE(x,y) ((xy)?1:0)) #define cmp_si_FP_LDOUBLE(x,y) ((xy)?1:0)) #define ccmp_si_FP_LDOUBLE(x,y) ((xy)?1:0)) #define eq_ui_FP_LDOUBLE(x,y) (x==y) #define eq_si_FP_LDOUBLE(x,y) (x==y) #define ceq_si_FP_LDOUBLE(x,y) (x==y) #define add_FP_LDOUBLE(res,x,y) res=((x)+(y)) #define sub_FP_LDOUBLE(res,x,y) res=((x)-(y)) #define mul_FP_LDOUBLE(res,x,y) res=((x)*(y)) #define div_FP_LDOUBLE(res,x,y) res=((x)/(y)) #define add_d_FP_LDOUBLE(res,x,y) res=((x)+(y)) #define sub_d_FP_LDOUBLE(res,x,y) res=((x)-(y)) #define mul_d_FP_LDOUBLE(res,x,y) res=((x)*(y)) #define div_d_FP_LDOUBLE(res,x,y) res=((x)/(y)) #define add_ui_FP_LDOUBLE(res,x,y) res=((x)+(y)) #define sub_ui_FP_LDOUBLE(res,x,y) res=((x)-(y)) #define mul_ui_FP_LDOUBLE(res,x,y) res=((x)*(y)) #define div_ui_FP_LDOUBLE(res,x,y) res=((x)/(y)) #define add_si_FP_LDOUBLE(res,x,y) res=((x)+(y)) #define sub_si_FP_LDOUBLE(res,x,y) res=((x)-(y)) #define mul_si_FP_LDOUBLE(res,x,y) res=((x)*(y)) #define div_si_FP_LDOUBLE(res,x,y) res=((x)/(y)) #define cadd_FP_LDOUBLE(res,x,y) res=((x)+(y)) #define csub_FP_LDOUBLE(res,x,y) res=((x)-(y)) #define cmul_FP_LDOUBLE(res,x,y) res=((x)*(y)) #define cdiv_FP_LDOUBLE(res,x,y) res=((x)/(y)) #define sqr_FP_LDOUBLE(res,x) res=((x)*(x)) #define csqr_FP_LDOUBLE(res,x) res=((x)*(x)) #define fabs_FP_LDOUBLE(res,x) res=fabsl(x) #define cabs_FP_LDOUBLE(res,z) res=cabsl(z) #define cnorm_FP_LDOUBLE(res,z) res=(creall(z)*creall(z)+cimagl(z)*cimagl(z)) #define creal_FP_LDOUBLE(res,z) res=creall(z) #define cimag_FP_LDOUBLE(res,z) res=cimagl(z) #define carg_FP_LDOUBLE(res,z) res=cargl(z) #define cpow_FP_LDOUBLE(res,z,y) res=cpowl(z,y) #define cipow_FP_LDOUBLE(res,z,y) res=cipowl(z,y) #define conj_FP_LDOUBLE(res,z) res=conjl(z) #define round_FP_LDOUBLE(res,x) res=roundl(x) #define floor_FP_LDOUBLE(res,x) res=floorl(x) #define pow_FP_LDOUBLE(res,x,y) res=powl(x,y) #define fmax_FP_LDOUBLE(res,x,y) res=fmaxl(x,y) #define modf_FP_LDOUBLE(ires,fres,x) fres=modfl(x,&ires) #define exp_FP_LDOUBLE(res,x) res=expl(x) #define log_FP_LDOUBLE(res,x) res=logl(x) #define sqrt_FP_LDOUBLE(res,x) res=sqrtl(x) #define sin_FP_LDOUBLE(res,x) res=sinl(x) #define cos_FP_LDOUBLE(res,x) res=cosl(x) #define tan_FP_LDOUBLE(res,x) res=tanl(x) /*********************************************************/ /**************************FP_MP**************************/ #define init_FP_MP(x) mpfr_init(x) #define clear_FP_MP(x) mpfr_clear(x) #define cinit_FP_MP(x) mpc_init2(x,mpfr_get_default_prec()) #define cclear_FP_MP(x) mpc_clear(x) #define assign_FP_MP(dst,src) mpfr_set(dst,src,MPFR_RNDN) #define cassign_FP_MP(dst,src) mpc_set(dst,src,MPC_RNDNN) #define fromMPFR_FP_MP(dst,src) mpfr_set(dst,src,MPFR_RNDN) #define fromDouble_FP_MP(dst,src) mpfr_set_d(dst,src,MPFR_RNDN) #define fromUi_FP_MP(dst,src) mpfr_set_ui(dst,src,MPFR_RNDN) #define fromSi_FP_MP(dst,src) mpfr_set_si(dst,src,MPFR_RNDN) #define toDouble_FP_MP(src) mpfr_get_ld(src,MPFR_RNDN) #define cfromMPC_FP_MP(dst,src) mpc_set(dst,src,MPC_RNDNN) #define cfromUi_FP_MP(dst,src) mpc_set_ui(dst,src,MPC_RNDNN) #define cfromSi_FP_MP(dst,src) mpc_set_si(dst,src,MPC_RNDNN) #define cfromReIm_FP_MP(dst,re,im) mpc_set_fr_fr(dst,re,im,MPC_RNDNN) #define cfromCDouble_FP_MP(dst,src) mpc_set_d_d(dst,creal(src),cimag(src),MPC_RNDNN) #define ctoCDouble_FP_MP(src) (mpfr_get_d(mpc_realref(src),MPFR_RNDN)+I*mpfr_get_d(mpc_imagref(src),MPFR_RNDN)) #define cmp_FP_MP(x,y) mpfr_cmp(x,y) #define cmp_ui_FP_MP(x,y) mpfr_cmp_ui(x,y) #define cmp_si_FP_MP(x,y) mpfr_cmp_si(x,y) #define eq_ui_FP_MP(x,y) (mpfr_cmp_ui(x,y)==0) #define eq_si_FP_MP(x,y) (mpfr_cmp_si(x,y)==0) #define ceq_si_FP_MP(x,y) (mpc_cmp_si(x,y) == 0) #define add_FP_MP(res,x,y) mpfr_add(res,x,y,MPFR_RNDN) #define sub_FP_MP(res,x,y) mpfr_sub(res,x,y,MPFR_RNDN) #define mul_FP_MP(res,x,y) mpfr_mul(res,x,y,MPFR_RNDN) #define div_FP_MP(res,x,y) mpfr_div(res,x,y,MPFR_RNDN) #define add_d_FP_MP(res,x,y) mpfr_add_d(res,x,y,MPFR_RNDN) #define sub_d_FP_MP(res,x,y) mpfr_sub_d(res,x,y,MPFR_RNDN) #define mul_d_FP_MP(res,x,y) mpfr_mul_d(res,x,y,MPFR_RNDN) #define div_d_FP_MP(res,x,y) mpfr_div_d(res,x,y,MPFR_RNDN) #define add_ui_FP_MP(res,x,y) mpfr_add_ui(res,x,y,MPFR_RNDN) #define sub_ui_FP_MP(res,x,y) mpfr_sub_ui(res,x,y,MPFR_RNDN) #define mul_ui_FP_MP(res,x,y) mpfr_mul_ui(res,x,y,MPFR_RNDN) #define div_ui_FP_MP(res,x,y) mpfr_div_ui(res,x,y,MPFR_RNDN) #define add_si_FP_MP(res,x,y) mpfr_add_si(res,x,y,MPFR_RNDN) #define sub_si_FP_MP(res,x,y) mpfr_sub_si(res,x,y,MPFR_RNDN) #define mul_si_FP_MP(res,x,y) mpfr_mul_si(res,x,y,MPFR_RNDN) #define div_si_FP_MP(res,x,y) mpfr_div_si(res,x,y,MPFR_RNDN) #define cadd_FP_MP(res,x,y) mpc_add(res,x,y,MPC_RNDNN) #define csub_FP_MP(res,x,y) mpc_sub(res,x,y,MPC_RNDNN) #define cmul_FP_MP(res,x,y) mpc_mul(res,x,y,MPC_RNDNN) #define cdiv_FP_MP(res,x,y) mpc_div(res,x,y,MPC_RNDNN) #define sqr_FP_MP(res,x) mpfr_sqr(res,x,MPFR_RNDN) #define csqr_FP_MP(res,x) mpc_sqr(res,x,MPC_RNDNN) #define fabs_FP_MP(res,x) mpfr_abs(res,x,MPFR_RNDN) #define cabs_FP_MP(res,z) mpc_abs(res,z,MPFR_RNDN) #define cnorm_FP_MP(res,z) mpc_norm(res,z,MPFR_RNDN) #define creal_FP_MP(res,z) mpc_real(res,z,MPFR_RNDN) #define cimag_FP_MP(res,z) mpc_imag(res,z,MPFR_RNDN) #define carg_FP_MP(res,z) mpc_arg(res,z,MPFR_RNDN) #define cpow_FP_MP(res,z,y) mpc_pow(res,z,y,MPC_RNDNN) #define cipow_FP_MP(res,z,y) mpc_pow_si(res,z,y,MPC_RNDNN) #define conj_FP_MP(res,z) mpc_conj(res,z,MPC_RNDNN) #define round_FP_MP(res,x) mpfr_round(res,x) #define floor_FP_MP(res,x) mpfr_floor(res,x) #define pow_FP_MP(res,x,y) mpfr_pow(res,x,y,MPFR_RNDN) #define fmax_FP_MP(res,x,y) mpfr_max(res,x,y,MPFR_RNDN) #define modf_FP_MP(ires,fres,x) mpfr_modf(ires,fres,x,MPFR_RNDN) #define exp_FP_MP(res,x) mpfr_exp(res,x,MPFR_RNDN) #define log_FP_MP(res,x) mpfr_log(res,x,MPFR_RNDN) #define sqrt_FP_MP(res,x) mpfr_sqrt(res,x,MPFR_RNDN) #define sin_FP_MP(res,x) mpfr_sin(res,x,MPFR_RNDN) #define cos_FP_MP(res,x) mpfr_cos(res,x,MPFR_RNDN) #define tan_FP_MP(res,x) mpfr_tan(res,x,MPFR_RNDN) /*********************************************************/ /**************************COMMON*************************/ #define initF(fprec,x) init_##fprec(x) #define clearF(fprec,x) clear_##fprec(x) #define cinitF(fprec,x) cinit_##fprec(x) #define cclearF(fprec,x) cclear_##fprec(x) #define assignF(fprec,dst,src) assign_##fprec(dst,src) #define cassignF(fprec,dst,src) cassign_##fprec(dst,src) #define fromMPFRF(fprec,dst,src) fromMPFR_##fprec(dst,src) #define fromDoubleF(fprec,dst,src) fromDouble_##fprec(dst,src) #define fromUiF(fprec,dst,src) fromUi_##fprec(dst,src) #define fromSiF(fprec,dst,src) fromSi_##fprec(dst,src) #define toDoubleF(fprec,src) toDouble_##fprec(src) #define cfromMPCF(fprec,dst,src) cfromMPC_##fprec(dst,src) #define cfromUiF(fprec,dst,src) cfromUi_##fprec(dst,src) #define cfromSiF(fprec,dst,src) cfromSi_##fprec(dst,src) #define cfromReImF(fprec,dst,re,im) cfromReIm_##fprec(dst,re,im) #define cfromCDoubleF(fprec,dst,src) cfromCDouble_##fprec(dst,src) #define ctoCDoubleF(fprec,src) ctoCDouble_##fprec(src) #define cmpF(fprec,x,y) cmp_##fprec(x,y) #define cmp_uiF(fprec,x,y) cmp_ui_##fprec(x,y) #define cmp_siF(fprec,x,y) cmp_si_##fprec(x,y) #define eq_uiF(fprec,x,y) eq_ui_##fprec(x,y) #define eq_siF(fprec,x,y) eq_si_##fprec(x,y) #define ceq_siF(fprec,x,y) ceq_si_##fprec(x,y) #define addF(fprec,res,x,y) add_##fprec(res,x,y) #define subF(fprec,res,x,y) sub_##fprec(res,x,y) #define mulF(fprec,res,x,y) mul_##fprec(res,x,y) #define divF(fprec,res,x,y) div_##fprec(res,x,y) #define add_dF(fprec,res,x,y) add_d_##fprec(res,x,y) #define sub_dF(fprec,res,x,y) sub_d_##fprec(res,x,y) #define mul_dF(fprec,res,x,y) mul_d_##fprec(res,x,y) #define div_dF(fprec,res,x,y) div_d_##fprec(res,x,y) #define add_uiF(fprec,res,x,y) add_ui_##fprec(res,x,y) #define sub_uiF(fprec,res,x,y) sub_ui_##fprec(res,x,y) #define mul_uiF(fprec,res,x,y) mul_ui_##fprec(res,x,y) #define div_uiF(fprec,res,x,y) div_ui_##fprec(res,x,y) #define add_siF(fprec,res,x,y) add_si_##fprec(res,x,y) #define sub_siF(fprec,res,x,y) sub_si_##fprec(res,x,y) #define mul_siF(fprec,res,x,y) mul_si_##fprec(res,x,y) #define div_siF(fprec,res,x,y) div_si_##fprec(res,x,y) #define caddF(fprec,res,x,y) cadd_##fprec(res,x,y) #define csubF(fprec,res,x,y) csub_##fprec(res,x,y) #define cmulF(fprec,res,x,y) cmul_##fprec(res,x,y) #define cdivF(fprec,res,x,y) cdiv_##fprec(res,x,y) #define sqrF(fprec,res,x) sqr_##fprec(res,x) #define csqrF(fprec,res,x) csqr_##fprec(res,x) #define fabsF(fprec,res,x) fabs_##fprec(res,x) #define cabsF(fprec,res,z) cabs_##fprec(res,z) #define cnormF(fprec,res,z) cnorm_##fprec(res,z) #define crealF(fprec,res,z) creal_##fprec(res,z) #define cimagF(fprec,res,z) cimag_##fprec(res,z) #define cargF(fprec,res,z) carg_##fprec(res,z) #define cpowF(fprec,res,z,y) cpow_##fprec(res,z,y) #define cipowF(fprec,res,z,y) cipow_##fprec(res,z,y) #define conjF(fprec,res,z) conj_##fprec(res,z) #define roundF(fprec,res,x) round_##fprec(res,x) #define floorF(fprec,res,x) floor_##fprec(res,x) #define powF(fprec,res,x,y) pow_##fprec(res,x,y) #define fmaxF(fprec,res,x,y) fmax_##fprec(res,x,y) #define modfF(fprec,ires,fres,x) modf_##fprec(ires,fres,x) #define expF(fprec,res,x) exp_##fprec(res,x) #define logF(fprec,res,x) log_##fprec(res,x) #define sqrtF(fprec,res,x) sqrt_##fprec(res,x) #define sinF(fprec,res,x) sin_##fprec(res,x) #define cosF(fprec,res,x) cos_##fprec(res,x) #define tanF(fprec,res,x) tan_##fprec(res,x) /*********************************************************/ #define DECL_FLOAT(fprec,x) FLOATTYPE(fprec) x #define DECL_COMPLEX_FLOAT(fprec,x) COMPLEX_FLOATTYPE(fprec) x #define DECL_INIT_FLOAT(fprec,x) \ DECL_FLOAT(fprec,x);\ initF(fprec,x) #define DECL_INIT_COMPLEX_FLOAT(fprec,x) \ DECL_COMPLEX_FLOAT(fprec,x);\ cinitF(fprec,x) #define FLOAT_VAR(fprec,x) x##_##fprec #define AUX_DECL_MULTI_FLOAT(fprec,x) DECL_FLOAT(fprec,FLOAT_VAR(fprec,x)) #define DECL_MULTI_FLOAT(x) \ AUX_DECL_MULTI_FLOAT(FP_SINGLE,x);\ AUX_DECL_MULTI_FLOAT(FP_DOUBLE,x);\ AUX_DECL_MULTI_FLOAT(FP_LDOUBLE,x);\ AUX_DECL_MULTI_FLOAT(FP_MP,x) #define AUX_DECL_MULTI_COMPLEX_FLOAT(fprec,x) DECL_COMPLEX_FLOAT(fprec,FLOAT_VAR(fprec,x)) #define DECL_MULTI_COMPLEX_FLOAT(x) \ AUX_DECL_MULTI_COMPLEX_FLOAT(FP_SINGLE,x);\ AUX_DECL_MULTI_COMPLEX_FLOAT(FP_DOUBLE,x);\ AUX_DECL_MULTI_COMPLEX_FLOAT(FP_LDOUBLE,x);\ AUX_DECL_MULTI_COMPLEX_FLOAT(FP_MP,x) #define AUX_INIT_MULTI_FLOAT(fprec,x) initF(fprec,FLOAT_VAR(fprec,x)) #define INIT_MULTI_FLOAT(x) \ AUX_INIT_MULTI_FLOAT(FP_SINGLE,x);\ AUX_INIT_MULTI_FLOAT(FP_DOUBLE,x);\ AUX_INIT_MULTI_FLOAT(FP_LDOUBLE,x);\ AUX_INIT_MULTI_FLOAT(FP_MP,x) #define AUX_INIT_MULTI_COMPLEX_FLOAT(fprec,x) cinitF(fprec,FLOAT_VAR(fprec,x)) #define INIT_MULTI_COMPLEX_FLOAT(x) \ AUX_INIT_MULTI_COMPLEX_FLOAT(FP_SINGLE,x);\ AUX_INIT_MULTI_COMPLEX_FLOAT(FP_DOUBLE,x);\ AUX_INIT_MULTI_COMPLEX_FLOAT(FP_LDOUBLE,x);\ AUX_INIT_MULTI_COMPLEX_FLOAT(FP_MP,x); #define AUX_CLEAR_MULTI_FLOAT(fprec,x) clearF(fprec,FLOAT_VAR(fprec,x)) #define CLEAR_MULTI_FLOAT(x) \ AUX_CLEAR_MULTI_FLOAT(FP_SINGLE,x);\ AUX_CLEAR_MULTI_FLOAT(FP_DOUBLE,x);\ AUX_CLEAR_MULTI_FLOAT(FP_LDOUBLE,x);\ AUX_CLEAR_MULTI_FLOAT(FP_MP,x) #define AUX_CLEAR_MULTI_COMPLEX_FLOAT(fprec,x) cclearF(fprec,FLOAT_VAR(fprec,x)) #define CLEAR_MULTI_COMPLEX_FLOAT(x) \ AUX_CLEAR_MULTI_COMPLEX_FLOAT(FP_SINGLE,x);\ AUX_CLEAR_MULTI_COMPLEX_FLOAT(FP_DOUBLE,x);\ AUX_CLEAR_MULTI_COMPLEX_FLOAT(FP_LDOUBLE,x);\ AUX_CLEAR_MULTI_COMPLEX_FLOAT(FP_MP,x); #define AUX_ASSIGN_MULTI_FLOAT(fprec,dst,src) \ fromMPFRF(fprec,FLOAT_VAR(fprec,dst),src) #define ASSIGN_MULTI_FLOAT(dst,src) \ AUX_ASSIGN_MULTI_FLOAT(FP_SINGLE,dst,src);\ AUX_ASSIGN_MULTI_FLOAT(FP_DOUBLE,dst,src);\ AUX_ASSIGN_MULTI_FLOAT(FP_LDOUBLE,dst,src);\ AUX_ASSIGN_MULTI_FLOAT(FP_MP,dst,src) #define AUX_ASSIGN_MULTI_COMPLEX_FLOAT(fprec,dst,src) \ cfromMPCF(fprec,FLOAT_VAR(fprec,dst),src) #define ASSIGN_MULTI_COMPLEX_FLOAT(dst,src) \ AUX_ASSIGN_MULTI_COMPLEX_FLOAT(FP_SINGLE,dst,src);\ AUX_ASSIGN_MULTI_COMPLEX_FLOAT(FP_DOUBLE,dst,src);\ AUX_ASSIGN_MULTI_COMPLEX_FLOAT(FP_LDOUBLE,dst,src);\ AUX_ASSIGN_MULTI_COMPLEX_FLOAT(FP_MP,dst,src) #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/task.h0000664000175000017500000002426711754747533015663 0ustar mpegmpeg/* * task.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file task.h * \brief Header file related to tasks. * \author Marc Pegon */ #ifndef __TASKS_H__ #define __TASKS_H__ #include "thread.h" #ifdef __cplusplus extern "C" { #endif struct Task; /** * \struct CompositeTaskArguments * \brief Arguments structure for composite tasks thread routine. * * This is for internal use only. */ /** * \typedef CompositeTaskArguments * \brief Convenient typedef for struct CompositeTaskArguments. */ typedef struct CompositeTaskArguments { struct Task *thisTask; /*!< Pointer to the composite task being run.*/ } CompositeTaskArguments; /** * \struct Task * \brief Structure to control tasks execution by threads. * * Typically, executing a task by threads is done in 3 * steps: * -create task * -launch task * -wait for it to finish * * Through the task structure, it is possible to cancel * a task, to pause it and then resume it, as well to wait for * it to finish (get task result). * * Some examples of use :\n * 1) Launch task and wait for it to finish :\n * task = CreateTask(message, threads, nbThreadsNeeded, * args, s_elem, routine, freeArgs);\n * LaunchTask(task, threads);\n * res = GetTaskResult(task); * * 2) Launch threads, cancel task after some time, wait for it to * finish.\n * task = CreateTask(message, threads, nbThreadsNeeded, args, s_elem, routine, freeArgs);\n * sleep(2);\n * CancelTask(task); // (send cancelation request)\n * res = GetTaskResult(task); // wait for it to finish\n * * It is up to the thread routine to take into account cancellation * request and finish earlier, via the CancelRequested function. * * Remark: note that although the functions described here deal * with threads, they are not thread-safe (like all the functions * in this library btw), i.e. the functions here should not be run * concurrently by different threads (although, if necessary, it * would be quite easy to make them thread-safe, by adding a mutex * for each function). */ /** * \typedef Task * \brief Convenient typedef for struct Task. */ typedef struct Task { int isComposite; /*!< 1 if task consists of a sequence of subtasks.*/ int launchPrepared; /*!< 1 if launch has been prepared (for composite tasks).*/ int hasBeenLaunched; /*!< 1 if created task has already been launched.*/ int done; /*!< 1 if task has already finished and threads have been joined.*/ int returnValue; /*!< Task return value (0 if finished normally, 1 if canceled).*/ int cancel; /*!< Integer used for cancellation request.*/ pthread_spinlock_t cancelMutex; /*!< Mutex for cancel variable.*/ int pause; /*!< Integer used to pause task.*/ pthread_spinlock_t pauseMutex; /*!< Mutex for pause variable.*/ /* For composite tasks: */ CompositeTaskArguments compositeTaskArguments; /*!< Arguments for composite tasks.*/ uint_fast32_t nbSubTasks; /*!< Number of subtasks (for composite task only).*/ struct Task **subTasks; /*!< Subtasks (for composite task only).*/ uint_fast32_t compositeTaskNbReady; /*!< Number of threads ready to launch a new subtask.*/ int stopLaunchingSubTasks; /*!< Instructs composite task routine to stop launching subtasks (cancel requested).*/ pthread_cond_t compositeTaskAllThreadsReadyCond; /*!< Signaled when all threads are ready to launch new subtask.*/ /* For non-composite tasks: */ struct ThreadArgHeader *threadArgsHeaders; /*!< Internal part of thread arguments (cancel and progress handling).*/ struct Threads *threads; /*!< Pointer to threads to use for task.*/ uint_fast32_t nbThreadsNeeded; /*!< Number of threads actually needed for task.*/ void *initialArgs; /*!< Copy of initial arguments (as passed to CreateTask).*/ void *args; /*!< Array of args passed to thread routine (with headers).*/ size_t s_elem; /*!< Size of each argument.*/ void *(*threadsRoutine)(void *); /*!< Task routine (to be executed by each thread).*/ void (*freeArg)(void *); /*!< Routine to free each arg.*/ char *message; /*!< Task message to print at launch and when it finishes.*/ } Task; /** * \fn Task *DoNothingTask() * \brief Returns a newly-allocated task that does nothing. * * Convenient for working on empty image for example. * * \return Do-nothing task. */ Task *DoNothingTask(); /** * \fn Task *CreateTask(const char message[], uint_fast32_t nbThreadsNeeded, const void *args, size_t s_elem, void *(*routine)(void *), void (*freeArg)(void *)) * \brief Create task. * * args is copied.\n * Note that arguments passed to the thread routine are not * exactly those passed to the function :\n * A ThreadArgHeader structure is added at the beginning of the * argument, which should be used to handle cancellation requests and * task progress.\n * The remaining bytes are the 'real' argument.\n * Free argument routine will be called for each argument when task * is free'd (can be NULL if arguments contain no dynamically * allocated data). * * \param message Task message to print at launch and when task finishes. * \param nbThreadsNeeded Number of threads needed to launch task. * \param args Pointer to array of arguments for threads routines. * \param s_elem Size of one argument (in bytes). * \param routine Threads routine. * \param freeArg Routine to free each argument. * \return Corresponding newly-allocated task. */ Task *CreateTask(const char message[], uint_fast32_t nbThreadsNeeded, const void *args, size_t s_elem, void *(*routine)(void *), void (*freeArg)(void *)); /** * \fn Task *CreateCompositeTask(const char message[], uint_fast32_t nbSubTasks, Task *subTasks[]) * \brief Create composite task. * * Create a "virtual" task made of subtasks.\n * Array of subtasks pointers will be copied (though not the tasks * themselves). * * \param message Task message to print at launch and when task finishes. * \param nbSubTasks Number of subtasks. * \param subTasks Array of subtasks. * \return Newly-allocated composite task. */ Task *CreateCompositeTask(const char message[], uint_fast32_t nbSubTasks, Task *subTasks[]); /** * \fn void LaunchTask(Task *task, Threads *threads) * \brief Launch task. * * Exit with error if task has already been launched.\n * Exit with error if number of threads needed for task * is greater than number of threads.\n * Threads should *not* be busy when calling this * function (unspecified behaviour otherwise). * * \param task Task to be launched. * \param threads Threads that will execute task. */ void LaunchTask(Task *task, Threads *threads); /** * \fn int ExecuteTaskBlocking(Task *task, Threads *threads) * \brief Execute task (blocking). * * Launch task and wait for it finish before returning. * \see LaunchTask * * \param task Task to be executed. * \param threads Threads that will be used to execute task. * \return Task return value (0 if finished normally, 1 if cancelled); */ int ExecuteTaskBlocking(Task *task, Threads *threads); /** * \fn int TaskIsFinished(Task *task) * \brief Test if task is finished. * * A not-yet-launched task is considered not finished * (0 returned). * * \param task Task to be tested. * \return 1 if task is finished, 0 otherwise. */ int TaskIsFinished(Task *task); /** * \fn int GetTaskResult(Task *task) * \brief Get task result. * * Exit with error if task has not been launched yet.\n * If task has already been launched but is not finished,\n * the function will block until it is finished.\n * Hence make sure that task is not paused when calling\n * this function (deadlock). * * \param task Task to finish. * \return 0 if task finished normally, 1 if it was cancelled, -1 if it has not yet been launched. */ int GetTaskResult(Task *task); /** * \fn void CancelTask(Task *task) * \brief Send cancelation request to task. * * Note that the function returns immediately after * sending the cancelation request. * You can call GetTaskResult after CancelTask to * make sure it is effectively canceled.\n * It is up to the task routine to take the request into * account, via the CancelRequested function.\n * \see CancelRequested * Does nothing if task has already finished.\n * * \param task Task to send cancellation request to. */ void CancelTask(Task *task); /** \fn void PauseTask(Task *task) * \brief Pause task. * * Function returns after task has effectively been paused * (unlike CancelAction which only sends a request).\n * You can use this function to access data being modified * by task safely.\n * Does nothing if task is already paused, has not been launched * yet, or has already finished. * * \brief task Task to be paused. */ void PauseTask(Task *task); /** \fn void ResumeTask(Task *task) * \brief Resume task. * * Resume task after it has been paused.\n * Does nothing if task has not been launched yet, * or has already finished. */ void ResumeTask(Task *task); /** * \fn double GetTaskProgress(const Task *task) * \brief Get task progress. * * Progress is a value between 0 (just begun) and 1 (done).\n * Returns 0 if task has not been launched yet. * * \param task Task subject to request. * \return Task progress. */ double GetTaskProgress(const Task *task); /** * \fn void FreeTask(Task *task) * \brief Free task data. * * If task has been launched, it *must* have already finished: * exit with error otherwise.\n * Note: a prior call to GetTaskResult will ensure that task * has finished, since it waits for action to finish. * * \param task Task to be free'd. */ void FreeTask(Task *task); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/ppm.h0000664000175000017500000000275611754747533015514 0ustar mpegmpeg/* * ppm.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file ppm.h * \brief Header file related to PPM (Portable Pixmap) handling. * \author Marc Pegon */ #ifndef __PPM_H__ #define __PPM_H__ #include "image.h" #include #ifdef __cplusplus extern "C" { #endif /** * \fn int ExportPPM(const char *fileName, const Image *image) * \brief Export image as PPM; * * If file specified by fileName already exists, it will * be overwritten. * * \param fileName Name of the PPM file to export the image in. * \param image Pointer to image structure to export. * \return 0 in case of success, 0 in case of error. */ int ExportPPM(const char *fileName, const Image *image); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/uirectangle.h0000664000175000017500000001062111754776720017210 0ustar mpegmpeg/* * uirectangle.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file uirectangle.h * \brief Header file related to UIUIRectangle structure. * \author Marc Pegon */ #ifndef __UIRECTANGLE_H__ #define __UIRECTANGLE_H__ #include #ifdef __cplusplus extern "C" { #endif /** * \struct UIRectangle * \brief Simple rectangle structure made of unsigned integers. */ /** * \typedef UIRectangle * \brief Convenient typedef for struct UIRectangle. */ typedef struct UIRectangle { uint_fast32_t x1; /*!< X coordinate of the rectangle's top left corner.*/ uint_fast32_t y1; /*!< Y coordinate of the rectangle's top left corner.*/ uint_fast32_t x2; /*!< X coordinate of the rectangle's bottom right corner.*/ uint_fast32_t y2; /*!< Y coordinate of the rectangle's bottom right corner.*/ } UIRectangle; /** * \fn void InitUIRectangle(UIRectangle *rectangle, uint_fast32_t x1, uint_fast32_t y1, uint_fast32_t x2, uint_fast32_t y2) * \brief Initialize rectangle. * * x1 must be less than x2 and y1 must be less than y2 * (undefined behaviour otherwise). * * \param rectangle Pointer to rectangle structure to initialize. * \param x1 X coordinate of the rectangle's top left corner. * \param y1 Y coordinate of the rectangle's top left corner. * \param x2 X coordinate of the rectangle's bottom right corner. * \param y2 Y coordinate of the rectangle's bottom right corner. */ void InitUIRectangle(UIRectangle *rectangle, uint_fast32_t x1, uint_fast32_t y1, uint_fast32_t x2, uint_fast32_t y2); /** * \fn UIRectangle CopyUIRectangle(const UIRectangle *rectangle) * \brief Copy rectangle. * * \param rectangle Pointer to rectangle to copy. * \return Copy of rectangle. */ UIRectangle CopyUIRectangle(const UIRectangle *rectangle); /** * \fn int CutUIRectangleInHalf(UIRectangle rectangle, UIRectangle *out1, UIRectangle *out2) * \brief Cut rectangle in half. * * Cut rectangle into two rectangles.\n * If the rectangle cannot be cut in half, out1 and out2 will be left unchanged. * * \param rectangle Rectangle to be cut in half (will not be modified). * \param out1 Pointer to put the first half of the cut rectangle. * \param out2 Pointer to put the second half of the cut rectangle. * \return 1 if rectangle cannot be cut in half, 0 otherwise. */ int CutUIRectangleInHalf(UIRectangle rectangle, UIRectangle *out1, UIRectangle *out2); /** * \fn void CutUIRectangleMaxSize(UIRectangle src, uint_fast32_t size, UIRectangle **out, uint_fast32_t *out_size) * \brief Cut rectangle into smaller rectangles. * * Cut rectangle into smaller rectangles. Each of these rectangles is smaller * (i.e. both width and height) than given size. * * \param src Rectangle to be cut into smaller rectangles. * \param size Maximum size of the small rectangles produced. * \param out Pointer to a (not yet allocated) array of rectangles for the output. * \param out_size Pointer to an integer to store the number of small rectangles produced. */ void CutUIRectangleMaxSize(UIRectangle src, uint_fast32_t size, UIRectangle **out, uint_fast32_t *out_size); /** * \fn int CutUIRectangleInN(UIRectangle rectangle, uint_fast32_t N, UIRectangle *out) * \brief Cut rectangle in N parts. * * Cut rectangle into N rectangles.\n * If the rectangle cannot be cut in N, the out array will be left unchanged. * * \param rectangle Rectangle to be cut in N. * \param N Rectangle is to be cut in N rectangles. * \param out Pointer to the (allocated) array in which to put the N cut rectangles. * \return 1 if rectangle cannot be cut in N, 0 otherwise. */ int CutUIRectangleInN(UIRectangle rectangle, uint_fast32_t N, UIRectangle *out); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal_cache.h0000664000175000017500000002151111754747533017445 0ustar mpegmpeg/* * fractal_cache.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_cache.h * \brief Main header file related to fractal cache. */ #ifndef __FRACTAL_CACHE_H__ #define __FRACTAL_CACHE_H__ #include "color.h" #include "float_precision.h" #include "fractal_rendering_parameters.h" #include "image.h" #include "thread.h" #include #include #ifdef __cplusplus extern "C" { #endif /** * \def DEFAULT_FRACTAL_CACHE_SIZE * \brief Default fractal cache size (number of entries). */ #define DEFAULT_FRACTAL_CACHE_SIZE (uint_least64_t)(300000) /** * \def DEFAULT_CACHE_WEIGHT_THRESHOLD * \brief Default threshold for ArrayValue validity. * * \see isArrayValueValid */ #define DEFAULT_CACHE_WEIGHT_THRESHOLD (FLOATTYPE(FP_LDOUBLE))(0.) /** * \struct CacheEntry * \brief Cache entry. */ /** * \typedef CacheEntry * \brief Convenient typedef for struct CacheEntry. */ typedef struct CacheEntry { FloatPrecision floatPrecision; /*!< Float precision for x and y values.*/ MultiFloat x; /*!< x coordinate.*/ MultiFloat y; /*!< y coordinate.*/ double value; /*!< Value at point (x,y).*/ } CacheEntry; /** * \struct ArrayValue * \brief Type of cache array elements. */ /** * \typedef ArrayValue * \brief Convenient typedef for struct ArrayValue. */ typedef struct ArrayValue { uint_fast32_t state; /*!< Value state, used to test validity.*/ double r; /*!< Sum of weighted red values.*/ double g; /*!< Sum of weighted green values.*/ double b; /*!< Sum of weighted blue values.*/ double totalWeight; /*!< Total weight.*/ } ArrayValue; struct Fractal; /** * \struct FractalCache * \brief Fractal cache for fractal drawing. * * When using cache to create an image preview * all entries are placed at the correct position * in the array (resized to image size), and the * image is produced from this array. */ /** * \typedef FractalCache * \brief Convenient type for struct FractalCache. */ typedef struct FractalCache { int firstUse; /*!< Indicates whether or not cache has already been used.*/ struct Fractal *fractal; /*!< Current fractal cached.*/ RenderingParameters *render; /*!< Current rendering parameters cached.*/ uint_fast32_t currentState; /*!< Current cache state (used for testing array values validity.*/ uint_least64_t nbInitialized; /*!< Number of entries already initialized (if cache is not full yet).*/ uint_least64_t size; /*!< Cache size (total number of entries it can contain).*/ CacheEntry *entry; /*!< Array of entries.*/ uint_least64_t currentIndex; /*!< Current entry index.*/ uint_fast32_t arrayWidth; /*!< Array width.*/ uint_fast32_t arrayHeight; /*!< Array height.*/ ArrayValue **array; /*!< Cache array.*/ pthread_spinlock_t arrayMutex; /*!< Mutex for cache array.*/ pthread_spinlock_t entryMutex; /*!< Mutex for cache entries.*/ } FractalCache; /** * \fn int CreateFractalCache(FractalCache *cache, uint_least64_t size) * \brief Create fractal cache. * * In case of failure, cache is initialised with size = 0. * * \param cache Pointer to cache structure to initialize. * \param size Cache size (maximum number of entries). * \return 0 in case of success, 1 otherwise. */ int CreateFractalCache(FractalCache *cache, uint_least64_t size); /** * \fn int ResizeCacheThreadSafe(FractalCache *cache, uint_least64_t size) * \brief Resize cache (thread-safe). * * In case of failure, cache is left unchanged. * * \param cache Pointer to cache to resize. * \param size New cache size (maximum number of entries). * \return 0 in case of success, 1 otherwise. */ int ResizeCacheThreadSafe(FractalCache *cache, uint_least64_t size); /** * \fn void AddToCache(FractalCache *cache, CacheEntry entry) * \brief Add entry to cache. * * This function is not thread-safe (like most of the * functions in this library).\n * \see AddToCacheThreadSafe * * \param cache Pointer to cache. * \param entry Cache entry */ void AddToCache(FractalCache *cache, CacheEntry entry); /** * \fn void AddToCacheThreadSafe(FractalCache *cache, CacheEntry) * \brief Add entry to cache (thread-safe). * * This function is thread-safe (unlike most of the * functions in this library).\n * \see AddToCache * * \param cache Pointer to cache. * \param entry Cache entry. */ void AddToCacheThreadSafe(FractalCache *cache, CacheEntry entry); /** * \fn ArrayValue GetArrayValue(FractalCache *cache, uint_fast32_t x, uint_fast32_t y) * \brief Get value from cache array. * * The function does not check that (x,y) is within * cache array range (hence unspecified behaviour * otherwise). * * \param cache Pointer to cache structure. * \param x X coordinate. * \param y Y coordinate. * \return Array value at point (x,y). */ ArrayValue GetArrayValue(FractalCache *cache, uint_fast32_t x, uint_fast32_t y); /** * \fn int isArrayValueValid(ArrayValue aVal, FractalCache *cache) * \brief Check whether an array value is valid or not. * * If an array value is valid, it can be used to create * a preview of a fractal image.\n * An array value is valid if: * -its state is equal to cache current state * -its total weight is stricly greater than * DEFAULT_CACHE_WEIGHT_THRESHOLD * This "cache and value state" is a trick used to avoid * having to clear cache array before creating an * image preview. * * \param aVal Array value. * \param cache Pointer to cache structure. * \return 1 of value is valid, 0 otherwise. */ int isArrayValueValid(ArrayValue aVal, FractalCache *cache); /** * \fn Color GetColorFromAVal(ArrayValue aVal, const RenderingParameters *render) * \brief Get color from array value. * * Array value *must* be valid to get color from it.\n * \see isArrayValueValid * * \param aVal Array value. * \param render Rendering parameters to render color. * \return Corresponding color. */ Color GetColorFromAVal(ArrayValue aVal, const RenderingParameters *render); /** * \fn Task *CreateFractalCachePreviewTask(Image *dst, FractalCache *cache, const struct Fractal *fractal, const RenderingParameters *render, int fillImageOnTheFly, uint_fast32_t nbThreads) * \brief Create task generating an image preview from cache. * * The task generate an image preview AND updates the * cache array.\n * When the image is not filled on the fly, image begins * to be filled AFTER cache array has been updated.\n * When the image is filled on the fly, image is filled * while cache array is being filled.\n * The "on the fly" can be used to see image being filled * as soon as possible, but can be costlier. * * \param dst Destination image. * \param cache Cache. * \param fractal Fractal. * \param render Rendering parameters. * \param fillImageOnTheFly Indicates if the image should be filled on the fly. * \param nbThreads Number of threads that action will need to be launched. * \return Corresponding newly-allocated task. */ Task *CreateFractalCachePreviewTask(Image *dst, FractalCache *cache, const struct Fractal *fractal, const RenderingParameters *render, int fillImageOnTheFly, uint_fast32_t nbThreads); /** * \fn void FractalCachePreview(Image *dst, FractalCache *cache, const struct Fractal *fractal, const RenderingParameters *render, int fillImageOnTheFly, Threads *threads) * \brief Generate fractal image preview from cache (blocking). * * \see CreateFractalCachePreviewTask * * \param dst Destination image. * \param cache Cache. * \param fractal Fractal. * \param render Rendering parameters. * \param fillImageOnTheFly Indicates if the image should be filled on the fly. * \param threads Threads to be used for task. */ void FractalCachePreview(Image *dst, FractalCache *cache, const struct Fractal *fractal, const RenderingParameters *render, int fillImageOnTheFly, Threads *threads); /** * \fn void FreeFractalCache(FractalCache *cache) * \brief Free fractal cache. * * \param cache Pointer to cache structure to be free'd. */ void FreeFractalCache(FractalCache *cache); /** * \fn void FreeCacheEntry(CacheEntry entry) * \brief Free a cache entry. * * \param entry CacheEntry structure to be freed. */ void FreeCacheEntry(CacheEntry entry); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/filter.h0000664000175000017500000002204211754747533016173 0ustar mpegmpeg/* * filter.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file filter.h * \brief Header file related to image filters. * \author Marc Pegon * * Convolution filters are used to apply transformations on image, such * as gaussian blur. */ #ifndef __FILTER_H__ #define __FILTER_H__ #include "image.h" #include "thread.h" #include #ifdef __cplusplus extern "C" { #endif /** * \struct Filter * \brief Structure to represent an image filter. * * A filter is typically a matrix (kernel) with a center of application. */ /** * \typedef Filter * \brief Convenient typedef for struct Filter. */ typedef struct Filter { uint_fast32_t sx; /*!< Number of columns.*/ uint_fast32_t sy; /*!< Number of rows.*/ uint_fast32_t cx; /*!< X coordinate of filter's center.*/ uint_fast32_t cy; /*!< Y coordinate of filter's center.*/ double *data; /*!< Filter data (the elements of the matrix).*/ } Filter; /** * \fn void InitFilter(Filter *filter, uint_fast32_t sx, uint_fast32_t sy, uint_fast32_t cx, uint_fast32_t cy, double *data) * \brief Initialize filter. * * Data will be owned by filter, and freed when the filter is freed, * so it must have been dynamically allocated. * * \param filter Pointer to the filter structure to initialize. * \param sx Number of columns. * \param sy Number of lines. * \param cx X coordinate of filter's center. * \param cy Y coordinate of filter's center. * \param data Filter data (NOT copied, and will be freed when the filter is freed). */ void InitFilter(Filter *filter, uint_fast32_t sx, uint_fast32_t sy, uint_fast32_t cx, uint_fast32_t cy, double *data); /** * \fn void InitFilter2(Filter *filter, uint_fast32_t sx, uint_fast32_t sy, double *data) * \brief Initialize filter without specifying center. * * The center is automatically computed : ((sx-1)/2, (sy-1)/2).\n * Data will be owned by filter, and freed when the filter is freed, * so it must have been dynamically allocated. * * \param filter Pointer to the filter structure to initialize. * \param sx Number of columns. * \param sy Number of lines. * \param data Filter data (NOT copied, and will be freed when the filter is freed). */ void InitFilter2(Filter *filter, uint_fast32_t sx, uint_fast32_t sy, double *data); /** * \fn Filter CopyFilter(const Filter *filter) * \brief Copy filter. * * \param filter Pointer to filter to copy. * \return Copy of filter. */ Filter CopyFilter(const Filter *filter); /** * \fn void CreateHorizontalGaussianFilter(Filter *filter, double sigma) * \brief Create a horizontal gaussian filter given sigma. * * sigma must be strictly positive (exit with error otherwise). * * \param filter Pointer to the filter structure to initialize. * \param sigma See Wikipedia (or others) for that. */ void CreateHorizontalGaussianFilter(Filter *filter, double sigma); /** * \fn void CreateHorizontalGaussianFilter2(Filter *filter, double radius) * \brief Create a horizontal gaussian filter given its radius. * * radius must be strictly positive (exit with error otherwise). * * \param filter Pointer to the filter structure to initialize. * \param radius Blur radius. */ void CreateHorizontalGaussianFilter2(Filter *filter, double radius); /** * \fn void CreateVerticalGaussianFilter(Filter *filter, double sigma) * \brief Create a vertical gaussian filter given sigma. * * sigma must be strictly positive (exit with error otherwise). * * \param filter Pointer to the filter structure to initialize. * \param sigma See Wikipedia (or others) for that. */ void CreateVerticalGaussianFilter(Filter *filter, double sigma); /** * \fn void CreateVerticalGaussianFilter2(Filter *filter, double radius) * \brief Create a vertical gaussian filter given its radius. * * radius must be strictly positive (exit with error otherwise). * * \param filter Pointer to the filter structure to initialize. * \param radius Blur radius. */ void CreateVerticalGaussianFilter2(Filter *filter, double radius); /** * \fn void CreateGaussianFilter(Filter *filter, double sigma) * \brief Create a square gaussian filter given sigma. * * sigma must be strictly positive (exit with error otherwise).\n * Note that it is actually more efficient (computationally speaking) * to apply a horizontal and then vertical gaussian filter (or vice * versa), with the same sigma, than to apply a square gaussian * filter. * * \param filter Pointer to the filter structure to initialize. * \param sigma See Wikipedia (or others) for that. */ void CreateGaussianFilter(Filter *filter, double sigma); /** * \fn void CreateGaussianFilter2(Filter *filter, double radius) * \brief Create a square gaussian filter given its radius. * * radius must be strictly positive (exit with error otherwise).\n * Note that it is actually more efficient (computationally speaking) * to apply a horizontal and then vertical gaussian filter (or vice * versa), with the same radius, than to apply a square gaussian * filter. * * \param filter Pointer to the filter structure to initialize. * \param radius Blur Radius */ void CreateGaussianFilter2(Filter *filter, double radius); /** * \fn double GetFilterValueUnsafe(const Filter *filter, uint_fast32_t x, uint_fast32_t y) * \brief Get some particular value of filter. * * Get value of filter at row x, column y.\n * Warning: function does not check whether (x,y) is within * range or not (undefined behaviour otherwise). * * \param filter Filter we want to get some particular value. * \param x Row of the filter value. * \param y Column of the filter value. * \return Value at position (x,y) of filter. */ double GetFilterValueUnsafe(const Filter *filter, uint_fast32_t x, uint_fast32_t y); /** * \fn void MultiplyFilterByScalar(Filter *filter, double scalar) * \brief Multiply whole filter by scalar. * * Multiply each filter's value by a scalar. * * \param filter Filter to be modified. * \param scalar Scalar to multiply the filter by. */ void MultiplyFilterByScalar(Filter *filter, double scalar); /** * \fn int NormalizeFilter(Filter *filter) * \brief Normalize filter. * * Warning : some filters cannot be normalized (if the sum of * its values is equal to 0).\n * If the filter cannot be normalized, it will be left unchanged. * * \param filter Filter to normalize. * \return 1 if it cannot be normalized, 0 otherwise. */ int NormalizeFilter(Filter *filter); /** * \fn Color ApplyFilterOnSinglePixel(const Image *src, uint_fast32_t x, uint_fast32_t y, const Filter *filter) * \brief Apply a filter on a single pixel of an image. * * It is safe to pass (x,y) outside image.\n * Pixels outside of the image will be duplicates of the pixels * at the sides of it. * * \param src Image we apply the filter on. * \param x X coordinate of the pixel of the image we apply the filter on. * \param y Y coordinate of the pixel of the image we apply the filter on. * \param filter Filter we apply on the image. * @return Result of the application of the filter on pixel (x,y) of the image. */ Color ApplyFilterOnSinglePixel(const Image *src, uint_fast32_t x, uint_fast32_t y, const Filter *filter); /** * \fn void ApplyFilter(Image *dst, const Image *src, const Filter *filter, Threads *threads) * \brief Apply filter on image. * * This function does not work in place. * * \param dst Destination image. * \param src Source image. * \param filter Filter to apply. * \param threads Threads to be used for task. */ void ApplyFilter(Image *dst, const Image *src, const Filter *filter, Threads *threads); /** * \fn Task *CreateApplyFilterTask(Image *dst, const Image *src, const Filter *filter, uint_fast32_t nbThreads) * \brief Create task applying a filte on an image. * * Create task adapted to nbThreads threads, and return * immediately.\n * When launching task, Threads structure should provide * enough threads (at least number specified here). * * \param dst Destination image. * \param src Source image. * \param filter Filter to apply. * \param nbThreads Number of threads that action will need to be launched. * \return Corresponding newly-allocated task. */ Task *CreateApplyFilterTask(Image *dst, const Image *src, const Filter *filter, uint_fast32_t nbThreads); /** * \fn void FreeFilter(Filter filter) * \brief Free filter. * * \param filter Filter to be freed. */ void FreeFilter(Filter filter); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal_rendering_parameters.h0000664000175000017500000002021511754747533022602 0ustar mpegmpeg/* * fractal_rendering_parameters.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_rendering_parameters.h * \brief Header file related to rendering parameters. * \author Marc Pegon */ #ifndef __FRACTAL_RENDERING_PARAMETERS_H__ #define __FRACTAL_RENDERING_PARAMETERS_H__ #include "color.h" #include "gradient.h" #include "float_precision.h" #include "fractal_addend_function.h" #include "fractal_coloring.h" #include "fractal_iteration_count.h" #include "fractal_transfer_function.h" #include #ifdef __cplusplus extern "C" { #endif /** * \struct RenderingParameters * \brief Structure for handling fractal rendering parameters. */ /** * \typedef RenderingParameters * \brief Convenient typedef for struct RenderingParameters. */ typedef struct RenderingParameters { uint_fast8_t bytesPerComponent; /*!< Bytes per component matching gradient colors'.*/ Color spaceColor; /*!< Fractal space color.*/ IterationCount iterationCount; /*!< Fractal iteration count enum value.*/ ColoringMethod coloringMethod; /*!< Fractal coloring method.*/ AddendFunction addendFunction; /*!< Fractal addend function (used only for average coloring method).*/ uint_fast32_t stripeDensity; /*!< Stripe density (used only for AF_STRIPE addend function).*/ InterpolationMethod interpolationMethod; /*!< Fractal interpolation method (used only for average coloring method).*/ TransferFunction transferFunction; /*!< Fractal transfer function enum value (to make the values fit the gradient better).*/ TransferFunctionPtr transferFunctionPtr; /*!< Transfer function ptr.*/ double multiplier; /*!< Value with which fractal values will be multiplied (to make the values fit the gradient better).*/ double offset; /*!< Offset for mapping value to gradient.*/ Gradient gradient; /*!< Gradient for mapping float values to colors.*/ /* For internal use.*/ double realMultiplier; /*!< Real multiplier (scaled according to gradient size).*/ double realOffset; /*!< Real offset (scaled according to gradient size).*/ } RenderingParameters; /** * \fn void InitRenderingParameters(RenderingParameters *param, uint_fast8_t bytesPerComponent, Color spaceColor, IterationCount iterationCount, ColoringMethod coloringMethod, AddendFunction addendFunction, uint_fast32_t stripeDensity, InterpolationMethod interpolationMethod, TransferFunction transferFunction, double multiplier, double offset, Gradient gradient) * \brief Initialize rendering parameters. * * Bytes per component *must* agree with space color and gradient colors : * this is *not* checked by the function.\n * Gradient will be owned by rendering parameters, and free'd when * rendering parameters are free'd. * * \param param Pointer to structure to initialize. * \param bytesPerComponent Bytes per component for colors of rendering. * \param spaceColor The color for fractal space. * \param iterationCount Fractal iteration count. * \param coloringMethod Fractal coloring method. * \param addendFunction Fractal addend function (used only for average coloring method). * \param stripeDensity Stripe density (used only for AF_STRIPE addend function). * \param interpolationMethod Fractal interpolation method (used only for average coloring method). * \param transferFunction Fractal transfer function (to make the values fit the gradient better). * \param multiplier Value with which fractal values will be multiplied (to make the values fit the gradient better). * \param offset Offset for mapping value to gradient. * \param gradient Gradient for mapping float values to colors. */ void InitRenderingParameters(RenderingParameters *param, uint_fast8_t bytesPerComponent, Color spaceColor, IterationCount iterationCount, ColoringMethod coloringMethod, AddendFunction addendFunction, uint_fast32_t stripeDensity, InterpolationMethod interpolationMethod, TransferFunction transferFunction, double multiplier, double offset, Gradient gradient); /** * \fn RenderingParameters CopyRenderingParameters(const RenderingParameters *render) * \brief Copy rendering parameters. * * \param render Pointer to rendering parameters to copy. * \return Copy of rendering parameters. */ RenderingParameters CopyRenderingParameters(const RenderingParameters *param); /** * \fn void ResetGradient(RenderingParameters *param, Gradient gradient) * \brief Reset gradient. * * Gradient will be owned by rendering parameters, and will be free'd * when rendering parameters are free'd. * * \param param Rendering parameters to be changed. * \param gradient New Gradient. */ void ResetGradient(RenderingParameters *param, Gradient gradient); /** * \fn int isSupportedRenderingFile(const char *fileName) * \brief Check whether a file is a supported rendering file. * * \param fileName File name. * \return 1 if file is a supported rendering file, 0 otherwise. */ int isSupportedRenderingFile(const char *fileName); /** * \fn int ReadRenderingFileBody(RenderingParameters *param, const char *fileName, FILE *file, const char *format) * \brief Read fractal rendering parameters from rendering file body. * * The body of a rendering file is everything that comes after * the format version.\n * fileName is used only for error messages.\n * This function should only be used internally by the library. * * \param param Pointer to the rendering parameters structure to create. * \param fileName Rendering file name. * \param file Pointer to opened file, positioned at the beginning of the body. * \param format Rendering file format. * \return 0 in case of success, 1 in case of failure. */ int ReadRenderingFileBody(RenderingParameters *param, const char *fileName, FILE *file, const char *format); /** * \fn int ReadRenderingFile(RenderingParameters *param, const char *fileName) * \brief Read and parse fractal rendering parameters file. * * \param param Pointer to the structure to store rendering parameters. * \param fileName Rendering file name. * \return 0 in case of success, 1 in case of failure. */ int ReadRenderingFile(RenderingParameters *param, const char *fileName); /** * \fn int WriteRenderingFileBody(const RenderingParameters *param, const char *fileName, FILE *file, const char *format) * \brief Write rendering parameters into file. * * The body of a rendering file is everything that comes after * the format version.\n * fileName is used only for error messages.\n * This function should only be used internally by the library. * * \param param Rendering parameters to write. * \param fileName Rendering file name. * \param file Pointer to opened file, positioned at the beginning of the body. * \param format Rendering file format. * \return 0 in case of success, 1 in case of failure. */ int WriteRenderingFileBody(const RenderingParameters *param, const char *fileName, FILE *file, const char *format); /** * \fn int WriteRenderingFile(const RenderingParameters *param, const char *fileName) * \brief Write rendering parameters into file. * * \param param Rendering parameters to write. * \param fileName Rendering file name. * \return 0 in case of success, 1 in case of failure. */ int WriteRenderingFile(const RenderingParameters *param, const char *fileName); /** * \fn void FreeRenderingParameters(RenderingParameters param) * \brief Free a RenderingParameters structure. * * \param param RenderingParameters structure to be freed. */ void FreeRenderingParameters(RenderingParameters param); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/error.h0000664000175000017500000001274411754747533016047 0ustar mpegmpeg/* * error.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file error.h * \brief Header file containing error macros and stuff. * \author Marc Pegon */ #ifndef __ERROR_H__ #define __ERROR_H__ #include #include #ifdef __cplusplus extern "C" { #endif /** * \enum e_TraceLevel * \brief Trace level type. * * Users should understand the difference between application current * trace level, and messages trace levels.\n * Using FractalNow_message macro, a message is printed if and only * application current trace level is greater (>=) than message trace * level. * * For example : * - Messages with T_NORMAL trace level will be printed if application * current trace level is T_NORMAL or T_VERBOSE. * - Messages with T_VERBOSE trace level will be printed only if * application current trace level is T_VERBOSE. * * Note that error messages' trace level is T_QUIET, i.e. are always * printed, except when application current trace level is * T_QUIET_ERROR. */ /** * \typedef TraceLevel * \brief Convenient typedef for enum TraceLevel. */ typedef enum e_TraceLevel { T_QUIET_ERROR = 0, /*=) than message trace level. */ #define FractalNow_message(output, msg_trace,...) \ if (msg_trace <= FractalNow_traceLevel) { \ FractalNow_debug_prefix(output); \ fprintf(output, __VA_ARGS__); \ } #define FractalNow_errmsg(...) \ FractalNow_message(stderr, T_QUIET, __VA_ARGS__); #define FractalNow_error(...) \ FractalNow_errmsg(__VA_ARGS__);\ exit(EXIT_FAILURE) #define FractalNow_werror(...) \ FractalNow_message(stderr, T_QUIET, __VA_ARGS__);\ res = 1; \ goto end; // Common error messages #define alloc_error_msg(s) "Error occured when allocated memory for %s.\n", s #define existence_error_msg(fileName) "Error: \'%s\' does not exist.\n", fileName #define open_error_msg(fileName) "Error occured when opening file \'%s\'.\n", fileName #define read_error_msg(fileName) "Error occured when reading file \'%s\'.\n", fileName #define write_error_msg(fileName) "Error occured when writing in file \'%s\'.\n", fileName #define close_error_msg(fileName) "Error occured when closing file \'%s\'.\n", fileName #define FractalNow_alloc_errmsg(s) FractalNow_errmsg(alloc_error_msg(s)) #define FractalNow_existence_errmsg(fileName) FractalNow_errmsg(existence_error_msg(fileName)) #define FractalNow_open_errmsg(fileName) FractalNow_errmsg(open_error_msg(fileName)) #define FractalNow_read_errmsg(fileName) FractalNow_errmsg(read_error_msg(fileName)) #define FractalNow_write_errmsg(fileName) FractalNow_errmsg(write_error_msg(fileName)) #define FractalNow_close_errmsg(fileName) FractalNow_errmsg(close_error_msg(fileName)) // Common errors #define FractalNow_alloc_error(s) FractalNow_error(alloc_error_msg(s)) #define FractalNow_existence_error(fileName) FractalNow_error(existence_error_msg(fileName)) #define FractalNow_open_error(fileName) FractalNow_error(open_error_msg(fileName)) #define FractalNow_read_error(fileName) FractalNow_error(read_error_msg(fileName)) #define FractalNow_write_error(fileName) FractalNow_error(write_error_msg(fileName)) #define FractalNow_close_error(fileName) FractalNow_error(close_error_msg(fileName)) // Weak error #define FractalNow_alloc_werror(s) FractalNow_werror(alloc_error_msg(s)) #define FractalNow_existence_werror(fileName) FractalNow_werror(existence_error_msg(fileName)) #define FractalNow_open_werror(fileName) FractalNow_werror(open_error_msg(fileName)) #define FractalNow_read_werror(fileName) FractalNow_werror(read_error_msg(fileName)) #define FractalNow_write_werror(fileName) FractalNow_werror(write_error_msg(fileName)) #define FractalNow_close_werror(fileName) FractalNow_werror(close_error_msg(fileName)) #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/gradient.h0000664000175000017500000001767411754747533016522 0ustar mpegmpeg/* * gradient.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file gradient.h * \brief Header file related to gradients. * \author Marc Pegon */ #ifndef __GRADIENT_H__ #define __GRADIENT_H__ #include "color.h" #include #include #ifdef __cplusplus extern "C" { #endif /** * \def DEFAULT_GRADIENT_TRANSITIONS * \brief Default number of transitions between two colors used for gradient. */ #define DEFAULT_GRADIENT_TRANSITIONS (uint_fast32_t)(UINT16_MAX+1) /** * \def DEFAULT_GRADIENT_SIZE * \brief Default gradient size (total number of colors). */ #define DEFAULT_GRADIENT_SIZE (uint_fast32_t)(200000) /** * \struct Gradient * \brief Simple gradient structure. * * This structure is to represent a gradient, i.e. continous * transitions between colors. */ /** * \typedef Gradient * \brief Convenient typedef for struct Gradient. */ typedef struct Gradient { uint_fast8_t bytesPerComponent; /*!< Colors bytes per component.*/ uint_fast64_t size; /*!< Gradient size (total number of colors).*/ Color *data; /*!< Gradient data.*/ uint_fast32_t nbStops; /*!< Number of stops i.e. (pos,color) pairs used to build the gradient.*/ double *positionStop; /*!< Stops positions. */ Color *colorStop; /*!< Stops colors. */ } Gradient; /** * \fn void GenerateGradient(Gradient *gradient, uint_fast32_t nbStops, double *positionStop, Color *colorStop, uint_fast32_t size) * \brief Generate a gradient. * * Number of stops must be > 2 (exit program with error otherwise).\n * Position stops must begin with 0, end with 1, and be strictly * increasing (exit program with error otherwise).\n * Gradient size must be stricly positive (exit program with * error otherwise).\n * All the colors in given array must have the same number of bytes * per component (undefined behaviour otherwise). * * \param gradient Pointer to the (already allocated) gradient structure to initialize. * \param nbStops Number of stops (different colors) for gradient. * \param positionStop Position stops. * \param colorStop Color stops. * \param size Gradient size. */ void GenerateGradient(Gradient *gradient, uint_fast32_t nbStops, double *positionStop, Color *colorStop, uint_fast32_t size); /** * \fn void GenerateGradient2(Gradient *gradient, uint_fast32_t nbStops, Color *colorStop, uint_fast32_t nbTransitions) * \brief Generate a gradient. * * Generate a gradient from colors stops and the number of transitions * between two colors.\n * Number of stops must be > 2 (exit with error otherwise).\n * All the colors in given array must have the same number of bytes * per component (undefined behaviour otherwise).\n * Number of transitions must be strictly positive (exit program with * error otherwise). * * \param gradient Pointer to the (already allocated) gradient structure to initialize. * \param nbStops Number of stops (different colors) for gradient. * \param colorStop Color stops. * \param nbTransitions Number of transitions between two colors in the gradient. */ void GenerateGradient2(Gradient *gradient, uint_fast32_t nbStops, Color *colorStop, uint_fast32_t nbTransitions); /** * \fn int isSupportedGradientFile(const char *fileName) * \brief Check whether a file is a supported gradient file. * * \param fileName File name. * \return 1 if file is a supported gradient file, 0 otherwise. */ int isSupportedGradientFile(const char *fileName); /** * \fn int ReadGradientFileBody(Gradient *gradient, uint_fast8_t bytesPerComponent, const char *fileName, FILE *file, const char *format) * \brief Create gradient from gradient file body. * * The body of a gradient file is everything that comes after * the format version and the bytes per component.\n * fileName is used only for error messages.\n * This function should only be used internally by the library. * * \param gradient Pointer to the gradient structure to create. * \param bytesPerComponent Gradient file bytes per component (read from header). * \param fileName Gradient file name. * \param file Pointer to opened file, positioned at the beginning of the body. * \param format Gradient file format. * \return 0 in case of success, 1 in case of failure. */ int ReadGradientFileBody(Gradient *gradient, uint_fast8_t bytesPerComponent, const char *fileName, FILE *file, const char *format); /** * \fn int ReadGradientFile(Gradient *gradient, const char *fileName) * \brief Read and parse a gradient file, and create the according gradient. * * \param gradient Pointer to the gradient structure to create. * \param fileName Gradient file name. * \return 0 in case of success, 1 in case of failure. */ int ReadGradientFile(Gradient *gradient, const char *fileName); /** * \fn int WriteGradientFileBody(const Gradient *gradient, const char *fileName, FILE *file, const char *format) * \brief Write gradient file body. * * The body of a gradient file is everything that comes after * the format version and the bytes per component.\n * fileName is used only for error messages.\n * This function should only be used internally by the library. * * \param gradient Gradient to write into file. * \param fileName Gradient file name. * \param file Pointer to opened file, positioned at the beginning of the body. * \param format Gradient file format. * \return 0 in case of success, 1 in case of failure. */ int WriteGradientFileBody(const Gradient *gradient, const char *fileName, FILE *file, const char *format); /** * \fn int WriteGradientFile(const Gradient *gradient, const char *fileName) * \brief Write gradient into file. * * \param gradient Gradient to write into file. * \param fileName Gradient file name. * \return 0 in case of success, 1 in case of failure. */ int WriteGradientFile(const Gradient *gradient, const char *fileName); /** * \fn Gradient CopyGradient(const Gradient *gradient) * \brief Copy gradient. * * \param gradient Pointer to gradient to copy. * \return Copy of gradient. */ Gradient CopyGradient(const Gradient *gradient); /** * \fn Gradient Gradient16(const Gradient *gradient) * \brief Convert gradient to 16 bits gradient. * * Simple copy if gradient colors depth is already 16. * * \param gradient Pointer to gradient to be converted. * \return Newly-allocated 16 bits gradient. */ Gradient Gradient16(const Gradient *gradient); /** * \fn Gradient Gradient8(const Gradient *gradient) * \brief Convert gradient to 8 bits gradient. * * Simple copy if gradient colors depth is already 8. * * \param gradient Pointer to gradient to be converted. * \return Newly-allocated 8 bits gradient. */ Gradient Gradient8(const Gradient *gradient); /** * \fn Color GetGradientColor(const Gradient *gradient, uint_fast64_t index) * \brief Get a color in the gradient. * * Get the color in gradient at position index mod gradient_size * * \param gradient Pointer to the gradient to get the color from. * \param index (mod.) Index of the color to get. * \return Color in gradient at position (index mod gradient_size). */ Color GetGradientColor(const Gradient *gradient, uint_fast64_t index); /** * \fn void FreeGradient(Gradient gradient) * \brief Free gradient. * * \param gradient Gradient to be freed. */ void FreeGradient(Gradient gradient); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal_formula.h0000664000175000017500000002226511754747533020056 0ustar mpegmpeg/* * fractal_formula.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_formula.h * \brief Header file related to fractal formulas and loop iterations. * \author Marc Pegon */ #ifndef __FRACTAL_FORMULA_H__ #define __FRACTAL_FORMULA_H__ #include "float_precision.h" #include #include #ifdef __cplusplus extern "C" { #endif /** * \enum e_FractalFormula * \brief Fractal formula. */ /** * \typedef FractalFormula * \brief Convenient typedef for enum e_FractalFormula. */ typedef enum e_FractalFormula { FRAC_MANDELBROT = 0, /*!< Mandelbrot fractal.*/ FRAC_MULTIBROT, /*!< Mandelbrot type fractal with custom p parameter.*/ FRAC_JULIA, /*!< Julia fractal.*/ FRAC_MULTIJULIA, /*!< Julia type fractal with custom p parameter.*/ FRAC_BURNINGSHIP, /*!< Burning ship.*/ FRAC_JULIABURNINGSHIP, /*!< Julia burning ship.*/ FRAC_MANDELBAR, /*!< Mandelbar.*/ FRAC_JULIABAR, /*!< Juliabar.*/ FRAC_RUDY /*!< Rudy fractal (with custom p parameter).*/ } FractalFormula; /** * \var nbFractalFormulas * \brief Number of fractal formulas. */ extern const uint_fast32_t nbFractalFormulas; /** * \var fractalFormulaStr * \brief Strings of fractal formulas. */ extern const char *fractalFormulaStr[]; /** * \var fractalFormulaDescStr * \brief More descriptive strings for fractal formulas. */ extern const char *fractalFormulaDescStr[]; /** * \fn int GetFractalFormula(FractalFormula *fractalFormula, const char *str) * \brief Get fractal formula from string. * * Function is case insensitive. * Possible strings are : * - "mandelbrot" for FRAC_MANDELBROT * - "mandelbrotp" for FRAC_MULTIBROT * - "julia" for FRAC_JULIA * - "juliap" for FRAC_JULIAP * - "burningship" for FRAC_BURNINGSHIP * - "juliaburningship" for FRAC_JULIABURNINGSHIP * - "mandelbar" for FRAC_MANDELBAR * - "juliabar" for FRAC_JULIABAR * - "rudy" for FRAC_RUDY * * \param fractalFormula Fractal formula destination. * \param str String specifying fractal formula. * \return 0 in case of success, 1 in case of failure. */ int GetFractalFormula(FractalFormula *fractalFormula, const char *str); #define cpowPINT(fprec,res,x,y) cipowF(fprec,res,x,y) #define cpowPFLOATT(fprec,res,x,y) cpowF(fprec,res,x,y) #define cpowPTYPE(ptype,fprec,res,x,y) cpow##ptype(fprec,res,x,y) #define fractalP_PINT data->fractalP_INT #define fractalP_PFLOATT data->fractalP #define fractalP(ptype) fractalP_##ptype /*********************FRAC_MANDELBROT*********************/ #define ENGINE_DECL_VAR_FRAC_MANDELBROT(fprec) #define ENGINE_INIT_VAR_FRAC_MANDELBROT(fprec) \ (void)NULL; #define ENGINE_CLEAR_VAR_FRAC_MANDELBROT(fprec) \ (void)NULL; #define LOOP_INIT_FRAC_MANDELBROT(fprec) \ cfromUiF(fprec, data->z, 0);\ cassignF(fprec, data->c, data->pixel); #define LOOP_ITERATION_FRAC_MANDELBROT(ptype,fprec) \ csqrF(fprec,data->z,data->z);\ caddF(fprec,data->z,data->z,data->c); /*********************************************************/ /**********************FRAC_MULTIBROT*********************/ #define ENGINE_DECL_VAR_FRAC_MULTIBROT(fprec) #define ENGINE_INIT_VAR_FRAC_MULTIBROT(fprec) \ (void)NULL; #define ENGINE_CLEAR_VAR_FRAC_MULTIBROT(fprec) \ (void)NULL; #define LOOP_INIT_FRAC_MULTIBROT(fprec) \ cfromUiF(fprec, data->z, 0);\ cassignF(fprec, data->c, data->pixel); #define LOOP_ITERATION_FRAC_MULTIBROT(ptype,fprec) \ cpowPTYPE(ptype,fprec,data->z,data->z,fractalP(ptype));\ caddF(fprec,data->z,data->z,data->c); /*********************************************************/ /***********************FRAC_JULIA************************/ #define ENGINE_DECL_VAR_FRAC_JULIA(fprec) #define ENGINE_INIT_VAR_FRAC_JULIA(fprec) \ (void)NULL; #define ENGINE_CLEAR_VAR_FRAC_JULIA(fprec) \ (void)NULL; #define LOOP_INIT_FRAC_JULIA(fprec) \ cassignF(fprec, data->z, data->pixel);\ cassignF(fprec, data->c, data->fractalC); #define LOOP_ITERATION_FRAC_JULIA(ptype,fprec) \ csqrF(fprec,data->z,data->z);\ caddF(fprec,data->z,data->z,data->c); /*********************************************************/ /*********************FRAC_MULTIJULIA*********************/ #define ENGINE_DECL_VAR_FRAC_MULTIJULIA(fprec) #define ENGINE_INIT_VAR_FRAC_MULTIJULIA(fprec) \ (void)NULL; #define ENGINE_CLEAR_VAR_FRAC_MULTIJULIA(fprec) \ (void)NULL; #define LOOP_INIT_FRAC_MULTIJULIA(fprec) \ cassignF(fprec, data->z, data->pixel);\ cassignF(fprec, data->c, data->fractalC); #define LOOP_ITERATION_FRAC_MULTIJULIA(ptype,fprec) \ cpowPTYPE(ptype,fprec,data->z,data->z,fractalP(ptype));\ caddF(fprec,data->z,data->z,data->c); /*********************************************************/ /*********************FRAC_BURNINGSHIP********************/ #define ENGINE_DECL_VAR_FRAC_BURNINGSHIP(fprec) \ FLOATTYPE(fprec) absRealZ_FRAC;\ FLOATTYPE(fprec) absImagZ_FRAC; #define ENGINE_INIT_VAR_FRAC_BURNINGSHIP(fprec) \ initF(fprec, data->absRealZ_FRAC);\ initF(fprec, data->absImagZ_FRAC); #define ENGINE_CLEAR_VAR_FRAC_BURNINGSHIP(fprec) \ clearF(fprec, data->absRealZ_FRAC);\ clearF(fprec, data->absImagZ_FRAC); #define LOOP_INIT_FRAC_BURNINGSHIP(fprec) \ cfromUiF(fprec, data->z, 0);\ cassignF(fprec, data->c, data->pixel); #define LOOP_ITERATION_FRAC_BURNINGSHIP(ptype,fprec) \ crealF(fprec, data->absRealZ_FRAC, data->z);\ fabsF(fprec, data->absRealZ_FRAC, data->absRealZ_FRAC);\ cimagF(fprec, data->absImagZ_FRAC, data->z);\ fabsF(fprec, data->absImagZ_FRAC, data->absImagZ_FRAC);\ cfromReImF(fprec, data->z, data->absRealZ_FRAC, data->absImagZ_FRAC);\ cpowPTYPE(ptype,fprec,data->z,data->z,fractalP(ptype));\ caddF(fprec,data->z,data->z,data->c); /*********************************************************/ /*******************FRAC_JULIABURNINGSHIP******************/ #define ENGINE_DECL_VAR_FRAC_JULIABURNINGSHIP(fprec) \ FLOATTYPE(fprec) absRealZ_FRAC;\ FLOATTYPE(fprec) absImagZ_FRAC; #define ENGINE_INIT_VAR_FRAC_JULIABURNINGSHIP(fprec) \ initF(fprec, data->absRealZ_FRAC);\ initF(fprec, data->absImagZ_FRAC); #define ENGINE_CLEAR_VAR_FRAC_JULIABURNINGSHIP(fprec) \ clearF(fprec, data->absRealZ_FRAC);\ clearF(fprec, data->absImagZ_FRAC); #define LOOP_INIT_FRAC_JULIABURNINGSHIP(fprec) \ cassignF(fprec, data->z, data->pixel);\ cassignF(fprec, data->c, data->fractalC); #define LOOP_ITERATION_FRAC_JULIABURNINGSHIP(ptype,fprec) \ crealF(fprec, data->absRealZ_FRAC, data->z);\ fabsF(fprec, data->absRealZ_FRAC, data->absRealZ_FRAC);\ cimagF(fprec, data->absImagZ_FRAC, data->z);\ fabsF(fprec, data->absImagZ_FRAC, data->absImagZ_FRAC);\ cfromReImF(fprec, data->z, data->absRealZ_FRAC, data->absImagZ_FRAC);\ cpowPTYPE(ptype,fprec,data->z,data->z,fractalP(ptype));\ caddF(fprec,data->z,data->z,data->c); /*********************************************************/ /**********************FRAC_MANDELBAR*********************/ #define ENGINE_DECL_VAR_FRAC_MANDELBAR(fprec) #define ENGINE_INIT_VAR_FRAC_MANDELBAR(fprec) \ (void)NULL; #define ENGINE_CLEAR_VAR_FRAC_MANDELBAR(fprec) \ (void)NULL; #define LOOP_INIT_FRAC_MANDELBAR(fprec) \ cfromUiF(fprec, data->z, 0);\ cassignF(fprec, data->c, data->pixel); #define LOOP_ITERATION_FRAC_MANDELBAR(ptype,fprec) \ conjF(fprec, data->z, data->z);\ cpowPTYPE(ptype,fprec,data->z,data->z,fractalP(ptype));\ caddF(fprec,data->z,data->z,data->c); /*********************************************************/ /**********************FRAC_JULIABAR**********************/ #define ENGINE_DECL_VAR_FRAC_JULIABAR(fprec) #define ENGINE_INIT_VAR_FRAC_JULIABAR(fprec) \ (void)NULL; #define ENGINE_CLEAR_VAR_FRAC_JULIABAR(fprec) \ (void)NULL; #define LOOP_INIT_FRAC_JULIABAR(fprec) \ cassignF(fprec, data->z, data->pixel);\ cassignF(fprec, data->c, data->fractalC); #define LOOP_ITERATION_FRAC_JULIABAR(ptype,fprec) \ conjF(fprec, data->z, data->z);\ cpowPTYPE(ptype,fprec,data->z,data->z,fractalP(ptype));\ caddF(fprec,data->z,data->z,data->c); /*********************************************************/ /************************FRAC_RUDY************************/ #define ENGINE_DECL_VAR_FRAC_RUDY(fprec) \ COMPLEX_FLOATTYPE(fprec) cz_FRAC; #define ENGINE_INIT_VAR_FRAC_RUDY(fprec) \ cinitF(fprec, data->cz_FRAC); #define ENGINE_CLEAR_VAR_FRAC_RUDY(fprec) \ cclearF(fprec, data->cz_FRAC); #define LOOP_INIT_FRAC_RUDY(fprec) \ cfromUiF(fprec, data->z, 0);\ cassignF(fprec, data->c, data->pixel); #define LOOP_ITERATION_FRAC_RUDY(ptype,fprec) \ cmulF(fprec, data->cz_FRAC, data->fractalC, data->z);\ cpowPTYPE(ptype,fprec,data->z,data->z,fractalP(ptype));\ caddF(fprec,data->z,data->z,data->cz_FRAC);\ caddF(fprec,data->z,data->z,data->c);\ /*********************************************************/ #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal_iteration_count.h0000664000175000017500000001237711754747533021622 0ustar mpegmpeg/* * fractal_iteration_count.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_iteration_count.h * \brief Header file related to fractal iteration count. * \author Marc Pegon */ #ifndef __FRACTAL_ITERATION_COUNT_H__ #define __FRACTAL_ITERATION_COUNT_H__ #include "float_precision.h" #ifdef __cplusplus extern "C" { #endif /** * \enum e_IterationCount * \brief Possible iteration counts. * * There are different ways to "count" the number of iterations * when computing fractal :\n * it can be either simply the number of iterations itself (which * is discrete), or more advanced stuff like continuous or smooth * iteration count.\n */ /** * \typedef IterationCount * \brief Convenient typedef for enum e_IterationCount. */ typedef enum e_IterationCount { IC_DISCRETE = 0, /*res, data->n); /*********************************************************/ /**********************IC_CONTINUOUS**********************/ #define ENGINE_DECL_VAR_IC_CONTINUOUS(fprec) \ FLOATTYPE(fprec) escapeRadiusP_IC;\ FLOATTYPE(fprec) absZ_IC;\ FLOATTYPE(fprec) diff0_IC;\ FLOATTYPE(fprec) diff1_IC; #define ENGINE_INIT_VAR_IC_CONTINUOUS(fprec) \ initF(fprec, data->escapeRadiusP_IC);\ cabsF(fprec, data->escapeRadiusP_IC, data->fractalP);\ powF(fprec, data->escapeRadiusP_IC, data->escapeRadius, data->escapeRadiusP_IC);\ initF(fprec, data->absZ_IC);\ initF(fprec, data->diff0_IC);\ initF(fprec, data->diff1_IC); #define ENGINE_CLEAR_VAR_IC_CONTINUOUS(fprec) \ clearF(fprec, data->escapeRadiusP_IC);\ clearF(fprec, data->absZ_IC);\ clearF(fprec, data->diff0_IC);\ clearF(fprec, data->diff1_IC); #define COMPUTE_IC_CONTINUOUS(fprec) \ sqrtF(fprec, data->absZ_IC, data->normZ);\ subF(fprec, data->diff0_IC, data->escapeRadiusP_IC, data->escapeRadius);\ subF(fprec, data->diff1_IC, data->escapeRadiusP_IC, data->absZ_IC);\ divF(fprec, data->diff0_IC, data->diff1_IC, data->diff0_IC);\ add_uiF(fprec, data->res, data->diff0_IC, data->n); /*********************************************************/ /************************IC_SMOOTH************************/ #define ENGINE_DECL_VAR_IC_SMOOTH(fprec) \ FLOATTYPE(fprec) logAbsZ_IC;\ FLOATTYPE(fprec) logEscapeRadius_IC;\ FLOATTYPE(fprec) logAbsP_IC; #define ENGINE_INIT_VAR_IC_SMOOTH(fprec) \ initF(fprec, data->logAbsZ_IC);\ initF(fprec, data->logEscapeRadius_IC);\ logF(fprec, data->logEscapeRadius_IC, data->escapeRadius);\ initF(fprec, data->logAbsP_IC);\ cabsF(fprec, data->logAbsP_IC, data->fractalP);\ logF(fprec, data->logAbsP_IC, data->logAbsP_IC); #define ENGINE_CLEAR_VAR_IC_SMOOTH(fprec) \ clearF(fprec, data->logAbsZ_IC);\ clearF(fprec, data->logEscapeRadius_IC);\ clearF(fprec, data->logAbsP_IC); #define COMPUTE_IC_SMOOTH(fprec) \ logF(fprec, data->logAbsZ_IC, data->normZ);\ div_uiF(fprec, data->logAbsZ_IC, data->logAbsZ_IC, 2);\ divF(fprec, data->res, data->logEscapeRadius_IC, data->logAbsZ_IC);\ logF(fprec, data->res, data->res);\ divF(fprec, data->res, data->res, data->logAbsP_IC);\ add_uiF(fprec, data->res, data->res, data->n+1); /*********************************************************/ #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/file_io.h0000664000175000017500000001121311754747533016312 0ustar mpegmpeg/* * file_io.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file file_io.h * \brief Header file related to file IO. * \author Marc Pegon */ #ifndef __FILE_IO_H__ #define __FILE_IO_H__ #include "color.h" #include #include #include #ifdef __cplusplus extern "C" { #endif /** * \fn int readString(FILE *file, char *dst) * \brief Read string from file. * * \param file File from which to read string. * \param dst Destination string. * \return Number of elements successfully read or EOF (like fscanf). */ int readString(FILE *file, char *dst); /** * \fn int readUint32(FILE *file, uint32_t *dst) * \brief Read uint32 from file. * * \param file File from which to read uint32. * \param dst Destination uint32. * \return Number of elements successfully read or EOF (like fscanf). */ int readUint32(FILE *file, uint32_t *dst); /** * \fn int readDouble(FILE *file, double *dst) * \brief Read double from file. * * \param file File from which to read long double. * \param dst Destination double. * \return Number of elements successfully read or EOF (like fscanf). */ int readDouble(FILE *file, double *dst); /** * \fn int readMPFR(FILE *file, mpfr_t dst) * \brief Read mpfr_t from file. * * \param file File from which to read mpfr_t. * \param dst Destination mpfr_t. * \return Number of elements successfully read or EOF (like fscanf). */ int readMPFR(FILE *file, mpfr_t dst); /** * \fn int readColor(FILE *file, int_fast8_t bytesPerComponent, Color *dst) * \brief Read color from file as a hexadecimal number. * * Exit program with error if bytesPerComponent is not 1 or 2. * * \param file File from which to read color. * \param bytesPerComponent Bytes per component for color to read (either 1 for RGB8 or 2 for RGB16). * \param dst Destination color. * \return Number of elements successfully read or EOF (like fscanf). */ int readColor(FILE *file, int_fast8_t bytesPerComponent, Color *dst); /** * \fn int writeString(FILE *file, const char *src, const char *suffix) * \brief Write string into file. * * \param file File to write into. * \param src Source string. * \param suffix Suffix to add after source string. * \return Number of characters written, negative in case of error (like fprintf). */ int writeString(FILE *file, const char *src, const char *suffix); /** * \fn int writeUint32(FILE *file, uint32_t src, const char *suffix) * \brief Write uint32 into file. * * \param file File to write into. * \param src Source uint32. * \param suffix Suffix to add after uint32. * \return Number of characters written, negative in case of error (like fprintf). */ int writeUint32(FILE *file, uint32_t src, const char *suffix); /** * \fn int writeDouble(FILE *file, double src, const char *suffix) * \brief Write double into file. * * \param file File to write into. * \param src Source double. * \param suffix Suffix to add after double. * \return Number of characters written, negative in case of error (like fprintf). */ int writeDouble(FILE *file, double src, const char *suffix); /** * \fn int writeMPFR(FILE *file, mpfr_t src, const char *suffix) * \brief Write mpfr_t into file. * * \param file File to write into. * \param src Source mpfr_t. * \param suffix Suffix to add after mpfr_t. * \return Number of characters written, negative in case of error (like fprintf). */ int writeMPFR(FILE *file, const mpfr_t src, const char *suffix); /** * \fn int writeColor(FILE *file, Color src, const char *suffix) * \brief Write color into file as a hexadecimal number. * * Exit program with error if color bytesPerComponent is not 1 or 2. * \param file File to write into. * \param src Source color. * \param suffix Suffix to add after source color. * \return Number of characters written, negative in case of error (like fprintf). */ int writeColor(FILE *file, Color src, const char *suffix); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/image.h0000664000175000017500000002041711754747533015774 0ustar mpegmpeg/* * image.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file image.h * \brief Header file related to images. * \author Marc Pegon */ #ifndef __IMAGE_H__ #define __IMAGE_H__ #include "error.h" #include "color.h" #include "task.h" #include #ifdef __cplusplus extern "C" { #endif /** * \struct Image * \brief Simple RGB image. * * A 2D array of colors representing an image.\n * RGB8 images pixels are stored using uint32_t (the * most significant 8 bits are not used (0xFF)).\n * RGB16 images pixels are stored using uint64_t bytes (the * most significant 16 bites are not used (0xFFFF)). */ /** * \typedef Image * \brief Convenient typedef for struct Image. */ typedef struct Image { uint8_t *data; /*!< Imaga data : 32-bits aligned.*/ int data_is_external; /*!< 1 if data should not be freed by Image structure.*/ uint_fast32_t width; /*!< Image width.*/ uint_fast32_t height; /*!< Image height.*/ uint_fast8_t bytesPerComponent; /*!< Colors bytes per component.*/ } Image; /** * \fn void CreateImage(Image *image, uint_fast32_t width, uint_fast32_t height, uint_fast8_t bytesPerComponent) * \brief Create an image. * * Create a (black) image of given width and height. * * \param image Pointer to image structure to create. * \param width Image width. * \param height Image height. * \param bytesPerComponent Colors bytes per component. */ void CreateImage(Image *image, uint_fast32_t width, uint_fast32_t height, uint_fast8_t bytesPerComponent); /** * \fn void CreateImage2(Image *image, uint8_t *data, uint_fast32_t width, uint_fast32_t height, uint_fast8_t bytesPerComponent) * \brief Create an image using an already allocated data array. * * Data format must be as described in image structure.\n * Remark : in this case data will be *not* be free'd * by FreeImage, and must stay alive as long as image is * used. * * \param image Pointer to image structure to create. * \param data Image data to use for image. * \param width Image width. * \param height Image height. * \param bytesPerComponent Colors bytes per component. */ void CreateImage2(Image *image, uint8_t *data, uint_fast32_t width, uint_fast32_t height, uint_fast8_t bytesPerComponent); /** * \fn Image CloneImage(const Image *image) * \brief Copy image. * * \param image Pointer to image to be copied. * \return Copy of image. */ Image CloneImage(const Image *image); /** * \fn uint8_t *ImageToBytesArray(const Image *image) * \brief Convert image to bytes array. * * For RGB8 images : the returned bytes array is the sequence r1 g1 b1 r2 g2 b2, etc., * without padding (not 32-bits aligned).\n * For RGB16 images : the returned bytes array is the sequence r1h r1l g1h g1l * b1h b1l r2h r2b g2h g2l b2h b2l (h for high (MSB), and l for low (LSB)). * without padding (not 32-bits aligned). \n * Return NULL if image is empty (width and/or height = 0). * * Thus the array size (in bytes) is width*height*3*bytesPerComponent.\n * Convenient to write directly a binary PPM file for example. * * \param image Image to convert to bytes array. * \return Copy of image data. */ uint8_t *ImageToBytesArray(const Image *image); /** * \fn Color iGetPixelUnsafe(const Image *image, uint_fast32_t x, uint_fast32_t y) * \brief Get some pixel of image. * * Get pixel (x,y) of image.\n * Warning : the function does not check that (x,y) * is actually a point inside image. * * \param image Image to get pixel from. * \param x X pixel coordinate. * \param y Y pixel coordinate. * \return Color at position (x,y) of image. */ Color iGetPixelUnsafe(const Image *image, uint_fast32_t x, uint_fast32_t y); /** * \fn Color iGetPixel(const Image *image, int_fast64_t x, int_fast64_t y) * \brief Get some pixel of image. * * Get pixel (x,y) of image.\n * (x,y) can be a point outside image : pixels outside image * are duplicates of the pixels at the sides of it. * * \param image Image to get pixel from. * \param x X pixel coordinate. * \param y Y pixel coordinate. * \return Color at position (x,y) of image. */ Color iGetPixel(const Image *image, int_fast64_t x, int_fast64_t y); /** * \fn void PutPixelUnsafe(Image *image, uint_fast32_t x, uint_fast32_t y, Color color) * \brief Put pixel at some particular position in image. * * Put pixel at position (x,y) of image.\n * Warning : the function does not check that (x,y) * is actually a point inside image.\n * Color format must be the same as image format * (undefined behaviour otherwise). * * \param image Image to put pixel to. * \param x X pixel coordinate. * \param y Y pixel coordinate. * \param color Color to put at position (x,y) of image. */ void PutPixelUnsafe(Image *image, uint_fast32_t x, uint_fast32_t y, Color color); /** * \fn void ApplyGaussianBlur(Image *dst, const Image *src, double radius, Threads *threads) * \brief Apply gaussian blur on image. * * This function does no work in place.\n * Applies successively a horizontal and vertical gaussian filter * to avoid quadratic computation cost. * * \param dst Pointer to already created destination image. * \param src Pointer to source image (to apply blur on). * \param radius Gaussian blur radius. * \param threads Threads to be used for task. */ void ApplyGaussianBlur(Image *dst, const Image *src, double radius, Threads *threads); /** * \fn Task *CreateApplyGaussianBlurTask(Image *dst, Image *temp, const Image *src, double radius, uint_fast32_t nbThreads) * \brief Create task applying a gaussian blur. * * Create task and return immediately.\n * Number of threads is used to create a task adapted * to a specific number of threads.\n * When launching task, Threads structure should provide * enough threads (at least number specified here). * * \param dst Pointer to already created destination image. * \param temp Pointer to temporary image (needed to apply blur). * \param src Pointer to source image (to apply blur on). * \param radius Gaussian blur radius. * \param nbThreads Number of threads that action will need to be launched. * \return Corresponding newly-allocated task. */ Task *CreateApplyGaussianBlurTask(Image *dst, Image *temp, const Image *src, double radius, uint_fast32_t nbThreads); /** * \fn void DownscaleImage(Image *dst, const Image *src, Threads *threads) * \brief Downscale image. * * Destination image must already have been created, and its size * (both with and height) must be greater than that of the source * (exit with error otherwise). * * \param dst Pointer to already created destination image. * \param src Pointer to source image (to be downscaled). * \param threads Threads to be used for task. */ void DownscaleImage(Image *dst, const Image *src, Threads *threads); /** * \fn Task *CreateDownscaleImageTask(Image *dst, const Image *src, uint_fast32_t nbThreads) * \brief Create task downscaling an image. * * Create task and return immediately.\n * Number of threads is used to create a task adapted * to a specific number of threads.\n * When launching task, Threads structure should provide * enough threads (at least number specified here). * * \param dst Pointer to already created destination image. * \param src Pointer to source image (to be downscaled). * \param nbThreads Number of threads that action will need to be launched. * \return Corresponding (newly-allocated) task. */ Task *CreateDownscaleImageTask(Image *dst, const Image *src, uint_fast32_t nbThreads); /** * \fn void FreeImage(Image image) * \brief Free image. * * \param image Image to free. */ void FreeImage(Image image); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal_coloring.h0000664000175000017500000002617611754747533020232 0ustar mpegmpeg/* * fractal_coloring.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_coloring.h * \brief Header file related to fractal coloring. * * Contains coloring methods and interpolation. * * \author Marc Pegon */ #ifndef __FRACTAL_COLORING_H__ #define __FRACTAL_COLORING_H__ #include "float_precision.h" #include "fractal_addend_function.h" #include "fractal_iteration_count.h" #include #ifdef __cplusplus extern "C" { #endif /** * \enum e_ColoringMethod * \brief Possible coloring methods. * * For iteration count coloring method, fractal value (before applying transfer * function and multiplier) is simply the result of iteration count function.\n * For average sums coloring method, fractal value is computed by interpolation * function thanks to addend function and smooth iteration count. * * See addend function and interation count headers for more details. * \see fractal_addend_function.h * \see fractal_counting_function.h */ /** * \typedef ColoringMethod * \brief Convenient typedef for enum ColoringMethod. */ typedef enum e_ColoringMethod { CM_ITERATIONCOUNT = 0, /*SN_IM[0]);\ ENGINE_INIT_VAR_##addend(1,fprec) #define ENGINE_CLEAR_VAR_IM_NONE(addend,fprec) \ clearF(fprec, data->SN_IM[0]);\ ENGINE_CLEAR_VAR_##addend(1,fprec) #define LOOP_INIT_IM_NONE(addend,fprec) \ LOOP_INIT_##addend(1,fprec) #define LOOP_ITERATION_IM_NONE(addend,fprec) \ LOOP_ITERATION_##addend(1,fprec) #define LOOP_END_IM_NONE(addend,fprec) \ LOOP_END_##addend(1,fprec)\ assignF(fprec,data->res,data->SN_IM[0]); /*********************************************************/ /************************IM_LINEAR************************/ #define ENGINE_DECL_VAR_IM_LINEAR(addend,fprec) \ ENGINE_DECL_VAR_IC_SMOOTH(fprec)\ FLOATTYPE(fprec) tmp_IM;\ FLOATTYPE(fprec) SN_IM[2];\ ENGINE_DECL_VAR_##addend(2,fprec) #define ENGINE_INIT_VAR_IM_LINEAR(addend,fprec) \ ENGINE_INIT_VAR_IC_SMOOTH(fprec)\ initF(fprec, data->tmp_IM);\ initF(fprec, data->SN_IM[0]);\ initF(fprec, data->SN_IM[1]);\ ENGINE_INIT_VAR_##addend(2,fprec) #define ENGINE_CLEAR_VAR_IM_LINEAR(addend,fprec) \ ENGINE_CLEAR_VAR_IC_SMOOTH(fprec)\ clearF(fprec, data->tmp_IM);\ clearF(fprec, data->SN_IM[0]);\ clearF(fprec, data->SN_IM[1]);\ ENGINE_CLEAR_VAR_##addend(2,fprec) #define LOOP_INIT_IM_LINEAR(addend,fprec) \ LOOP_INIT_##addend(2,fprec) #define LOOP_ITERATION_IM_LINEAR(addend,fprec) \ LOOP_ITERATION_##addend(2,fprec) #define LOOP_END_IM_LINEAR(addend,fprec) \ LOOP_END_##addend(2,fprec)\ COMPUTE_IC_SMOOTH(fprec)\ modfF(fprec, data->tmp_IM, data->res, data->res);\ sub_uiF(fprec, data->tmp_IM, data->res, 1);\ mulF(fprec, data->tmp_IM, data->tmp_IM, data->SN_IM[1]);\ mulF(fprec, data->res, data->res, data->SN_IM[0]);\ subF(fprec, data->res, data->res, data->tmp_IM); /*********************************************************/ /************************IM_SPLINE************************/ #define ENGINE_DECL_VAR_IM_SPLINE(addend,fprec) \ ENGINE_DECL_VAR_IC_SMOOTH(fprec)\ FLOATTYPE(fprec) tmp_IM;\ FLOATTYPE(fprec) d1_IM;\ FLOATTYPE(fprec) d2_IM;\ FLOATTYPE(fprec) d3_IM;\ FLOATTYPE(fprec) s1_IM;\ FLOATTYPE(fprec) s2_IM;\ FLOATTYPE(fprec) s3_IM;\ FLOATTYPE(fprec) SN_IM[4];\ ENGINE_DECL_VAR_##addend(4,fprec) #define ENGINE_INIT_VAR_IM_SPLINE(addend,fprec) \ ENGINE_INIT_VAR_IC_SMOOTH(fprec)\ initF(fprec,data->tmp_IM);\ initF(fprec,data->d1_IM);\ initF(fprec,data->d2_IM);\ initF(fprec,data->d3_IM);\ initF(fprec,data->s1_IM);\ initF(fprec,data->s2_IM);\ initF(fprec,data->s3_IM);\ for (uint_fast32_t i = 0; i < 4; ++i) {\ initF(fprec,data->SN_IM[i]);\ }\ ENGINE_INIT_VAR_##addend(4,fprec) #define ENGINE_CLEAR_VAR_IM_SPLINE(addend,fprec) \ ENGINE_CLEAR_VAR_IC_SMOOTH(fprec)\ clearF(fprec,data->tmp_IM);\ clearF(fprec,data->d1_IM);\ clearF(fprec,data->d2_IM);\ clearF(fprec,data->d3_IM);\ clearF(fprec,data->s1_IM);\ clearF(fprec,data->s2_IM);\ clearF(fprec,data->s3_IM);\ for (uint_fast32_t i = 0; i < 4; ++i) {\ clearF(fprec,data->SN_IM[i]);\ }\ ENGINE_CLEAR_VAR_##addend(4,fprec) #define LOOP_INIT_IM_SPLINE(addend,fprec) \ LOOP_INIT_##addend(4,fprec) #define LOOP_ITERATION_IM_SPLINE(addend,fprec) \ LOOP_ITERATION_##addend(4,fprec) #define LOOP_END_IM_SPLINE(addend,fprec) \ LOOP_END_##addend(4,fprec)\ COMPUTE_IC_SMOOTH(fprec)\ modfF(fprec,data->tmp_IM,data->d1_IM,data->res);\ mulF(fprec,data->d2_IM,data->d1_IM,data->d1_IM);\ mulF(fprec,data->d3_IM,data->d1_IM,data->d2_IM);\ \ /* Compute s1 */\ mul_uiF(fprec,data->tmp_IM,data->d2_IM,4);\ addF(fprec,data->s1_IM,data->d1_IM,data->tmp_IM);\ mul_uiF(fprec,data->tmp_IM,data->d3_IM,3);\ subF(fprec,data->s1_IM,data->s1_IM,data->tmp_IM);\ mulF(fprec,data->s1_IM,data->s1_IM,data->SN_IM[1]);\ \ /* Compute s2 */\ mul_uiF(fprec,data->s2_IM,data->d3_IM,3);\ mul_uiF(fprec,data->tmp_IM,data->d2_IM,5);\ subF(fprec,data->s2_IM,data->s2_IM,data->tmp_IM);\ add_uiF(fprec,data->s2_IM,data->s2_IM,2);\ mulF(fprec,data->s2_IM,data->s2_IM,data->SN_IM[2]);\ \ /* Compute s3 */\ mul_uiF(fprec,data->s3_IM,data->d2_IM,2);\ subF(fprec,data->s3_IM,data->s3_IM,data->d1_IM);\ subF(fprec,data->s3_IM,data->s3_IM,data->d3_IM);\ mulF(fprec,data->s3_IM,data->s3_IM,data->SN_IM[3]);\ \ /* Compute res */\ subF(fprec,data->res,data->d3_IM,data->d2_IM);\ mulF(fprec,data->res,data->res,data->SN_IM[0]);\ addF(fprec,data->res,data->res,data->s1_IM);\ addF(fprec,data->res,data->res,data->s2_IM);\ addF(fprec,data->res,data->res,data->s3_IM);\ div_uiF(fprec,data->res,data->res,2); /*********************************************************/ #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/misc.h0000664000175000017500000001011211754747533015634 0ustar mpegmpeg/* * misc.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file misc.h * \brief Header file containing miscellaneous functions. * \author Marc Pegon */ #ifndef __MISC_H__ #define __MISC_H__ #include "float_precision.h" #include #include #ifdef __cplusplus extern "C" { #endif #ifndef complex #define complex _Complex #endif /** * \def UNUSED(x) * \brief Macro for unused variables. */ #define UNUSED(x) (void)x /** * \fn void toLowerCase(char *str) * \brief Convert string letter to lower case. * * str must be NULL-terminated (undefined behabiour * otherwise). * * \param str String to convert. */ void toLowerCase(char *str); /** * \fn void *safeMalloc(const char *name, uint_least64_t size) * \brief Safe memory allocation. * * Exit with error if memory allocation fails. * * \param name Name to print in case of allocation failure. * \param size Number of bytes to allocate. * \return Pointer to the allocated memory. */ void *safeMalloc(const char *name, uint_least64_t size); /** * \fn void *safeRealloc(const char *name, void *ptr, uint_least64_t size) * \brief Safe memory reallocation. * * Exit with error if memory reallocation fails. * * \param name Name to print in case of allocation failure. * \param ptr Pointer to memory to reallocate. * \param size Number of bytes to allocate. * \return Pointer to the allocated memory. */ void *safeRealloc(const char *name, void *ptr, uint_least64_t size); /** * \fn void void *safeCalloc(const char *name, uint_least64_t nmemb, uint_least64_t size) * \brief Safe memory allocation. * * Exit with error if memory allocation fails. * * \param name Name to print in case of allocation failure. * \param nmemb Number of elements in array to allocate. * \param size Size of each element in bytes. * \return Pointer to the allocated memory. */ void *safeCalloc(const char *name, uint_least64_t nmemb, uint_least64_t size); /** * \fn float complex cipowf(float complex x, uint_fast32_t y) * \brief Compute positive integer power of a complex float. * * \param x Complex float to be raised. * \param y Exponent. * \return x raised to the power y. */ float complex cipowf(float complex x, uint_fast32_t y); /** * \fn double complex cipow(double complex x, uint_fast32_t y) * \brief Compute positive integer power of a complex double. * * \param x Complex double to be raised to y. * \param y Exponent. * \return x raised to the power y. */ double complex cipow(double complex x, uint_fast32_t y); /** * \fn long double complex cipowl(long double complex x, uint_fast32_t y) * \brief Compute positive integer power of a complex long double. * * \param x Complex long double to be raised to y. * \param y Exponent. * \return x raised to the power y. */ long double complex cipowl(long double complex x, uint_fast32_t y); /** * \fn int complexIsInteger(long double complex x) * \brief Test if a long double complex is a (real) integer. * * \param x Complex to be tested. * \return 1 if complex is a (real) integer, 0 otherwise. */ int complexIsInteger(long double complex x); /** * \fn int mpcIsInteger(const mpc_t x) * \brief Test whether or not mpc complex is an integer. * * \param x mpc complex to test. * \return 1 is x is an integer, 0 instead. */ int mpcIsInteger(const mpc_t x); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal_config.h0000664000175000017500000001420311754747533017647 0ustar mpegmpeg/* * fractal_config.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_config.h * \brief Header file related to fractal configuration structure. * * A fractal configuration is the conjunction of a fractal and * rendering parameters. * A configuration file is more or less the concatenation of a fractal * file and a rendering file. */ #ifndef __FRACTAL_CONFIG_H__ #define __FRACTAL_CONFIG_H__ #include "fractal.h" #include "fractal_rendering_parameters.h" #include #ifdef __cplusplus extern "C" { #endif /** * \struct FractalConfig * \brief Structure containing fractal and fractal rendering parameters. */ /** * \typedef FractalConfig * \brief Convenient typedef for struct FractalConfig. */ typedef struct FractalConfig { Fractal fractal; /*!< Fractal.*/ RenderingParameters render; /*!< Rendering parameters.*/ } FractalConfig; /** * \fn void InitFractalConfig(FractalConfig *config, Fractal fractal, RenderingParameters render) * \brief Initialize fractal config. * * Fractal and rendering parameters will be owned by fractal config, * and will be free'd when fractal config is free'd. * * \param config Pointer to structure to initialize. * \param fractal Fractal * \param render Rendering parameters. */ void InitFractalConfig(FractalConfig *config, Fractal fractal, RenderingParameters render); /** * \fn FractalConfig CopyFractalConfig(const FractalConfig *config) * \brief Copy fractal configuration. * * \param config Pointer to fractal configuration to copy. * \return Copy of fractal configuration. */ FractalConfig CopyFractalConfig(const FractalConfig *config); /** * \fn void ResetFractal(FractalConfig *config, Fractal fractal) * \brief Reset fractal. * * Fractal will be owned by fractal config, and * will be free'd when fractal config is free'd. * * \param config Fractal config to be changed. * \param fractal New fractal. */ void ResetFractal(FractalConfig *config, Fractal fractal); /** * \fn void ResetRenderingParameters(FractalConfig *config, RenderingParameters render) * \brief Reset rendering parameters. * * RenderingParameters will be owned by fractal config, and * will be free'd when fractal config is free'd. * * \param config Fractal config to be changed. * \param render New rendering parameters. */ void ResetRenderingParameters(FractalConfig *config, RenderingParameters render); /** * \fn int isSupportedFractalConfigFile(const char *fileName) * \brief Check whether a file is a supported fractal configuration file. * * \param fileName File name. * \return 1 if file is a supported fractal config file, 0 otherwise. */ int isSupportedFractalConfigFile(const char *fileName); /** * \fn int ReadFractalConfigFileBody(FractalConfig *fractalConfig, const char *fileName, FILE *file, const char *format) * \brief Read fractal configuration from fractal configuration file body. * * The body of a configuration file is everything that comes * after the format version.\n * fileName is used only for error messages.\n * This function should only be used internally by the library. * * \param fractalConfig Pointer to the configuration file structure to create. * \param fileName Fractal configuration file name. * \param file Pointer to opened file, positioned at the beginning of the body. * \param format Fractal configuration file format. * \return 0 in case of success, 1 in case of failure. */ int ReadFractalConfigFileBody(FractalConfig *fractalConfig, const char *fileName, FILE *file, const char *format); /** * \fn int ReadFractalConfigFile(FractalConfig *fractalConfig, const char *fileName) * \brief Read and parse fractal configuration file. * * \param fractalConfig Pointer to the structure to store fractal configuration. * \param fileName Name of file containing fractal configuration. * \return 0 in case of success, 1 in case of failure. */ int ReadFractalConfigFile(FractalConfig *fractalConfig, const char *fileName); /** * \fn int WriteFractalConfigFileBody(const FractalConfig *fractalConfig, const char *fileName, FILE *file, const char *format) * \brief Write fractal configuration file body. * * The body of a configuration file is everything that comes * after the format version.\n * fileName is used only for error messages.\n * This function should only be used internally by the library. * * \param fractalConfig Fractal configuration to write. * \param fileName Fractal configuration file name. * \param file Pointer to opened file, positioned at the beginning of the body. * \param format Fractal configuration file format. * \return 0 in case of success, 1 in case of failure. */ int WriteFractalConfigFileBody(const FractalConfig *fractalConfig, const char *fileName, FILE *file, const char *format); /** * \fn int WriteFractalConfigFile(const FractalConfig *fractalConfig, const char *fileName) * \brief Write fractal configuration file. * * \param fractalConfig Fractal configuration file to write. * \param fileName Name of file containing fractal configuration. * \return 0 in case of success, 1 in case of failure. */ int WriteFractalConfigFile(const FractalConfig *fractalConfig, const char *fileName); /** * \fn void FreeFractalConfig(FractalConfig fractalConfig) * \brief Free a FractalConfig structure. * * \param fractalConfig FractalConfig structure to be freed. */ void FreeFractalConfig(FractalConfig fractalConfig); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/fractal_compute_engine.h0000664000175000017500000000770011754747533021407 0ustar mpegmpeg/* * fractal_compute_engine.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file fractal_compute_engine.h * \brief Header file related to fractal computation engines. * \author Marc Pegon */ #ifndef __FRACTAL_COMPUTE_ENGINE_H__ #define __FRACTAL_COMPUTE_ENGINE_H__ #include "float_precision.h" #include "fractal_addend_function.h" #include "fractal_cache.h" #include "fractal_coloring.h" #include "fractal_formula.h" #include "fractal_iteration_count.h" #include "fractal_rendering_parameters.h" #ifdef __cplusplus extern "C" { #endif struct Fractal; /** * \struct FractalEngine * \brief Engine to compute fractal engine (specific compiled loop and data). * * A FractalEngine structure contains a pointer to a function that computes * fractal for given parameters efficiently, as well as all the data it needs.\n * * The cache entry returned by fractal loop can be added to a cache, in which * case it will be free'd automatically (when new entries come, or when cache * is free'd), or just free'd if cache is disabled. */ /** * \typedef FractalEngine * \brief Convenient typedef for struct FractalEngine. */ typedef struct FractalEngine { CacheEntry (*fractalLoop)(void *data, const struct Fractal *fractal, const RenderingParameters *render, uint_fast32_t x, uint_fast32_t y, uint_fast32_t width, uint_fast32_t height); /*!< Fractal loop function.*/ void (*freeEngineData)(void *data); /*!< Function to free engine data.*/ void *data; /*!< Engine data (used by fractal loop).*/ } FractalEngine; /** * \fn void CreateFractalEngine(FractalEngine *engine, const struct Fractal *fractal, const RenderingParameters *render, FloatPrecision floatPrecision) * \brief Create fractal engine for given fractal, rendering parameters and float precision. * * \param engine Pointer to structure to be initialized. * \param fractal Fractal to be computed. * \param render Rendenring parameters. * \param floatPrecision Float precision. */ void CreateFractalEngine(FractalEngine *engine, const struct Fractal *fractal, const RenderingParameters *render, FloatPrecision floatPrecision); /** * \fn void FreeFractalEngine(FractalEngine *engine) * \brief Free fractal engine. * * \param engine Pointer to fractal structure to be free'd. */ void FreeFractalEngine(FractalEngine *engine); /** * \fn CacheEntry RunFractalEngine(const FractalEngine *engine, const struct Fractal *fractal, const RenderingParameters *render, uint_fast32_t x, uint_fast32_t y, uint_fast32_t width, uint_fast32_t height) * \brief Run fractal engine at given point. * * Compute pixel (x,y) of an image of size (width, height). * \see CacheEntry * * \param engine Fractal engine to be run. * \param fractal Fractal to be computed. * \param render Rendering parameters. * \param x Pixel X coordinate. * \param y Pixel Y coordinate. * \param width Image width. * \param height Image height. * \return Cache entry that can be added to cache or just used and free'd. */ CacheEntry RunFractalEngine(const FractalEngine *engine, const struct Fractal *fractal, const RenderingParameters *render, uint_fast32_t x, uint_fast32_t y, uint_fast32_t width, uint_fast32_t height); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/lib/include/macro_build_fractals.h0000664000175000017500000000521211754747533021045 0ustar mpegmpeg/* * macro_build_fractals.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file macro_build_fractals.h * \brief Header file related to macros for building fractal loop functions. * * \author Marc Pegon */ #ifndef __MACRO_BUILD_FRACTALS_H__ #define __MACRO_BUILD_FRACTALS_H__ #ifdef __cplusplus extern "C" { #endif #define FLOAT_PRECISIONS(x,y,z,t,u,v,w) MACRO_BUILD_FRACTAL(x,y,z,t,u,v,w) #define BUILD_FLOAT_PRECISIONS(x,y,z,t,u,v) \ FLOAT_PRECISIONS(x,y,z,t,u,v,SINGLE) \ FLOAT_PRECISIONS(x,y,z,t,u,v,DOUBLE) \ FLOAT_PRECISIONS(x,y,z,t,u,v,LDOUBLE) \ FLOAT_PRECISIONS(x,y,z,t,u,v,MP) #define INTERPOLATION_METHOD(x,y,z,t,u,v) BUILD_FLOAT_PRECISIONS(x,y,z,t,u,v) #define BUILD_INTERPOLATION_METHODS(x,y,z,t,u) \ INTERPOLATION_METHOD(x,y,z,t,u,NONE) \ INTERPOLATION_METHOD(x,y,z,t,u,LINEAR) \ INTERPOLATION_METHOD(x,y,z,t,u,SPLINE) #define ADDEND_FUNCTION(x,y,z,t,u) BUILD_INTERPOLATION_METHODS(x,y,z,t,u) #define BUILD_ADDEND_FUNCTIONS(x,y,z,t) \ ADDEND_FUNCTION(x,y,z,t,TRIANGLEINEQUALITY) \ ADDEND_FUNCTION(x,y,z,t,CURVATURE) \ ADDEND_FUNCTION(x,y,z,t,STRIPE) #define ITERATION_COUNT(x,y,z,t) BUILD_ADDEND_FUNCTIONS(x,y,z,t) #define BUILD_ITERATION_COUNTS(x,y,z) \ ITERATION_COUNT(x,y,z,DISCRETE)\ ITERATION_COUNT(x,y,z,CONTINUOUS)\ ITERATION_COUNT(x,y,z,SMOOTH) #define COLORING_METHOD(x,y,z) BUILD_ITERATION_COUNTS(x,y,z) #define BUILD_COLORING_METHODS(x,y) \ COLORING_METHOD(x,y,ITERATIONCOUNT) \ COLORING_METHOD(x,y,AVERAGECOLORING) #define P_TYPE(x,y) BUILD_COLORING_METHODS(x,y) #define BUILD_P_TYPES(x) \ P_TYPE(x,PINT) \ P_TYPE(x,PFLOATT) #define FORMULA(x) BUILD_P_TYPES(x) #define BUILD_FORMULAS \ FORMULA(MANDELBROT)\ FORMULA(MULTIBROT)\ FORMULA(JULIA)\ FORMULA(MULTIJULIA)\ FORMULA(BURNINGSHIP)\ FORMULA(JULIABURNINGSHIP)\ FORMULA(MANDELBAR)\ FORMULA(JULIABAR)\ FORMULA(RUDY) #define MACRO_BUILD_FRACTALS BUILD_FORMULAS #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/command-line/0000775000175000017500000000000011777336375014712 5ustar mpegmpegfractalnow-0.8.1/command-line/Makefile.configure0000664000175000017500000000274211754747533020334 0ustar mpegmpegBINDIR = bin FRACTALLIBDIR = ../lib SRCDIR = src INCLUDEDIR = include OBJDIR = objs TARGET = ${BINDIR}/${TARGET_NAME} DEPENDENCY_FILE=${OBJDIR}/makefile.dep CC = gcc LD = gcc CFLAGS = -std=c99 -pedantic -Wall -Wextra -D${SPINLOCK_DEFINE} ifdef DEBUG CFLAGS += -O0 -g -DDEBUG else CFLAGS += -O2 endif CFLAGS += -I${INCLUDEDIR} -I${FRACTALLIBDIR}/include LDFLAGS = ${STATIC_FLAG} -L${FRACTALLIBDIR}/bin -l${FRACTAL2D_LIB} -lmpc -lmpfr -lgmp -lm -lpthread OBJECTS = \ $(OBJDIR)/anti_aliasing.o \ $(OBJDIR)/command_line.o \ $(OBJDIR)/help.o \ $(OBJDIR)/main.o all : $(OBJDIR) ${BINDIR} ${DEPENDENCY_FILE} $(TARGET) ${DEPENDENCY_FILE}: $(OBJDIR) ${SRCDIR}/*.c ${INCLUDEDIR}/*.h $(call quiet-command,for i in ${SRCDIR}/*.c; do ${CC} ${CFLAGS} -MM "$${i}"; done | sed "s/\(^.*:\)/${OBJDIR}\/\1/" > $@," BUILDING DEPENDENCY DATABASE"); -include ${DEPENDENCY_FILE} $(TARGET): $(OBJECTS) $(call quiet-command, $(LD) -o $@ $^ $(LDFLAGS), " LD $@") $(OBJDIR): $(call quiet-command, mkdir -p $(OBJDIR),) $(BINDIR): $(call quiet-command, mkdir -p $(BINDIR),) $(OBJDIR)/%.o:${SRCDIR}/%.c ${CC} ${CFLAGS} -c $< -o $@ clean: $(call quiet-command, rm -f ${DEPENDENCY_FILE}, " CLEAN (DEPENDENCY DATABASE)") $(call quiet-command, rm -f $(OBJECTS) , " CLEAN (OBJECTS)") distclean: clean $(call quiet-command, rm -rf $(OBJDIR), " CLEAN (OBJDIR)") $(call quiet-command, rm -rf $(BINDIR), " CLEAN (BINDIR)") fractalnow-0.8.1/command-line/src/0000775000175000017500000000000011777357367015505 5ustar mpegmpegfractalnow-0.8.1/command-line/src/help.c0000664000175000017500000000700311777357367016601 0ustar mpegmpeg/* * help.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "help.h" #include "fractalnow.h" #include #include #include void DisplayHelp() { printf("fractalnow v%s - Generate fractal pictures (raw \ PPM format).\n\n\ Usage : fractalnow -h\n\ or\n\ fractalnow [OPTIONS] -c [-x |-y ] -o \ \n\ or\n\ fractalnow [OPTIONS] -f -r [-x \ |-y ] -o \n\ \n\ OPTIONS:\n" #ifdef DEBUG " -d Debug mode.\n" #endif " -j Specify number of threads \ (%"PRIuFAST32" by default).\n\ -g Specify gradient file, overriding \ gradient from configuration/rendering file.\n\ -x Specify output image width.\n\ -y Specify output image height.\n\ -l Specify float type:\n\ single Single precision.\n\ double Double precision.\n\ ldouble Long double \ precision.\n\ mp Multiple \ precision.\n\ -L Specify precision for Multiple \ Precision (MP) floats (%ld by default).\n\ -a Specify anti-aliasing method:\n\ none By default.\n\ blur Gaussian blur.\n\ oversampling\n\ adaptive Smart oversampling.\ \n\ -s Specify size for anti-aliasing:\n\ Radius for blur (values in \ [2.5, 4] are generally good).\n\ Scale factor for oversampling ([3\ , 5] is good for a high quality image).\n\ Scale factor for adaptive (\ integers between 3-5 are good for a high quality image).\n\ -p Threshold for adaptive \ anti-aliasing (%.*lf by default).\n\ -i Maximum size of quadrilaterals for \ linear interpolation.\n\ %"PRIuFAST32" by default, which is \ good for no visible loss of quality.\n\ 1 means no interpolation (all \ pixels are computed).\n\ -t Dissimilarity threshold for quad \ interpolation.\n\ %.*lf by default, which is \ good for no visible loss of quality.\n\ A quadrilateral that shows too \ dissimilar values at its corners will be computed, \ as opposed to interpolated.\n", FractalNow_VersionNumber(), DEFAULT_NB_THREADS, (long int)DEFAULT_MPFR_PRECISION, DBL_DIG, DEFAULT_ADAPTIVE_AAM_THRESHOLD, DEFAULT_QUAD_INTERPOLATION_SIZE, DBL_DIG, DEFAULT_COLOR_DISSIMILARITY_THRESHOLD); } fractalnow-0.8.1/command-line/src/main.c0000664000175000017500000001144511754747533016573 0ustar mpegmpeg/* * main.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "anti_aliasing.h" #include "command_line.h" #include "fractalnow.h" #include #include #include #include #include int main(int argc, char *argv[]) { setlocale(LC_NUMERIC, "C"); CommandLineArguments arg; ParseCommandLineArguments(&arg, argc, argv); fractalnow_mpfr_precision = arg.MPFloatPrecision; mpfr_set_default_prec(fractalnow_mpfr_precision); FractalConfig fractalConfig; if (arg.fractalConfigFileName != NULL) { if (ReadFractalConfigFile(&fractalConfig, arg.fractalConfigFileName)) { FractalNow_error("Failed to read config file.\n"); } } if (arg.fractalFileName != NULL) { Fractal fractal; if (ReadFractalFile(&fractal, arg.fractalFileName)) { FractalNow_error("Failed to read fractal file.\n"); } if (arg.fractalConfigFileName == NULL) { fractalConfig.fractal = CopyFractal(&fractal); } else { ResetFractal(&fractalConfig, fractal); } FreeFractal(fractal); } if (arg.renderingFileName != NULL) { RenderingParameters render; if (ReadRenderingFile(&render, arg.renderingFileName)) { FractalNow_error("Failed to read rendering file.\n"); } if (arg.fractalConfigFileName == NULL) { fractalConfig.render = CopyRenderingParameters(&render); } else { ResetRenderingParameters(&fractalConfig, render); } FreeRenderingParameters(render); } if (arg.gradientFileName != NULL) { Gradient gradient; if (ReadGradientFile(&gradient, arg.gradientFileName)) { FractalNow_error("Failed to read gradient file.\n"); } ResetGradient(&fractalConfig.render, gradient); FreeGradient(gradient); } Fractal fractal = fractalConfig.fractal; RenderingParameters render = fractalConfig.render; uint_fast32_t width = arg.width; uint_fast32_t height = arg.height; if (width == 0) { mpfr_t dwidth; mpfr_init(dwidth); mpfr_mul_ui(dwidth, fractal.spanX, height, MPFR_RNDN); mpfr_div(dwidth, dwidth, fractal.spanY, MPFR_RNDN); width = roundl(mpfr_get_d(dwidth, MPFR_RNDN)); mpfr_clear(dwidth); } else if (height == 0) { mpfr_t dheight; mpfr_init(dheight); mpfr_mul_ui(dheight, fractal.spanY, width, MPFR_RNDN); mpfr_div(dheight, dheight, fractal.spanX, MPFR_RNDN); height = roundl(mpfr_get_d(dheight, MPFR_RNDN)); mpfr_clear(dheight); } Threads *threads = CreateThreads((arg.nbThreads <= 0) ? DEFAULT_NB_THREADS : (uint_fast32_t)arg.nbThreads); Image fractalImg, tmpImg; CreateImage(&fractalImg, width, height, render.bytesPerComponent); switch (arg.antiAliasingMethod) { case AAM_NONE: DrawFractal(&fractalImg, &fractal, &render, arg.quadInterpolationSize, arg.colorDissimilarityThreshold, arg.floatPrecision, NULL, threads); break; case AAM_GAUSSIANBLUR: CreateImage(&tmpImg, width, height, render.bytesPerComponent); DrawFractal(&tmpImg, &fractal, &render, arg.quadInterpolationSize, arg.colorDissimilarityThreshold, arg.floatPrecision, NULL, threads); ApplyGaussianBlur(&fractalImg, &tmpImg, arg.antiAliasingSize, threads); FreeImage(tmpImg); break; case AAM_OVERSAMPLING: CreateImage(&tmpImg, width*arg.antiAliasingSize, height*arg.antiAliasingSize, render.bytesPerComponent); DrawFractal(&tmpImg, &fractal, &render, arg.quadInterpolationSize, arg.colorDissimilarityThreshold, arg.floatPrecision, NULL, threads); DownscaleImage(&fractalImg, &tmpImg, threads); FreeImage(tmpImg); break; case AAM_ADAPTIVE: DrawFractal(&fractalImg, &fractal, &render, arg.quadInterpolationSize, arg.colorDissimilarityThreshold, arg.floatPrecision, NULL, threads); AntiAliaseFractal(&fractalImg, &fractal, &render, arg.antiAliasingSize, arg.adaptiveAAMThreshold, arg.floatPrecision, NULL, threads); break; default: FractalNow_error("Unknown anti-aliasing method.\n"); break; } if (ExportPPM(arg.dstFileName, &fractalImg)) { FractalNow_error("Failed to export image as PPM.\n"); } FreeFractalConfig(fractalConfig); FreeImage(fractalImg); DestroyThreads(threads); FractalNow_message(stdout, T_NORMAL, "All done.\n"); exit(EXIT_SUCCESS); } fractalnow-0.8.1/command-line/src/command_line.c0000664000175000017500000002040511754747533020270 0ustar mpegmpeg/* * command_line.c -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "command_line.h" #include "help.h" #include "fractalnow.h" #include #include #include int FileExists(const char *fileName) { FILE *file; int res = 0; if ((file = fopen(fileName,"r")) != NULL) { res = 1; fclose(file); } return res; } void ParseCommandLineArguments(CommandLineArguments *dst, int argc, char *argv[]) { FractalNow_traceLevel = T_NORMAL; FractalNow_debug = 0; int help = 0; dst->quadInterpolationSize = DEFAULT_QUAD_INTERPOLATION_SIZE; dst->colorDissimilarityThreshold = DEFAULT_COLOR_DISSIMILARITY_THRESHOLD; int64_t tmp; dst->fractalConfigFileName = NULL; dst->fractalFileName = NULL; dst->renderingFileName = NULL; dst->gradientFileName = NULL; dst->dstFileName = NULL; dst->antiAliasingMethod = AAM_NONE; dst->antiAliasingSize = -1; dst->adaptiveAAMThreshold = -1; dst->nbThreads = -1; dst->floatPrecision = FP_DOUBLE; dst->MPFloatPrecision = fractalnow_mpfr_precision; int widthSpecified = 0, heightSpecified = 0; dst->width = 0; dst->height = 0; int o; while ((o = getopt(argc, argv, "hqvda:c:f:g:i:j:l:L:o:p:r:s:t:x:y:")) != -1) { switch (o) { case 'h': help = 1; break; case 'q': if (FractalNow_traceLevel == T_VERBOSE) { invalid_use_error("-q and -v are mutually exclusive.\n"); } FractalNow_traceLevel = T_QUIET; break; case 'v': if (FractalNow_traceLevel == T_QUIET) { invalid_use_error("-q and -v are mutually exclusive.\n"); } FractalNow_traceLevel = T_VERBOSE; break; case 'd': #ifndef DEBUG FractalNow_message(stdout, T_QUIET, "Debug unavailable: FractalNow was not built in \ debug mode.\n"); #else FractalNow_debug = 1; #endif break; case 'a': dst->antiAliasingMethod = GetAAM(optarg); break; case 'c': dst->fractalConfigFileName = optarg; break; case 'f': dst->fractalFileName = optarg; break; case 'r': dst->renderingFileName = optarg; break; case 'g': dst->gradientFileName = optarg; break; case 'l': if (GetFloatPrecision(&dst->floatPrecision, optarg)) { invalid_use_error("\n"); } break; case 'L': if (sscanf(optarg, "%"SCNd64, &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n", optarg); } if (tmp < MPFR_PREC_MIN || tmp > MPFR_PREC_MAX) { invalid_use_error("MP floats precision must be between %ld and %ld.\n", (long int)MPFR_PREC_MIN, (long int)MPFR_PREC_MAX); } else { dst->MPFloatPrecision = (mpfr_prec_t)tmp; } break; case 'i': if (sscanf(optarg, "%"SCNd64, &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n", optarg); } if (tmp <= 0) { invalid_use_error("Quad interpolation size must be positive.\n"); } else { dst->quadInterpolationSize = (uint_fast32_t)tmp; } break; case 'j': if (sscanf(optarg, "%d", &dst->nbThreads) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n", optarg); } if (dst->nbThreads <= 0) { invalid_use_error("Number of threads must be positive.\n"); } break; case 'o': dst->dstFileName = optarg; break; case 'p': if (sscanf(optarg, "%lf", &dst->adaptiveAAMThreshold) < 1) { invalid_use_error("Command-line argument \'%s\' is not a floating-point number.\n", optarg); } if (dst->adaptiveAAMThreshold < 0.) { invalid_use_error("Adaptive anti-aliasing threshold must be >= 0.\n"); } break; case 's': if (sscanf(optarg, "%lf", &dst->antiAliasingSize) < 1) { invalid_use_error("Command-line argument \'%s\' is not a floating-point number.\n", optarg); } break; case 't': if (sscanf(optarg, "%lf", &dst->colorDissimilarityThreshold) < 1) { invalid_use_error("Command-line argument \'%s\' is not a floating-point number.\n", optarg); } if (dst->colorDissimilarityThreshold < 0.) { invalid_use_error("Quad dissimilarity threshold must be between >= 0.\n"); } break; case 'x': if (sscanf(optarg, "%"SCNd64, &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n", optarg); } if (tmp < 2) { invalid_use_error("Output image width must be >= 2.\n"); } else { dst->width = (uint_fast32_t)tmp; widthSpecified = 1; } break; case 'y': if (sscanf(optarg, "%"SCNd64, &tmp) < 1) { invalid_use_error("Command-line argument \'%s\' is not a number.\n", optarg); } if (tmp < 2) { invalid_use_error("Output image height must be >= 2.\n"); } else { dst->height = (uint_fast32_t)tmp; heightSpecified = 1; } break; default: DisplayHelp(); exit(EXIT_FAILURE); break; } } if (argv[optind] != NULL) { invalid_use_error("Remaining argument on command line : '%s'.\n", argv[optind]); } if (help) { DisplayHelp(); exit(EXIT_SUCCESS); } if (dst->fractalConfigFileName == NULL) { if (dst->fractalFileName == NULL) { invalid_use_error("No configuration or fractal file specified.\n"); } if (dst->renderingFileName == NULL) { invalid_use_error("No configuration or rendering file specified.\n"); } } if (dst->dstFileName == NULL) { invalid_use_error("No output file specified.\n"); } if (!widthSpecified && !heightSpecified) { invalid_use_error("At least width or height must be specified.\n"); } switch (dst->antiAliasingMethod) { case AAM_NONE: if (dst->antiAliasingSize != -1) { invalid_use_error("No size parameter ('-s') should be specified when \ anti-aliasing is disabled.\n"); } break; case AAM_GAUSSIANBLUR: if (dst->antiAliasingSize == -1) { invalid_use_error("No size parameter ('-s') specified for blur.\n"); } if (dst->antiAliasingSize <= 0) { invalid_use_error("Size parameter ('-s') for gaussian blur must be > 0.\n"); } if (dst->adaptiveAAMThreshold != -1) { invalid_use_error("No adaptive anti-aliasing threshold ('-p') should be \ specified when anti-aliasing method is blur.\n"); } break; case AAM_OVERSAMPLING: if (dst->antiAliasingSize == -1) { invalid_use_error("No size parameter ('-s') specified for oversampling.\n"); } if (dst->antiAliasingSize <= 1.) { invalid_use_error("Size parameter ('-s') for oversampling must be > 1.\n"); } if (dst->adaptiveAAMThreshold != -1) { invalid_use_error("No adaptive anti-aliasing threshold ('-p') should be \ specified when anti-aliasing method is oversampling.\n"); } break; case AAM_ADAPTIVE: if (dst->antiAliasingSize == -1) { invalid_use_error("No size parameter ('-s') specified for adaptive \ anti-aliasing.\n"); } if (!complexIsInteger(dst->antiAliasingSize)) { invalid_use_error("Size parameter ('-s') for adaptive anti-aliasing \ should be an integer.\n"); } if (dst->antiAliasingSize <= 1.) { invalid_use_error("Size parameter ('-s') for adaptive anti-aliasing \ must be > 1.\n"); } if (dst->adaptiveAAMThreshold == -1) { dst->adaptiveAAMThreshold = DEFAULT_ADAPTIVE_AAM_THRESHOLD; } break; default: invalid_use_error("Unknown anti-aliasing method.\n"); break; } if (dst->fractalConfigFileName != NULL && !FileExists(dst->fractalConfigFileName)) { FractalNow_existence_error(dst->fractalConfigFileName); } if (dst->fractalFileName != NULL && !FileExists(dst->fractalFileName)) { FractalNow_existence_error(dst->fractalFileName); } if (dst->renderingFileName != NULL && !FileExists(dst->renderingFileName)) { FractalNow_existence_error(dst->renderingFileName); } if (dst->gradientFileName != NULL && !FileExists(dst->gradientFileName)) { FractalNow_existence_error(dst->gradientFileName); } } fractalnow-0.8.1/command-line/src/anti_aliasing.c0000664000175000017500000000346411754747533020453 0ustar mpegmpeg/* * anti_aliasing.c -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "anti_aliasing.h" #include "fractalnow.h" #include #include const char *AntiAliasingMethodStr[] = { (char *)"none", (char *)"blur", (char *)"oversampling", (char *)"adaptive" }; const char *AntiAliasingMethodDescStr[] = { (char *)"None", (char *)"Gaussian blur", (char *)"Oversampling", (char *)"Adaptive" }; uint_fast32_t nbAntiAliasingMethods = sizeof(AntiAliasingMethodStr) / sizeof(char *); AntiAliasingMethod GetAAM(const char *str) { int len = strlen(str); if (len > 255) { FractalNow_error("Unknown anti-aliasing method \'%s\'.\n", str); } char AAMStr[256]; strcpy(AAMStr, str); toLowerCase(AAMStr); AntiAliasingMethod res = (AntiAliasingMethod)0; uint_fast32_t i; for (i = 0; i < nbAntiAliasingMethods; ++i) { if (strcmp(AAMStr, AntiAliasingMethodStr[i]) == 0) { res = (AntiAliasingMethod)i; break; } } if (i == nbAntiAliasingMethods) { FractalNow_error("Unknown anti-aliasing method \'%s\'.\n", str); } return res; } fractalnow-0.8.1/command-line/include/0000775000175000017500000000000011754747533016332 5ustar mpegmpegfractalnow-0.8.1/command-line/include/help.h0000664000175000017500000000227511754747533017441 0ustar mpegmpeg/* * help.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __HELP_H__ #define __HELP_H__ #include "fractalnow.h" #include #ifdef __cplusplus extern "C" { #endif /** * \fn void DisplayHelp() * \brief Display program help. */ void DisplayHelp(); #define invalid_use_error(...) \ FractalNow_message(stderr, T_QUIET, __VA_ARGS__);\ DisplayHelp(); \ exit(EXIT_FAILURE) #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/command-line/include/command_line.h0000664000175000017500000000564211754747533021137 0ustar mpegmpeg/* * command_line.h -- part of FractalNow * * Copyright (c) 2011 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file command_line.h * \brief Header file related to command line parsing. * \author Marc Pegon */ #ifndef __COMMAND_LINE_H__ #define __COMMAND_LINE_H__ #include "anti_aliasing.h" #include "fractalnow.h" #include #ifdef __cplusplus extern "C" { #endif /** * \struct CommandLineArguments * \brief For storing command lines arguments. * * This structure is to store the arguments given on the command line. */ /** * \typedef CommandLineArguments * \brief Convenient typedef for struct CommandLineArguments. */ typedef struct CommandLineArguments { char *fractalConfigFileName; /*!< Fractal Config file name.*/ char *fractalFileName; /*!< Fractal file name.*/ char *renderingFileName; /*!< Rendering file name.*/ char *gradientFileName; /*!< Gradient file name.*/ char *dstFileName; /*!< Output image file name.*/ uint_fast32_t width; /*!< Width of output float table/image.*/ uint_fast32_t height; /*!< Height of output float table/image.*/ uint_fast32_t quadInterpolationSize; /*!< Maximum size of quadrilaterals for interpolation.*/ int nbThreads; /*!< Number of threads. Negative if not specified. */ double colorDissimilarityThreshold; /*!< Dissimilarity threshold for interpolation.*/ AntiAliasingMethod antiAliasingMethod; /*!< Anti-aliasing method.*/ double antiAliasingSize; /*!< Size for anti-aliasing (radius for blur, factor for oversampling and adaptive).*/ double adaptiveAAMThreshold; /*!< Threshold used when anti-aliasing method is adaptive.*/ FloatPrecision floatPrecision; /*!< Float precision.*/ mpfr_prec_t MPFloatPrecision; /*!< Precision (value) of Multiple Precision floats.*/ } CommandLineArguments; /** * \fn void ParseCommandLineArguments(CommandLineArguments *dst, int argc, char *argv[]) * \brief Parse arguments given on command line. * * \param dst Pointer to the (already allocated) structure in which to store the arguments. * \param argc Argc of the main function * \param argv Argv of the main function */ void ParseCommandLineArguments(CommandLineArguments *dst, int argc, char *argv[]); #ifdef __cplusplus } #endif #endif fractalnow-0.8.1/command-line/include/anti_aliasing.h0000664000175000017500000000474711754747533021321 0ustar mpegmpeg/* * anti_aliasing.h -- part of FractalNow * * Copyright (c) 2012 Marc Pegon * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * \file anti_aliasing.h * \brief Header file related to anti-aliasing methods. * \author Marc Pegon */ #ifndef __ANTI_ALIASING_H__ #define __ANTI_ALIASING_H__ #include #ifdef __cplusplus extern "C" { #endif /** * \enum e_AntiAliasingMethod * \brief Possible anti-aliasing methods. */ /** * \typedef AntiAliasingMethod * \brief Convenient typedef for enum e_AntiAliasingMethod. */ typedef enum e_AntiAliasingMethod { AAM_NONE = 0, /*!< No anti-aliasing.*/ AAM_GAUSSIANBLUR, /*!< Gaussian Blur.*/ AAM_OVERSAMPLING, /*!< Over sampling (compute a bigger image and scale it down).*/ AAM_ADAPTIVE /*!< Adaptive (compute more than one value for some pixels).*/ } AntiAliasingMethod; /** * \var nbAntiAliasingMethods * \brief Number of anti-aliasing methods. */ extern uint_fast32_t nbAntiAliasingMethods; /** * \var AntiAliasingMethodStr * \brief Strings of anti-aliasing method enum values. */ extern const char *AntiAliasingMethodStr[]; /** * \var AntiAliasingMethodDescStr * \brief More descriptive strings for anti-aliasing methods. */ extern const char *AntiAliasingMethodDescStr[]; /** * \fn AntiAliasingMethod GetAAM(const char *str) * \brief Get anti-aliasing method from string. * * Function is case insensitive. * Possible strings are : * - "none" for AAM_NONE * - "blur" for AAM_GAUSSIANBLUR * - "oversampling" for AAM_OVERSAMPLING * - "adaptive" for AAM_ADAPTIVE * Exit with error in case of failure. * * \param str String specifying anti-aliasing method. * \return Corresponding anti-aliasing method, or AAM_UNKNOWN in case of failure. */ AntiAliasingMethod GetAAM(const char *str); #ifdef __cplusplus } #endif #endif