pax_global_header00006660000000000000000000000064136022332170014511gustar00rootroot0000000000000052 comment=17357211a16394884a981fe0c062f94250b40300 haskell-mode-17.1/000077500000000000000000000000001360223321700140065ustar00rootroot00000000000000haskell-mode-17.1/.gitignore000066400000000000000000000001261360223321700157750ustar00rootroot00000000000000*.elc *~ haskell-mode-autoloads.el haskell-mode.info haskell-mode.tmp.texi dir build-*haskell-mode-17.1/.travis.yml000066400000000000000000000015341360223321700161220ustar00rootroot00000000000000language: nix env: - EMACS_CI=emacs-25-1 TARGET=check - EMACS_CI=emacs-25-2 TARGET=check - EMACS_CI=emacs-25-3 TARGET=check - EMACS_CI=emacs-26-1 TARGET=check - EMACS_CI=emacs-26-2 TARGET=check - EMACS_CI=emacs-26-3 TARGET=check - EMACS_CI=emacs-snapshot TARGET=check - EMACS_CI=emacs-26-3 TARGET=deploy-manual - EMACS_CI=emacs-26-3 TARGET=check-external matrix: allow_failures: - env: EMACS_CI=emacs-snapshot TARGET=check install: | sh <(curl https://get.haskellstack.org/) bash <(curl https://raw.githubusercontent.com/purcell/nix-emacs-ci/master/travis-install) if [ "$TARGET" = "deploy-manual" ]; then nix-env -iA texinfo -f '' fi script: | make $TARGET notifications: email: false irc: "irc.freenode.org#haskell-emacs" # Local Variables: # indent-tabs-mode: nil # coding: utf-8 # End: haskell-mode-17.1/CONTRIBUTING.md000066400000000000000000000015561360223321700162460ustar00rootroot00000000000000# Welcome nice stranger! Haskell Mode loves contributors and we strive to go extra length to help out both newcomers and serial contributors. Haskell Mode project is managed according to rules outlined in the wiki: https://github.com/haskell/haskell-mode/wiki/Contributing > When I started contributing to haskell-mode I had 0 experience in Elisp, but it was super easy to learn it. > -- [geraldus, 2016-01-16](https://github.com/haskell/haskell-mode/issues/1086#issuecomment-172177949) # Hacking on Haskell Mode To try out your changes to Haskell Mode without affecting your global Emacs installation, build Haskell Mode by running `make` here, and then run emacs -L from any directory you'd like to test in. This makes Emacs load Haskell Mode from this Git repo, instead of using any globally installed version you might have. haskell-mode-17.1/COPYING000066400000000000000000001045131360223321700150450ustar00rootroot00000000000000 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 . haskell-mode-17.1/Makefile000066400000000000000000000122441360223321700154510ustar00rootroot00000000000000# # Note: Due to MELPA distributing directly from github source version # needs to be embedded in files as is without preprocessing. # # Version string is present in: # - Makefile # - haskell-mode.el # - haskell-mode.texi # # We should have a script that changes it everywhere it is needed and # syncs it with current git tag. # VERSION = 17.1 INSTALL_INFO = install-info # Use $EMACS environment variable if present, so that all of these are # equivalent: # # 1. export EMACS=/path/to/emacs && make # 2. EMACS=/path/to/emacs make # 3. make EMACS=/path/to/emacs # # This is particularly useful when EMACS is set in ~/.bash_profile # EMACS ?= emacs EMACS_VERSION := $(shell "$(EMACS)" -Q --batch --eval '(princ emacs-version)') EFLAGS = --eval "(when (boundp 'load-prefer-newer) (setq load-prefer-newer t))" BATCH = @echo EMACS $@; "$(EMACS)" $(EFLAGS) --batch -Q -L . ELFILES := $(filter-out haskell-mode-autoloads.el haskell-mode-pkg.el,$(wildcard *.el)) ELCHECKS := $(wildcard tests/*-tests.el) AUTOLOADS = haskell-mode-autoloads.el PKG_DIST_FILES = $(ELFILES) logo.svg NEWS haskell-mode.info dir .PHONY: all compile info clean check check-emacs-version all: check-emacs-version compile $(AUTOLOADS) info check-emacs-version : $(BATCH) --eval "(when (version< emacs-version \"25.1\") \ (message \"Error: haskell-mode requires Emacs 25.1 or later\") \ (message \"Your version of Emacs is %s\" emacs-version) \ (message \"Found as '$(EMACS)'\") \ (message \"Use one of:\") \ (message \" 1. export EMACS=/path/to/emacs && make\") \ (message \" 2. EMACS=/path/to/emacs make\") \ (message \" 3. make EMACS=/path/to/emacs\") \ (kill-emacs 2))" @echo Using EMACS = $(EMACS), version = $(EMACS_VERSION) compile: build-$(EMACS_VERSION)/build-flag build-$(EMACS_VERSION) : mkdir $@ # Emacs byte compilation state leaks from file to file if multiple # files are requested to be build at the same time. We have to # workaround this issue on Makefile level. Note also that we consider # an .el file to be dependent on all other files because we do not do # proper dependency tracking (yet). build-$(EMACS_VERSION)/%.elc : %.el $(ELFILES) $(BATCH) --eval '(setq byte-compile-error-on-warn t)' \ --eval "(setq byte-compile-dest-file-function (lambda (filename) \ (concat (file-name-directory filename) \"build-\" emacs-version \"/\" \ (file-name-nondirectory filename) \"c\")))" \ --eval "(when (check-declare-file \"$<\") (kill-emacs 2))" \ -f batch-byte-compile $< \ build-$(EMACS_VERSION)/build-flag : build-$(EMACS_VERSION) $(patsubst %.el,build-$(EMACS_VERSION)/%.elc,$(ELFILES)) touch $@ check-%: tests/%-tests.el $(BATCH) -l "$<" -f ert-run-tests-batch-and-exit; check: compile $(AUTOLOADS) check-ert check-ert: $(ELCHECKS) $(BATCH) -L tests \ $(patsubst %,-l %,$(ELCHECKS)) \ -f ert-run-tests-batch-and-exit @echo "checks passed!" clean: $(RM) -r build-$(EMACS_VERSION) $(AUTOLOADS) $(AUTOLOADS:.el=.elc) haskell-mode.info dir info: haskell-mode.info dir dir: haskell-mode.info $(INSTALL_INFO) --dir=$@ $< haskell-mode.info: doc/haskell-mode.texi LANG=en_US.UTF-8 $(MAKEINFO) $(MAKEINFO_FLAGS) -o $@ $< doc/haskell-mode.html: doc/haskell-mode.texi doc/haskell-mode.css LANG=en_US.UTF-8 $(MAKEINFO) $(MAKEINFO_FLAGS) --html --css-include=doc/haskell-mode.css --no-split -o $@ $< $(BATCH) -l doc/haskell-manual-fixups.el -f haskell-manual-fixups-batch-and-exit $@ doc/html/index.html : doc/haskell-mode.texi if [ -e doc/html ]; then rm -r doc/html; fi mkdir doc/html cp -r doc/anim doc/html/anim LANG=en_US.UTF-8 $(MAKEINFO) $(MAKEINFO_FLAGS) --html \ --css-ref=haskell-mode.css \ -c AFTER_BODY_OPEN='
' \ -c EXTRA_HEAD='' \ -c SHOW_TITLE=0 \ -o doc/html $< $(BATCH) -l doc/haskell-manual-fixups.el -f haskell-manual-fixups-batch-and-exit doc/html/*.html doc/html/haskell-mode.css : doc/haskell-mode.css doc/html/index.html cp $< $@ doc/html/haskell-mode.svg : images/haskell-mode.svg doc/html/index.html cp $< $@ doc/html/haskell-mode-32x32.png : images/haskell-mode-32x32.png doc/html/index.html cp $< $@ doc/html : doc/html/index.html \ doc/html/haskell-mode.css \ doc/html/haskell-mode.svg \ doc/html/haskell-mode-32x32.png deploy-manual : doc/html cd doc && ./deploy-manual.sh $(AUTOLOADS): $(ELFILES) $(BATCH) \ --eval '(setq make-backup-files nil)' \ --eval "(setq generated-autoload-file (concat command-line-default-directory \"/\" \"$@\"))" \ -f batch-update-autoloads "." # check if autoloads will really load $(BATCH) -l "$@" check-external : check-emacs-version $(AUTOLOADS) $(BATCH) -l tests/haskell-external.el \ -f haskell-check-external-batch-and-exit @echo "external packages okay" haskell-mode-17.1/NEWS000066400000000000000000000457761360223321700145300ustar00rootroot00000000000000Haskell Mode NEWS -*- org -*- This file uses Org mode. Some useful (default) key-bindings: - Use "C-c C-n"/"C-c C-p" to jump to next/prev heading - Use "" to expand/collapse nodes - Use "" to cycle visibility of all nodes - Use "C-c C-o" to open links * Changes in 17.1 - Require at least Emacs 25.1 - Many fixes and minor improvements - Improved compatibility with newer GHC and Cabal versions * Changes in 16.1 - Require at least Emacs 24.3 - Implemented standalone deriving indentation - Removed haskell-indentation-ifte-offset - Implemented electric characters - Added LiquidHaskell annotation highlight - Introduced haskell-hasktags-path defcustom - Added font lock tests for pattern synonyms - Hardcoded haskell-ghc-supported-extensions/options - Added multi-line input in haskell-interactive - Added haskell-mode-stylish-haskell-path - Added Windows CI builds - Added syntax highlight to Yesod rules quasi quote - Added support for line continuation in #define's - Added support unterminated strings in indentation - Implemented /italic/ and *bold* for haddock - Added significant speedups in font-lock engine - Added support for full complexity of backtick syntax - Operators at the end or beginning of line force expression continuation in indentation - Map haskell-mode-format-imports to C-c C-, to avoid conflict with haskell-indent - Improve auto add dependencies in cabal - Fix inferior-haskell warning font lock for GHC 8.0 * Changes in 13.20 - Require at least Emacs 24.1 - Honor equals on its own line in data decl - Honor equals on separate line after guards - Allow haskell-process-path-* to be lists - Fontify True/False in cabal mode - Align | with = in data declarations - Remove haskell-package.el - Run stylish-haskell before save - Improved lexeme parsing in haskell-lexeme - Add haskell-interactive-copy-to-prompt - Remove haskell-mode-contextual-space and related var - Make haskell-indent-region do nothing - Add c2hs mode - Improve hasktags handling - Move documentation from wiki to haskell-mode manual * Changes in 13.18 - Removed haskell-bot - Implement shallow indentation - Removed haskell-simple-indent - Removed haskell-indentation show dynamic positions - Improved indentation inside multiline strings - Implemented font-lock for quasi quoted XML, HTML and JavaScript - Added '{type|data} family' to font-lock-keywords-create - Started using undercover.el for emacs lisp coverage - Added keybinding for `haskell-cabal-visit-file` - Added type role to font lock - Detect and respect the comma style of a section in cabal files * Changes in 13.16 - Improved parsing of comma lists in haskell indentation - Declared turn-on-haskell-indentation as obsolete - Improved QuasiQuote font lock - Fixed indentation for Unicode symbols - Improved completion engine - Added support for interaction with stack ghci - Added haskell-forward-sexp - Added overlays to haskell load - Made use of lexical binding for all emacs lisp sources - Improved indentation of guards with commas - Made three indentation modes mutually turn each other off - Added an additional trigger for pragma suggestions - Improved and documented `toggle-scc-at-point` in manual * Changes in 13.14 - Add official Haskell Mode logo - Add auto deploy for html manual - Improve presentation mode - Font Lock refactoring and improvements - Properly delimit operators in prettify mode - OPTIONS and LANGUAGE completion using ghci - Merge hi2 (haskell-indentation attempt 2) in place of haskell-indentation - Prompt to reconfigure when Cabal demands it - Fontify pragmas while fontifying comments - Operators are fontified - Remove all mentions of cabal-dev - Merge hsc-mode into haskell-mode - Get type information from ghci in interaction-mode - Prettify Haskell types in eldoc support - Added haskell-hoogle-url - Fix w3m-haddock in the case of no local files * Changes in 13.12 - Added haskell-bot.el - Added support for cabal repl build targets - Automatically add import lines via Hoogle - Automatically add package to cabal file - Added w3m-haddock.el - Added debugger mode - Added preliminary :present support - Added haskell-sort-imports - Added haskell-complete-module - Support if and multi-way if in indentation - Add support to generate tags on windows - Add haskell-language-extensions variable - Improve haskell-simple-indent mode - Improve test cases * Changes in 13.10 - Small fix for haskell-simple-indent: Certain indentation situations cause valname-string to be nil, which haskell-trim did not handle gracefully (naturally, since nil != ""). - Luke Hoersten's Shnippet merged in under snippets/. - haskell-presentation-mode is now a haskell-mode derived mode. - Small improvement to haskell-process-do-info (works on constructors now and underscored names). - Add haskell-indent-spaces configuration variable. - The command string to run cabal commands is slightly more configurable. See: C-h f haskell-process-do-cabal-format-string * Changes in 13.8 See also [[https://github.com/haskell/haskell-mode/compare/v13.07...v13.08][detailed Git history]]. - Make `haskell-simple-indent-mode' a proper minor mode with `SInd` as mode-line lighter - Support popular "λ> " prompt in inf-haskell by default - Hide internal `*print-haskell-mode*' buffers (used when `haskell-interactive-mode-eval-mode' is active) - Add tab-completion support for haskell-interactive-mode (requires `:complete' command support in GHCi) - Add support to `haskell-process-do-info` to perform `:browse!` query on module name when called on import statement line - `haskell-decl-scan-mode': - New customize group `haskell-decl-scan' - New flag `haskell-decl-scan-bindings-as-variables' for controlling whether to put value bindings into the "Variables" category. - New flag `haskell-decl-scan-add-to-menubar' for controlling whether to add "Declarations" menu entry to menu bar. - New manual section node `(haskell-mode)haskell-decl-scan-mode' - Add support for [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#lambda-case][LambdaCase]] syntax extension to `haskell-indentation` - Change `haskell-indentation-mode' to never jump back a whole line when pressing DEL. The old behavior can be restored by setting `haskell-indentation-delete-backward-jump-line' to t - New convenience function `haskell-cabal-visit-file' for locating and visiting most likely `.cabal` file associated with current buffer - Add support for [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#package-import][PackageImports]] and [[http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#safe-imports-ext][SafeHaskell]] syntax extensions to `haskell-decl-scan-mode' parser - Add `turn-{on,off}-haskell-doc' commands as aliases for the existing `turn-{on,off}-haskell-doc-mode' commands - Add support for "cabal repl" process type to `haskell-interactive-mode' - Add new Haskell compilation sub-mode and associated `haskell-compile' command * Changes in 13.7 See also [[https://github.com/haskell/haskell-mode/compare/v13.06...v13.07][detailed Git history]]. - Convert NEWS (this file) to Org mode style and include NEWS file in package and add command for visiting NEWS file (M-x haskell-mode-view-news) - Officially drop support for versions prior to Emacs 23 - New work-in-progress Info manual for haskell-mode - Remove deprecated `haskell-{hugs,ghci}' modules - Font-locking changes: - Remove deprecated `turn-on-haskell-font-lock` function - Improve font-locking of type-signatures in presence of newlines - Use `font-lock-preprocessor-face' instead of the previously used `font-lock-warning-face` for CPP directives - Use `font-lock-warning-face` instead of the previously used `font-lock-preprocessor-face` for Git merge conflict annotations. - Improvements to `haskell-move-nested' module: - Add support for operating on active regions - New interactive commands `haskell-move-nested-{left,right}` which support numeric prefix arguments for controlling the amount of shifting to apply. - Add `haskell-unicode-input-method.el` to distribution (enable with `turn-on-haskell-unicode-input-method`) - Fix all byte-compilation warnings - Build-system: - For in-place installation, `haskell-site-file.el' is renamed to `haskell-mode-autoloads.el` - Auto-generate ELPA compatible README file by extracting header of haskell-mode.el - New "make check" target - Add Travis-CI build jobs for testing byte-compilation with multiple Emacs versions - Reorganize customize settings - Add new convenience function for browsing all Haskell Mode settings (M-x haskell-customize) - Add `:link' keywords pointing to the new Info manual - Add `:group' keywords to modes to make (M-x customize-mode) work - Create new customization groups `haskell-interactive' and `inferior-haskell' to clean up namespace - Create new customization group `ghc-core` containing the two new customization variables `ghc-core-program` and `ghc-core-program-args`. - Improvements to haskell-interactive-mode - Add support for deleting compile messages superseded by recompile/reloads (M-x customize-variable RET haskell-interactive-mode-delete-superseded-errors) - Fix `C-u M-x haskell-process-do-type` inserting bad signatures - Integrate with Emacs' `next-error` subsystem - Add "C-c C-f" binding to REPL keymap for enabling `next-error-follow-minor-mode' - Add support for `-ferror-spans`-style compile messages - Add `-ferror-spans` as default for `haskell-process-args-ghci` - Add optional argument to `haskell-session-{all,installed,project}-modules' to suppress session-creation. This is useful for yasnippet usage, see commit 517fd7e for an example. - Change default for `haskell-process-path-ghci` to a static "ghci" - Fix `haskell-interactive-switch` not selecting the REPL window - Make `*haskell-process-log*` buffer configurable (controlled via new `haskell-process-log` customize option) * Changes in 13.6 See also [[https://github.com/haskell/haskell-mode/compare/2_9_1...v13.06][detailed Git history]]. - Switch to new versioning scheme - Switch to MELPA/Marmalade based packaging - Cleanup/refactor build-system - Enhance `M-x haskell-version` to report more detailed versioning information - Make haskell-interactive-mode emulate comint/eshell history navigation (see commit 0e96843 for more details) - Improvements to haskell-interactive-mode - Improve killing/restarting haskell-interactive sessions - Improve directory prompting and resolution - Fix redundant-import suggest trigger to support qualified imports - Detect all abbreviations of an user-inputted ":quit" - Fix regexps for recent GHC 7.x compiler messages - Customizable commandline args for GHCi (M-x customize-variable RET haskell-process-args-ghci) - New command to load or reload via prefix argument (M-x haskell-process-load-or-reload) - Fix haskell-interactive-mode prompt detection - Add cabal-ghci as supported process mode - Add a customization option for the visibility of multi-line errors (M-x customize-variable RET haskell-interactive-mode-hide-multi-line-errors) - Add forward declarations to reduce Elisp bytecompile warnings - Improvements to `haskell-indentation` - Add support for the UnicodeSyntax tokens `→`, `←`, and `∷`. - Indent "=" following data/type/newtype declarations. - Align "->"/"→" arrows in types under "::"/"∷" - Make customizable whether "" deletes indentation too (via `haskell-indentation-delete-backward-indentation` and `haskell-indentation-delete-indentation`) - Properly indent 'rec' keyword, same as 'mdo' - Minor optimizations. - Add support for "'"-prefixed constructors (-> DataKinds) to font-locking - New experimental haskell session menu mode (M-x haskell-menu) - Various minor cleanups/fixes/improvements... * Changes in 2.9.1 See also [[https://github.com/haskell/haskell-mode/compare/2_9_0...2_9_1][detailed Git history]]. - Bugfix release adding missing autoload declaration * Changes in 2.9.0 See also [[https://github.com/haskell/haskell-mode/compare/2_8_0...2_9_0][detailed Git history]]. - This is the first release after haskell-mode was migrated to GitHub - New experimental `haskell-interactive-mode' module implementing a new REPL interaction mode for GHCi sessions to eventually replace the existing "inf-haskell" mode. - New `haskell-process-cabal' command for interaction with cabal-install - New `haskell-checkers' module - Update haskell-cabal-mode font-lock keywords - Improve scrolling of hoogle output (haskell-mode.el) - Derive `haskell-mode` from `prog-mode` for Emacs 24+ - Add new binding for "" to haskell-mode's keymap which unindents current line - New modules `haskell-navigate-imports`, `haskell-sort-imports' and `haskell-align-imports' for operating on module import lines in Haskell source code - Add new binding for "C-c C-." to haskell-mode's keymap to sort and realign Haskell module imports - Add new binding for "C-c i" to haskell-mode's keymap to jump back and forth from/to the current Haskell module's module import section. - New `inferior-haskell-kind' function for querying kind via GHCi's ":kind" - New `inferior-haskell-send-decl' for sending declarations to GHCi (bound to "C-x C-d" by default) - Add new `haskell-doc-use-inf-haskell` customization variable - Add support for bird-style literate haskell editing and a new related customization variable `haskell-indentation-birdtrack-extra-space' - Font locking improvements - Add support for Git's merge annotation (with `font-lock-preprocessor-face') - Improve `import', `foreign import' and `foreign export' font locking - Add support for `rec', `proc' and `mdo` as keywords - Make whitespace within `-- |' and `{- |' optional when possible - New `haskell-move-nested` module providing utilities for interactively {in,de}denting nested "hanging" blocks. - Add stylish-haskell support (enable via `haskell-stylish-on-save` customization variable) - Add support for generating tags on save (enable via `haskell-tags-on-save' customization variable) - Set sensible dabbrev defaults in haskell-mode - Added `SCC` pragma insert/delete commands (`haskell-mode-insert-scc-at-point` and `haskell-mode-kill-scc-at-point') - New experimental `haskell-mode-contextual-space' command - And a couple more cleanups/fixes/improvements... * Changes in 2.8.0 (since 2.7.0) See also [[https://github.com/haskell/haskell-mode/compare/2_7_0...2_8_0][detailed Git history]]. - Minimal indentation support for arrow syntax - Avoid opening a new inf-haskell window if one is already visible. Windows on other virtual desktops or iconified frames don't count. - Force comint-process-echoes to nil - Autolaunch haskell-mode for files starting with #!/usr/bin/runghc and similar - Added minimal major mode for parsing GHC core files, courtesy of Johan Tibell. There is a corresponding Haskell menu entry. - Allow configuration of where-clause indentation; M-x customize-group haskell-indentation. * Changes since 2.6.4 - fill-paragraph (M-q) now only affects comments, and correctly handles Haddock commentary. adaptive-fill-mode is turned off, as it was interfering. - Yet more unicode symbols - Better support for unicode encoding of haskell source files - mdo correctly indented - Indentation fixes, fixes to the fixes, and fixes to the fixes to the fixes - New command: M-x haskell-check, calls (by default) hlint on the current file. Also bound to C-c C-v. You can also use the flymake minor mode with this. * Changes since 2.5.1 - Parser corrections for haskell-indentation and haskell-decl-scan - haskell-indentation: Pressing tab in the rightmost position now moves to the leftmost, by default with a warning. - Typo fix: One haskell-indentation variable had ended up in the haskell-ntation customize group. - haskell-hoogle aliased to hoogle, haskell-hayoo aliased to hayoo - Courtesy of Alex Ott: - Additional unicode symbols for font-lock-symbols: () == /= >= <= !! && || sqrt - M-x haskell-hayoo search added, opens using browse-url - Bug-fix for inferior-haskell-type - If haskell-indentation errors out, it now fail-safes to inserting a literal newline or deleting one character, for return and backspace respectively. * Changes since 2.4: - haskell-indentation, a new minor mode for indentation. * Changes since 2.3: - Update license to GPLv3. - New derived major mode for .hsc files. - Removed the C-c C-r binding to reload a file. You can still call inferior-haskell-reload-file (and/or bind it to your favorite key, including C-c C-r) or you can now use C-u C-c C-l. - C-c C-d looks up the symbol at point in the Haddock docs. - Haddock comments are highlighted with font-lock-doc-face if it exists. - Use `tex' rather than `latex' for haskell-literate. - inf-haskell.el tries to find the root of the module hierarchy to determine the root of a project (either by looking for a Cabal file or relying on the `module' declaration line). If all works well, this will make C-c C-l automatically switch to the root dir, so that dependencies in other directories are automatically found. If it doesn't, complain and/or set inferior-haskell-find-project-root to nil. - The new command haskell-hoogle helps you query Hoogle from Emacs. * Changes since 2.2: - Trivial support for Cabal package description files. - Minor bug fixes. * Changes since 2.1: - There are now commands to find type and info of identifiers by querying an inferior haskell process. Available under C-c C-t, C-c C-i, and C-c M-. - Indentation now looks back further, until a line that has no indentation. To recover the earlier behavior of stopping at the first empty line instead, configure haskell-indent-look-past-empty-line. - inf-haskell can wait until a file load completes and jump directly to the first error, like haskell-ghci and haskell-hugs used to do. See the var inferior-haskell-wait-and-jump. * Changes since 2.0: - inf-haskell uses ghci if hugs is absent. - Fix up some binding conflicts (C-c C-o in haskell-doc) - Many (hopefully minor) changes to the indentation. - New symbols in haskell-font-lock-symbols-alist. * Changes since 1.45: - keybindings C-c have been replaced by C-c C- so as not to collide with minor modes. - The following modules are now automatically activated without having to add anything to haskell-mode-hook: haskell-font-lock (just turn on global-font-lock-mode). haskell-decl-scan (just bind `imenu' to some key). - In recent Emacsen, haskell-doc hooks into eldoc-mode. - haskell-hugs and haskell-ghci are superceded by inf-haskell. - Indentation rules have been improved when using layout inside parens/braces. - Symbols like -> and \ can be displayed as actual arrows and lambdas. See haskell-font-lock-symbols. - Tweaks to the font-lock settings. Among other things paren-matching with things like \(x,y) should work correctly now. - New maintainer . haskell-mode-17.1/README.md000066400000000000000000000133551360223321700152740ustar00rootroot00000000000000 Haskell Mode for Emacs ====================== This is an Emacs mode for editing, developing and debugging Haskell programs. [Home page](http://haskell.github.io/haskell-mode/). [![Build Status](https://travis-ci.org/haskell/haskell-mode.svg?branch=master)](https://travis-ci.org/haskell/haskell-mode) [![Melpa Status](http://melpa.org/packages/haskell-mode-badge.svg)](http://melpa.org/#/haskell-mode) [![Melpa Stable Status](http://stable.melpa.org/packages/haskell-mode-badge.svg)](http://stable.melpa.org/#/haskell-mode) [![License GPL3](https://img.shields.io/badge/license-GPL3-blue.svg)](https://github.com/haskell/haskell-mode/blob/master/COPYING) [![Twitter Follow](https://img.shields.io/twitter/follow/HaskellMode.svg?style=social)](https://twitter.com/HaskellMode) > I just want to thank everybody involved in one way or another with the Haskell Emacs tooling. > It is one of the best language experiences I had in Emacs. > -- [cocreature, 2015-03-01](https://www.reddit.com/r/haskell/comments/2xjum3/haskellmode_february_2015_developments/cp0qa9a) > I've been using it for a long time and love it. Great work on haskell-mode! Keep up the good work! > -- [LukeHoersten, 2015-04-02](https://www.reddit.com/r/haskell/comments/316hcm/month_in_haskell_mode_march_2015/cpyutph) > This sounds wonderful. Does anything similar exist for Vim? > -- [earldouglas, 2015-07-02](https://www.reddit.com/r/haskell/comments/3bsa0f/month_in_haskell_mode_june_2015/cspdbb6) Users manual: [latest version](http://haskell.github.io/haskell-mode/manual/latest/), older versions: [13.12](http://haskell.github.io/haskell-mode/manual/13.12/), [13.14](http://haskell.github.io/haskell-mode/manual/13.14/), [13.16](http://haskell.github.io/haskell-mode/manual/13.16/), [13.18](http://haskell.github.io/haskell-mode/manual/13.18/), [13.20](http://haskell.github.io/haskell-mode/manual/13.20/). ## Quick Installation Make sure you have this in your [init file](http://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html) (usually `~/.emacs`). If you already have `custom-set-variables`, merge its contents: ```elisp (require 'package) (custom-set-variables ;; custom-set-variables was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(package-archives (quote (("gnu" . "https://elpa.gnu.org/packages/") ("melpa" . "https://melpa.org/packages/"))))) (package-initialize) ``` Then run emacs, and evaluate: M-x package-refresh-contents and then follow by M-x package-install RET haskell-mode Voilà! `haskell-mode` is installed! You should be able to edit Haskell source code in color now. `Haskell-mode` has much much more to offer but the above should get you going! ## Advanced configuration For setup instructions, please consult the integrated `haskell-mode` Info manual which can be accessed after installation via `M-x info-display-manual [RET] haskell-mode`. Alternatively, you can also direct your browser to the [the online haskell-mode manual](http://haskell.github.io/haskell-mode/manual/latest/) for setup and user guide. ## Installation - more information `haskell-mode` supports GNU Emacs version 25.1 or later. `haskell-mode` is available from [MELPA Stable](http://stable.melpa.org) (releases) and [MELPA](http://melpa.org) (git snapshots). The latter will generally be considerably more up-to-date, and is recommended for most users. Other means of obtaining `haskell-mode` include [el-get](https://github.com/dimitri/el-get), [Emacs Prelude](https://github.com/bbatsov/prelude) and [Debian package](https://packages.debian.org/search?keywords=haskell-mode). ## Installation from git repository Running `haskell-mode` directly from sources is easy but requires a little preparation: - `git clone https://github.com/haskell/haskell-mode.git` into a suitable directory, e.g. `~/lib/emacs/haskell-mode/` where `~` stands for your home directory. - Assuming you have unpacked the various haskell-mode modules (`haskell-mode.el` and the rest) in the directory `~/lib/emacs/haskell-mode/`, you need to generate various files, the autoloads file (`haskell-mode-autoloads.el`) is one among them. Invoke: ```bash make EMACS=/path/to/your/emacs ``` and then adding the following command to your `.emacs`: ```el (add-to-list 'load-path "~/lib/emacs/haskell-mode/") (require 'haskell-mode-autoloads) (add-to-list 'Info-default-directory-list "~/lib/emacs/haskell-mode/") ``` ### Installation from git repository on macOS There are a couple of things to note if you want to install directly from git on macOS systems, as of version 10.13 High Sierra: - The version of makeinfo that is installed by default in /usr/bin is quite old and will cause the above make command to exit with an error. Installing the texinfo package using [Homebrew](https://brew.sh) will fix this. Be sure to follow the post-install instructions to add its bin directory to your shell's PATH variable. - If you are running an Emacs distribution packaged as a macOS application. such as the one available at https://emacsformacosx.com/, you'll need to add its executable to your PATH before the system's default Emacs version. That project's [Tips and Tricks](https://emacsformacosx.com/tips) page has detailed instructions. ## Contributing If you followed the above you are just a couple of steps away from contributing to `haskell-mode`. `haskell-mode` is actively seeking contributions from users of `haskell-mode`. For more information have a look at [the wiki page on contributing](https://github.com/haskell/haskell-mode/wiki/Contributing). haskell-mode-17.1/doc/000077500000000000000000000000001360223321700145535ustar00rootroot00000000000000haskell-mode-17.1/doc/anim/000077500000000000000000000000001360223321700154775ustar00rootroot00000000000000haskell-mode-17.1/doc/anim/company-mode-import-statement.gif000066400000000000000000004736461360223321700241140ustar00rootroot00000000000000GIF89a ."8* .";1333::9''&*CO\TrfM.Y,v:i+]33E33m33pBPA0oH/VABO\T-\.J33E33Xfs4s-k2(kA[Eu0Is1CHNNNDDCZZZUTSpUNvjYLVtUgmvuxmlpab]R7R.*OAU\gV3R.h4q/U5QMtIoQuKyklclA(*15c+(epm.Rurvmm̑Kҙ\ܝ\ɎM˜lիqxޢRo..AOAP3K1X8k0l\j/vgKUNovzIwSx $ :/&X%m/ Lh]_y]Ut:+rKWkouV.LUnqt[nяھٳͱͻฉ͓ҙٚōɳʨܺجњחՎɮ̆萚ЙϮײՑدʷ!d! NETSCAPE2.0! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,  ȏ!W y #:TB +⣸ GCz1#ȑF4Xb‘cgҢȕ5.L0L|<-+"Eʈ } Y ġ1_:Pbģ^Uuj֤]s-Nnp.>Jy.R#KPnigO0fd*5-M' ϲ14ԛ%[};o=¨oUk`ke Comq7h7m]x&ׂRz7r֎[u66mҕ5vlImBvee칩<q:4]xЀE% &Ha *X`< Dυ"aba&!'BUP`xaW2H!"Fq-c2#C!Б%b?h܊0d2c'VcIYCNhf(ATj 7hczXB!i "=Hi>)fp#iq!4)iI)?J钉.jbhrkȧ}izj>*m:کG $vr-z+.vh+~[sgʩa,n߆;)*,`>rH碋0F̮|{Zp 뭾w\<(Ip<n%7.6l*3 s 3LGpˍ20K ODOqF֨!ڛOY7=n?,S11K\06p/?s׀5fps]+?0+5_Dγ]Ц3/Xןgwӻ74W.<= Ǿ N+o}cOҺ_ };/5o/o~}ỏ/=o𷼸o{# a-SgUP+ @ |{ " K}lc1gmcXHvnv(Wp۷~Cr;׽ѭZ3;A1X%Qyk1O" q71{LbAQk^B~L$;Q Y Џ|{$%U2i} IMx+e 0UBђä#]IK2|.'HX撃/ICbR;f1 er*ԙ3ug/jd״5akjcѤMpְD#4Yt# )d\r:e"Iy=~П\Ł~pwg> *Ѕ ^Jj-yuZueBJS@6͖zh;? JRyFO2ez;D4?-FoSv/H'9S6UEŠ>¤z4x9(M[ UաGX{:Vjj_HW+Ujt}+Yix4"@I †өbl[ JKj2ͬY9z-WbJ4ePяskFYUf3OrpgYP, ?kR n>"_Pz+\Rִ}.|;ׇmN9KV[,)Yx\ujoP7N-aW VT Sz`Z ,R9VkLԷ-G`2-|u7¾{iFȆ,k o?, :k~aJ 1 f5V+x#qdCN9{6^3 cFxrì@WDfkxi't⥵vgl8;Ɛo}oM~( i{Zǡγ/_uw(%n`ԘsE9x#٘h[.švQ J̶GL^P~deQ֙%W}9r{4-9Fy%)V۪) g[ޙ- 3RMLhBЄ#uG7KXCۯ<ƑkKg2 [SZfqm`Vh,p~=n _:_曟LS] q-}$_܇/m:غn>ۻO ϒ<?sO3[wlۇ~8-ߧYdG_F_ T\M`G0KP p հp 7zVlm%[p'rhUqQ'n~3vd&d}z_Hm|F'dxgc}.ggO7U|}w,7}@Hdv| j^hg`1DŽa'<8GfGX}4b؅nXbbdh0Fgp 0y p_x 7@H YF_~x~xH}(g< ؆Hyfh؋^xF}HcubϨ0^V0sv"jƘg؊ͨwҸ( 30)ryI@$e- seX }3Wa ՐX}g_0 ^x}mx-؊^~YFu#݇-ƍeL6hfx}f,K  T@HJ`L@Jݠ ٰ Pـ < V358sۀ ؀3p ֐ T |[lDL e}< ߙ #Z~[B|l@K& (̳\,.~<+3e|8;ʥ{ɝl"|3ʣL,¨ʬ,@,\ $Ź,"[ hẦ ʈ, Lb˶׶N:PKUeٽk˶ȟɔ\ϵ*{ r jU;=  ؋'њ,lB *s>] DPB@@޴ R([00 :K`΀f ,s`x3 e3׳: p/ I0e\0 !M[=+v+с%-WM &ғM\-=/}C, l<]2 A=/١M)},mΪ0?=Ԝ,Ў8-Һh ۾mmٳجp οG {ۘ7ݿ=kXZ` m+L ߓ{m ;- ==-|ʌD쿦}ʠ"{#>m<NB=@^N Ɍ` T80 K MœlD/` i@f`׀' `\ =[0t.i//ؑ{\L'ҟ0L%;L C,「M>L !n.]䔮4 /l68η:^'6C.뾝ݞ ޖΤ7 ʙ{} |7mt0ܳY@ [Kߞ|0<Ml ,p֠}ս8-~ ]rìn% Tz= о*z6N/$!9 !/EӰ {M5HAU1 ^%{ IAՉN}$s|pr Nz%ǡM=hN 9ǧ(tGHZB<#S P+ "fScֲF: q3'PF+I۪Uv-nsK@GhR8:"q0@L?yCW?|uHlh aQlT ``Ʊj1btG'y\GtSž‰f4Mqr*FУg"Ģ^щ҇R#LH4R_о>1LMUiDyZVv%,a+Z3)_uҹn+KeӋ { k[~ͱM;A:349^sfR#7ɝDӟ)M:m6\qNQyC6:k ,e,D`qt +sp؟IêMPZ^lPKyO&Yj R]/ay8-E J#D@눗ز+9dن"Dh@ l@l3`QЪm؆nV@a@ЁD-"LiKiz9VC F|R=Ci:h:LpdV?>BLGRGw$kȇw4ǕPȇd qGHJGGȌ|HHlȎǏ4I Ǒ$I7kȊȗHtH$zɐ,ɉJɓMDĠh mXزm0KҨ"RҀ98j*kȆ\+ JImѸ;+ʈt;E@l0dYX؍əɘ$$IdHLLIṭL\L|:\0ȝltIŜK\͠,MI̬дδM4͖̕dJJMהLNRyBDLHzJ8ȏHˤI 6$C7A/VS5>L|GTT$GC2(ul},I+mͻJhA%L"?ŪRw,Ք<G^4ʠW}K-ZmK\]TZUX R QE_MM(EVL^_%]MUaiMʵj!xHLH܆ҁC?Sl mKG*!%l^,Hа;^ KkBn+dƈTVTUֈDԍV_V,=ɫlgGDUԖmUV[Y֎mX6ПՒuMtɔ-֛ҖيUY\jGՒ5V\Y]ZS%ٛMi?G0 ڜU[mL:PG?i(Cm۽ʷ[q̈́iPʈY|hU[}١tٽm\dMT4\֮e[Ǎ\۪]ԯ\=\н]J%م]-ݐ-E\ʪu]u B*K!mQ!ʆvQW̥]ڽlj`˪i]e[e݆Wku˅\]ƝZ-] ]]ץU]_]UސݫeP}_u E]^G _6_U\E` ]UXRx@j bU0b,b5͵b,FZ~^/Y6cMȆkkhH:xP* -\;Ucxl@6r]j}9M+ܑ[M6V}bHV-~^d1 2T_R5&6b_b召XNY6e`7eNVV $b6Vdc81I4`fl-[=d}N\-Z=m\sv_x`yU6g{gtg|`]Nzgsx>h%hnhLg nhl|.\|>h h_.Lh&^_Փhܔq!MV`WǴJaǓn]fi~YF=fhhI.Fj-ꕶg^h^VVighi%jNkNin걎kFVkabQa^_l߿^U^ǝ߫^`e}6lj]gX]llN5ejmnvy nn^骂b |}p})SNmim^mٶf.mmJjі݋ح޽^۾]>o_ZouYg3>oNm&`k^q'7Wqw/iGqq/hMœ qH:%[藠"77$W%_q$g(k) Wq((wrr0öq24j _?s+Wq%߆VvL?g?vj5qs3o;sC'qFOjws4s#OHt:g.)w"ttLM?R'TkV/u2_rWkY/uZ_q[rXWr\?h^?Uuu]/qb7r_FUO6uTov\vhOvc/ih?rmv)nwgqrkvt_r7fWvgvwUy\y,Oud^Vwuyvausv[wUNg\V^WuYu^wYO[hWx^ky7Olxxyw/xGw_yyA@^W7y zzogvzwzz q\?xWd˅7q7zv _zxG{{vv_wO/{'dk{wqg|7q_uϏ{b||g7gy`v_q^{|Wz?uz͆Av*i`~\ijpw~2\ j\X77KakiXm.d 4Ԫ2P!ą-FX!ȐBɇ K,0"KqfǗ-S90Ȕ*]bܘqщ<1gѕ=Q ɑ'աXWiaMUo*TNeCjIunԝh^sj&ً~v-)BOq'EdAG.AL%m֞#LtƜ"l޽wJ[5գKjƹAONM{@TҧSުuVQb};ݷcG=;wS~}}wVÛo=|'_zz֝{!Wv}Q8wuUؠgxȝ!H`zhIh߉ލh#>~X;h$%ZGcO߆8!⹈GVRfR_z*'vhZIR$Mj= $Bʙ]vئ|+9$P9#|cxfr駡)/jxb)**:+z+++ ;,{,*,:,J;-<϶܊*>O֪..;/{/K-<|[0>݂*0 ;0K<1[l< oۭjjm|2)2-21r r<13A =4E=q#,GK=5U[}5Y{ 2?53=k}6i6mtǽj<٠D67 >8ᅷ wj3*T$LEو ~9k9瀗L3b,4 2טmɝ:>\>r7>zOMM;<*;SQT:2-?+={Id& 3zXaɢf>?ˈ;*KVzO 5(5 4tF: 3XxC[ÇhHwn鲜S|0¨(>4&Ǐn]5 ' } ?|"(E[p J=(1dU ECB^(9]Yjx>ȅ0a)AXV OwIVIRd8f. rIT,KϩCOa,L#pd>Ѕ_4 Ә (F3y @\l=)JSj/zlpdb>Ҵ6KcX:|R y TܴF=j)m|;HWUC%*RUf\8U*lVӪ֚~{Пh[L<'Zת׽2T|ri kXTC+bNlDMH2U,f3Llm,nJEM9PDRʫfSK"!+U]-ns[]BJ+wԳ^V=yCrP4eŘ(QT/lmq+bV3—Pdd;mx+ү_ܖ\]Ԍҥ/ž-If 6^QО/&[sîQW9/=ΡM>O2U8m5ʕ8fm{%Wv=w&07-syh +J' .C•_h~ݬ=쐉t,#o8ͤM1edT"yU:^43MTHKwCYӦ>5v}|"15[jTӺb3IL-cכS\]Y~6NSDp]?KGޞ}{ӭXTf_l (/'l ;@FvK>]eR &8?vjṆit87U^XP""4&uWUrb'm+}򙣜nk#!QӼkG"Ï⺧ϓhƎNcJ{qS͜>(Shþ4֯ cto_3 h;ޙ ].x_׮f, }p9&pN<7dKsm&ӂq# dt=u=]ݫ+RYnl?f]֖X'&u rG^i_;""3g~i.U/F诿zEizҷ?5"ՠ4 8@lE]^`Fq+˧d`JZ/U4u A3aQpA S \ͬ 5M[PA߶Ԡ61& 0x9!^U^Ue^iЉ] ATI:)tSE8 ."!?\XSbd*1!#^^ 4,&YXUa=͔w>?:b5,ªH1)�]8] % ?3X /#7v4/89:C-.@A9B,B9:" 2) C&\,`T3X -c9.B,/#B:$ =cB>|CAFC=*#ٹ?&90\ 9H(EF+( >L$9;4Gv(]=c^:TL/$תDA;$/JXc4T%dWңR2 J-"?Í] ZJ A$DQ$%A"e.b{Q^^V9\#1\5B5^$|5A,'~Ab5. g| =9<>'VU>! ?9F$@fW~`0zȀXV,\'&~F0BId_h~| A &)tJ 8 vrTiW!)mYF@ih,5ެJ XÜ$̢5ƨ<()0s 愶`'Z ?PdR >PڡH*z =i6ʝF&/jC7tC7x4*㈶J8X)MV_bgOfjAzKe͠>2Jz+VXï+- >h(a:Bꭔʷ`g20kX5-&>XcJڃu÷ĶiLfX^Ϋ Ȫ+ 4p,yP]P_$^t+)+Rl ,d,4Xkʔb,ΊN4 eba&וT^#Ξ&Cϖ9ܨ*+ѮӮJC쪲 vkdWhfm_Yެҭ'[雺j - bXCV>.CJF_ؠUܔ~el+)|, 0A70B *M&&W,`#n`Evnjk0}<9/6*(Z6B$!`'!H1 jt=f,qJ§g6b50U6qӢ'J'.hdBN- {,4c Pw`9`p&< "&w."Ί,2cB9:&+2 XAH4Jm W"^҃Qc,2-_~S8SvVIP޶ Bq3 ^|K/?$#3w3Bu 9k =l:L_#Bb4B4OI'Ι9Q)e,\qbH;Q3*RpI+2(`IZ>:k f|&28Z1 8TCv%u}$Fa+I^!ۋʣ;/=x*1o߹/5r_<@f ei3KFi [+Tz'˂Ymm /ϊmovfn~0YY,mflj&&-flnmFn%? Do5|k u~2rxg.%P1? w~72Zkw 1nwscbW7g).dd>{3gg§К+~Ђ+h~k#'h(8x&lddy얕"1,91A ?@&u-%D;( (wn(-1 isK-DhJwPhx6CDy>l,,v@(dú'Pdi-s |+2ڃ6fŲqYfJ`"~/B,C/-bA Ā{@0l6̈́?a?@fw;b* {m*HU- '3*о߁$Ԣ.0A<ʓ; ,jÙQ e/8;Qz! {:$ʾ+ˊ>(ךj :*am zd>p-VZ{1,'2鑾= put:m.PB(PB<3rO-><[+b抾V=)M+Zcj>D{Ě=q8B,׾,\Ct ʗo? ~Y J.|9ۊNqWcL̞'Z /J_Ll+?@;&8s#8??@o &T80'-8'N雸cGA9dI'QTeK/aƔ9fM7qd.>~45 ٴi&U:M }-"BDM6;S=6xgERAF9p'}jb.ƘCxc&G*';<~ā2R4gOTLp ,S Y ͉f`o Wq-צmO<8q'#9S;rB*6?S6Spyh1z$}ȉ cEWhv͑,zRܗaYi7yJP*jkUШ\=8lw_޺2!Aj>SR;IZ˴+xgEG ^ }"vL2 ,l0AUv}[0o!gji(YThQwB/o'lnIuzyE(Ww$/ yǨEK< EIHg͋Pš7eO_gtqNF~uqH"'9a@.PBISE CϚ"1p\!"t4 QB$9K)zV-|#X?aE4bhQF1țUŚDjE/Js腝јF5IO~3=͑/G=s )%sIZGE.t$98УQD4'AʔCoWH HP(aKYΒ\\>g(D h ~В41.W]2)$J*Ȣl2Mmnyn> 5G )Nن&4%ntg. P:qH8E|?PL2wC!QdrI=BO6DAR#]o(Ρ{$KaS.DHR'NC:)SlGhK`i͢NU]d w9EC'RenV9*Q,CWՄlq(Us PHW1ՙFENOP\BSZ5-"IΤ/Li*(}6mq+)CBuʔ35q݀h7J_0(W&յnKdKFQ%jbR^5oGeQd8b\On/y:s 5JXѪ6qq3f#]6(pi'ڦP#)\p*WCbQ<5og=ٕA)zTrFHGRQn7LRވŏK$OŪju \-f1s6D cv󛏩z%_2}'>M2Zb Jύv"1*jlӝAjԥ6QjUխvakYϚֵqk]׽c] ag6lezʦ%H f{˶mNc[pwfrZv}^s#¦vls[7 z7 wZ c8> g\x~񍇜#O +]y=|)cO\+9M8 ߹et|Gȑq\g=tKyǛ>;Dr^zv .{|?u{[w Eq7 ^(S闟_7_75z~#'_{o~b? .̯80ǏoP8ԯh.38Ώ%5{яQ͏W-=PoJ]XD\NbHeP/owNdaXCn /?PQŽ N[ 8BLp D! (0f]mp)Q^PP* PN  g ;sO U$榯RD p. ^N멞\YQe .N/ 0PR  %oGۅ6. 0A@8NiJA  !6A6V @QH!M/QpY*P 0p1 7Qd/g@"_ obqNSO"q2o2)W) qR4e.d,q%d(`R1,. ~? p&P@.窲}j.p/G$ eG3%% =a@8@b TA-n@e =r28a/ @ Gr,-ů]&D$e4#o =i2S./o*A[-'T+B!p@sr:1,7:[s 4&9I.=R!woYR4>Q30R-PF1UN DFN|#;4GGJecX%ccG%+LL Xs( 0P JcP38UA+dFS#c]bAn5 @-n#\h1q.Vusn*KV) `.$`oB,` H$ >BF;RP@ BOH_݅VP@d+%)qdMT65o9QF3EyPn'QlESZd![XoIuS$%[,%^ OQp's ~N4spWLDP ( (.F$ O?H.a]DB7.*&wN&1weOUvFqOa*)ytk@#KCpb4ql8P5$@gˆ8TW#PXY4 oGOSQoFl'Ye7Մ/=q]v=X,Brlj`@UuLRA4Ʉ^*d`d(! 8phd`N5j^Ÿor`c,AOWS|Y>@gWnm tT| rP(u$tfWR~ er)YaZu>o4U\ZbWٔ <`ohI8\X@a pF!QahY4 Pq:@BPMy[!M,U XAHa!u ug77q OUֹް aHn.Mo7zz\P (ю]X)}q0@WinNEAÇ/'vn=7e.YvsrOYO270SRUNR<1Zi:U\!\|r D10ڠbRT.;;yצH[D.{U7@!6%.lLVb Zo $vpWAS;qhY$&p$VaeL Ga*!vLR Y!$c7c7<E]:%FPrx^Yay] vH[DjR?=Sq]v66LƴF}4c @ڛ%t\,y]b0;`&R[ 3}F]\# hD²cqoYRx-ur2 2C D Pv1lc Zo2KoTyq(cA`EKGSzCQBy< H.ž\pHGm B .&Q㼋 cەsZ髰MD&aI2PqF)R7 kZ@j3@#0N!d /S[$\1bR Wa?Lbt: tc[#:K[FLȸqZ(.O(3ZbU71I?4= I_F5LaJ]4E-,2hb!˺R?QT%&Qrb,hsbdh$;3W*FXBfiAe;!jwPY.(blIOD$#RV3p .S`u Pikq `Bax!7`Au";F4e$E:ONTrcJF^X;8  Ӊb t n@JB/@1BJ0ka%B }w؞"WF WkYۉa_"v#Omq %J&PDәҰqi*XA@ ;#T,S{Fv7 Mɖ Ol)@5'щ@@F-kS!އDа z"2 WNe5ڥs-GyST4mK҆ B:qB1k '8Viu~9y UNPJ,!6BD$%^Jfy95G%J2:,2RmND44jF\Nn-S.H2oee[V *Zi-]OR;dQqhS"δgŞD`lJ 9MiphyjWED^x4Dxm*uiar^PRpu?°QL<ۍ,L!U4ڰbcrذ<@UX}B%c$ЛIW5Tҙը=YEeY @hbڮɮY|>̥I0aJYvNXhw+&:\-y"R6I©P3Zҽc#_Mk1xX?.*2py 0[MoE=Q̂"+s>Qjf@NLR 򢕼BCnh{r"(5%CpzNܯ^ծg57IAn@#B]rWio&=";,k|Qn3t-!\Ưv w]u' 06wTׁw]bWcE֊MY{4'#Ş)p)d̰MrY"$ z+>XX5PcZ::u6QJ"SAD4f}94=:?4u2A2.}=GyS`6E%raV~9r+%/1oa16AfU\"&Av+T)EP!5 !jzs+j.u$Usr1U7# F#I¡QQZm! [Qb;p2~S}e%}x(kקzr؇(~8Q';}:F*6hC1D&90'̳fOf1Xct+T"  # ,-g1@b%\1J'y2a- W*6!~TyJl wL7hQom% FDi 4j8NcxlU 0`- UG2 $4!U sgX9@YIT9t|? ) PIrDc( kBc -6C>^-X '! > I[E \C/EdPa# v#5[1P2y/[! e'ik#@TҐ=aJ! io@4SoSR1)vơ-inI01oh?pZl GpPOs,0 kd -r=jGZD1Azw\8a)&;˲kPXVy`-5PhMDx#AqKE'kH!!-a&ok9X#/JuKr!֋Va"ax+խŗӋW\:Ӎi')pR:ԍ a-n9h"wI&q'JLv'nxpC+:&Qjҿ <'|ͲѴj]˧m62Yl};фWd!{9j|lή)Mfu-;$L2k*Cӽ%}8ӡu8-ikm&h֥dA#_<}!r&>"Kו{=;ABA|IN]6؄}3M5źj>Z2ٚ,³IxM`h:w.~&i~C-ٙ7jsM1E+"kv–Ăن-RVMy܉^~چ =ڿ, ?mRݼ .N] N @ a > >%"N .*n─-] .~ $~^ߘ@?nL4~ >=^UnO[]a%bfNil#^Pg>a2~u{y~>e瀮.n|n.Nn闎陮.Nn꧎ꩮ.Nn뷎빮ǮȎ.Nn׎ٮ߾ 0@ŮNPNn.>̮/OoN _ '>s ` n3O 7A/CO˾^>^90DŽ4@t0 ^cO9 >L@;c >toc`d/O.N M>ﱮ TvpJoP H^ P >=g0^#? ^Nn~.0 0Fo}/^?/.v$X`A|=Wy XE5nǃ~,#?%MdK1eΤy0^<~)p'?}yړ(5snql ՌR%[LN#$Գk9MvD(Vԋ7_1 oa/fܸ#x;:t_N=)oL[squfyvaϦ2-7i=5 x.v(%k/gQ9ͥO^`ZP&$(\ }b14 R}DI06raB+!@4Q֜0O$կPt dP%3G9N9UXcU 2;J3'7 NYo/RXiJY(IFM@iʃP4vg4hV8 hZ<]A!)dbୌzPt ?/"-ār4q|ڊeNj(pHcH(EZ&$שseY*"mwuY+81*7fe?yP6[W4[p1V\eMzu}WnU{m-N;(;z;Ѣk p$(m+.DY6`ZgF) (LCu<٪ٽc6(x\O#r0!C(ĕq| 6~Rtj:J~1N8 Ar)1 c65yF!!ԑ1ce)xox?@U!D cA]t ϪFH Jc vRJ!6ϊXtJFv)DtDzI=ōPT@wd؍WHI/rIK7Q:f"Hr$!Tu$W{lKMxc;ݹp;O,l fd+cW p b32'P_NЌtC|X8E䀏$8Z7sdǞ,BT 17O>%mp/)JZ zցq Uir2?By-Q*S%r=EZE4DQ*Ep{+`āz v:~ sIQ >iXT VW2\BERLY+h4`pA4$NPPR]6(Z΃=Ӑ!N ma * $-#bI8"5K,ne5eYjTOr 2S ܵd[8Ve/tJVe\M#FZz2#&LЁ}hg2Edb}%~ۗך^^RgDj kmZ [YMr#uc  ~\di}s_B$et~gK̻,"ՏT7 | yYhBs.&wN19B#oTud5xS7K]1պ1#~`ilP@@ky{F.owW AQ7׻ޞT"bgS T$N1aJO'BIvPS3v Lm!|7"X}>#E oqGR@ ?/hys <> s+s> (Ȩh8 @#⌿ X^`'8}H[Aаa0rR(2H#][0@.+o@ ۇq00;Ȣ$9rB TA( |At@+3a!BJQ˨,-H!l@FdG‚Ca\īċA  :#<&\Ex8"z҉S ~#`/aH#<2$`~Op2(XQ@i 4@q@)+`.`3E;tnqGN⇴#FVt'\Goھ;3q Y"@GjQHRjۘ0*SF{nxh*@8&܈:t,D9{qcy\X=``FgFiTt č jDXF~H܇i\HƂFxG !ǂtdKwhGZ T#)yBJC~TPt⧩Tq TtгT&C-꣈i) BhLe1iәh0P T!*;4-5(q<"4MQLJ 6̈TN)JzCL#\ATGNLyJ{.);,!F~?EЂ ;o-3"U-\"m\ǟz+lm+ QةPH0ЙBLHy 4p`@ ]pPe'$I+ݏpQXRO,EЧ`QJ;#Ӌ@P8O!Et |V²Jjt|ІllFȆlFjxCMԚY8?SGՊnkpkTlgxk؆l @|kTOUI}GՃpUXuVU[EWXQRubEVmT-W8O(:({b5KsxWzuݩW|x`WymρxX|CW=|L]X9~Y=uK׆XmBXX>,zzZEMY]]Y}TYXV؂YY!WY=L{=ؠ]ZmZ}ZY"'UZZWuYQ1A5T=[M[][8\X jІ~Z[[q@Tmaadi؆![ɝ\ʭ\e.ae\͆yڇ\-]=]գv݉mP\ϝeTX Dcxm ոq؆me ]X|H\8>\hV`V@Lc k]qTpp@V(VhCE\ޖ^eR}R^V65X_e*C=؋=u ]QA$ oha /hx#B \P\jx]ƅX]\ȅ$8™X,M_꼊)Pa@:a(f`bq^ )@+@Eܬ _- 2b*hd F }ȆŝdiElUhc 4DvM H6"Ƕ" 8[JEfd qsbH᥈LNF ~PMne}X>T. zP4hxHdrZ;eIdŨ|θ~8a\@e\\l1,A?QaUe~+g0eP/N ِgX`|xu  UTE DLMv+荀*vZ2n\y6 Y=\>=~}q໘P45LϑJL>*2N՝ V88jjr^fx=c"ji:g&*v'Kf (fQE\,n׷ .bƘ j^! ŅjP?>\=\!I@k@,=BGهW81JJ!Q:XKX<:mHf,_`?9ȅێNc!Jpئ6@Vmm9^ 3Q% ?hJ8I) FAe*Ə"7Bz3I9an >) @9KQ/0=G pn~m2ʋJmvBEfm) 4lr":)fA,HQ2n @)J 8 rmn"nOomJX9WNعp]a]ڸhm)[(}A.@Ԗ)6m hő94^rotR TҜ_LtiC^v2.ftO C?qdVU/ue귦rl&aZ]י3u+~IWu^6_,S8{u+i$Y5qW0uMW?B.pWRϚM0zDHS|j;zB( !+ņaXZ+BY0 *b: 2!Y M x =L*!Q :ޯWցbw'p -"d$\ qCrpZ5u?BLqEu]9L+h|CSy='pdIW(y#j䒔qcA3BA<(SJ:C /^<~' 4\ [;m4d#+v/߽ +8Ob0h#D؃:#G#r!WȟVC b}5?sT`,_2u@~3|c'^zX2['WNJsuקoŠčF\, .bbq <7xFf`PqiHY%3PoWv''APllO)>='v(?@~ RA֘u`baQ7Pm:X>f1th@Ijy\2 e~C d18!Bi'`O>`v(N'饚ՅHhv( 1 XX8eHAnY KXdP$@^,#A͂%pթa +LG|C @7F10*!G&5ې2XDI$c)j3 Ҝ6N\Dra# BRgD(Kr$q] ]hCI4(Hg5Oˋ%zP}*IYfѨsWdIY1U%Ut0RTE` `2,ZV(NH(ǓLb2@c}y-a8Bٜ>`UIj+Z_) |х+HߒBș5®.f](;0-E $g?FVVo[$NY>5,l]c+cՂ죬XǴܳYo+,QqFUfAw9%u\ Y(YֲHHBJv %IQ_fmc0@`EB"J:ԮvUj_E0NNO_1'aS UL M8uA %m`5EW  J]TR] V`mx>䟅_O ȼ`ܡϢx0R1#@23P3G6Ս +E4D)b*27HXQ7BC=D"#qX@EAPX@,Y$THIZ#6υEol03BP(PQ^E4$MvC,DE.be/:-$eĐb5Jc`<9L֤1dM0G愂@3%%7΢9Ԅc5٬^ C_E*#LRChڬ±BKA#fEq]!\SB(BmJ4̵TݕsCmN ppoFpo&RYgIrjkDl!<ݿVͰ!sO|!$SKK] D)m,E@ Ds&cV r,&E` fFVLqE`8'ᇄNguv`bНE'|(BXrNTBVxfqJi>h5wrbH~VSݡ&B("(!Ax(vZNIȃ 5\ʎnrnH?5V?m6-j-6 f.H.B-%ܖ@֎\xv~` n-~nE?HBoqB6n< Z̅\,ipo XAo.?pH(#7!/sp{0ۺ`$0D$Bَ p .`p 0PĂ&*.11$EB#cB ^{pDPdqJn%l_1y11Q&&dBH"髀[|f5U^)kr_A\jm݊A|2m22#ĥvK(+χr w2)#(~r/p--* 3i)J)B^#Dd[T:XX5*XfXH˒ )F0sGKpIk4JM2MtX4+ Zũ&ZB*]AtS;SCuTKTSuUBo/%bYV&[XuYYuZ5*S8nAyXhsFvUeCzK:Qs6&.p?֬hmzBY؅`,$l9t9҈#zzcu !ޕh8WeiC{K{~7*Q9>RR*`#qeJXϳO{6Y y*|vcOy|G6صVEo64#Z3qS|[ZXU*(]ɣ|ʏu @!:s56p?fTJ[||Go&u!UoU{TScC}K}(i*z׺@A4Â{ԛ٣ G4EJ]z׷.Ay}k9\lW0>,@%uS~Kx/5]YEx{<  d~뻾X8E$,m)dC6r*a$BK~䧹4^\@V 4xaB 6tbD)VxcF9vx^<|F' Yi+W r2YgN;yhPC5ziRK6 # rJY0qUsIMcɖ5{mZkٶun܋D4OL\t).?r 6|qbŋ7v`[i/WZ.dѣI6}ujի-yW&LX"KEdu˖MO~m0.VXB .?]Ufxac^`2Y*aŷwg#B&4ÊIp- pwg㻶B +܇ dWba"9#rp4-8`mG.ab%LȦq ɉ ƸAb 6 9J7sq@iNb7 e!%`'4PS-2@ y{ 9l3P"i*pZgǚ̺ch`}|ob`a Hb @ +ha8;I l9i`5 $Q!e>VzHD5dQ F 0 5yJ nHJ ,)Y(fQ-}h"6{h:,59^Ï LsԐ&4@.pbA \s@f~І> `T ).iGC_S@**hKPЩ+q݉d_MNAI#*@4Ұ_P8c GP6Ep MHd*AV ,W pG{^FJcSְF\$l%A%V"P'_W &C S&ȍw!0\!##C^_tVsixɠ¯@00 AK߀)~z+$ 4I[7[t(()!efg!c,wrfeWg>dCk G !A'3* -VZ7jWK$$e%DzTԓ#yc∸EI* ٨Ʋq"@-cKrMeW"P|G~M^o9('`tA<ôbrwyѳ[tuFxX` P - hVȹ=YA0NĺOl#p(>"z˦.)L8܊Ї|QsSQĽ6*bBdyDzJ(OۻvxxNݖ~#_T7"3}렌)L%~zE@2ēWPN ?t?d:(G\. d$ԢAtH;Nr(n@X GKdkȇ\ZFjad/OM MԯO 4;Pu|Pl%xpG $c@ _ D$jj+3BLf7z)(#lCV .MD M*ޜL6/N.TNO' 0J"-oX)弄x嬒 戅 n(_傎IhTzo P H`#`ւQc2'!0q"ފj(HQIo |"쬑D ^$|NёAzT k ς+ ! QڠG6uf.}?E,"[q >IʾH%'5jHj2(Zn_,fk"veBwҁиF x !$-zy,=w^)5Ɓ #ˤ1$,Jv2Χe rb- "GNZEF2e. ;~23_Rv{A@H.Y15q!'ӕ>20N qb >`24{g'! 0[<;Xns<+$.3g@ d"sf}Ƈ>z6V(s aS 4N 2!Dpa !"3@ecV`a$ $ SbAj@5w$A%B't dċhFB;S<ɳ5kD$a-A*@0TCSh 3L8X:LBQ/ pX E a"v rRB\AhR+ cN簒N͚ xAA D@ C:fQ/"!q%*Tڔ$ 2@0(3%4+SBToJ2IDdN+[aZ%Z9X@[)uAO5Y C*>ήhgP?"]9F| ","P)W XAoM`k VbibF+$+cJ aSadΣb)r<" aF5=! "aq,df݀A#!aDks,clǚ /ߔ@`t!d[l]nPM^3[%d4VBcb[6VB\ v@O6bnq eYò%&dB")dHmAPBJai),Tu)b=W7(!ҁUAaeyb=ar <Bwl!v_A |w3!7zwRwu[#x"uu7z~WY'*Hl\b3~Y6 ׀q_*_`7WC5!;؃?x_h+%H*NKcDb gk-bIum2&CD؈B>eV61!<Ё#$.k19-ٚA=w,Ú[X>>PYsh #  `+Ȝ'zHWCO>4fkDb}-B5"^T BϢbbxz~$HrWabrMS@)IKEO!D#N$S-N$R5D1h)޳"```i N$Yê,)BѬ3 ELBQ2;b"SIKX$!"T-$[![5!* *BzQ b1'r`(N1{e*YZU0 {#T3BӢE#G,:Ek ¹5'bϴ*{5~:|@ .b)9Ѣ$m."Q'"|㻝µv)[Sfefb"N #npǾ+)@{(m'qchZ wo!iFhm@v:Ax{n<B#6!v>4^DMM+Bp9F^a1ϛ!b~%K5bjhu^Wz|ޥ3ph,Bo]2!Li ~Ae:) b >HbeYyd+sWf$|CZR/xK% /ʡ]JN院 Ij@hޘIȦItj,`˲j!ϩruh@)5nwdQ'Z8[8an!rG. Dy ,PՒ/@dጽ}H_aW djW@2Q#G0]*I&- Ȓ9Ghú}" "1!AjL(pI*16|(J& c2tY f.ڬ9mkѪ R' `LTQr>KJiuI+a5M#eUF) m0qc0G)Zo^μУKo/>|ƽ;w\p~={?pmP  f8˺,t%gH9G H1D`0BŅR" C MQBa 2P_j$$'.u?!8z&ߐ  |pa{i\\Kfx<;G=bXsETH%z"LfGS5Bwc W rN}!P`b$('ʅ@'BmiKdT,aa JH&AC@xužE >(w':_/Յ-GNÄ4\N8=if{mui,ӄ#L51T^v*iٮkrb z-2guRm>9?U3W*2Tq:0R$oJ.e\7ծsr_ <\&s_pj"Kd/|@+}̒jsa-h(r֩CXV5HQ=.!tMJ*}̅3 |v LUH%s@jrlSW;  ?^XK6SvlPot]-=n-Ȃ0wfy>3"}xD~ZlAM5PeܟFf=⻽sMg~5[oњ &#lg-3} ^@ n@' k4 L;`@#3 g<+p_E2% dPA )HBP%Fap^0AQ#ڬn9CG~59# YT2GrτcZEhh̰XDcQ[,X!1{¨?jLcl #8Fs1I$I66ґs\*<<HZr$?-dc]S~\\xYcL V48(L! -D*j꩗B%j#HlYC2X۔o9K+6X9i oy|Ps9U A>!#,Mf!ΚCztk!R 8j=`@NЙNqgD"g9Y044 Z'.&7#H6^Nj0P6T LQP(T'.&@i{ t*FAPFjjvGv֣?#ӪAV )%?v;Y+\^w£~:8Jt4;SkArdɧVy ƖmY"BN[>G$i2ѷAc Ip&p)K^WTlfsVh[%X&:a7'l wW)Mu9 BD(V27H..]kޗq23{ g6pI': ! ^ w!⼪eZ\/.N:HϷw4rI{i8lKd8qNR2Y6與d;.d|xY}0P \( [OR鶬G3A{}%ƌ9BF;oaX@s湠Yqo%j8n)tdv(:puBVMg)ŦiZzQ%̓5jF; a5LPmlqGܫFi90(H3t$$kmj%^U{hYrdjtouu&ː CF,͐kᔏÙ@ ܧC r,%@Ejnrnೈ=m|6(@LsֵT>8y\CfJ "Ftt3m̂#p0sqs|ދtǰfQB޵2Yycw~ 28b.G;=zэzrk/.1D^Pmmt#wW>~}V8r&~գ>@f:R6@VX$q(/ow}m:3KC'w#4 @!$Ck4H7$rc3x΁Eqi#!lEA%u6kw'ݷd2Q3 |OXG%x^_<:zlXK-K?<.0K!#C1 qiqrC' #r9K P' 8Br1F6 4&t؉H!@Xh> 84%Hx)]'aˁ4!P # @&0g('I> baQW MA3s6acqjE  ڀ I`1s؎q "I  gCL|8YGPc:tЁTr@t1 hHweP)NX1 91Qq)Z Pw9i 6RUG@w*C~^ϗtJyy=|k 9iM.X)>Gxn>i/ .e%.uwؗ 1VAG Y/X9E P=B &8cuBV_J ўp"Їnf! 4{Dxl<7% y*TB!T81W`l1P asNb0EjH*xGF W*KjvE,ף # uB0!P5j9&17F TkRWGZP7%xK'Tj #3Z8vkn ^# Ipj0W`GppMŨqaUz *P#P8 & ^jȚ! jALڬbh19aTh:jʦ, KU5{Y$f7 q@ +:{ H$ ِ@ 33 sṟ ˱R%QpY# wf c5eY{ +(X8Q%ED"װ p א K,a([TK ; TCb3 d >KHP{ ; %KH +794۷!K{nV{gGg!緌)@;t{+`Gn;% bY4 (.Kq[{풻;`Oy{Kwf.E{ ;Pg˻˫+; a.D#*A<, g.ر웿ۿڒ 3p"p7쮹Y{3uf#q |JK؂ 0g ܷ!.ã{Y)|8:<>  l<&ģY! LNPRqA\q.DL.6X<Sb=;{wqKޑ=1yp|p)4 :T]V}4ᾲ\- g͔q0A ]8MSpr'qp,6}im=o=׈؊-~{.. e}}j}}q؋ڢ=ڎa) \ im w Mڼ۾if˽KTqM=M=ӂ`ٷ6ۿ}؝7[YELDg,(Pa}֭=mf-]q~=h- Շ } = 9G,mLP} ӌ0`,*m#Y@ epF r,w<$ D^Fnto W a~}bwE`GGR=G>d^qɯԮI>Y|.g.ZtL1ܮ^K>#zr\OY4gB- #-rܗю}}(=*,.? +*;1.89*޶. +_@D_-3.wKFN:CV;J\A;˜ U?wf/wyңkfRoF/]*qz|?=cڸ0zA#D0> [LՊ 1!d8ۏGdMF; 484M'URTuQT㤲LaUPZͳ8oݱJBˣX=.?Ҹc5Wׄ=m6DrJC0Xl#ۈ,M 0OOt]B D ]X^Cx>|H_mBgI;8tA'bW9^mjEAմ\tp4{suصlpkAމ[6?ONya;#a9ʣ6[xAgYhx-P8{}_H+;mPZ>}fXnmC)rn66sd*#WQ۔;S.A w1r2c(<7r@tx A '||@X@D6eSAh,~$xH@`VHR/`85P&)9x f! O\NPP@cUagD[1$Fbs R[[ UlN\ <ʡFs<.NG  $麖9f@xEAnHG UuF֨ԟ*Y *'~#"$`!bҳD aCX f-7K@h 0tcH JV RIf؀6 :σ6 6(ishf`c.I*m" (G a_WRsNx0lçe^N ijM 9\Ir[>P>qghy%pr5gj6lO(6%0!c{qayk:kCooQ \P4Hgk!lf4VzZӞ?ܮ2տ o`u}(ѧP[a[WkO"#/SRc/:@T 5ѶT؀/oߡ#Ε>ӓiJ KF>!c 4f0"fq_/x*t+]xcob5zs$tK68'(ՠvYs>x#);>[1{)_J2SS  Ҡc:;0 *,K`ؿ!%  P.Ot$Qڰ$)5 ~) C::%x03fB(+_Re n ,o13d52'Ҩ2>[:=j JT踏xKHD|M$DUD39E R,B!,3 81/\`c _d0*kXCWƕ!ZhBʤq)Yr$-Bq7 XHFN䰔1dLEox"\{CG> 9@ep5KBolB00!,hSClLTmK>d6X @oBr1cB,dLqʽ,:)SЉ,Ys \$H2d# \R(s+Auq4NBbU#[ Jm( ~4Oٸ"3l x``*tHqClȆpHLc'ʅ_ @ЫVѪ)KP8KO8+,aQ[Bl\ xظ&>DVQ㽹,FCۑ(mD1)&N\x R"' @⻍2 j?Ax ҹ?CddxD`p%щy&, R[AR2iH#T`B6U;,#Sޘ2>H= T)ڝ%HY-36$K CQKPRPؿA 0t32)ósyIn58H)>sQԡ228qIiDW^Cfl'1lukgPᗠZGFr^`t~bxI4UFD2RLK@z/K3GSp8MLٜsڨסVӰVa`MNT*= ԔqT@Sa$BP7G:ۿ8p%`jX"O*kn_CrVyǛ7ة#y'H4r2<<(LK3╴+#G5Jj2״2ߘ;+[qAiN IpnMKE!L5\ϡ #:"B{ZVXuZVPG#KXlh"5CP6PG&^=^Y3 WzE-ԙ¥V S,eك 1YQ(>HX.u`G`'Cp=weH!nyg~N* ,`?2۔󥟂G_M#&7&&X´Iٰd69$J T{z]_Ђn`BYx3Z ޑR'؍.tYc0~Y`%?5y'{5%IV ]?EsEG`.u\H  nS =X$D`RpL`R"@Veeu f@]`9`~`8T05:~A<-%٤̟ vG`U[q(̾ $ Eyz+HZR .;-Q RԲExz=rG].9*;&*1x5;$j=69JƳ>ayʳRBf #4c"UItc% g#{iC݁]mJ\7¶\(,X NGGzdJ&QJ^Y+E/&bc^Qk8 L[dӳ$>?IfvPZQ3`Ȇ~LCξQi^;'M7;Uy/f/ ^b &g.F'KYpeN%4 GSa Y@^++&1.(2%Dšk=2u[y(Ű.w֓nz'f[e>}PgH3Zth[@*F)j^t?bv'G6mEīZhHGUK<Z0`B:.3e1S厓w/SUgg@J9ްaI}th}cXj*MOCE"y?xؿEF ~IG#5YpMOS$W6n/_wdU[6~{L2]PI(\nꩃ إ q?fTC;ݘ2Uxa5 Jߑ7J7a6 R-yoK'Yta|#E||ćD0yo \Л AY{&EX3CI}M~wqPs~KVLQ6q*?*MzǷ~aכEMM6N'hP1H< 'PشW%`! 4HQD";j,idA?I&.|qX76mg a9ukD0tݸ.^nBIW"DdqRx_ &h,.,s=N)Ua^#>?/~d+#v%wFm\x>}| # .w%M 0;M\7RNxrz%i邁@ųWd%8@ [<7Re8F%@28Z#ɣiGQhބ*`CaYQhF R hp^@Lw`$D BdҟQ` آF(avLDL<;B7N*<\TeU)MJƹXATydU:+$,d<$*xw]JU>BaixN],[\"QpgN݃~y`2V+"g9\&'yz/L1w(qhvWJmh%p8G;=27wSzuHmET̃2!d"@5Yvp+5̚ @%koEGj%6@G OVF&#U8p|^/PDj&`N96L{#SIB]G9t2E蘮h>I$ ^g_ 5 F<(LaHAbaCH>gA)!NWaBȀ a ThB R)M'*h=cA  :)`?UB%ʑ Ԗ|q:ϐr=5:iby ֖AqG0}v|7ns= NIr2N6y#"9R@ڔ%O"m`s?dS)tI4R}$ I*'\ԟv,:2z. }$Rôkaz:Cj&!#T|Fs)sLKk.#jVgZ] mSXV>+(l% a'jj ѨӨirڑ6"8"4hKԈou+u æ T_3Y7d )6NJ,|V`7.<__FC[Ԩ[q'沋uυQL8<4UUH$1{a|4$pd1_Ls;rR d47/1HK|*1WӃX26Hq|SϼcGR>F.q\!1J y9jR;q@]$Ls1s%|`N{Bo\#o$Tzp,PuדEIoԯ^! j= ֨fc\k׍Dp}10S,-mZXnϴ}ƥRKln'>7u[WjL{ƶeGo}N>kiIwOTm泅Ydqû 1_<P q4kE *p si澵qnDyǼH_pִrrNO5z5e\ٷ.h:DvoYeQ L[{ݛ8 Z& 3= cj|,4#E1ty#Dž' ٳO{_k ߼{O{/7LVe|;@? k^x7GO>{Аԡ_1re2\--WB ^L4i^"-`VI Ξ ` `ڽ F! L AV!_YaΟaa >!]HѝNUN^y L!R2_5^. 2a"nbI`.`Ib8͝a b!i!)F( _$R*Ƣ)B!z%j FrL!b)}/ *62b"3F]&0aa jvc3Bf!#J>>#??#@@$? A$B&B.$C6C>$DFDN$EcAV$FfEREjG~$HBdGBIHA$HJ IK6KK$NN$OO$PP%QQ%R&R.%S6S>%TFTN%UVU^%VfVn%WvW~%XX%YY%ZZ%[[%\%Z!Q6؃\^%__%`.pa;#9TM9t@C`Ve^&fffnf&h<>e>Cf#p&lƦl&m֦me&>.Xa2>dn'tFtjf-&$#=Aa@bC8qf tt'zz'{Ne&#9H@aFB>qduC{'(:$/ e#fxqBf2^(f~?~Ä@;~bun(-'@i~:xgq@!0(O&#$9D?|' N)V^B)*zàNjL~i H>+;*&.kC*D>f3 '-&?@a2fh*Ci&,c?k+&j.PA|*'s'chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,LM+8.";1333848&&%&DN\TrfL+Z-o2_33V33F32m33rBRA0pJ0VAAO[.T33E33Wfr3s/l2#iAZFv/Gq4EKFFG\\\UVWVSSpXNugXM[nqpqZfiV3_.*OBSfR2Y3Q.i5n/XtHpOtOyg^Uk2(*15m,T*(epm.\Pwtoj̑Lҙ\ܚ\ːNɜmԬpx̷Ts.HAOAZ3L3B1X5kj lPopxMxO[ $ :/&Z$L-m/ J Vh]_((<*)yKUsWXsVJwl:(/oKWlluV.+LVkUoscnяѳ⛣϶ܤ͓ҙښǎʳʨ޺ִսխǖ̗ԉѰΌқȑϫʰԘ׳ӑխȱ H*\Р6JHŋ3jȱǏ Aɓ(S\Ȗ0cʜI3a'_ɳO(΢H*eYom+Az구Y`5׵l>Ax-Hݻ<ջ-̷x~T\y<˘?$ 2X(۬F;o_fz _|AnMp3>cd}]$s|=ųZt>itΐc27T>uދ]# $y =-GPtucNuh:8aA^UJe6Aٶ(5&xsC x06ς(w-'hbiA*ꔝm:xn.MViūϩzZ< K>Шm^e{iZ]U# %^ǵ +IFl`0VTSnX@ċZ ,[#n7/ 1ȳX2' 2CDO?,˥X&hjvH.'Q-|A^-m82~ThʵNww$c 'TNtGԬcB#O7a7&䒗ԹBJGn<=Dm:τz5ݞ,^8o.*:Wogw/o觯/o HL:'H Z̠7ƬW2䠉Lv!?H% &0 ?7L9ⰡiDM8gpdJXb"t%)`l2]Id%E_ H@'뗎c&я9g?qnA8y M8W0!M.Av02bDt́Kȡ@MPGPD!F$`\<x-Js D7JcG}h湃+K1ςC0HM'P&r!aRvtD&a5w8FICjN ǐτ--PL[+t ggs:.(Ѡ:[!!J Vu&kV4w [7+%AT"dͭ_; pv|[$ &H| U TD*0 b_sćrnOL~w + g!/nY0YFRW;}Q -ɛb$geᩏ5Sy/\,x32|: u|技cEpFcʁhD"1\(1i./]_W!)_fX =`pf+6sz/"Z Bn o #h\/b;G.jcG+u1 ͮ?XyP@!%PyClFH10$Nm tC~7!-PzhuHV7^=zaOp]ԫ|]}#$D(`B$p(?P"QDHH7}M-1>q)d܎w/ӫyǻO羑 }0{t<q_{!gHǣlt>Lc-nz J:WUm o$}Cw  $MBvS5D@+~kH_`|dg~T5QupQ&R`jUp3Q ' C2  P ` 0,TT8]).7H7h,STXEuMXKT״[t}+bUZvp =`u~l Q%w2( Qz'sч {~ ~hPl\dcW`QzW[UYc#%MsEf5t2Jz2W  (E.-¸X͂zgH_h D1 zwnF;;u5puEb[ hb&PCh8@sq_O؉Ͳ"C D)  95WgkHe&؊T%j:wVE;6w  ` J PTs_؇<9> h'1yfv_\X`bVb&Hu0jԧ@ ('(W@ cq(҈LؐчP~ aUK"W:vg"U(^ptʑ`w$sa{pLYє !gJT 5EԦYTld\H@R@0)&iBp6 טٞᛦ5es&bu\hq `6y6҈,FU2 !- 9c`_gWe>`  wi6 zDꩅ1S71hS9)H9jnPjqj0^׀%'FFh]XT=Ā uQ` " 02M ʡ !glmEgZ&UvxU2R!?xp&7 >p{P*Z XcڥCwنpM G}Hpj0 pl,mJ zcʚq7qKDݣ" U  PH|xns=*@@tJuG7ID,Itax8uTXı3vewv$*,.02;4[6{8:<۳>@B;D[F{HJL۴NPR;T[V{4 Z\۵^ _a+Zka ^KfkcKDgrl{t;u|۷~}붂˵i+w˷l[[]K][KyKb [[j۶y; e۷K*븎ۺ[[`zK ; [ `ʻ k @ {˼ ˼ۻ;;‹+۾۾; + k˾k |  r+ \| !̾ k k%© ț\ 2"; *( L JK< P(ۼL5B1 Rbl$L wK zľ<|% @P%`t\ȆL;0 lª C D RܼZ۪p s\ <  ` Ơ  L Ȭ) < ]*\IϿԍRЬf@ Ь׬ b`m=ڭ 0DМP 0- &-$` . ߊ Ŝ`, Pϥ So 5 ;0\N m=Ѝᳰ̿+P 5~8L @s=@[ ̺,v\$0ݦ)V.п Ԇދk. jK6]l̼RX~ݾ, 7ӛ  \ } hMbժ 8+~_˴-důЬRyw۰M w8ܼ*-@ 9j Q ^~~UM3٢ R~-LC I l𻝎@ h0i= 2⭾hm6^ *Lpڋ1`Yԫ1\l P< ǎ˺ ˾}ҥ0-P[`"n0+P PJ =! ?᮰ӵ-mě(0~ mPlv ʎ"ץ H˾\P\ `-o)NeĮg0аb p~*yjĺPx⺀xܼ @ƐٜҎcpg ܜ0P ͬ W_ @B 26V)^p`G^e(kUȇ\|a()\nc΄gb:1ҡԉHUkV,2$,  (K,t*kֶ]h WР-eؽyj1]4-dʕ &> lt /Ƙh.\m _OJQWpWBz^J٭~ŀꂶИq~5 x!kw/br!h/N&THԆj!Rdkh8 aȭs(<. ,FXA-W&TSi(kCsq&<1ON"j! C!3ReCPq#T 6OV lH0 ak!0%!β.>F>TZ!0c,볢OF˂v;0iRTc U!/!<Ӆ,a34]Le3W[(11 eNP&drj0E|I\i,S]s! B0 %%X P:V$RW {C&hJ"5hTtj$=-BV]i`a"A{bUcڂh(@ E`l=+lQC)T](QdG)gIyr=Be%)" Vvm>r2 U נLnܞ2+iKph @@ :+ Z6%uE$?e8Q,섄ە%HV/מɅH+XgG6T<-4cNaW.R_}9x)ʕT"{H /tÇ.8DൈR+ 1aE@EDP1oc{E+bDWA졜9P'MHZȌfHkG#(( K7HBҐDd"HF6Ґ $$)Qґd"-INvғd'CQ~ҔDe*MYJUNrle$ V$)K^җf09LbӘDf2Lf6әτf49MjVӚf6Mnvӛg89NrӜDg:չNvӝg6|SՇA5bCqr6P3|00K4 &K] SԦ ҁfs/́2Jd-CFyT*O-8Ģwd"-Jy */eTbL%+T:OzB)O R -j/A("`̠iIX+"0 ^ { Bx%0մkOjD/ VVfLQ OH5Q(]E.e- "om 50HPO]pvu B;] lFwۘE(0Ѕ\VTL1!㾚o/ԕƪ\}Zb jW఻|-аKzTRQ ,1 \d Xj^0"[elC0B5dbNT5>B\T ;R6a7Q'yQ^-}0xņƻL|F*D0EiulgNP.&q vJ`/̱汃NO8A݆r*ia^a*Z%_nγLWgFf9pۿ޽̤5L,h?k{k̇Jll,ܗ^e\gf+?e Vde|kTK zc0/!E˴Ϳ12}L]Zؗ9|۠O1 [3Mp-q~C L+:vdԣVĎ}C&8P ad (5MLAf;[m,}*me*WTw[64n[֖ &|oba7Zbæ||hI+-s0S3EK'/,03ȃ&sk-O 7BȀ 1'50t~hj<|j"60D`N9}h)cND_ˇnKl286˺^jxD~6d&` 6Df<*&\E;8k.B,P)>X@Z|_ګṄYp,ZL˧]XSXڇ̒;(|f2^g+sAHGw%s\t >,zHzƂmGDGu%r&4'n,&F%{G+OH9m=`;rT<.2xWZ~ܥpXIHIԌ%`P(0ʝ,2Lʗ %JSC4,'+L&=`<0oHP+ 1JX"({8[Oj[6cʺ˯=^"D/(h, )`_KK+MLƴ]=C'qV˖X [ȧٴ܇c p/ǒ1d%^C,O|`2N*/1l2+*zȴKlO^rN0%%Ȥ&A_ǖbCd탵GK*{^Fd8j\(P4L]ZM,Ӳ} РF%-Pcw%K9Br2)lA &kNײ]k%bܵXK2ѫOPL"% H2n)+P<ؗ:b!.(lg*Y_"mopr?t-B|p?&~mn?;]rnȨ &K䌪1.Kf㚚NӅ# Q3pHm8eFmhQ>F\p,0M|xc\α^eJe^;BemC8^}hf^i6 j&kg&~ogrޥsu]6rgpΦz9zDo6Φ~&hzVfv臆舖艦芶hrc菖&|>p0MsABfidڅ іcJ%i^i.Gr4\ܞh_JsiZuDh,p /XdV5s3P<6]RfUak]T2O}E^k4A%mbȎ]^`BTNg .٢4Ц-36]sCmnGR_cW^ET7>meSvϓck73E.Aq,tvgz&6FVfvȯy3olrnn]0B%Yip  j%|c+qؐf>|Q yԷl33_XXÍTy]mU= aM7& R[{vJֺկ yydShZmLV&k\WycⱛF_~Im~u~m/ƿ&w5{0+h-1Š5A`w0 &5D(pʊ:Y"}3t%ƖPdHt@:)ԨR>aRN1H "Н }F4 mZ,g`E - ]5r!'{-P6:632% ȃ^(@'taD˻wPjT\J5O@d5* 0'ݙD7_v>W:7@Tc^h95s?€&؃IH7f\zQ!ӑ@ FalqSsC.D@Vx1O>݆!FPD ,wAVyA 4 A 8g9 !VYZX]܉\]Չ dTAV 0!5ɧ@`8>p* zhW9A,$=X o?śj-i D%L 'RKYZE䐯u$UP99A1Nng:}x3+>)K*Fu6Z>l ;IqD?\xQI\>0A\215͠9iA =4ET>5`GK=5U[-rYz]{5AA6igx16u}7y7}7 >8~8+8+18cqJ„C.㦆 ̋ jX[P,NX6"6P_'^& >'VjQ?e|FI #Ϣ򽇖E,I[ 'L%)A6QD'R /VӻҷH~곞J$b@gx}LA{T68-B̏)px02`3yA[YY $Y9 yx#&lQ Їr 1.a |c F > m>4 C4BvY  jITT O+0'"%tU\!A  ! (p,@#N(V(|OLĆmlCaPqP` P6ɻu2)VB: ۘ=5obB ]y r@ s 8jQ1GX6u}iJLnllR"$XRTiMq}`YB<@1+•)" G̱Xu `z5*@Ԉ+qC+Ydgs@]rזPƪ14)>FH1f WC>XH"&~k< 7![]0Q 赱-SsI|kG~ i Xtr(9-.f  ĺh'Na9P|D S}IMJj2"}TS:ŀTkHXƦC_r_ΠF)V(2p8nG@)'0A|Y-KlQ;wVU΂Nr,\ y8 2P{F=π a,ŵg'^u%־e,AD/z/q|(aGOB{dZУ,JC8OetCo $0S^o}O|jsgi Qj()3x!3uly79./pr/Mf_[#80z6̹2U,(I q,5BG0Ti  G9DaC">-"@9@𮐈̒(G, 'm'N1A}.6I9mg(p\#EIbNviԦw}%TrY'$M9@Ggn[M"Bvާ셼D{SӾIV+v3jn\'OrCFIsX \,qqH֚քz"}J&g@ 0ҮNj=Kr09X?1K){AkĹ'ļAQl^F#yUò{5,)H/мPLm~c/K _r g ͌>5bSvs /^ϯ~ƥ?\/?8@T?~ ?ȁ ՁG3CjB$NgB2Y~H nTCNCE}r :?AjiE V Cܠ h` >B$0?` B `>!RE:!.CA2FPa^aTdRAAW?T A* :!`6@aaաafܠ&?, SС _?0A?$"`R`K@b$3|Ap1&A=b AvN:,"6C-\(¢52D;#/Z:x1d'NE3:#7V6v#87#7#99c(: ";#<:<Σ>>#?#4BiM?d>AB@+$C$?BCChME2$En$GvGcF~H>Vd>G,@CzdK#J#@>$?@$AE $EJH$A@$NOM$?>B2@eG.I.B.jVj&hD |T[@1t'j^Ԕ hGygn%{)w襞e,)"hhƂ.kn_順&FjbVgn%nesfjVjo灎lVG+&AYl-wƩve/h%9t-**XCiir#l9j 0j從oꮼGX΃ GI.9ܩ^,]ޭC<blk#X+4/瞩G-B0 @8A>Gjv.p†k .4C\3'{T%\-h @+ qwJqvmڢbz+ƯWZۮ7|‹Z/ <,&7Þf%8-|΃{nڲC/('&r從<`&&;-7NiFeiY3Gs!pJb/QJo4eݚ0WbXVhEo%2biJe4/+jP@5oVVwZYCb/*.tle\CgZϵ<ץ6ߵ f8e0営h0C\YC@5kJi ~CȳXJte[6Z"w *%g\5i%7w%J^0ʲeײ4t&nwvVx(XBLV-Y:wg^w.:&bW1V'_kerkKӐ)D8G242G+X'9nfqꮂ"sצS4 { fXł0d >V\,v%9,BA_0C".%/w¸G1vgGl)*Vkn5U{T t NOto@ +p{(>IAw&VB6o!)`t 37p/*y{z^, ubZmz/gr>-fci}*oV~C_njw'>Sw'6j&r"qZN}z*.$:1ǀC"2++(s;i 6 z'oW:;Vo%ںX>ageb9'x:T*9'@C&e_!ggVvN%V7hxZ37LO{h.fù<37t\n'5=g<\6ʻO=YyKh_:=w=YJA̓=ڧ6=\F(==˽ܓi"%fNj$E%E:@ZI?*>GrG >?:M2>DRH"T6d?&E{>L >gdKe?T다P>׾C*E>H@z>U~C#?'/?7??GO?W_?go?w????@!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,(8%:1$$&0/0'DNYpT*v;r1h*H>0f?(kExHtR-\P5ENW Z2Pe~1rLQHw0RuMMNJJF[YNQRQpSNrhRMSrWktuuwnmjZfXF=E   43835 *MDVQU,j6p._M Y z7bFT4wYMMUMsGqRvOzurq[nxH(*33a,)^li*.RSurumxdҔO՗JΐKOӪprУb~p΋8?7'KXh9k1n'lNps|KwMM $ :/$X%j3 J V l]`=((4*ONzk\Uq:)42qUknsVnt^dڇṷ̑⛣̴㰛Ȳ̄Ɇڛ̑ǴɱݵԾְͥά˚Й˫͘ӷˮګװё H*r@ {qޔqNOάRS'ef%֪\+K0jvlWK^lKn>}x&r/߿ LWxEL˘3k̹ϠӨS _U[K.W۸sͻtlm&+xOWF/8]`umӎv׿CfWxqș39{tEu!wt_\!zdsRX^vFXv衆J z4 (W2s͍]w d+߇ .'!~=I`MxcYI"UZ^IPPb%_Jk.I- >B9g^IW۞%A:d]UZlc%o4E%4)e6^Rf* Viz碑N8pE'ډ".2Φ&# Z'(vB -h'p1 (kxM,}מZ[J\}\9F;,p SaZ7b|Ë.mLʛG?u:_p ͔ogŒ\2l>Z͟@4-M+Y3a.MZ\.=cvj[K\`GqzoGK k?f-J䓏坸` 'Bމ䔇L vzd9Cˮٹӻu3m>|øO83Ϻ=gw>ϼӺwYzbBm-9X(oNbI1xQ_7'q\8)/֯x"u.r{վ1m|¼G<}{Xp7dP\tz @ > dGHWP AT[RX'LTGPTQ4 dq9%J]R:ַb+ױzJ=:ּbb*Xkd1;.{Z2C&"F1YPYgFS'7Qydޣ*VMBfq\ZTQP;#JE'dAqWQ e_%knMZָεI|縚s*Tӽ@V:lf9V7^0 Kܱ;z׉1Mn.!)@]x.!Oq龆c 4 *=/@&`=ryjg=p6G8^ Y<#zcqB='?CnGr\!ng^k˼(qU!ZP,b@ `Pu}I$x~(M$Mx{y|dj_9-x=~ 7~߼1;˯=e7m~WvGW'nXwdzG~c9g_vP%wg 'JU,Xfgp&80 1u4 WvF7Y]8քdRaUIXWG؁ H`#P 0 4@iAp?j=V[) [p(}.O) >Z%Ox,rjuop(Og'ycH[v؀txKYM؄XbWfXU炫 芲wP?m x`S+`'X"i6U5IؖG*V+ .IPg+0C!MwĘtK'+8+.lǎ^*>18~ZqȀ(h~帏-Eяא8x< 8g v.(b}rjWxwvOgv, &O oDO&O+zuEq Mp' [o&`؀{NyXkwtXXSv儐|珳FsG)og溜َ֑9!8'ـ,9t 8vɐY9閕Yۘ+vvvƨ` Aw`gHǎvփ_עGvd'@quP+@(uix(ot iw( vHJ~p  w99蹚`8ƴ6p7FWi&w9I@ DēdWNɠo=Ye9O?& a գFd rw>ڢ/o a 鉤aבWsy{9u ʟ`ʞ)7vfڟ?wnʞpڀh8ɟ_ V+i"p4lHMljHٝ"{ ا *(uhn鬯:&)dj婭* Z:j|ʠʺ zڨzZ 23K5Izo&@=p |&gQIG[qحEdeGigd`Zj:کʘ${隷9z檠*y:H ZjTk`ڐJBj՚ʴDAQS;;X+ Pwi`I:ƷuNM|t[KJ[┷hwus"uZ{ں*ZznٹY=뺘+ ~3Qy?̳˺{QPA3V4@3F&+ꐲw2:p7"s O'0jFz(qb(w+{`'N 4WC[NKb뼽 tʥܶy9ɋ~4˵w*¾ v[¥{H@+ꩵ;(rj(Hl@ )o[Q|IP'XL+"ʼnmF+JcxƚNܭNM`sts8; |ԥК5 "8EKY|8 ]ϊW=șkծi}=S]e '9w8 9c Nvi1p 㐓l@G&-0 @ @) |Ok H` }qbL),y-ֽm|ygý֙|Ѭ_cXMM} _]rM]m| Dp`WZܭKW:vӆI>fՀq m@ -T&g=_N%U`g59/P gɝy] ֟mmּɎӾtm!3^+^+ =/X Rp) ebi2 fp,J룯jvML{zDn" I^x|Nդ\֓>A>(^]҉⎍?^<č K\ ՘\>2P3D,HT `ZM *dQG9kmEB)̼|-K^o[;L&-ҿ[.v4 ٍBϽԓ^z^v6["[{' k}f.Z|||лr"K>޺.nګC<]~IK_/NXD/ ׻a-f/:o?4V4 $ҙy\ `*8g^ gG. bs׫Kgm|Hkg[ߣOm/n/T:Nj⸟aMV J'_@zx& N,'ƃX@1Z7Z @c6oa911۸ >|881("ŋ)2$7#D%!Xĉ1jhcJ[K"M:R$ǛC%T&̍2W"9'HU Ҥ)1:yfΊ[}ZEѐk?ݙRt;UQ$AUOB2 ‹ߑƹPflj]*7"Av0kޜygXCxepc{y侕_sRǧ͘QjS{Wɶ"}xoؕw9v_\'%g˦>|hw'L*'Lr^{q„Xx^01bN8a rQ„K& mcl0$/ MHEp8A|фVxf( M6\O))Ll[ *2J ­4dKnL;2;4FAzӣν,-4 ʫ :YM ;\цB UJU0] NBS=ITͥROG|4#概L*DۈʯMVdBJ=Iz6R/ZVqlh"VR7c f\vs7"g.>qZ+q l>y\эKdm6ki&/- .A _[Xb,oŅ; _Ma!μ-gr"'UVTCɌ3;REQia'36u(CvDڜ|v =߽JvbokcuGn3 ؞yͧ }V‡@{G,q)%LCndxYX Bhe8A eg FAoeBSp"32B6*^rioQ*^䝰N4$Nlg}zW(ِ{;EN(ZkKG_RYI08$\v=]>l#zIy PR(Y8Xd}+ч^ ~s{5!8zx0'bgMx mZH廼ƕSz";4bJX) VSAՊIІ;sSl[򎷣kbo88 q>49Uq;R!C&TTJo ZQhZSe$5QWLۮy(6-~Q£t&q&9iq8vqGu88w$5ej^4aӲ)peb%0{Ǻr~[#ҽH0 '962DOZc3<^4), PX[-bT\\ =p콭1?iK`bX|/=Fs%m|5ق!I_1kZg6.E=E[!s`R21Mf-A (FTM`V7f&ujb۾UIc~sdGڕSimSWM,['xa3|6k\-)MS|Nrt?|+,yWH(Zw{n Yhמ9K Iz)~ =qzv+k;ş-;=1o1Q{b/^g3{O=ā{ ^ sR}__~^|7JoWϧ͟cDo?~ß>?˿?\?@?S=3>˞{= $@D@@l@% |???& `ջA>|ɲ ԋ9"",\QB$ $#A*t?(B#|B*)A0\CCC1B&LC2 #69-3,C87AC&C#?C DETC5CC6D3?BD8FGCN,E%C,E1d&CS$DOtDN!-EDDc>]DId.LAd4@MH4F9hzFRtF6LbjERFFeFF_,"B'qLGkFo\vDDSC`$Exo,DveSTU8TuP; RESL5TFR/GRYTPCD;K%R0}??5U ϻRͻ~`a%b5cEdUeefughijklmnuV~W~ Vq WqsEtUuevuwxp~z}Wpy؁%؂5؃E؄Ul-q-Ws]؈؉؊؋}~WW}WXؒ5ٓEٔUٕeٖuٗ٘X{퇑}׏Xٟڠڡ%ڢ5ڣEyŇ׀؜pMڪګڬڭڮYWs٧؎WpڴU۵e۶u۷۪|WW~ۀ۽۾ۿb5퇞|מȕɥʵ5|XZ@oxZ@YEUe֍\ڀo Ds YEYzq@ZjH^V}oU^%5E_%^% LoߣYW}m^&6>XzH _ `f}=}_n ½W}Va&va՝ۍڍa[e`MaF$V%Yeڐ&e*+%r_Z01&la "`V2v78\pb5a9=>cb#>&B6 V @nCHc)MN Wpud`O6SFXW"^c}TY嶥W/dZ_fd|~e eff~?>jedmXglfwݍeZFc5Vkr6sכ5fa6ek@|g Efj&bfE[2g|Vx^qbfd%g1>N VdW&e#g5{6il⏕b~gtB]@TguP| וdim֋>&jgPWbC(B_f)jƄ}`YȂjHie6&V:Y5&֧>BjF@G\i}k{kl0Ik+&il>jek_dEXkF(D8e,ipĶnm*tў׆ֲ>iUeVfkBHj4nVҦs-fnngmܦn.\~#cfdvgPW|X~Ї]T؅Exb\|؅B hy8C@{dXi_^nb݅&ᦇy }Ea%&qdR)VfK}Fben%vIXd5Ƅ]v*[d}8Bjmas(C'B0 ?߅5ׇ5/ VykCpCsiXd pz '; [^ipV4jMHvqs])k+@xRkV(Rj`0VLkr+m\maE`Es WdpBgi_gw`}jCr`.nWsC5ygpB@gVlpqjH~t$q~h&wklyV)^xm[`bVyngxPsЎsvhd Dj`;'Wg7yp;d OE Cx'mQGV5}%gq~LWZ}h0#iքDŽ}ez+p&+P{'Ve'~`-5qsmvw _y~vBw` n `pz/pG8?{mmkVٞzfYWqg|X{&%}eYb~qWtuojԯvzDlwns@o?VGb~tI\yuNmbXkWe $~.6e 'ÂP"Ì5c#Ȑ"G,i$ʔ*Wl%̘2gҬi&Μ:w'PgZIk1]ԩQ1"aTd 'P!iFwYG=g;Dȑ?Z A;[ԼR'VMcIYfI=xJaLbOń!GAG|ǏAWn5زgӮm64+Z߿J64ԾnXzcUZBCB7nƹ*^e pZH/nBT?3`qh>iRj9 J8!Zx! E"Ry3R)U 1Ws_Yԑ]?Fu_#]Ci sPB=|SlV_AҒ9iDeiRT!i&m&Qx'&UFisMu4VW}?>%V?wK8ƥedT7] RNIeztfz++?QT"657zQ(dڜḄ!0VEWFE#GcKj fQVʜ{Q)*e|r>*1+L+ +0 ;L!oVTGbSVU=HSp\ע[IcXs[5Oyڍ\ҔtV"u j)Vt?\?<4&L'DF[c:c WCQ3Cf5|FS7}wCUq gq-!E8m[w,kW8oMIr8'1teTӋ$A"Ygdia뭿>E; @6y+<;/P13x 1bHu="?;rbRvbCҦA$&3Mf$b9 ɧxC[9 'bT|~5:8NfJXd%0)4 ΍* 'Pd3)iR5oQˋY՜/)q"c"Έpʳ'/Wܦȑ0m=(BЅ2}(D#*щR(F3эrCe ґ<%Ԩu'ވx(6)Nsӝ>)FK*ԑP&>#z7v8PRV*VխtC5*Xx:P6 ^8S5*Wncv+^S 5~5"1~Cꇼa@ɢ֨3 UH(D Q<ãq55\aOXbЫN̡Yu5\ZҶ|-_s;IlGS1(jPRDFN\- R@ Zãk4Q -h XA彯BokRy,JjE%XQԕDQЭ)nZ7H M8  X߂x zpڬj6sP>VovHXf&T`h> k@)tQ+uDB pbjnh+\p571H0;avpA%X?>t,FnQ/੖Sk(n/F߬4Z3yLT65B -DzoրGF 6FRY[P<ӭR66^}fV}gq'T׽>w966CK!Y ¥  (D!ۤ 3@AAp" PPx)|0R$ FDgiCdzO탒&x}Q@RJ!VH^K&Agܡm7:;lú:5 n.`ڸyγZ1Ntrs;‚<` ^$. Jxm[ΐ8Impk, : g"uJz"Bxbr3 bcGo|; 6[$ Z eb6@ؗKX6~^Cg,ᩚc]kxR6?Q%eeeYYL $j :IONb [:CeZP* rE VT%P֖U2*,B(]!TQejA%aB*B+z9fkB>e.ލ_%hew1e64A}w'padLµIZ+=gyq'zgi$fȜ ^`hqCI./&sh`Ay 2> A(TʀsnaT]_]]ZjgBa'BAhebBIiAe $A]C),c5tTV+BgaDY/堏F lm ,"ݒj%|g$4X4tH@&\5$ TQ^i)&B@X/4`%v@ BwpB%6\ǝ-ڒqmVc]4pAq55TFʯ51 lb9ci)xsM093eЎ ؀iBP524RTQ,!E]d߂BYl X%̣\*d(enlda32;o;T6R$ o DPy+0@2mX:!.`r{lx/þ ÕHؖ\!8MÊ@Еӧ;8z}اx59iGڷaۛ}:}i}yqׯ"Wy=@pA+>wﯸ<~,hyS;>l>}~ω.f:M9D; 8{A ݔ]@`A&TaC168w:W1A7dI'QTeK/aƔ9fM7qԹgO6KJѢ~:ϙѐ!GahW-k6tpݎk^˖o_ķ +Lŏh6dV1gּsgϟA=S_M6MT)QiMcohCIк[5{5?mENwfjl\G(PԵ˾5"Z=xA| zv/0 ,x"K'h tJX'aX$wt"yvPQ`Tt0C+H'hT3.I+PG1yib0'đ!j#/x2I.33QwG|B 2FK1TM9 Ӧ*ꩥk* jV>XujTTk˦\&(b !*υw-hԓAJZ[Vk'RRrA%\)(fop1e[#a ( jRP@YxQ1Ȍ* `c V<m a^QJŘ xȠx.fYcc(2xhyhpj\hIР4 "c1h1v٢h:[[tQEeJT*ʤTUh~`[wp=%nd蝴dxieh^qBgF@AEZLecoo u^}Bm b RQe".; EOV9!  a"`RtM/y^Y<OB^9tƏ}pW.O|!H *D4 ?ȏ~_[lZd/M$x3D%.%ЇRHTTd*6#j}W+I+g9IU^I(c*K R I OEQA-TuhC!3g"l]V!K>-apKЍ}BG7ˬk!B$Sǃ`GslyYRmxÉ+uij DubH#Kw~\l׬(mI[j !p}s7>:Ca/~B=xE)o 7tHW 0Lb:ϊF"HOuh'RyN\/!>YA؂mh$Kދ®p.䂶Ro b   UNbh C k 6 80n oo(g*77Pܨ֋&A @v"Y:i 6 yJ 5 B A@"򣣄t\!" oД%IK `F0x!&Ϣ/2T.L#d fa U`Z!!T) daa&/!OG, Oޡ1 pk!R4 Op`d#pMѤA0+XAAQ$c$8by>d6A 6^ޢX! 8d W t "-.+h rh aY>I" S- :aF$O@` .֡ 3:OOdzHM\/GK ^I "Jb\֡,>DUG(:x;:?;PW gUXUXePV *.grPEMY qz ZA3%ye\ra9B[d^(/" -B"2ଌ?Fn ±ւ[efaBabn . kGSh[x!FpV_ UUq0qÿ#Mm(_q#QZGv`% HAy>\=wjxg.iyA F,'r- @=~V`wd,ӅHLd `A2wDY gA3Ld$,T\w˙=J;"K<ۦMat<J|]Hh)<ށ)Ӷ6b?5ie]=OT@B|5iNIr #ķƫdà0 o_‰,z48gQFbi P >dpLiשȠwف^8ڕYpj.mT  > j¬,R+F ko4NE ]J,ÉR1*mH@ܮh4#k Ϋjy HkLUrf+2 {~u>M7^a7;;pbs-@޵er`&wmQm: (' ,TG_JhG`.h> )A)ԃD!? V?`ͅ hqxH`?n2Px_0PYQ(2! ЍFd8rvCi-+Fz 5,ۺ +oµam20#r3$%OGmzqolѡE r"Lr&Q.*X+W^a>R!Ijf07>qL"`4 2C)L=$mՊ0qj͵]$ 7 p:41ּW&]YxЅm|'&ǢN:}trꪯz4O5TBszXYLժ; Z.B.|.עc[C }"CeDj3$m:e/D;$ gGom <kY-Fy4@8k2<2w8D@9dqHvgN3O*hz4N8Vʐcnp)J1Q фfV3 fЩҠG\eX!O'DޑcZO#2>:=Z!f#ycyurcb ) 6u(i%"\xN"$( *$^o a<¡&h:u"*t$$^u"9 HIG_@,a9XXyr N?<,9ωtDX DSS)f ^4ő.x IдH##{A_1 n a6-Z[f,*jH/MHiFx<ut.!;0H9s} ֑z"᭻]Ie2%j¦ z?bpuGԉִu!K>q e+<}J0?Pg& J !*%1#P+8(.$HrQFe+>"lDᗊv!(_l wj5p"=m+G4! &y2" LCs!55œ [O fDW#f=[ ʷ'nՇ9ϖ ͞6G=QVDhiɏH3]<9n$s퀰9R#dX؋iG/tQĦ☇#kxN8a K <c( O-de*~xO8< :za\4KInߌN~5/+ʚy2E@ z2d3DZPV)zQE0YzӜF Pzԉs< L1=ikմAM\z;I<au -w4b ԮUb ;uo {&Դtڇf{VǷ?|wĬIm x 2=o}+| W 2J}kp|hRq;3YAK_9$s&Lre~5 }͏Ri #8G +dK1,f;܌ L"G$ {G/\@'p ^u\Nc5(F=Ϻ2 V` AG:& 1V/-GwHg|&BkxC:~;kWWXΊ$`/q; 0P#'.k_3Q'"FP06_FE% 1HW 0af3 W̨ /\O  #} *p'W`f&Ɂ-\ = ߸lO`6`#P )?xx/ 8 [40XOY0/1 he!/ wKɔ'r= q#2?#S񠉾Zeca=5n{'5,EBׅtpIY0P.1bi.{2^Alǒ?p7T$T@ `P& 0 1R`70[4bw3]@GMˀ碙i%#邅jb1Hy.`E#w(BRĀ.Lu7'(ؔ{O _dUY^SG Fpn^ з 'UH2RQI@ @]0e` 6|I1@ ;%W[yU=/M`.GP  %N-Z i&U/\6AE {A``JZ44ڢp0j a !&gJp򐤶zqI]y Ơ _@p`!䉨grquq2'G1eIW$u2 q ZXKnDN@ggR q#7f7c$$u 7r3QA[4^B42t.f6ˠ{)|E%4DU1z ABMwyq@-oRUU۱KdB*p a\$#u&b̀ '[2kȞ5adCY_)B0W$@"62G4 2 ]tHY}`VU%=$ !9N @:z5499AH.y?"l4"{K/ t7i˒he%xA 'T坘pNCtA#l>*@ 3pCۊ~fQ, KpEށ2k(ԉ(SG DGג4럴,FrJ*PGς6'4. 317~h6j[/rN:J;&3N@mL]P @7|o"tRJ+RL3tSN;Ss>uTRK5TTSԜPUuUXcuVZkV\suW^{W`W vI[XbQYMvXgOe6i1kVh[p)p]7sqMWu֖b)z뵷[jzm長aaWj>bz}w^+.9zAI޷I_?dE>5gixK^k[}7x~bwfvٗf&lF`7l|N[mnzYoNႫ|&Y`o~Y]F!%O`^pyq9} W< uu[0N|_ƛg7iu'63wYEa'Yߟf__'8zhw|˯/8Lj_9n~D[:}6Ch{}s8#_雞-* ^+DqMa`趵lc.^ay1'CzU3uCUƼLDJa#A'6_Øɀ3[iF4W0őC[xC L#oB?$!YB"[$2(j.bq b$ ǧurZ Ȇk4&X`Yh]5t!̡s+>ogc .tLqL@&VGГW71 Rw/\ Q"k81&}!$3gdLP'ЂD^H_MnP u#hN}"E$I/e> IURa׾`Qrv\hJFTo@}OgҕԧDݣ9g ` R5@ jSL/tqLKԂ]xĕ8h1|&ghN3|^&{ҚB%zmf4;A>1gЋ$b 'y[J@s˲l^o`K*,JJ<6 ;Xm8shcK6xhݨ-Z]El&)P97PqpKLX&xۧk1ŷ^ 0WR nw1˹Fϗ)s10bT Ʃ}bK&ZW[t̐0jPVj.XY7(UϚ>#tn vmE3gv^Qq-DF't#;D~^B^fnXgxt/_e _gus=`_<]qy1ܣ(iV_fnp΢L:b̼hə䟙B8C5zjE'^&(< f)Vc8zY:ˣ[?$I(^Z@퓪4B'pqQ!WNx_ؒ-^2s2.)S&UQ6}Yв rc16[#K3ͤ4M 1XY1>_&UB;Ce~1L"^ TEO{]j$5Ū8I-6Rˊ#8ydof6^ccI>T@ei€q] `Kg-֘4P~ŗ *ig%>:IPhP 4ISᩋ[OhΩD֙-oT1E= JUk3r`_U8y۞r2><}yF~<1*K80˗U%;)RPy c'oK#)ƨ7>Eed{1wd/.KΗSݗͦEl]22PY*ʼ Q5.zfxndr0gq#7\?;VIYpI2.Sq>1syIorȹfo#fX49"ٗr, t?"gH$w:^Hg*4c<<2:< 2$}y4E #(yNyiֈK.+E~[l}dvrXbӾ >/{y?(fW3{tyDљrU`ouu3˻[Hfs*eUy_8Ko?c%7z<[VbެR9Q\$QŦ/0ABFF%C=]OW$ULVrXJ YGKt%>p(%'ɱKjU$XjkyɼI']i15E;Wjщvd3dhDI!ZPHw-03 #R@PwwF 3- jFE4d9SWr1Bc~-U] 1]1@Wdym(.mPw)@E\R T ]t5ozSM`X4*fe+`QcJ1DU3q&u׆m(ڊ2"B([J>V_()BB`n5r ;A *^aɝt /:GJ F #SUt\Fdj`@"a(Φ 8;3{˔U$Z:qĭ2 ṙg8":*%cK 0#1UP1`ҺPb.x_&"bu+p Rԇ0hX<"ecҪ"3t)H* R j+/@ R/h(@,DD2I!À%` (؁iozx:9SZ1[- A" %Ӟb1Ti!հ]Z W v3ym\l12TBNM(PXF7!ݶjg"j$@8%X) G[3.R&:X¢4+h  b jԣ+l)@MRi2ΡBZT-jlNZbzH@yf jlqqo͒-*nI h_Q]Ky]G]p"P%H!X ċT#8)F]U[}ſ+ BR"k%םbhbuidy88萲(/bt+фzjŊCZP cU":+ZW UAkkOyXi% NxzJufquHA۬/iKػ EṴT*Q9v6(-FZaCghu|e( "; -nЅ熩RHhy.Иvj&+̆~ I SV7{>:DEMK|._4ZbhtHB,Zs,> )q$]1CieY1XxqRy*b?Q&Sb OknWl2Wr* V[,R5v̂B`ikF" 7k0AkB-28|%rkMe.z I-FtG. Ry0w-vc:p3mozY79 YJ"Ÿӏޚ"?7SWڑQbTAFjyUϵhH< lHCRzEf6k\/|HUD Qc+93>C$ !/Ec3@8H1#QlǥAU=A##F;r,dld**9KGHIi@ AO ᘩNl9RE5Z8 cFdO"%LP A7$6ΤOB!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,L:".<3(":1(2"""00/+CN\TmU+g$h7v;r1y-H?1f?(kCkNwItQ.\Q4ENX Z2Pe~%i8g-|1r;t?~0'RF=E>NR74? *0MJ YNUdY&j5q.u3] Qe7gsGsSwKzt~kWM(*42t*(avn/Ȋ8RST|rjrtix|yʋEҔOԘKїTԪmuhϞ]~|vm?77'KYif;l3i2m%hMpi|F|j762qWTflgtqwkVcrtXgלγҽɲ®ş̄ȅՍښǒ¬ȴ˵ܦֹݵͩ㱚ƌЭȔϑΚǗӞՊϮګֳذǽ݉ HH"9ȰÇ#JHŋ3jȱǏ CIɓ(S\?}췯߭[rܹ…, JѣH*]ʴӧeœ9N<{n ׯ`ÊKٳ&Ƥj3+֬>Kݻx{TmM9fժ+È+^̸je7x9ǠCMi~gִrΉsx SӸsͻlo v-^ٖ뻹УKG L֮uJd/'NOen:gx;[}Dq)Gs% 6Rjwk5$| B: `4 6O!7܁ρ(46XD![9#P6iHdص5M .wCg}+.H: O笷.{ࠃ>nd6/?yF#8,T/ &?| 0rd#_8??2m]=Pr? :HupF̜ JyUt( kO[[pFmX!ƍvؿo`,HDq>vmA(4fmp~Haڲ,j֍lb^'EDbX,E0qnB$\x l[) ׈/Y!" iG1i3p7A2su<^I})&,$ vYhs̉Orc+JʭěaɷnF&%G tcY(C)=qc 9ʵ m]DzX[/vod# !\@ 0-m `SxQ6w;DNvMںA xnKfPѢ '۸yQpu<q$qn \#J F\7" 1QR{JN䀇!`g* e*U"C%QG;#UmcDTJbo\9q`+ĖU/\LeJħ@i Wh[5 uHVwU+HtVm B<0=-j _#{pc8V ־z+{+w?O|omod57YVPkMEeF `Qmܰ ^/7[#Dyw=q_!@Uw a+J7 n n-a*>+v/ކW I7?FO?_YdBܭR8<_ nҾ} (;eDn9#A L186 Z A{٨DP٦Hlqqh#GpŹV=g&K7mȰVkmC-z۷+bi×g˔/22KrTTnp>/Ͷ[ +Xjѯ%Xg%F7t̉^X蹷 $ hD{^vlbxT`>+:Ҧq/kY& nx0&RnW#m:TnMMwhe<^IL9C)?m6o(W.nⴳŗ$Z24"fYH翬t*x^;xK-ۆ}8'[٢;ڀq6|d'L-_{?x`lxNS]8|\s0h6vmk 7zzMd*#JmޏFM[}hhvůdL9%-O_gv1=6׮ Ӽ#tȓ}3ut7z2*.d\l~jo3H}'DGu_NPp`Qd?fkMiCrWjm\`eI cjttv5cyczGo6:? PR< 0} ׄi6tlη66"E hӄ!tH^Gַc3XSPZw` :6S&WmTv Հ#W0M .(z p ? wKp(thfƃhs ;jnT`7 Xk)6wc@ hЇ.t({؇|W6b5k8ܠu6Tip\;t=pnj#I|$I`6 C=C6jm CdMd7Tqِ5RM>BC~Ïh58}s ;`oАI а7 ІpS \i 9[ٕ q9 djf_oÔM4Ӳ;sS/K|cs3|I I]xYXW7W藔4Sq䙨Y4U'Id:әYYؚLyֱ}#Z._Y] 8Z<Lz ?Ԡ df b~W< \r}߰jjgΞfnlq.ws;f*˞< @$Ju12 {#" 2"zP `7BZ3yXk&a "A@l&QT4b'1'弧'$9sfΪt˩65oV,M0U5YZjHժĝz^dѐ!%]#H$lYf~=ZhҥMFZj֭][lڵm [}׮رt]MKfXsM֋rέ[}dR]EԱB>yS?30@$@D0AoH} 2 {#.0C 7?1DϿOD1EWdEl0|o1GwKE!$H#Dp|2J)J ,I-K/t-)D7+D3M5K3N9~I2dO?4M7PCE4t @'RK5!E7SOkTSOE5LUW_<#|I[J5W]wES_X%Xc?32#pF^6c6[DQ'7\qZmE7]-tF Dž7^y)Zu7_uOfe\S.`yAS5\y'`8c'1ەaB)"jB Bb5X؍wg7R#n gD)p!!"C G-2`$j_^fZ&gvt"mrG `-bИEGyC,l_FDIӼԁN_;ֽ]TnkoXjDIH܈&hkZq0ץNzani+Iܳ7˫%2Ȭ8DUH/2ͩX",w L-_څ%&<9fKU!$0~O0p)b $E~ɺ8h49.Ax26be1+B+aUrHƃ2/[8#8'a U$#ar: eF]i2A 3"L PNH3Z|:ԣVI C%`u13h2gEάܐ 9 =pȢU"G>v=nJYTr3+R XƠuI N8U&/ HI&.*rHx1fEc 1}Ql;$$xw\k#1Z"FDX B E)LqJJTX٧rmOx}Ǹ p="`@;VGaN3,G>" O|4nu['#JiahюkRa/|AFm<5(C;3~0+YUߧ Zzާ di}GILJ͒|z颿qMwUq i~ ~L8~+Qh @H=3?TO;Qy4X S`ٻ(y_0we0\6T.=?.鷽15c)a\hA).(IB$zCR2.‘zE)I@@B7 ˑ(; yX B9QȲ2ğ 9@P@; 0C;Ldþ LkMRjAH= 1E? ALZ** +@Q6Q) &4 T,IIZj<3"*> y8iCU" 뉘)GE@W؅ ؁]13؟y]-FHz@4ed,+~zT) S64Zy`-灟"{]ȁ 5PhL@kJ" G |`t1C2V|{0%(!&b$"2"$J&jR)*!,x.ڡȧ/ !R {K7T!R(b"{i5aS@ hBB-B @Dƪܐ"{NHL5d$BҚxH$^`xHQa "cNArN%D}bLS%Vr%PF0)Tήΐgc$GBOb-yKM{z@$thC(P<EFr-9X(Y@ dDڼ i>_2K7vш)AKK.0O*I&pzf 's tR'v"+O'' }rϐPcojXd(I3ǘ0pkF #5,6F+ @ 'Y EEՍrQ1(Dz2.,PNU,]CDHK+N#yz)@ȳҶR5A8EϽhH{8&b I`zBp2hiJFWs#W,4*T* e v]F犚F+52E׊חbjȶ( ${',( p8O`uk!H #IVzQhh`L4;B pYr%0,u*u3,}(,QRuڜ@j-K eRкVM}%\51̄x%[ x%gYtfPn ֞Eܿʣ.) .:b"!˵S}T[.$Z0R3UD9 ͛98/R/]eEVDHU@M l`1\0y>mZMV T)G QθGeE/xQ,ڵe3U k ;% 72܏ܝ^eXbXdň;ۋz$]{UY6XSٜ =t5 l)<_|\ A"X#Kٽm8ʱ TC90pz&x$ƈ̟Az @ԘV͐:o1j+H(9/4cF3c* ύ:" d8 H;ȧdn- 5Z N֥A&%`4+ۉŝF6eeMjޯ/JYr[;"5^pvnTKLE4O[ PKT0kfUXs5?5"W]l5`l*6u6SqpK"Vd6!y0Q-C]v5`xZLtN\Te R)fgbpeL6 K|g؁c>fFF#Wmjy9/ŰL7U83 lAeZl:VxjMrILcͽĔ^&&\=gl&1dŁ`ޡLpk cMxBޡQEM )h*4`v&9ءͶ8Rc 8:8< ޜmT✏ ~  D,R튓H \dK٤$f%ء` 2HAjkS5hG96EWͰ#(C;N^ƽhcX)5t ɻ S@ ɎoIWIpNc#= ?J4:\2.>pQl Ju= vW/7Gqk˥҃q[p4]Wr Sf]lr'6H/,l3ׯ*s1_@2s:;<=>?@A'B7CGDWEgFwGHIJKLMNOPQ'R7SGTWuUVwWXWY[Y7\u^^[Z^bocGewubgggvnijuglmnopq'[Wvc(wr_ZPmwW7s@tZvkw{~/}xg7GW^wsO[`gxzywW/xX7i_ww~v\_YG/wgp_yf]Yxnw\'yuRYxZb_7oyZx58hy'pW hٌ'[gVbh{\{ov_qpvvY`wOU]hVH\@DuiCVo%wR nP[(FX{g[ׂ8K@|~X'h~{O txZ(Z ȤC[ʔ['\inɢ@Z2l!ĈACTp  I,Y>@kDƌMKZɗ-j(ҤJBD %&XƒҝXB+װb*%JL#4\dٕ:rn-ma- $ᚋ3ވ|Pq[f 4EǹnDJf,X|Ay#ė$:M i5gdhל涔F J&=%>ܘPpɫP ߒ.n졍I(b7r(]oIEn˩wDs|HCX4|T^KR,l"74w024 9A]S)ql2$9„u҅u)w -2k&-IhCeXRG8Z'GSՋ|Sx4P^"ťq9wqy_+,c=eK.!(rTKzlOMP1!J FGbC(\2a1$+,1č,F"H7B[M]A>0JrX Z].\0ꙋRK.f(0jCC#a+ eHk ++y+h$g렢rUk.֒(<0X,(Ьr*2 ,D2o#ҡ6)z(\ݒ " "@ffI'Y5F}g@)} Q/h ٥+$]_u>čOnХ1 T-pBd սd@P-`@P/2)MA")ad 9C5."Q9Hp8qxPA+Av?*B9^ %saE"t2Ktw e(HvTj@lSʦeG>󕄮- !0pv 9 ~{{ò8e+IL1֧B#OxW_x6&$^H"cD-`]SV0)Ezh*ND.F$Dm h0 FFGD[7hLU1J9PnAitt7Dՠ ˆމ6" bB -&#A1"\IN#'؍'r"r|!c?6}AGp]_n!CzN9#9%bC[a=af)"|m\q 9`2ly ".JE$< xEgHf2ɀiĨmNN@9Ba1F ‰ڬ@E Q z5Ƙa B^NE\ȂD, .(B^Ф~ݭ0P-l0ɊpbdH/))}iTM%d .BrD K$g0 Ղ,8Ȧة(dNfJ@ih-"Bޟt΢ +H&OT\xI,jx,NefCB(+|IS(BfKHk g V둍35D(@Ղx{ثXفjÿM![$Z vC%^MTf(MX-tgWM ؂ZyQ˒-kp~ pn\bu$Ē @yNG\ %:%D-0R\ՊB -mug0l-h P*)* iO^^/hҦЎRp݂@eB tDzQpǥpTOcydA! G1Җ )j=|%Br$$znDS\QDH*.GV^F%US /|4V5i-nِ@id22FJ:휶 :@ؤlmHH,* H/[To鮉/(u@F-T.}˩zEw\|$؅,h΅DDgSdP@YLĦxvt ZpKC8I G^0 `|< Ba4d)0.BK HEK|07Ei&E H1˕qZ+G6ʅ18J0VN.ݾ V@!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,L".;1*%".;1)&&*EMVT)h"v;r1i4]zErN+VD4DNW)T"i6h1r;t]FyMg,Nt1GQQRRtsslknb]YM;ENNX#R2X,i7g7[)k2sFoStTzt__(*<*(>X*K-f*v,(L(Y(g,umUddzittO[*/**7TQnrvmyzgҗX˶SӼdͺhܨpr|m%DN&Y;l1i1l lMonxN{O\ $ :/$Y$O/j3 J V l]`((<(<)KUsbXsVJykچ:((*(-7rSflhtnSzo`8XOrenz䜛Ţ⛣ѮٛÐƫ֘Ӑұӿ԰˖ԋқȒΪíːҒ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\2"vbҫw/m8sٲϟ@ JѣH*]ʴ)˗bƴk͝9jʵׯ`ÊKYIj[n7ʝKݻxץZzyu[ q1VAv­#KneF 1AzYP繴ӨSnVfzW :tʙWl߿+ / ߇H_FȤu88EĈw#Uxӫ7z={wr}p[1qG8q$TG" Vto@ :!^x`KB5@M pխ08W{2f[8)1lEt"D 3j S"I,C!oDCڳ%O6e!%$ (rʛ8ӥti>T[qؘsvh!6Dq h(RB=a5xjꩨ`[=FJ╜H!8fBszȕjɬ` ҮnZ&$-Dfۦ*EcTAQ˻W8| nG`؁@0ntARN=\ 8T@ia1&AFBPɠX(,' WAh,EE">wyOо\E @953VGQI-,UY#AŒ=@TImE J6t`Lҿ1tAu3F.cafUP0Gq/nupsBGy d_#C繍p .L3C& s% o8z̋..p==Lڣ84 $]vw-.C*\0Ԋ78?P!P qQ/H?hlʪ Ran%z \"B[@ )(rl]n`юvBR]D f7 ĉC3TytOD]䭄7AF8bH (HY!Yb  /@# 3kQ$%FL |Dp01T<)HB'po*%{T&5?Z;U%4!y=H) P2"Z@JD6 d1CR lnJ-| ]q(vv &= ɃrȘzCP t}Ce$P0T|&2:@k]#װ bd+ڊH ;s?X)VLl;}_e͹ [&MdBAPB{c"yd`1YTnD2 \7A_%=ŠiTS2L9DB`qlfe/mm.&UpL̕n~0vA3Bsrթ2Wt˚BkB  ǩNr~"NzuéoO:7damqxDTÂHA9wgOВ6H~ .W(4gk;t66n?X7'vYH)ꂻxJ˞ӧ\8÷Vqf7̆xuǾꠎjj@γQSļr:ɕ7Ů{.vٙe'BJw<[A7옯S'Oa0gҖBrxN?QF׏[ѠR֑ }-c扞UtȀϩ%T5pᲙ:HX0}2}# 9 `D00v8!3#3rF3%*SZDPM֢mФ,I:dzR1498¡'e:tZAPjPaQli2lӛ|FV ˳"qPkc7p%B'3,UB3*M2ut[w*'gᓆZ "JBlu|炭 \Lȡav51 a{1vlo˻  `™`jC0<˾ "<Q&< e-0'|Trc">av6wkq&| &l@j qnpaXF'  G<cl!zԜI a;x l`Ϯl˂`p"}j 1-/ Iɘ IԛְDѭLp0ˠq@`q0 ,Qp@a|,Zm0Rf{#qMG13 n6HlLAD^Hd#} KJ>L.ۖ-N)7P7# A| ;>MSyPџ\搾{;k.q̠kp2PЉ5N.S2- d6]@esH8$F>;j>|Ιln';ݮ Ll nDdƞX{ʧ[~-n|γ)& (}. !ICGvvv ! +{q  q, 8H-ŰIj:MUN{w09 I{'OPY Wdj_9hڶM 7#xʫޚ~%JNܻć&KǺϱ X\/;;?`O! n v CP 6­ Dq>a,B9?._P%ȿN|FU0OK `۟Ow\TMQ@ DPBXpqm!<&cQF=~RH%MDRJ-]SL5;sw{T6m5 <ݨ#r<~VXe͞EVZ,qރk^=5OбyԨd5kD6͜9d *gٜs%ga``G|>)B_gJ3hEd4mϖi?[u08t`k]vݽ^o¥m~<߿D?5d ʗӜib28l -$!RR:!d"D)/ gB{ 0<`骻,#H#D2I%dɗ̋ sR 8c?8"cl>-+K8ƍ+F 7(lGNFᤱG00﬐Eٌ4:]@4O ;@-ڤ#q;D$TSOE5UUW JҮ)re7L 53-jzIqx ˰gP@a6?{MԞbTBgǍHj(P#pȊU8`&X&v zpa(+5pu{3\ "͎X^7 NO6d18LNL :W-!r :w6IOy BLgh.yQICv芇)8kkt@58؞`VX.r>2UHN/pHOnc) Vԩei2|gUfҙ#qvk_=vg_<RYˎ/U?X&/5(ψ\꩷囗eT(EB\Ys|p *_q0D[~?]Kݷ7R+ >h<1My[A7 h!A_B˃iHT.w d|L 1WBR?І7ġvpg#w` x#,2N >)Tj2|Vgc @և/ p 2j8ZG>я&q\bC + $y@Luɉ+F8Nk<N#.8}r m,cFjt>cK^җ{N!L&rRv)"ͨMY FA2l 2 ` \$-4K(@<&ָEnrOr͇UmIQ;bHv|@u$:yp,R̻>ЇFA&cr%=iJJrIvTӟ9@?6щUx#ԯuйpCYu'\-k^tO=Fvo6)Qʆv;ׇ󴵽mnl¼stFw=Su=oz%cv]o~3_z{̃Fx3ι !>qW!Vأfwg2n| 'GmgݭNyemfc[=yu~.O1Q螖@lM6nOyPzLk{x҅:qpWjOqg`g{܃XF{߰.wέG=qkh<{_%lB eq,Rۣ7q:gw*{`s>b{\⎒[8ľ>pIolI}\p*`~|Wv=zC~9'?1cx؜asJ&v$4DTdt o@?$DA4AZAk| An0 Ak L <t l&(?($@+(AC\CY؅143D4T5d6t789CY9lC\4<>?@A$B4CDDDC=<] E8,HJ\DK:CMDLD7IDfDJRDmB!"UABO0DTɐ UYA4Ih=klGqQݴGY(T; 1]4U3܅TVJ|VF8 ]Xʍ=o9|3Q{|PVXLX] RR;,TJPC}K0|=iED/-WV0,S9uXPGXWSНm-LD[pS0zCg|8]On[@3`WX`ʄO[B[9nLX=F\TRVʄEY`TGX3 -ݪqm]?M0$V0xdRXmO>U[0t]f\(]LCYXL%cM k޻^u]ZW(TNh_HR 3脵 _\`W>CޕK0lC\X8[neąOE(HUߵ|ߍ^4 ^3\^A_ VNF0ߛ܆DCDZZ2]ڿLQO4Yb (d8 P̀e/PPQB1UCRw%6C890C$JY&5MD>d3ąְQ5GVC^عXą]h-7D|=CCHPnd8%N=D-TVV%M`HHcXOMXHQxxHT%TVU7nb q1 fjр4 e5tj> OKsU?%I`8Ӑ柈h=e\0e f= _ͷC`HQHr\t&vhB#0tٲlSA!\hRP 9c2UѴu^LR84tiv^ْ@J]pяVp^oF45^YS4W4TO[<գ(m%Q(p;\x{Y`h6fSEi@]V rjjAkXp݀PɜxތEo܆Uξ6`õǎlـ= (=hU o$S6cE q~f8Z\O O\h:ETnƅ5Q(O`HenO8Pa42xW0($pUlY(}Ø~(eXK+6ş݆Mݟe5+fø6XP6d]5|PcĺJ[PߕqmHN0Ta}}SqISeDprkx]G#k%W؅HhX`:r;9FpGZ(,CrS?V#oIH%57HkYZp7rI2ՄTYӢL0p(x5ޅ2o uK4xx]pS~jDVq\OuS\oh$Y%>C^GYKVx_D]pJo-XmdӍmo CT؆ F]0w&E6hGoKF%UjIJ`M'snLX3 áFGUP=d{mpŒe .2 Rk@Tg@|$ VuD꣇q Am/9+NYT IŠ1e+(jH3gR@kQf4BK!I@dD1Jيrҭk.޼z/`:. v9@"Iik*_@ɾ@3ua0u.?g48bLH S}-Y:l9] FrEk֔Ρ>Y.ƩST Q`X6m7FOciW^'(q2`g'Lt0NyE)Lq$%gQ$Pi]4,pN%Kxi&K, D]‹;ťㇲpv,]E l)*\&cXbKJ]IU#T'9Ő@L,xXN3G6AYͷ}uy'y'v%6WCU*aM2z$~)KkS%4! o+W`Ef\0!z}i ILi|M{bTa5@ӆۀ]A욥,F։@ JJ!,FIEq߭%~NFl$Se-Bl]dA8ozc]&KIQmK3 Kꖅ'(.$]6(X_ ̬}7^9ɍ(]̠'\'p Y*lI,vLń f\`-*(|G#$XřYs5],.\sddFKZk.D̝%9b6DRE*.]͖! ]/]R0q*ŸR@v_lb%'H=P˗B1Li 6O?r)ĸcg>q^1ω&p5JK:; k0BoNuY .>Û վ.*Uk $P(GWՐf7`V]({Z@p `YZ D”*Y ]H9+P\d$ $\;fI9b"7i$㟔 PH~"ߨ@ 0֙ &<%*SChh,FAR)xA3NFLbXt"Q5*I*bq,לpE)p"Ԩ&浥Yek*\㖃%E  Oxb$F] YUH,uRDZ9XPN0: r21VsyFgm‰F_cƑV nb`"A4#yd#lzdEvEr*@fQ=JσJ2y*1PM:oS =È*E&\ ˸ҵ/ܐg! R_]w @lL0KT a"ĚxXhdQ P3xq"]$T_<)MU L [ٞ8eA3"'&* U@XRR-\"$X0sGRܿ>J]Ha@XHEl$@)d1 R؀DyTmz"oAplʂi@H^Ǡ즁#JQA _ |- P2ND @KK@b2D,b"D^`f>V ,̬E.8ra*`iPvAS64HRDme~猝VPuF7`jM)\'QH_R;FT<Բ-q "]LO¶SuJ+6D9|5wBX L#C2=~rS9痾죶GP&fqRike.,>XzA*ƩFU՟)6-A6oL@ qwfƅ;eQd7 :ҨXZp"7@Fz.Y όuj}VV6e]N}vPtbQ;rV'l0E m1bBXsaAlQ{$6zߴ`.nu&& `/»gH5f+U ySvN.Q g*߄XmR94)x2#f!wa! G n]\ ,2Ef>\g>]0s|aF<,0<QY_A'e =Ua}}T[x̗_Bd0 r+R҂L\QBP^r@AG_sNT+`-q[ "O Š,ƼG8O.$F!`\7ŕLAXT8a Z EapZ ҌR`!\  tZ_`O!a ,6a՜ _0#:f4;haskell-mode-17.1/doc/anim/company-mode-language-pragma.gif000066400000000000000000002377671360223321700236320ustar00rootroot00000000000000GIF89ajl#;1*%".;1&&)0.1(EMVS)g#v;r1h3]yErP,WD7NDW(V1r;t-i]Fz*Ns/GQMMNEFGSSTQUSrPMMMyLQommqqquzz~ttxmkpcf]M;ENMR2X&i6[)k2NNMMRPsFmQyLoZ{reh(*15T*m,(eqvlX+0Rrunwkә\̑Jζk̬ds%H?Y?H?H?q?H?DN&Y;l2j3n lPQNo||jiHUMuQjpuiS $ :/$Y$O/j3 J V lJt]`?Rscgz~YVJyo:(/Qflhumvf4XoUttenяʔ֠ۦȫд߱ԘђƥижˎΫ¬΋қȒϩϱՒ֭ȱ!d! NETSCAPE2.0! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,jl ^{&\x!ƒ{HB".qD 1BKԨ0I*_flȏcDoL,]Yś wp$͘A>JΕI5H^*ňY̤6Cz**O%'T.ݱTm4g>{lEJ1dI/l!{|[ =S G{q(K|))W˥& U"P#HH5UAmbT9Oʔf!T5gk*HvҋE0P &&yT tM%$hYEkXJŢU'YQS%h]96-;ZϺVElo×5uhA4:C dq*TT jtoٹhҝ=kYz'`öy Q/zSY_s 1n5G7la 3v9paa7m tU=g|6Î/j )l[\01;c"{ũ$.W:p# _+3Yʀ +MS,Dx7 Թ;e\YrVh&=wlGL i~nټh6P~rf1˸1ͭ}C`j ~r$_6 6.q qY=`V5gjmտ.jH8u}C]2YŦSNߖE=r<?+nǼVGλnOL! .pF[\ w;G{oxV-7+>n7apcGUÓ/'Q b&x9z`=Q`<O~;Џ.=䝸w*|;?^D:!zj"|'x_Ͽo#7EnFD #j/{dwa(VL 5N{F؁ ؁ |͗`bv|gqJU *yw xy}^. y0hUpgS:XzRƃ<8yH(}K{N@K#$hDL 8`  P GU㰆0@ #_;L' U h UZd j|#էyrUrw舧{#Z|Kx|xz((PЕU #7x e b h~7*~FF{\8\e >O(;yh(zHS؈gVxX> %WzO@U `XkD7 bF& p \&E|0X(@ <Hࠈ8牚hOX8FҨW%ّH$Iph)f(H4Y2I(zS}f gy 5ɍQSB8o6w |w~SrA~j_ 9ʑu:ywJ|h kf@(p ;h#`WDs᠙ƅ`g|%# X}:j.隦_z/z{ʫ>ɬj*٭j^bVۗSXI +UfyS\J *{~o xqʯx:ؚ:wڭUxH  9נ|Y8 `y(D UH|cz s`ʨU 6;˧Jź+7kɬ~JJKJj˰MGS˰ͺz+ʯʚky85Y#pn۫᠝hwMٝBX\{dk  ۷]{cKqWsɳKGd ?Wǎ( Т)*~#{tٱ@tX 㐴l;ˣ˫ޚX+Oj΋M| {Cʶ;[} i˕U yLp\ ]񫸚˶wk`:,i :+*_Xt+P=p{9ТYzEtLJ˨[ʳ+`+嫼 :Pk뾔KW< Wk|3ĔZ؂ZExN LxН~QL]Spg}{_|ȌllȐȑĈPػh@z$=Й)h)p ʎ#ܗU|H|Kt Ȗl^;ɏȒt:_LˬD\͕g J\ܾ̒ + 'Ȍׂ . |l Me~dw* J+ϴXYL͔\l<m ]ЍUhܐ{pŸ>{I`*/8L ɯ x|,7<Љ\J Ml>،ڼДIKݿjSEJE}{|ƝWN \=OpK-t͚| &j©;єв@( 4LwۻL5%u٠ڢ=ҫФ٦pMΗp,w U~g*Jͥ\^ yȝлWV@v('J;83 KX ;:L ه ]} ]NN{ vqWlX,& L^~}-*N1.*-,./]֭@aOp0Pj:6\S@79ޥ $ @ a+爜.v^x7Nw>6nj r.ɒ w~ۤ~Ȏ];:Nm~耮'nq^熞|sL۝X>˾=ʰƇoNk!Lln: `Îu缎~n3n,߷氎~{ pA+ (^o ~y# + _ .7^N.&*+/7Ok >p`Y2(p ѭ݀`ъ0@ھ| V< +#`}2n(.s@^0xmtO5o0?4O}8p?L O?o UL &._UZ_3n&?^u_)̯ˏܰ U8kn@ @oOoo_8p ;h0@:xPÃ!&8 ņ 6PdH!6xѤŎ#2S#H O܈0%n0Y ULhÎz^bbEKAiSI.yTFPWr-9PfM8[k҈K)PYoFVcH7gM8fAlhSL`ʑ$po s3޻%/^7_ 6'o xq'~QňƏS7Ny٭_}yx耑[bľ^|ޕ"Tϗ 4ϻ+0'9O=CY>[? ciC,.9H'p;| ~T 9 2NA3ś D* :$rЛrDBjET-$R8"2J..Y9%dl/8ǔD\03{R=q?0%1>\RK/*3T8 AT%ME5UMUeJ}UYgMKTSm\60QuVQ6XeCQ@geXSe YkYk6\TӴ\q3MW]wŴ]x}]zѽy~_7_ ˵`UxنbQ%᣼u\z->847d#?xa]Uߗ` 7zp6ffaÖ:bs짵{b[^`QN{hVZ}4l g[oĻfoaNӛ=VsAq'<#z]%dV=pm[!y_vyW+x 駗~m>{{e~|ݧW_@} _H@{ 2=V{p,D8B0`,BBVP't+Z(X02ta WBP,D s3|_XB A!kxBK+bq6,l yhB%0H}E\: 8'qp 3t0?ܢ1bPDyh<&g$d5юD#hG&^1? c%xI4Zq#d&C*%BI\% 1Yrt#Yq2st,1MjVӚf6Mnvӛg89NrӜDg:չNvӝgϚӜ@9z|ԛ`3fTx&X)l՚:Bޡִ,ͪ֐el` x0'@jS}#$ʲq<Unf) ђh5}VEl Z}02_hVCnOυnfWv^Gg?}Y@nW;^򖗥Ml@}ѧTx6͡ɦ!P=Y +l]زԅdz fp`}x|a XX5 &8az],LcȂxKoz㾟-;d"Y=lS nlWyMSrVC:u1,QMzܡԨ%+ഊypa~Yh@i0dqM|졶s x4)H1fw" uh]VxE=jR=a=[Bİ1Qә7< tǯm^Yס&%>xi2$>kBc66|m{ B$sЗץw}ͤhnpß-,7A_L3Y9ta;;M5O6s;fdsc6VH/V~FY\+l^?|L GxSpɢYt)fHo͸zڷ g당 |Vvov0٫-h[۵+>=F;cl)$7Vkۆn`*㦿#'z=: ?r7v4Ɋ95;ۅ1pC 1CT6Ħ}P64.3>xzrs)B:b>}@y&:;?)k66+Aᛦv;?J=;z ?Lr;=68ԇ9$&KXh 45$C3_/CP*ODB lk 8lt&h3YE3H{7c6)ʱzkp3F˺B0ֻ6h^S1خ}01 1=[X4H#v]&^D1Yܫ8 1BP{45( 5e8,^-۽:}CuCfK&ϳV'3CCT 5{63<@6HZ$j?tg'//ܬiB۳ðeǡ$nE-4E5[ |5k n5*J<۽ZkHj ppʎ{c D63Djl,@oH˵I`&8=sCvkFӶl:eKR{ĂzQ}|(n IK9#&۽P8L]wP@46I6ÇV6<΃%&Srе2TvbUW}XE+PVLVR3)Tèi&;`c4'Ye1uӻ%4CLG،İk[X_]Qo$MԋNRN{YvEJX#W ~>|>M/`O(5`]m:U8x~-'oȅ#`}2#hbJ ևOmJTT>T$bރڇ7`62#,#Іj2$0!ߵa1&1F!㿂:a 5Zاv(b=`pBHX46dD.'zH!c#H|E"ȆM.*ͼ)R &WW+m,?v'uX*,sȅWK~\"`{1q$c8H| "c!eNVf9ú[PN '37aJ&B0^q1Nflr0.\w>:( UڕP |[mflCH`Z&K0.&cnXfdx:>j\[+c+~egbK8`9ThJiei+~X;1b;nR}i 舞&s0" )fq"hަsHcdFfvZCUX'&ue@)jJ7h뺖Ska}H)A)Ngp(k8.&nB&'cv}8gv"v*}8Y,5`EkNi붦f@b9nk9Xf: 's0l&>>'˦&&sHB]JYd'Ѿ4/sva:vP_)74&2nώv~p `jxo=.DhbGi?@tkcp 4ߦ~mWio"_fw5ZMu@צx6s_+vxdr u;?ylnʆc ghϦnM& UbWft_?st6`ux6zjk@h0w8}3j'zns.onh]B #Ȑ"G,i$ʔ*Wl%̘2gO=8-bx*S^x^C׎dF!n*1_W_9oX*4&D`!w -ܸrҭkJxrgО}uYNKaF}[ 6Pw #2СТG.mx'8О|I3'NyQ-ҘAeHdʗ3oGqVfKZa ֧:uH!0o=yo"mP_ISgn =l5O?H6 :iNA[- E=!u!2&"%xI6tdeKQ? -I"9#'J_@Yu=m$M:hz60 e-B-"a9&eju6= $(:ꛄ^UhYJ3]z)te7lvbR` %*od [<T-I m=\ [0 Gq1[ 5[-ĴyAэtYm6N hGOMF6ŲSlme7tT0q?'z.TrE3y;NY'Pq(M4"$tD)e@F4EA5eZNie#Y2 NlȱBرLF<2''y ac:s{t9? zhu\ɬ2QG:j%rA)h>]9=6OyTwo*3ۅUz>m<  ?@w`NJH1H|A1U*: .LQUadڰ  @,E`IpINCdHblʗ68P(@ω*-9$}[F@C V(`s@*t=5Bh\J\ԀD,ԉla*qc,!&qTeC}%iX"&q/ùlCF-:-Tow.Q2G~m|YhNp9a#&xA ;=!\ Ȍi$sƄD鵒DO 3 ޙy>akӟ /J9J9Ή >r9\!tAl ˒(F-Z bB䐆@3`b8HF1"Q)giw,D$)ӒT$iK# тzUD۫Q>JaI-mˊ G0,!cK6P$ZӪV dUK8Wb0S"ԇpp͝BF6h+59*V@rElF E9҆SJ3*K6\eDDZƸ .|[^趷divL GvS] gJw$Id\G֗}\'ͅXz[ V jkq1"W۩BpUIT~h6_eu`F$HsGbϜ$e+s:AMQWn*@{/m飠ʏ* ֵjD{ې MOhB2{a`!c2l m.旭’-iC9]ڵ I.{l[}Z rIκE$SRA~-]f]l8iem3# oP|2h dHc (t eօS鈜ަ n2{ i/vGBH-M5#%01/<|f@}lhi_ˆkmNG@F"f<%@0 RFw5 3"eus~>MhPh35,ݍE^;W OemEEħms 9U,ӎ(:rc8#dnBx2<'pK(?d.%ҭgl.F9 ט1*B4LFD|G__q<$=mHȦfٽx9_:SHu IG7G`/w,hزCߓ.zKNbHd2̬93ǰk̙(ˑ`GkIT]A>@H1P`XhI-΅yq݌ ؇a~Ԇ`dM E8(H`KtP (儴(.!6\ 1N ^fƼĐOmHCS]LlahH RCxOOhIh{!!\d NTY ɠkCa߼ >"$ޱIl F"(b!ރL Hō+j",P1$ m0)E-tIT&t8Ģ0>"=/˻ dR #5ڡ=QbLRQ#V#8# 1'#;2t=H†MGc;W'UݼPaNC,B8#BQuϕϐbNC'cB^$=ʊ4b$I&RܼI( b:r7L5j`>Y'L$M*R SU!/~RfXggmQ(Ju݌GI'|QԌ4zmgH'eYZHvkxYVdn:rW %^E]+v(Aׅp&hkܣdzyNȁ O@旤hDhO&">{⨐HvݩPhĥh6i =>Q} E:)|J> fφׇhC)|t!lRGcrfψ5(s})` hsL"nQ4.ZN`Ffҍ0nrL#OxP DԂp*FR ߵK͘lq !l (m肪\l~el t+z)SyaF+"}tGcvg~RD&v+NN_k֫HX&]SZlMjҪlMjȫ`XJX>lH/JjB,~ċ\JX(~fgǦ,B␄Ҡȍ=ҫ ,?V* :&ijblrlMh7Gh 'MlϪQ݅ODv&8l>Fev,_HnB,p>hYP̎mn}J _3I-#Ϻm#lljm5>RmP:z^b,V?6l{N'XvBR6fTֈ(؃D~bxjY n"jNd:R!ba0w)]m`Xxf) (޼F(L,Hy.wN"JeDĬo"?"!X6_6`ap%*`>mTʯn(oj"ENb D4Lg󮲞vau`䍐-i *p3&MY.1"3= EX616z!`P/aSb8n* mn;)t\"q=7)`V̠**\?3o_ r$%/>!fk`EwCudJ}(pHiATJ=a@$ ;t|>$bFt3kQJ`~$`Q#b)mx+RԢj2ނ2c EVWh1 ()S)!곶x$$c Q3^Wu45uT!t`&Xfضnd'd#F` 6y,> Y u.m)QZbm0!%snBe%N啞Ufu_K2zFw ZxS[r\f=e^7vPn~bz!ͩN&. >] Zs0F1!T3yH~8#6sq b?!e997dq#;%JN Z)Ȓ3V_ȠOb*m3cC!ygxRB9Fbpqnqylyvd95tcIL9[4Nʃ>P J"'Z7O%6ɕ&`WˤUs)Du}*i_-. Y4(p:81Ƶ̵L'o)Cbu%[Lkzaw?EL,BƭP>ƫ"7 ߓo&Ev ۛnPf`x~=}2?jV#q0?;̺kRh&FHD0Ɨ^,jLnn9z%FX EEAzǣk)>H7[Zi,_*ɩ\YNVa PA@vdhbG ߴ-/4JNQ=KRlEqP-tCle,s0 `SBP,6 ;@Wł2!eON-b-jg(zĠ9Q>EyZtb hU tSW0Eؒ0}*K<1Uj='\YbL)/BMMb)wiɯFNUDYuMXi>ˉgUݣ*X& VfҘ"% w5XeBTE/DZkR,ّQUh$ TXF2Nw<$ QBf h+P Z/0䂂L]1_C0҄Q*@*\g tfg]VlD1(@DxXXq~Z/b'"'x$H4@TTTgvF ,;2܊mÞAZa,yL,zK*Worf7DQh.jF O+¸ SE|p ڐ@gd-,FgZ 6q)qºHqPATT,$MNL~y؏Ȅ |({hEڔ1qrfprHoqg8,Z&Â( -2ba2KI1lMn~kN b PID"g$G #r+F(OjC%3#eVEw褈RqU')$)L )b򏳲 a @Gh`O)e;|<@j+]0(e:(jb+jlDZdk4Q3'0'Pd?/"1"XG@A]a Ĕ 烮O axf7a-+gDGKhq>k-cflJguB)+8K:4Qf UFh5/=AsB!r6a&涠(~lna tO2,N |tkt7D_2RH#X:8ˤe`XgZٔFB<t3,XB .f $QbMma@@*zTJ@׭ SP[UfJ@ue *LQϞ>V@IBU`aZd (^@ѕH&FKa^dh&HAjylSa^a2`b ]YH0HHaGҐu;v :4Ȁ>u/UVh! gN Nk/ Oɐ fH2c]s͢+9HW .aCࢗyYz&.#,٠@#.B*XC㈀b:xxY)>QZ)h_960C3@ik|RLre-YjfC+|0F*Jɦ%=>z/w^«7Tܙ)z`*NHLIU3CBB>;5ū+=*PY {8hZ_c){B;$i'/L:oZ۳-y:,fəY$|('0t--{{-;)亹z<@{+/YK{`<#< #{-[#{{[ |-#|)#. ?" K|7-;%Q~ >~!>%~)-1>5~9=A>E~IMQ>U~Y]a>e~imq>u~y}>~艾>~陾>~ꩾ>~빾>~ɾ>~پ>~>~? ?!?%)-1?59=A?EIU> !d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,"1;;1"1;""EMVi"u;r1g1yEwM"EV;E"[a;t"jHz"T|1EEg[M*MV"j4r;a1wE|M(*<*(>X*K*j*v/(S(yhSc***7Yargl̶SѼdvmH?_?T?H?H?w?i?H?H?M"g;l1g;r"l"[[YHMicicHMHSQmnvTwHvǘMYvfy~Y((((2TMelgsrir\_izKXurm̚њȓ֠ߴڦ㹮ݗؕҦ˳ҹ۷ˎέë¨ڳÃ諼㖚ó͕ HP` *\ȰÇ#JHE -jȱǏ1Iɑ"O\ɲeʖej U`\ى @",TE[gWzHEΫ#1MJYчzQ:Gaubhp=j1?"pb&'Vj l7qk[׆ʢ K}8Ĺ6(Iɞc;$5AR*TBq1Ʋ+öBr^$'gZS} sG3OṬ"RuN\F^P3bhZU|1׃k ~5&NHS'=D GHEv\]yʆ $EmIOX#PLaA1D8b߉vC#k.)4P 6T*V IdmFfĐaSNe|ʙfduZŜsfW=gsvPdALTsDem.̒3D(b5ixG:TۅEerIi 7f4~asʩvN֑a],(*M-J#z-HPaI\V4첋0۸[,l' 7G,Wlgw ,$l(,0,4m-݌I kD).AɆ;o %4 FN4&23H] L7͂-VG RS]4τB'RC:M6dYsT M204 G =v qHTJ %72] CtP ^TM=%21wD94K0E`;Q%N90oazC3@Dy4;Q0+Bt7Jӻ_}O^G{ Ot/>t~J R\!>!2Bѽay+ۤOjt_(49PH d2z ()tO gH8̡w@ H"HL&:PH*ZX̢.z` H2hL6pH:x̣> IBL"F:򑐌$'IJZ̤&7Nz (GIRL*WV򕰌%wtAZ̥.w^ 0IZ<&2f:Se%IjNȘ6 ln 8 XL3&,X1vZӜ`g87 t\'>OXlb6Cq":ZІ:4%iSD9YaQzCGJRbT70M e(pjrԟ>ESiI PD5uҕTg'B tP8 ajW:Nh;OJԶRs*(ͦv ',d A\U| v'\UjXӭP+dIPĵ+cpjd-[ iآ5d9j l4ټcm#A G$p{~mm[͔vo}M&\ji Tޕ?\P*5oaH`9^ε),E`W՟*:vVVBAM]8#jzΧTbx9 l &,7p`q^⸼1&chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,"1;;1"1;"6"""""11"EMT["i"u;r1g1yEuM"ET["[;s"g;EHz&Rug[Mgggagj*MX"j4r;a1uL|M(*<*(>X*K*j*v/(S(yhSc**7Yajrraj̶SѼdvmH?_?T?H?H?w?i?H?H?"g;l1g;r^\YNPicicHMHYHMHcVvmwHkH~˙MYvcgy~Y((((2Rdlgrir`_izKXurm̖̈ߴ㷩֠ݗؕҦ˳ҹ۷ˎíë·ɨڃ諼ҕ H" *\ȰÇ#JHB -jȱǏ0II"O\ɲ.V0a꺈eA?QD ͟uBhfSF\E hL(tW)Qł`M(yJ갉TR׻] piȖ]2cz&= QPϼ ƏC|@}1R,!6JhZ!0JV!J8Q742ܒfd8jѢWJfcCC7B` !!Z  [O Zl=w9tq[4 qGT rvE3Fq"(HEZvJ`aK fBf3H#r՚B\w[3XDY'/\YdW.6iR(%Tg Nǐe-3yDqEraٹP0;6LujSnG20izP[1F-n F0iJa7ah`yT,LE" +A bWmBTcM!,W˲:͋C]іuE5wVْTUQF$-j40Ц Kޫ,l' 7G,Wlgw ,$l(,0,r)O.<#sDg CQ -s*Ѐ R 1´B؀5M)/ m ) 2)+ m)SuvHd *@σ Dj7B E^1)?BrGбfPκ }m5Ñ2R00 IBL"F:򑐌$'IJZ̤&7Nz?(GIRL*WV򕰌,gIZĄ.w^b,|IbDŽ+Ld2әτ4ɊKXs&&`f%M]f. MNP3&&L.!LȄwmX O@iq޾wE&$V<59@|3QRB (N9ZV_Z W}M EPCgS+"maX 9Kb_+i\M}RZipӞ[]^rӻ%&X%+zWۙL J@3slW_ e FML݌vkkhUsYmhv54&8 sp/_lX}'ʊ>A%$j^|ypT4m"n7Gq^Zc% шF!h!zvL?C4b꼔HTvq:WX0YG^M,sk%:YaR-@g_|chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,'3<5("(;1)/"""13.-ENWT-h#v;r1h8Z/ kClNxHpP-gU5FNX\/Si#i8h1rNR=GHGzDk.PsSRMjYNqiNThpsssmniI[gM;E  59 274 *MC J TZ)k6p-UM Y m)GU6Tl3}NTYRRNsGqSwN[ltvpgYPyuQSZOr{rsiz{ҕNэIPYpҙk~ي9;'H?H?[?H?r?IXh;l3i2l3y#aRTMoomIUOomvHqʼn?7:'IWqe{{Y8pNTflgqr^UmmuZΏ֠ͱӲբ˴ʲ¶̄ϕƳư׷ղΧѬì͎嚢ϔҨŷ̮Ǯڭ׵Ո H*ǣ!#JHŋ3jȱǏ ңO_}4r%˖& C8sɳϟ@ғ%>NTɲ^mBJիXħRL' *iVRϪ]˶۪#%yҫKf'~}Ig;1P{,ǐ#K8eJsK2en>O'ètҥ3}n ~]4 Q#@K["Fo^=G:,V)߯+ȫu{b[;li/D&spHΙO7!Oխ+5[WNbSX%MQunʂ F>d^E)T] ]8aD'Z&(!UFVJP3Ӣ9cs>B 8{!~l8QÚ&9J$k PB4@LdN1E-W95u>;8CzZ84Qg&O9H8YW93&E#EսMDiH=𵶇9P<nL(>sэ{j}g8]f 9DO !BIx>\g] toުV~ . cX晬=kвuf&< V **X&Z+TU>R(,k6j6Y?MWb(&'%k{lL4dL~.*% {@zLP3d' TWLB&(s`Q\ 5ۦ*4Ž W!9cN9rH[>dKb}4_ji_m 5>B]b1(3O˕uI+<-dbfk?<+c:ܪ;.7v2 -;4 Ԍr[Nd9Ds4 U1"Nv C IJj% FǭD2o۫"Bg@76ĄN>674Lr-A9mѢMxdzJ9IU~tc zHߌLT%_Ӈ1Ds#<:Oh$FSVF7 _H|zKe D"Qأop̨JCO(Ld|*%]NmP?Ԓ-lFj|fF;KNwU2UTjs?IR<9 b`l0b9ڇ7ֶp\J׺xͫ^׾vE43\Z:d'KZP"}-Kb?+1]MjWZf"dº4T=SZ p Zh}.\aV7t\[]|4 -q(M2,KbJ5M)8A B vo[PpC߸kq ز!KB$[B6s\[CJЁ|xkj Br jD@X@6.ء]xb)D.GbI: .5k0.$ RVk|A SPp0Vp|k k\@đ5\-[^ßUk ` '.s *N{Vݖ29t t (m%'at W.`t/ Sg70ҧ*P/:=[/Xr1fb#ڏ]2!eU܃k5bLԵkE}{NHOOIi:gp?ysE O g7D9SX W_{2"qۭ8vJs@bl '? 2@A NCBZ\_^+ `$*pdF%`bG, v]Mla }%[ 9>pxr7C<|  ,ԛ7?VQ}G^]_u{D3|= !u5fO `& _lRŃ5}p"#/_ /m3ŧ~~~zlP{q5o!i" kUsX1su u'byVbx W bz!vЁ'gj /Xӧ:6fZȣl9@`9 l! V\*m [f V`juF e X}%[ Z kY94^A 5 C5u^) 06g9h gW]]¹ r` ܺ l* 5`'z"^( x @ -j`Iser8G0 w W0! ^" u( 0 W4( /W<ݢ0@}2Rk`dYL 0yx'JO W`lٴJK v쩒/{3V t-(bg2{& % h!RǶe肛0ʳg>6$wA.yn`o@ /~K0 lG}6SV 6y }i bvse;b *hv"U,PBV?e @ pWbl`%䫯q5 z p5 ^uq *W Ҁ p}u=%VP6P8g'uo%P%*_9W\"0:d+T2@kRp2` kcBRK~< O-X)C g@) i6maIpMy@Ü蚗⎼r 0g 7z&p  0 7zlp۩. e]:zgȰnJ T 3}v !mɊm<̐u= j h`0ʠ`5LLP7xM02\>e];ΔbЗu0D0uP ?=L!v l0SW'7pP p"v 3  ܎a*Q(H3LsJpU0>` ٢L Ӎ<ڒȊ` Ia_c?ߢ Pi O0"Fh 3up\kІl| t-7 pv7+ﴯysqpo8:l׭ 0tɩ/b?k >S FHxzwFk@N.RնO~yoLLw#6tb'a.=e"z4 p x+$6Qp^1F:ʇg9q|G>ż.֊ )b3x/T:ǮA; , %'kP")@3\3^4 +1#ej Bh';O@$".mf=G%TR9\EGV+Hj((%D-E)\oI0د&.d G9:$ r'qENUt ur k: 4xCrm5`> &G\!'6Yogl+Iz P֠~QD㯮A;*0D MyK~J95pK0RʋJh/B(wx 9c JlB a6FIGyUi§V#WWzFHr(؝ :'JB}h(̨!/\YaOEr%X1 g`Y,o>﹅gf Cl|xMxZ+ e!e\tTex^ы& Pֈp@0F/ ;j)HzUCêZ%MJVb,eI(ܓ0dHh$~FD,A~@ R`b!$bA5y?x[!ǰ# `$ x#<'pAhȾSyZǀBzƎ$VV:ֳmhEȖmL Y>:Zֶiu;#飯M"#_"[gq\6׹mtՅ]VO8v׻ŭt;Z95lᓙVo|{%]Gs^q{;`e~}A[d6VjUfA&p5->n! mBpUb'OZ bEmucX{ԯ/F [UAGPc&7u[{Qj8|Go9Rd.w˲,>`\1~QbQo+:;H?rܒ|qtEm0GW*rzW?7epWu .e[__N`G|F1;]$Fzni\V-=emg~n/(_g6>~Cyo먡oC?ת°xߦ?@+̿s;6!d 4?US2<Q8 >s Az0k#:?@A*^5s,al[=}㷱$T L;&$T)d9MS6$.L94<+,/4=˽ӹm 3%¬(<4 U:V@B=49+8;@.d¨k[j 9 7[jHC?x7EDs$ÀH{9k4I:%Ń4:tɗ<=T6tx9DB4s<(IkD#f:S!9ʨ<dKUL G<>TI[>ҴM+/s4ķté;G,ļDN Eɍ͟Nj|L;8I?O~ =,AHUh/}HVcc3]R[p`$:pE\J4Lw}[CݤG%M{SKfTk7ׇ۵! D=XzS4;{M}oF|?lX]! 9KQjǓT ZtX6Q8MIXW[Eǣ)5XU7ü%4Yհ R-V{Z=6hԪZ>Z#@]5<=[ʫQ|An5˫}[+GUyXU[xO`S=?ٿXI%Tč6T}3[cUs[BXY Å\ݭYYB0]d;˘u] S9RLG:0b(Fbg(2 ?d2/+._h03.+^c!b=GHF d,2a3KcEd!OMNdQ$vc"Ƴ4nd`@e2`xK&/Ua[IKdZxb]d_iPk.b>cl^b4kQ8Ug8(.g#f\Xe`OT_nb/gfn&bpvlvd0N/ mc/K/Jpb+ng}拾b XiP^hX=~Vb[>!=dghQ`g hXf>c'&ךg3hn%8fd0 kg(:Pi&! ;e^&b PhnP[Sa`jf?.&:&j\jVb&i^/}VNsf?NxOm.$>~cv.C^bga6Zb`*M҃i_([Pn\b!6cWR[07%Vd&b`l/~m'~s.&$l.he$ahfKNrcc_8؆b&b*`*&#fʖeL,'.0?_`հn)&r+Fr!.2iJVo0vضHb Ohr$ff oc,f>^m~?c=p a_fsY)%fd+ ?g4[ ~J6b_Tj'cFUPdO>/XZiPTXid..&c1c#j00]Q;HnGc`jj(vάoFÅw~8V/jsTieS.vGc[`7np'm9WU tq)@X|qsXxr.T`cst_cXxXPgxg]؅GX釙v!`Rnb(kYe~*.(h^q Ix`'1le~;|F"eiF[8hԯbN8!]Zz/MGV^$ sVjQ/ujH7!<*pTAƳ2UkoԞÅ3/1W)Z,P0qԤTlACVb.,cH( ̈C-`}Y8I&th̡Vl*_PaZR-li- T%Ċ%Ջ@E-[B'r##pZrA(Ȓ'SlyrgL"hX*4`$L.d82S Ǒ2yd/ l UZj 9t^+ F kX8(e/fA\(X24ib5ULfԌ͌t\$_^UL>]S|KyXrPweˁuy ;YEtUi JfU$ABAA{" 6Pw5X7%UN$[؈f6B.` B%4ّJ^Kd1ufp KR `&A-VZiKy̞TQ5J$=-pI5DB1cQ2cw^ PV+e:I; 5Bٱ@YŝQe]e6bP/^`/a,dP,( aSt:.ٵ Kϴ Y̩Asq )PC o}>Q95TKNTV+EcB \a/J`38S5eI*pͨTP}hrѧa Yb TB8Iť$fjJgI ٧;%uU˄QZ.3gP]X[JM`dYNJȉ[C 6X'*pq=L0pr0zFd;UqTLR*$*x/,U.PQ~K L(.V:RbE0,E/,5 UkIݵf4YR%'98$ TI%rT+6qM"d@ =`SҔ= A.kITe wAD 2L^g'(5EXb88؉' *fn1*(5~=V√%N]Vy #a}ʼnTiVv%')(3FD(ň!dS)ТQfÐ=Ce + rI_w 9l%tH|CMn3J/dY dLHfEr$ #):TkH^8L!~֞Ko 3ف-L4].{^?kkͣ: \ 2p+!8˸S8.QN$]G2PՇLOή:NYvV"( )S",8 ܈J@,A-f1?Rә1 y= 4) +&F&)Ḹ͗1JRAMa< (q4hA# ()d/[:NgO<9=*׀V)jC }ب,Ah82@rHh(~ kPxha(y> rk ) ;d?4;I/ )ip}muNr YFRĮpWevI$ʆLaȟݒ=i"[ )j1dDH`E8 EdBh.ly`3udy,*~zr1#ja1Fp(}eXb"L0x1fL60Ϻrɾt`w_- ; P$C|moERS,ܜ Ƃ C^Gi]Cq7P=hа/hA>T,c!n)0thڞq T%nѿDQLLa1c-6y!;UB2IHv<3I`+@[A8ϘvpmS XHˁ3Ӗ" NA MF&D]C-"mW"D96UTb@YjlEZbtBA)Hl% Ymd( qIq4.̚mKO`_2(1ϨV[-y\#nI[L$O4/zzR&[p=|ϰ')Y;'y~>B#_%Qdu>pPRz6VFYP>N{` -`AP=,>N[b!x'[$2/:!|A jGYN=- O׫~7 'Seׇz~WAN&iA y`pIEu.l_u D`D5qMRliThi_@ŋXǴ6KPq K[$_PE%!X V$۔T ^;`N fH 2 I\H F K{}Yte)hCP ȍFneVBX!!"RNIb@@\H!%(.$+ _@!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,L @-;9')9*-+3#OB\pfP/j8G<.f?(jCjNtTpW)PIFO[R\'R6Qf~5w.Y>NR;IK Gu1Rm\YO\YERQNroRJ^fVSpUjsqwpb`Q   :19 *:74MC J XO]5u1fM Y v5d GR[;W*Ll-~=|NTYRTLrOuN_eVtuzmtmbwrYPww}mш9RUS\Jq{l|wxҕMьHPYГjԧpgxסY~~?77'HVh3h6{.~lRsc{?77'I[\zkq~9.YmITjhuXcrv᝙ʬҵʹƮʶӼ«ǟ˄ИìǴʴʴֹٮ㾒Șʖٍ֗ʥʩɚΙԖשŸγƮɮڭ׳Ԋ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲeKx aŪfo&۩ɝ]\LH&+۽ .J}GJX\`** ya\B/΂DvbVԿ*׆ c;!7%TY yAv{Cc}:{4Z5_D fS0 뎵6:8rv^.^Nzr+NGƖp R[Vrlӻqp GI%@2]z€^\A^ZԎ~'Z .Pu72cEVC:Va[H4V:rXc (D^  yBdBJzMwB  `@Ѧb7&B%Kۀ!` I3gG`/, EաEA)X(j^,˃A8zC@N:`2F &b Ak$8)zi« x@Au.jE/1`!;\UvĽ/R¹E^wz%za,P0UrFxËƆ@Ku{-#/ 1d$/tǟJtRlHdUΠ 1EeA7؟EEt,G$! iȢ ,0̆c!sS43T$CLԪ>P%{DH *@j:zL @%d3%AƸF ~ (4B| م$J`(@#B0#IU @gG*dP/ߖG-eq#*iPR!(XOvÓ ""k0Oi:RZL? 3i;n*6 !9DDƌ6up(S9BH^\D3 Ucv%J^:$ k5٢ vCkA|PnA. ֺb kll w5J:sbh/و͂cx@rn_B,h.ȐlrpgMݭ`N<()Ǎhau"%<'UF%{)zLX z &N6uֶVh C\ʬ[eET& *x/ flŒ4@&D'Ytr(P'CD]b; R0˄JO0V Є&pڦQ{%P˽nB'jP拣С'cx9tt7"88Z)oaE'2 DF.;s"~&o7йGKBDҘδ7N{ӠGMRԨNWVհN6fMZָεw^57Mbضưf;ІMj[ζn{v6Mr[)2nv 1n["5*naX8~M0! Oxm@ccQ:bܺD6HدPG>rP(Ap=@f1q #]s-$GA=`.AR[|38)[ÎzS"8׹-&F8v4@c7O8nvuln|B/ƴ @;ʟ>^k5"kh >wx缯#_z~Kyyzܰx\0m4 S6h͍gŕQڀ&njܺ53`wZE/*XjpC@ Ng`{9@ $akau44@, 0~w~~ ( )`&qgk̐ Fy}bPD p[( Bs sF 2@)Ep pk%8*wkx *@+@kPeAn3Vh_OHGQK~b*` ct Nsm{@׃fxaaaq rQ/`v Q@Qgk^@)Gaa}8 ` Gk~{%|0k@7 -sp {Qnf"g7CkxP}P H`}`y@ Y  6/ ROGF.(`avgٟEw{ ׸餕1s zAVh)lħlanz%tO4|NJPo i@`I& )8lxZ{ `QtʖpxʥZ !Z jB Z ? l-J bYvh~8 [ [meg;pOg 0k/ z aqšI{D` )Kk/g P zI 0k,KG Р ΐ˹xJԠ jjkZj~Є # )A €P ~ д]זs0Wq"q` 鞃HI)`eqix/Htph,@Y7Jk-*ѐp_(3P6!ȼ8fk6*R b8HvhzK)R0{k,^ кQ*'kj} {qG Y,2BX( hf\n;k& Ҁ kvǐ pEl= P P kPz?\ 0{W^sP0pULrbLp=chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,",;1".1;"(/*EMUW+h"i4v;r1M1"zEqP-UC5ENW%X"i8h1r;tVM;EFz,Ps;EJKNLfXKtttomu[acNW"V*b4i4r;f.sEvKoS{L{xwa(*.8R*q,(S(xf_*9*VnkruezhјZѼd̶SuH?_?T?H?H?i?t?H?H?J?M"[;l2i4okHMRVrSNoidrmxkuzHMHYHYMUHcTqlwHhHzɂ?MYscgy~~mY(+VMgflitxtkZioMqtmpɏ̗̓֠ЬӬ㸬֘ԔȴӻгԴПԬ·ʦֹى稺ዚµӔ H*\ȰÇ#JHŋ3j!r9]w#۽c7\0cʜI͛8s$GO쀎d)ɣ-c s)ӧPJJ:HS4KT1: Kٳh ~D(RmۖʑwŐ:z.^_z;MX.`Y$"5i4ɐtCKbJj΍.N0!Cf:)N(3؊ o ݑDQCNtY15YW!:7es9!YL4=؊Lba=K.aMDn% H.qaFLeM018T` Q3/ȇea:'u44NNh Di$/Te$YS5TL@BcPW%Ď8+\!kT-fXk9#5*g e&M1Dt2agM7}ċ"yaH,5}⧎'S9)1 IjK [bTN4Agr(NRԳYܸsML0CQLjT笳RK 9swFbQR%%Xҝ5XR$%Hhw!v![Fm(۾- X3lihS9jbk%JaX°@A 7ĢrbG]'˿@(ȅ!<"!L$BnI~|됐*dqd7" $/qLb !O,0ޱmD1s @(:r2(BI/oM؇8r._xNpA@a޿Y71NVyBglWZ[S<ɜ4j 49M5 ~89'R S`| 2C1WA 5Yzc"5S0g#Y~jB9 KB!ب\dH5J:T FZPvSbd䗚,$r,]qǙ9(+ .fB"\A8IҠ&,\;@'銂줒OJqs–;*Twh y+sDxO`?6$ Y[I@M^B2֕¬ ݥBAfCHd&(ɪMs[CǐNPzCLfk%9M 3c,Xђہ "b,"5և  -(`pUz.& iez*#F&2B4/*W-x0A p3Q}m'i׵`cu+@ԁP_ØgIgRp*E*oL6';l jA*F%`gł`5,`E mҬzxW5 g"P7YvNAVqK+K\%ث3{T]ņl\fABR1KȖbK ueՆcj$DOxFWX<<}/b i0**߇];ju&%sጐwb:s*s LLnbw,z^{qk'T %Z<+4iɖF%y)f6",Cz/2KMHa(n#joUi7A87qh9G<tk}âǝ2L B7$Gq2lcq8Rx^@vr$O]y1K-E%^ '0 ;m" U0 6vS O_&lKQSmdkϠqqq@9hA^ Q,!q0okOp< JP^7; Jq 4!kP􉄎 $7F0XψwB;hq#Optq(C mxN0C @XtK,$:v^p" j2T@'`ԇ}&My$=<(g'Zq 1V5D '<,qYM'SSQgMY &&Az#j ?\"/N0"A}09wzBPphzb,>O)s<˓lAS֠2Q!R)FXNa p :i c<_':g:EFw.,q,'.*: 0&1i(ې weq#8)hsWrx Sp% FP6+b>|XLxu2gJ6Q6)1X(7AwH2,qi.E 2Ōؘ\BP8H.x a@%q5h|؎xxgC|v9昁9onH8YlQRk3)ّ'!+n(y(itė y|7+sA)94&*ei9wiUV>=q< N5!xu:tuS0 6p6`\P9dytNM/Y>{p86Pvy茙A}—m9_yu?a i_>; y.Hс@_yY~ mitl!SI0d'F ni| qΙ]$_쒛&2? N #Wqћ6` ݙ'n(M,K詞28>J \y9)>Mg1JjдIF+J@(#q š(znN|X _)z*z&tLw`_i8ZGAY ʜFrx9+*ZY6 R* j*>!7 rIb&ъ '4r ~z'jT4*6MjxSx`Qzz0 qzs J Kh)z D٫[<*!:=  ֬J*~Uފ. RNFeN150 <  }z'j*p= F qٕx pzi|e J)K)vp)t鰧R6'){W ;"'a!+k90E.) inJU' p  gP)]T+t=~p/A b / |[jj; 9mViSb[ 6p00R|b`*0g˶\6)cĮ\ 0%#x` ayEz8yboEg x`]λɏ', bK+ڼ㛢~`[$K̛8X#6 +@&ڠٻƚ(;E #Lž Y;\ A 5꽉J7Ld*nP;B!3MܽZRI;Z~Rp mFVAbJI}Ҷ~]MF D驙+j)#-}"niQ&+<+?ST=N-y#2Nɯe]K䧉پ}i\Vj؍E MCyKnk->bc~ᵊ|H# lx*LdΩ#N{ޘ j399TQJ >K!Ӳ>>;mҹ>y *엉ӋmΘ>ΎK&;[1I.NFc]NVQ|ָjs8Э8vMO.[-䪎In'!&_#-7~i -M5o ;`ntsfA?>|ي3K/pSڿ%_5 ߬v?I )JOpK|Ɩ箎Yrx_=aOBڏ)ه]Q>+V'MxJ%+8 Ĩޙ~/6JG^T/zq:Ic/!?SʏƏ:yEORK1_ 7ϾU&WMq]w >Ku 4b T\9w-^ĘQF=~RH%MDRJ-]HwhKPBb6+NTPEETRr|,SA4˝[UV]~[RfM <;Av𰆅W\uTWT;oJgW`… v״&wt ;-_ƜYI+55!Ã4۱sYj֭ mؔ)Ɲ[nco>yvVoF\r7*tr_Ǟ}uӼPم)%Y-KT jL@gEsA Mց,6, 9qEpeGzgHI(GfW¦<;?b5_'tn2Ol{fxGkjbyn/Oq,%59Mvғd(9)JRz!(BYJT”,%B`Ic,7KR򖿤)Lbґ<)tKb—$&/7L[55MM>SDE&#Ii~Ӝ(9oMuhg<)KJR32_fsE+yrΓA? m0:Qf.G< ?)RQj%Q QxD(QSG46ЂN(D*QHJX/ѐ%@ULZj.CQ)VӪIB#O! F@*Q_/pSLYU>í3BtkkSD(0KR^Փ@(@!аFjIG֓Amө~--iS[?phg* G>R@TWg~!xYbU5%Zkw({Nb%kUz@RilzA'P |qdo`IzgoӌFQ$Rr?;LJO*hVByvxSa`Kr dvzk{d(>UbhF/WzddzȮ hS0t<H``{GM&3!21R<;1;JJ,YbʫSP?sT2X:خ H=Pc*S@RPx@;R6{:D{6 6ě$N3ۦK/G:@ECU=Q2$Ą39S7(G@P[;Z)YT<* >#@3N:/(f#$;C9de#%YLH'V\z[;V$e,+L%JC 4ȼgb@Fs< @;?:,,BC䫧k%^KD[*J{KXei;M*H`#g( uފ/P8_gH \,V|5JZBV ,Hb-F#ndBsJ'JC]`?AGK'[+jAPl༮'zB+I-)D' 貤a(>x8OHĒ2U𻹓Ñʀf$"Œ=z: A Hu\X0A L9 U0O7PH\lE+.L+M!\JyRMB8D?TJX,G >Lv+ѓNFL{~ ԲNP*(K,,$+d0>tG[邼gĻ&F;$OzrĪɹtYrkHI>nʾL(dϣFdTL(ɜ,:4HKCF*"ȂĦ Lk&z$-(: TSJ*@Iܤ*G1uM GޢT.mCE,4*jNr$|$V O dG`@RXp0$.EVtL1<^řB<W([R:)L#e;+yT#յ0M+亀LPOPXNʮ&8H$3r0\Ir*QPK0b,W4aEX(HT`/5=Ѽ M SLP`.U~@{U< n3ыN:L8.ziK:?NN`(QU7ۡ0(>:L?ûHh/FA@`{"IY?5׏@@S(RNT}I/X|JOp޵7N7FSkEVD^xMCKFU5m>,$Vb8ꕥb$;l&[? &,t`b(M/fE/˔Y $( 3ӣB>z:ݰs@e;<$,T6< |K]=Es]Yb Urʮ=&, Xcդ_@=A&bD|}-oQBQ¨_+DQ@Zb+d"7cz2S>GF]VzPp*.#Ifr%XAV=` 傺9_J(bP[>hz'O_H2bGp{[惉fJOh)fb8ʦOS{TWނ$}UMO5R"8EC$(+d%8փrr"?UtڲY&S%恅uSgnĽIh ^%T؞զxi0EZ%.|/k,C>>cs2Ga'byX&fJ6'}o2*/LV궆Y:YZ`\;haskell-mode-17.1/doc/anim/flyspell-prog-mode.gif000066400000000000000000010451361360223321700217210ustar00rootroot00000000000000GIF89al";1($".;1%%(//1 'EMVS'v;r1h(]yDhL0NDX*V1r;t.hbFx.KeMMNDFFQQQZZ[RVTrOMMMyLPommqqquzz~ssylkndh]*OAMR2X&h6i&%R%]%R%R:V:R+R%o%f%z:qMMMMOUWRKStGmPyLlXNrdyzqryWfWRfSw\wf.Rprupx[Ҙ\ΔM֔pwo{ѥwDO;l1j4nfMm|}gxMuVyMM $ :/$Y$O/j3 J V l]`.(()+:'l|JWRm`bUu:sQliuiytxg.ڏϗ˪鴎ɵϱ䴭⛢ҘŖťѻ΢Ӧجε付ϡԕвί狕̹ЙѬד!d! NETSCAPE2.0! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,l ޽*oÆ"laD !^ȱ}<&h&S.(2"˖ ClI&F8lΏC֜ihǘ7s*]Ѧ.tG=Ne괫T[~ kѦ={5&ת]eKƟiBd{)ܨrT0P^By=:g72M˒bf?3,rf9~lsEר iztGاK}fؿo3ވrÓۮpβiΕ4rwn]lsR_4k 3T!>d~|_tX߀%6aiŷ }7ާv~B!?Z&FhB m#(r8b+h!ءX"9(YdF# 8`K)d.^I#I"(f _r Sh>IeѩD 9$yS e Rg(ivbZi]J.zꦨ2"*z'%ꊥ+lrkg몳jiF[-\Z=۪Κ\r+.Ɗo+bk* {n/n˞{{d"k.pcW|+ J2\p؞|/(k<0<@-DmH'L7PTWmXg\w`-v g6k-oAӝu=Mߣγa>ۈck8ʋ?8gWxŖ;xis>9tϳ_ks.衻~|ˇ瞳M*<.{Z.wMS:d,:߼՞|O?<+^g޽iߞ}?OpW>uNx7@0yvS`>΀#> t`:x 3(ς ןƎV~&Ğ OxCPs؟0;pA$"5D:~cb O!&|oj\vVҒq!WҰW%gA4sIE! zB42cDXBӌ6f1Pv.4fuӗ<'Lm&{,ya2ye5m9}$')N3 2eYPf$/Oa!#@FL@D&.Q K(dXŴQC(H%.K(8BD&2RE 'GJzcM(RbZW7HQ)"0f"Uh9#k$/*^V╬}U+8ؐƕzTc G s[G}VE.6zlzXͭ+dX:6e^f5k_GET\C{ۮ6,+_kܚVNLbXK{X)R5 vH,;oT,VRM̈́%V0^U5z-ޥ׿No<׿ޗk/~JDnӵU_7a1љfKڮF=lg*YVXU.LT<"N/LT50q X4/fؗ8` 76(ϨVX N0CQ\x*i#H!/3f2g1V/A#7YN.L\Jw\Ϧ Gޭ Tq8u:~5÷n yv3lG(՜;OJ$~)ɻW»KK`_i 7~؀8XxȀ؁.Gz$ zSF g0 Hz" (}zEM B؀8FxHXJ؄N'u&}O _7v?LvWb]W7H e[x߅džjȆ%{ȃH8&Y^&H<8u^Vx8nlXIv}fG(X17~$n$o t "o-o6v?\SI׀GƐ_H^0lx~SzRq_`q|R'{ SZ8tW"vDxY({OWHIdF؈X$fTk&Hٗ88p%c'YT7vە fl jK~f ,@ Xؐa+]#D'@ƀxv&EX`H8GwkqH>2 ޗ8 8 Mٔ8>r@yBix`?p lw,owqP  Ǔjנ@~ p u o: s q.g   ~$ThUOzyHH8~G)ָJI RIPٚWfYJؕߗ{ȚiQ R iȓZ镼iNik qS 0 i ~ݙ.~y ޵~\؟+_&מaG HLx9a^{'itڇ}j9IIDc4Y}Ggg ڜyy=Ú$ڇ& ֗UUoWmY?G  yf Ǡ_x P Y` fɂm0~ Y֩-Zz!Fهɡ2_":i).ʏ/ҥH٠B9r.g6lڔꪃD}'jt5Jٙ7ʣʛ@ƪW-+ ޚ )_^UjZS=];u>cSޕRڞ* zJW݀?ک7JJS2*X}J);گ>? J0K)EW Zgs B P g T o`x `mif:oEۇ0ck"pFx/zjZ^#O:)y >)Y%{% >x-C2I:۴Bk/;F[۰۱|:6x۲ʹzZ+I{ѳ':f us ,,&\mne/zn]x}r]ѻlح* A"}${m 鋾%[7<_) 鴲-йkl߷ }mۃ2؝չ] {v< ѕ=!]йm[ qLbk y V Mju KzM 2ko*h P m=۝ހ Zң6<&2}7ޏ#ܳ㸻G6|=ěmMKS{ M|-G]~< !@~ݴ`S8>5ۥHH,L&m\{ /ĝ j1noA sҪՁX]VNm锄n㓝޼蚙xF & p %'y Ie{`Hpe 7c{ P^)A,N.Qͼ緮鎩|4[iꅍ_߭ o ~M~j I.O+/)k<ŭފ H\*x-=N\ ~YH0*II܀*_~^1o[I/udOI0;Իhx-|])x#o+OȾwR ًV: >n4  W^ Rd+okk|Oi{ ™3n :kyןݭ;k_)t6v۽Rni~:y T'PaCĉ.D rƉ=~(G[:1%E0/؍Cx f'IUѤ)SK2 @A4.ͤ)*E=tӦ*Y*tQ[]JEReڽUW*%T `6 FlX``!2)+_ 7Eo>荢A 4F S "b\ @4vDdݺ!aCضE*'qvn-5:BRk%{˓y۶qj띋~[tekm?4G5X@++ A  MS>7&D*NPfXhQ-J)bLjP   H̔d;&2 JĜR ߸ټ36 m|m64Gnj Nxxf;G <ْU(NnaLx.KK/4S R,3N95OU+b dr2!Z*DUmtE]C%RKбbeclPP@즜r;!nᶙr̖Tz*H6HjW Su2ћ$VZk"Gnx^j\nܭ9q n83uE1S:']t8.UQ-[\!FkxzGzlRփޚj[&IkGuN׭=k{~ۛ}v=xD֩4RK)~YUyKh%ZYUǧ}w7Hv u/w,*G(YŽy夓P&$*ʶrj1?eKnಒoCHIeJ7E{CFnA|a{Tk]\2Ix9t;[$xOGA5%VyԞ,j}f^ F3~41MiV7l[Nw*nh/X6emg\ `Vj3•26`Pu X6ĀF3TQtΪPLʳ^v7-5q:ş+Z,k^ ̓->j…c%}3W:׽Sy؛uB]K^䨟V/zClvj9lwLxܟkmt':ӥ[WM'|}KDwٞv]'|\]їLѳ%W=ŮwE[|or>o=_ow{Az~ۮW=&pe-{N:O| AC<&|\ "c:L#CL?.A'dK#?.=/LB>B#@kBTCs670z=:B˿ :¾ 4GD!:?̊B@=C[=)??$>X\AESE=tE;@Z[L?6]tZBCSd gE\TBd >F Ej$FctBK??aF9n+`tG],GkG @\Z<{lAHCEl\Fb:p`F[\ȁlDHnFE>k$y$H>TG~ƅAZԺkȂFUHɚdkɜɝɞFJw|àD;@DʜŤIYJɥʪ:J$ʭʯ$<˨<ʲKIICSl?=,JJ@̛LΫ4ΠSTMjN D示k;T=$<K:TKK6;:I:dS3XˆBN2X%X]Sh&mY!hϐ5WRO'NuԛMٙYWWXVeU8ٳYOڊΔ}ڎEڅX%T=ړER-XN%ڦuOYYX,JuIU=٘Z/=[uW7δmۗ8[6ەR)GR;i\bϝ6b]_Eif]u]]%a]%U]%\%u ^]]=]]6-]ߍ%^Uc]M-Ee^ߥ^5-^EU^m=_Mu^]^_fe]n VU j`u 6_ ]M__ v__~na%6`Eץv^_$`,a'_b]]%*'F2`^VYPYxWpc85VVxc9V7^c;v85c=~U;^c6cBcAd=nc7GcIc;eeeU(ecvGinfUepeXfj^>WBfbeFf\_.sdYcjngD~Z^ugL.dQ~`Qgfr}>enS^W6EhhVZdhgf?n焮fWfQVcrhYfVh_Vgfw6exv敖demi=>iGfycfeoiFg6>圎DcBfx.䰾>h}@vvv뷆븖빦뺶&6FVfvdžȖɦʶ캖y{؇}Ї{m}&ξyknv׆ؖ٦ڶmlm} }fv>n>nfFVfv>no&fm'7l^po^nn lGmՖpWgwpmq~a[n.ֆ !'"7#lGnhX [`]qo7qo$-./𐠇?mj^xrYh[Xhjrrp0;<=އn8_5Xt_n(:HIJF^[YcOY{KwWXum}(Y%Bt8m9Y7cGdWNjhQ^[\Y?wt:Geop^n26YPDvsWnz{|Gk {R^QCo9G,wIot5?c_tυΞq'7OwuY8wy?yu&ׇQOw_O?wXuxbgw.w'Po^ t%B5'wnwr)u_y'{Ns5Gs6{V'—ol_O7xުxb|çʷWRitgGn}GWoGЖro}XҷJG|N5tOwbtgrpvuzbu7~gwuov(w'qyV''Ow5r]=Nx},h „ 2l!Ĉ'Rh"ƌ7r#Ȑ"G,i$ʔ*W,(O{fuL,XjvkhwϠ.Z2m)ԨRRj*֬Zr(=͂6٫XdjMz/*j.޼z/3νwt۱6״4݃YP7s3ТG>(e}3qd,V3ӎMk6fҺw7‹'s2,l}ź|Zۛsn:ڷsre%NYvo=?=>;:Ɯ|5w}x *`T_1g,tm3 z!!dSz:`XZ&"18#5uqbV/4sO>7݋6y$I*D߁ NnݲNv Lj%]zKaZ$N>/%q9'#xvckf[[^z(>d?hrm%K(j) HM&sbtv*<=蚊1>*뇅Ť=S>)'  ,J;p_ +/46b9J-{n`Vi!۟,}o{/TG&, +0c\z8ֻ k1a8YL2Z;SX1cI\33=J>49I3M;W Zm et3O{52ZK=ob"LL6q+Q}]ۤ&g,7}3pDijߍ;8hu-<9{70IMdY:XO'),7Y;*EWx;FMZN c8{@֎9VOf ?oe܃>_b&1 ^Գ>/Y-q ҋkQ|`}j9UCNb%<=, mC |! }fD9"0/>aǀHH'|X%2_Bb99j`i}j2nILʢ"E5sӨFNQzZpؐͅk#5}LgENSlk#" ;iO^c\k$&}8'O"1<(GA!Qf"17xasDVc}9K+&4 G[-L&Ĺdcŭus7'-1J^ӈ0۩}za#D<(B2QS%Bc'm5A3/*ґ^hBNl#&$})L2<Q52ąƘ ]jDjevӥ2"tӇv 9m*V[N/ C >(+[4+\:]K  %ظT~*Pk'3.2_ X/s MHUhB=AeC{Q,#O VѲv[%uEH/Ā*SOs(in$.tI:R_b?6j^.zmDbgjהOkqEduFWLqP2ϔ 5G&9/3=Qf*ڠ!u>1 G-k[RQ,c-nLJu x>*kThE*dr2d1ֲ(ͶK2E,cd5ψ`,}$䶠tLrω(gs]fs+OԹ8]kWk~lu54t;z41 .}ʸQNrU Ia 7f:5]Jdw.KgZng#j A2I!I#h{2^q_~P[dL>78/Es%ώl(ak=JUwIґ dzXF'~ txA;@&`"LB;D>XC!T`!A@.!C] IbD:^2^AC % D: l  3^40E8xf f  f!B4Ma^l a.``=#5qK-!(C3b*D5f @aD B$8&87D8c,b9-A<e!F !("$*¢5*$6!_C TE^dEB:]!=H/D0A1=Ci#(ڃ(A5n#CAM2D8R.%S*%68D-b`O:IDU^%J?E E1LFT>=`7.&d\ ZDQC̢md٢Rej@`n% n'sEEZL;DeNe,ƢO%"]C C`4A'&jf,#` H; &b>L/ t(@e4r"5ΡdhhCP$Ffg!xĀ_Ag >ԔQķue(,eZ2'ڟu&@90lhAJ`RB>a1NI=pM.'f3].RB+(QJ -%ݶTE2 DZ:a@e=NiDD=@Ùb ƩDdeG.;;^C6Că:C6䃥6Hg:i ݮkv}VLOŝJ٭>+pAZ\kkgVxY,bXkibc֙P~б$kͭn(ݾ^8M sP JIG!֍^+M,r ~Wdjz͝NDݝG=t6F(QXAj>--l}WyRkvm8-DB 8 @@z -4v-Ar> J.GBF9-bGn.B9nKv_mꎮÌ> AAB -A,^H9@C~ hE J( nmZ juC>EDJpkxjh =T0p46|#p[0wB0vy rF@O0 w=Do 0Gp _@C'(wDKqTp gp˃ 5WFAC0GVGpKFDt/1  $F81GD'ϱ'npo`=qKtL|.`xc00'od:j [@ w7 -0AD2A r!ˈ/ i"! !_E?>vXJeSE/(&lM-Tܢ%`‡ւ%^ D8 /@sAq::/ܶD0('.x3*C/p>! -K@C (D=ЂX*@B'x:EFw'/0!B t't1@AtG4E.,(4@M X.3G* XnKP+Q#5g CM/v A,@!@MuR'SS5 -`tUOD0'P/V5NRoZm!@1)o-tAu`kuQgu'4@^FBcCr}4U,/ /^^Cl>ԃ(&8\(lqo4&p=&@*lo7h3Pl7@ .-*Ѐl#@F[>tNP0En.1D8246b, 7GVRnvDC~b%~n |w:C@3x~@|W~K/z= 2C6C İConTt7Eۀ3@3@c{xE_}8xEBˊR՝' ܎>x7A8l vbq8 oCxo7spBf@&<(/E . B6 C6(- />6sr1oK?RP1ީD ) //BoC*c';ߞ@zB0(4!D84 `.;c-x ߫_C;DA\{({И;n:_:I ギm'B'|[.[X$rٻ<ڲEmE˭$/-o<̭<@ЃvmB<" dDGBЈp11Gk:hG,+0m.<2B!l|0 #OD=h.!lL" o#=DxC4;z{>pmN&_%23.32Fl:!>ң#p 0FmWʳ?C33ABЂl;" Dm;#7jPF ػ,o @#}n~6j;@}OlW! 68!= %#b#2%ྍll bN߯+b;}"I:<ňw0\TlYŧG JmYrbleɡX4V^lY>Du 6lAzkެXYǏ!GF#HNZk$A_kO$(Ţj h k,lc/ j %)!0/ #ÆxU ̪ m?Щ ua%Xg(+Sz6ZYIjƬRHUV"jrD/Vz5y!}?G}. 륏WaҎsӊ#J8?݂IxnӗaYi9Cmf`%5a&ce5q9H%WCN9seREZkPNS4Sb^'ʼnb 轖t܎B-'Kw]}ىؼ'/v)j[!)Mjui"3!4MVopɼ-]ϊ$Du\.Uj{nWDm3z[`gY{B˾l ^ca!S'KzYAb Tak2N?r8hA`PKqfrGr)#yYvw< ) (HN`!BȐ`P4,pca1*B`(ď) a"V1u!G ũe4ؐdG| #nҠ$/#ȏ g)𯐉ƾG~Lb:#1m IBg!< B!"$qI%bJp%VBgKX7F *P#TJ].[a/GE(&suueEY2qv 2;L3t;9 (=eAɆ`>f#"1ȯ]:c":Vdc HNDs (C"ȘddJ'JM&|x)DƑ'& M6"})HQh6 ^D`%K-FU[\.&FFi,9l9bc ->Ætc!YlQYTe)Qm4UF7utRkhcv1HtК>vaG#"tRːVmqKɉP*6Lf@4/YmqD PGiA-ȭi-SeR}W&63.odly=ơ^XVu]̵!Ĕ1JSԗt03jԨ 3IEPAۃchBa#w Xj5XK#AO6bE>i1gGqkKe63آ{ĦE,0HB;hhPg .#<H`90n@!zL'y#CrMJ,N.6cvxY6(rSuXu$ m`kZBb# "`J\D&1=D\Zw|/S=RiaH2jwr V[r dJZ!Z5*l.pfAhYDe!ۤO΀12 @OsINpת=a xɀҜ C!9A:]L Vϖi) ŬZ*ZmD;/)qe s,b-sD%'Yxς샡-i:v$~`a Qndz+`.0~rdaƥx)0͈b7V4Awê]BzwfRb1O,|-.p~T"#!+{ d8>lt#G91!y`C6ԑ{cB ~dʑxJHD_b8z0?7-a!3/A"Ι`/5pUBFc|ڌ||b 9]PwrDmbЌ*(y{BR(%hdR0P|0 P.Eqfj gvZZﴰ ͰdO4B6z!hx6, '0gYf0{(K4>ge!6.hԇq)OP*qfAX@`0Eq/tgZn,(gHm12Anp !)chgg|a6!D 21q' %8+.R} ٱ1'2hQPRNC΢qPr AEgH^2kQf!-"12#5Ǐ!)h".a6gzo#Q2%Ur%Yrq؈[hn6n$[r'y'}'_ftfQpxQdCR i()2*Qgd'aPQ`iq*2,r,?6xF+E.+x&⼒,r..4r|A$oachdR)0 0AÍ4!hR6ґ0213353#ufsOI62735Us5YP!_q!5q# L5[s7y7}3*mC&WCf#Q"99wPRQ2(A Q&4:;. !*5pt2<=3*=P/8h䌟p??Sr Mha7Qaa}"uf5 x}8x8x8x8x8KA8+8Ә88xي9!9Ԏ'y/ً3Y79x}xyTyY]a9eyimqٖ%Fs}9Ag9y9gS599Rf6FLʹԒ6P9yW9r$9y69yc9-Gy ,ٝ5&{l6(ذ4jGA6al!yY-;:6L+e 2GyRħyPk{aA``:aQ9#[9G9۪;}y{Wa5p aangLWaFÏGA  RZ`<t}!(;ܖA6` \_<ƙɛ +aR6^ J }F `Ѐ;lPAa٭h9h&ޜ`;` 5PqWZa}6a{ xY@|5˜1ԯy͜ԓ[CՍՍ9k}L|}5Z X J{=]؉]S Q|۵)c!]ܵ|_gq/ 2e9p ck U #]Y=`a9{{G<`!G`=@;:4*_Y;j߿!eQU~S䥹R*%_[|\ZGWYse}Q!5Yy|܏`eKAg`AAa<`:^{&:[-!U٭:WQ ȠJBcJ p{a/e_!U4&Г~$_}4YqL=|y}?ű.Ry۹B%  @{$?Ю*4칞5H?E1a<3aݘRh;L-Y lK`c4VÇee`CUbjLő(`dV-0u ,u׬<{xO (Z(Rc:PhAXduk^!R`d+קEeB 8 >8Ō;~ Ǔ#[KԨQl֫ efida+ b XǦMeR*ňqZ,12K%$DP*nP*Uu)FZB5vL<g?OMlW-~h$ )H+ 5*" .V>Ԓ}O"Q34BFFB^I4_(J1Ti 'UB%ZAՈ /bS2&dc/B 5At=S3bjfn gr2NTE0"]ۥFA<]RZFڊeIb )S{5) KgRyPnY{y`}j'*w.6ZVjЊ*e KԌPŴ,tS/2āpK–KW]Q4C\D)L`V Qm*2,t5g{l r"L %T ChBdB8o6ۜrl!k'%|2"i-[Bl( Ku-S37l_ېAMhP- P!2@`o%@ƅX/'*ZP8Z\82MuW,7!M ! @VQ&ԋI%K9~Ty. Mv/|vc??{ܧTew|-ǜ܈b'X^PyvV^0G1!F(f V k8Ҙ+Z,G{!G@SnAdMD ܅022Pk)0B&XL#8&HE3`+T,(p0R A:1u5@"dLU "CPD,¨bfaFD+[Ph2ř#(Zw @$’Ed^b*iI1C쭬!dJDB.&"XIF4 9hk,!+F YD&WU7)"nrPq7SI(rAX-#Ӽ_%w*! N =IɢcЅ # r@6%" )g)n!GLNݝ `jCNT 0v/RM%;6cj0XZsFD^|Y]dϫ|~`;vC"`AqY6&o'hU1GeHh&H2hAŁ~)0 0MąḠ*l%g*C`v7.`U IC&yƒE_&Fx˳o h9 .ri CX0Q mAzs~1 G0,Oy!tws搻ãϒN ?Z!Uukצ!i`i#!J}v J!$@-&)~  Zרjci6` dZe6 a)u atǚDp.V Vh/"2d> aǪ F$o `}V6a1qշq/ ֊rjσ< 8DFHmҕ@' UM})3B]_ ac=h[g e]Л!!2}j}y |~V-| ҁ=ԅ m } M֖ ԑ mk}ٛҙ]Ӟ-ӠӢْ٦ ٨Ф}Ҭ]Ү@ z=ӄ]Ӹ٪׼mӾ=MmǍɭ -Mm׍٭ -Mm -Mm .Nn .Nn!.#N%n')+-/1.3N5n79;=?A.CNEnGIKMOQ.SNUnWY[]_a.cNengikmoq.sNunwy{}.Nn臎艮.Nn闎陮.Nn꧎ꩮ.Nn뷎빮.!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod., N`";1($".;1%%(//1 'EMVS'v;r1h(]yDhL0NDX*V1r;t.hbFx.KeMMNDFFPPPZZ[RVTrOMtjSNNyMPnmmqqquyy~ssylmpVgk*OAMR2X&h6i&%R%]%R:V3R%o%f%z:pMMOVWRKSsGnQyLmWMrdxzrrxWfWReSw\wf.SruqxnҘ\ΔMדpwoȣy{DO9l4nfMm|}ewMuSuNN $ :$/X%`! J WhX_.((*+:'l|JWRmabUm݆:sQlivkyw{nrX.ڏΗŤɪͪ贎ʳб峫⛢Ҙƕťλ΢ԧγ付ТԕвͰ犚ҙˑѴЙԭӤغדܴ37o@z ʣNzTڔbEKU`By4RiaAO6}Zdz^qGIWf贞U"&;.͵p `ٷn={.yxFMc~k6H$}AY0\+h-%=54c3fӮsb%۠:5')kjJ4|+۷_;Z@vZVz5 [O"eQ&PR*F QɃYžU &oXU`$_ݧon`a%s_WRr|Vڊh7ru~F$21trHbTqe=7oWG:N\u&Ve^Mդ.s P6O"V2eN CLG1B$&3[%'V&A<B]Ft*T/ @"H9eGF檡SL:,X { WWJ hɴYBJ 饲ХچkKifʡ*Lnain`{%e[@fp''j5IiDGR8A)B1&*n hx-KD Yd NyFwR@ n2^"E5*T+&GO\-/v4`OMPwxכ7{ַ3w.]x)x9 '#En6 Bw?0 f'sjV;<"rHA D}D @@C#ohۄE>i-э"spok-Ԥð(2̟7%:P} XHHP#]ژ/kt)эVƠC2P+ވ }CZ8єnbr!@}Jdt-H e(eZd&Y)(ʖuH$VNKj>*˥n:6Q \˙Ly.鎘wKi"\д5M8ϙ̚4u=7yWԬvRũR:hr%ؾ=RRe?3t(sAiHEH'ByV, H~FU7?!4.#щ ܘ$U,Ki%.4 h%VNj:Yb%Q*4vشKTòVOX#\p8V얷kXolMp1;.vl3|^02%&& 8jb g)U@ZN잝 ( Z!7H  0@!L~71%͉#Jb# @pC;x⋞%n8N9WB55Q_3OuͅbBϋ|('{sk:8z;Njސ Լ囑) vڎ\nSSk3cqv(wJgU1r uC1oLK<-8C񊷰.:;\m"%oYg%:m{W]=ďwxc=m| OG(74F2yp-vv q&bC/frVGd`@s\8C)J\|G{S8$ 0ES2US-Fk&pT25$gTD )C)BGIQoȎ} "EYdiH|o897xi 9hGPГx9>dc #)^v K =O6G,H9ĒR XHCy5ٗEHIIiȄhUTNd甓F~ia([`j -#y jHZ&yD@<`gF39w(F=9i+#ր 5n#-?q * ,=r#ϸ l >)@`iHEYȨ*yZ ڑ*HGڙJ&L(Ő@80HVu~~%dH8Zg @!P Q(`[tk砞7H1,.7a e Ӹ0!"5pSJ񹥒 qv`!ϸ*YJpʧQ# = ۰$Jj}::: !9VI˙~Ž Ǜh8sЀ Fv @pT[Y; zCiJT;4 ,a , $zUS?!l BRbJjϺZ:`:*HGʣЭڬ'럓(::ڊ::SY:z􊥒*X:i+Tjǖ Z!@d HDQ@wcI=:OT)2*e-*GJ$ʖȢ'*Zʣ S-IR;[Fd3\:r- |ޱzfڵr \G4 uHJ F+s[kZKz {k {ʻ'gˮY+ x5à>]-э ^hmM-/>1>ϣ}&0(.=>]:+]ভ6@N{mVNnFbX^N_ bNc1jnoeNlu?~ ZNq>䅾s>լ凞s G3^]蒎3Gj'`ns~N橞>ϴ.N>N<|F|^f߱u..w׮H>緾~ .~Ȭ^싞f^\~njN)N^b^h~ Ӎ^謾ldN ^ N/F, 닾.ꧾӾ%ڭ-*0O˜ )> }LoD!ͅN}NÞV.~*_Z]MSdmO\mFx{<_ Pnj_{l ? 8o ǵOo ?ƀ ?{ Q؟ڿۯ ?_/O?pOoJ@ DPUB>j!CU#&ė1=~RH%MDRJ-]SL5męSNyTPEETҗ>>UTU^iV]~Vؖ[ɞEVZmOuW\u{W^}W`… |Xbƍ'vYdʀ;VƜYf9ZtˣMFgխ]&lڵʶ[nyoōIrC*w]zqӭ_]vw>w/&^ٿ}|η_U_?$0( D0TA0B 'B /0C 7C?1DG$DOD1EWdE_1FgFo1GwG2H!$H#D2I%dI'2J)J+2K-K/3L1$L3D3M5dM7߄3N9N;3O=O?4PA%PCE4QEeQG4RI'RK/4SM7SO?5TQG%TSOE5UUWeUW_5VYgV[o5W]wW_6Xa%XcE6YeeYg6ZiZk6[mHfD-qYn[ 6ڈ&-]sUK 6E=gԚAލ_ ͈MX)${7|Q7w>#!s)dV6$uVnf谗jFʞlCAWތE$R^dwuz8:8nZ=:B!'׾#>kz#AOو܏춷 dpQhQE;'=Y쎤^Xs W.#ؿp3v_ɞA$];:]6] vyzXUG &8|/BYv=ݎi^|õwJv16Ё Fbi};gb,]X|LcC=Na>vr†7ġ ߵ#  rЃ_!>D |-$\{Ő 3LKiW<hd<"WD|4ӇE魊Q"%TU@cn" jϘƮQ]=Œ .b﨑Q?x byڌQҸ#:1c+SjVUvի_kX:V5EF7%X>[BE -!ֵ{I_ØHIc`,ïzJ6ء0ֱ~u!tֳbاLl12' n0 {@ˈ, buIkoZӵU-o?Z6E jUKָEnQڥ8׸Bhg!%,`Jأ ˵^/{ <'kZ~8/I !p l`$.l%ALB 0xCr8@ޑX/zٻ zE#9M FI>jfQ , 'k0.g9 w …CE>ւy^{$mI ^?bN{ݴ$Fg`$dG\4'6X4ѳG2]-Fj[s0h-*Y2,2J8xiQa|".ldWC;ыx6 BCPa'`.K-\`\}iG% ,t`\aC#s N$iVGnl$mHC6wnq& ! 3`0+ocH`9qnԘYr`a4rQa><#K ǻp\>P%6.s/O9>VږݺӅWҋ}\izqס&@\ *2rHc )Q1=훈6>xgp[OHvYgpJ!s|v}֛ss*X+_f/nP17.vUwbV s`|kZPoQ=`~nhq`Wmq{~_y|1;czCF?40ߣ߽:𪨌€g " @ U< x;!c3JˈjS@Y0.ز껁0lY:3|9 m03[ a0nSA[A#4a0.K-'${>Xp6AʻT-;,9N 3'zn`BnXC3C>>04׺:@5Ӵ&?, + ,Ub8,10RH㳂!8ƒ)˳6pJ!zļKK HŮ4>ćrˡqs0Gpo,xLD3|pɢ3r0;M#M@JJ12LFcX_ l>?t H-4҃*0.p7J%7DGzRj: ] PXڱ,Rl1qRC2}>ҏx&M]S1=6OC MŏH/M`?u0z0<NzIQQ|xQd|lï4$QZ 3@0{.UϞX->=2&)̵-z/pmrےϣFղ^OHH^V R-5 E\ՐhN<ص Dꭷ=\*L\,zD(v0*^W:F|8T0Ps]0FH1x;xsHQD*cC[QU"cm3CZȁS=$0y !riDތ@@1I$.ppAE7lx^.z/<(ck'- R-cȅ-%-~.N:;cj}/(3<Z7\Ed--c]0z_X?&$E/Ev3Bcr1neR`8@NҲl(#ݤ ϲ_ [tfZODJʛ6=:璽>=CJc-b@zSA}.c*=.K {vJ֫>cgt6~^Nug|2#eʀbaزκW1aCe/2H4fi ]iݴ #X2СQXtl[LmsF>" g]jۤ6jJ$c|0Ƣ+m<z;؆6GБӏjj#|.c< kzkkggJ~ }1ov0sH+osVac@ k {my'͞*ٮmQ ކo`cmڶ퐘㎉ۤoy`6~f| 2]3>ZaLIo`I_ZXƐ|]e[67GWgw '7GWgw !'"7#G$W%g&w'()*r,-l/01'273G4W5g6w789:;sl,t;0/k>ECG3wt04t3tA'LGt5tNsPgsQ'8/AFOotROtEot-Z[VWhh_`[u`u___^OfwvggijklmvWvc@m7n7h'gsbuh`i_vwvvetv_v[u|qgwwd7uuzw[gwVPsGx_wOpxy{uixbxjGyl7yda/xa_vcdoT@GUuywcwovsuvo[w\xXvv_ vwzOWzmb"(\_k1]OuxwvwCK wOWЀ{m^aRXywwwo^MMPu_ ҟ.mJZo~HV yz||=׿u^7ycShghP[PFxT`jgOHD_L Alp`VÌ zbPq"G,i@OlBDc&%hEd jR}э8uR0dCk8, R1@AskۼzO^*큝 8!4WY#FUŴ0XDrL4I~TC52iW`Baܺ5֢xiF(l§7)%i`#gr0o;l%W--z*j]Ϯ~޾x -0_v3QRR9Q wR-z+\чk}<1UN"AI%\qQ!JTI+HL4f TX1bIVT@L\pY "Y\P/@,MD#THz5^|o)4_""c^wɗ_i!`JH ƕF6TŖIE*"obmHxiS2E4'F5,萘zy(DuFTRF*bV":[R'QdzJW1H8%Qxd$Vh)ع&S(׷E@>5♖#Ѷڐ\™'hS^@ʞf!HYX1AE Pzi ( tB*D\ "`)b %BEgJ,& 74t "B ^vͽ*P* &&*p3'CTh~F}KsIPbM@őiS1-K&mm2C v ,1<+tRoS:!{GHSC;*rD\*$H,^iEQ`wS%v;QٛSD4@)p4QEI?v UgNsS Qr2d௑<",n XX !5dd %hz1DY8EBÔLQPqLREc <+J #Ô[| AhP܈h +HmӔX Fch^+(cFF0(Fp=dKO<$AR6dI G$2T%1\^R,]m F3%=IY CX \\qA_"B $p/+Ѐҳ]M!:Cxg<aZvh4`1I S eCFtl IE) 2ŚlfF H*(yKt گCSH K+U$ʄԂVqY*%i#h R`u,R]&mǂX)=+# PpFsS9үfYf~\^'斻XT!4F_OT"`Р w}B z" fmZ2 BMi6p,3ȱ\k?k0x UF"BU"@P$FY)lě-hjBH^ L<E/5dSlEPX\B -8DN`l0_922Iu`@JEchp4zlMY#˸ڑK,07?0GOgo0w00 0 0 0 Scp װ 000 11'/171GO1W_?1o1w1qk1/DB;011p2 A=@0 q q/2#7#4؃!ӱ_#o2'w'+q$2<2!g*2+2 <4=A,2"k>:C>83s: O>@c2C!:2s*DO4ESq$C:C/A5s.Ӳ4 K7=L07W4KKp$3+tJ994O;`)==Q5R24C>!C,1N;)_32?4QGtR5X5;G-3>L1[43P3%w5 ]]L@/ts!K5^'b4`˳$/TwpB-5DbgfTWLsdop$3Cs56#f6k3`86ϴ /pF6Wov'O5:TCJ5.s0=8u5S/t4pO7uplCsHSp$sS[Kwuy#5yzD7{7|#{7}w'Ϸ}~1~78chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,=L........AO\fpyk.A..OAfAyAOA.AO\fpy.y..AA\AfAp.OOOHHp\Af\OOkpfyyyyypfO..*OAAO\\f\.p.v.\.uOpAypLfpfćFʑH͘\Қ\žp͟pŘfץfܥfըypf..GAAOO\\ff.w.pAp\pHwAy.y\\y.AOLO\f\kpy噘ұ̱巂Ƕ׽ƚĄ͑ҙڟȟ·٧ӭ踚ƑȂד؉¨ͷ‚ۉ H*\ȰÇ#JHq"(*jȱǏ CĘQɓ(SDIr˗0clIWKz LfDJTЇ4 iS6Me'NݺR fALZiMqMU-k V,RDL&2ڇTBP*LdA@ASCn034Y-mrGSX#S!y}դCS@S4zaw¸S`3JSNXʞD_@բT6@ڪ$ۣNj4 %CSetCSBSb At5ep}".4-fnmj|SS"iϖV@6.1&/1CP0(@c{{u6qp!(h)P)4ɘ%@i' 4huKAu4e@2CëC>-4sJA`nV % ; orgTy)X+¸6c;4e{rd1Õ TD`H%AvvS|&HۙV%.:,ꞝ*{ݔb_Ÿ;X%BЯ 18+PmN@!\8 @V 3Y*nqhS$@W:;6U7ZӔo~V0O,X¢KM.kNcFkEQ@L<;}EI@06#osk\ ET@p5 umJ.8<o~~ /oA1<$H TH)Wt b%5weJ!t@ly ę0 5 E 2E RCg Nk P[/I) dK#G$*B't8AMcڼHcpGJ\6[hFs d0vtU !R2EM6Pv]pA HtEYAeEE3-J&t"$ԛB뙯A5 !( 6If[9E!zIĮ̋ Mxe;z]EYb2+,TG!dROaY/FhR{Չ+$R'~h*8`Z hZ(E+nACDwOW'"qR;|u$aH_8@oBEs-5WtD]S8D3iU*P"0؎pCՈX ؕˋcY FqDT̐>A 60AfE^.`D$tSXN I!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod., {`'7';1$$'//1! ENWlR(v;r1h)D/,tCcJ*COZl1r;t.k SFw%JcMMNDEFSSSSUSqPMMMyLPouuykmqag_. *$2=(5OASR2X'i6l %R%]%R3S3R%o%f%z:q5AMMMMOUWRKSsGlNsQNrdyypryWfWRDMfSw\wjQortpy\ҙ\˒OҖowo{Ѧt.AMO9k.khNn|}gxMuQtMM $ :/$X%j3 J V l]`(()4+lJVmkhUu:SliukzpOOrttc.Ώϗ̫経⛣̳崬ҙ՘ǒ˳ԧܘϔѱΆ鰸痒ιЙѬ֑ \';vx]*0YHb[hp*DU I*Ld@C0ɈUZtG4n(ASr̐#"/&Qc R$Ѡ9iL^S(ЂGr:vRAԸLwD40G fשLɂmӸv6,UQ|bkX3[]R!3U.eL{=Iz+PtY{9#\&\4ЏkM -Y91Rg$Y$1D$ad mvJ %}IgZI`ΥWx;g^}[{WYS \W'YT4 z%=RW! eQHBuQ`wcHƑY[Mi"`<:Q)nct>b3NT\3e`WW-;u$8Tf$Q[i-!xyބԄYfLțys/Vddݙ[UrF$SE%VZcyGISyz&"RGOUtnעu]{kܰxՆvbNv6>em5.װ_GniX{:Z԰:nqdB܎cPb:6?'03u}௓4 !(S\LUBA#);ܲ鼹%l$37nd1ʬHҘɀ'I}W |lBAǚxJ`LL/BWקT4[;mh;lli,Pq׍߮}x}xM2 psqkh̟"1 ^D^Pnk+y#}f1z~yڗ$BQ$_[%N&crE)M]$ID?P&]bbxik7y7rwo>~6>Pb_o}.P F0PUl# kDr f6׹lA˄JrDbl >L0BY %Hv8]R^7H14Amv^YKRE)Z뉐k"$&SB7gC@*TAq>q l#8E)-|HwL8|H)PgTb8Tp$B<&*qR@Z!Ne5&OUIwI(RʐT[J`57_y  |p{&VةY+NC"Tf-{r_0Ku8}d i7,b3I$Ű$ XCIɡA   Qf:h$dj &j`|j;$ڧzE!Ca$Yr"P$d$v^iNgeby3 N|DBi: D WJBWQkԊ(W0DPҀ53PMZZSK'-J8uz _e+5)/q*F0j k3rQj2!!3!}Yuέ2Pkfim+gLvb1$WבWMֱr5:WP̡ /( dJ4^X.)cnsdj>7MaUe+k7+ZD@US?`UJڪ.s7}z,HH3dY%a΀ Wro`^+?{`pgSi2ic8!+a7lG T;c/҄8ͪ0\MVٿ,ol+wYP3YP8]NbG :oG9?Bf ŚpFՈ*wk 5!51^XS nBzƭDo.yv;eh +k ofMV:Lyh dRƬ+2]$i _8|#l ;R1w+ v_BV&c*LT\[Ln ,Jli^l6`n1[_o;sW;>M07p Fˌ0RlWtڛEm/(4cȰ#7xAvS\s|p!"D\ ;gzu)&'~Wh @k 57fR  M#ewzgnumeNTGǀmg}v_1I~W_0S[4yhY';v<'6wyЃ=C@ar}}|ykX'kgN,pB@%lQ~Fp Hf{rdɷV&WSXvev$qXGWw}hG~iyQ(Uzg#gxOgsS9 E[sܕW@ t[ lZPXsWR$@68~f {slW}}w~Ow6ktPBz0 M{T0?U(}ٸV6X<5֓Kǂzwz kQXHxp3ǏWoǀP6lאt vpg{/ 9at~\kRـ hA 0E@@w  O·؏ܖ6} &&$ G~khh"4^،m1 ɣggP ՈTؠzX .DP {")SH+IP ؒ'jGaI` rՒym٦Ǚəv$|i|9gu ŒT0hs&9zFP `g6tM0%PUtPz8Rv NEiؐ [^~ 9 S=05C6 YG mByǃ& iP Z Jf yz iژ  ZarY֢pyʍ#86Zamי P fe bdl &h i mV:bU P9d%Zx}+tt09l{;=ۘLpTx} =i43Ka;97z:򙢙jɢŨy5:zp0\Q8j`uW)@ @OWrmuJy `j ꅧʞ*a釜i`)a=$S z Z  aI4e ;X)hk 6 'I8˱Zk"!{ Jz ]&tzq9{-YPڒPhE eh hW+c -? : J*z_F̷{2ȨPȆl4K| =: p& ȱ 9*'{o:ɒkĕ\D:'ʨLt˞ ʧ8;ʺ\̺LG+\Mʹo̡uL\z1{pD\Gx_[k p#iה%5L m쓮h:[ H7\{@I Pk ̆xl8,ʞʵlkI 3a8D<ˇ `=(ɘL8JѠl'5B0{/ ,̡\˥Laa}\zUǯp &lkͰ,r-J[jLLB\Ӎ k|uG-ʼ[{d1,`=Ѡ  PG:ֺL-M;8 ,lCٚԖLֻlt %0s&͞(=Eu 0 mQ Ri:K`]gP作 Zԓޣ &.h,s mx=|Ļme] έ \.\^/>̃!tMʷ.]Wmߥ6`:,>.67LF֊ s]_|ݪ]gO^,^R^...MN>pyLέl>Ncn]mk,^}NGgC<n޽>m+.>3r].䣜ͬNUfu╞LUxN냾Χʆ>S!.oN>sG^슎(Nl|)=;m^戾]g. ~ؾ˴ >h :N>Ďხꡮp^-zMϬ?sN^ ߞNo$^)/nN%/ 8=-_/R??NXRY^?Ib?YOAOh^.oi_n vkr|?{bOZ/ /ͮ/ fo._/O??q~?NdgQۄ}/ 9 /oSdiOß?ҐO/}TßnOG˾o__Ml׮I3x0aB jSCNx'xG>ygy矇>z駧z>{{?|'|G?}g}߇?~秿~?`8@ЀD`@6Ё`%8A VЂ`5AvЃaE8BЄ'Da UBЅ/a e8CІ71{ت(FqH2{ mXfa;cD4":4#91 !jVbfQE'a]l=8'!TcE@<"`Qr q8uHB>"=H FM 9q :XA ?!~Z!u9-ryc3xne.PV2\S/\8J;TvLjrqe1K>.H:8ÏlC&eEw賊9kj+(";9PyCt 7{Pꩋ@밇h N#E;/ʆ$1ݬh.Ɲ){)C] ],GEjR t)}ڡk8^Z-a#rM'$C=O!F!tE :W 5~hXJċP:r0[* 2ᱡ|Yɪk#$9'oЂgA+ZmIq4)@8EfjIJ.GZ%2uUMQ -TZ_u0,lKI&4bCtqR$+f8B UC[MW(;Ba2 \zl\irO#T;sOmF@ڋD_*ԥΧ,E< y0jv׃ k(^= =8B:.5={k@nA5%^j~6 yd!HycNX:%vc 5A箃g9lP@}'^hb1uWXsSs+yc@Dz0_uVWk'󜸾oj&q]3=4ʇ󽀸29>SSX==7yz?+4ꓦ6e&ە\HJHy 83 3^ЃD*X"+s>k)o8=xy82(|oЃ38A gz ԰C22%# 2W=Q@2ZM`2*84|?/t';[sp`C{8̓w$X#ЃC\6o(Ds^X#)5384lHDIDMD$2)>?C2œL=P2DCVt]Qԃ=.:֋TҤ>u Qm6܁Ȣ9$ Ns<;k]Ў>oILQ uFSMkIMM{"h`P(:2Ȱ 6uSS82NZB3]A-?A<hCڳ\H/7z,MeNP' D? \nc79OO5LT$5ƻO5yl99Q"SM,V2邎=MEUh>0fH=۳89!KpJ[= 3 UUPRTR"wм):ST!U/GFp0,T2: ,DUl!"G He̎=WS;&ֳcѐV}uUթ|Q=aוUNרY9N}"s"(h+LrWɘZSO>/\V6-Y[2W$=WO%RO=BMΥMOE2]@5MNtҋp0+"6QIEI`XA ."T7;b#mԥ?2I֎;t=sHCۻP]վ[ɠ}FVł uh%KCKԥ[x5d3=#\ĕ^pSMӔ8~ ^DɡVsُeI=TmÎіXI9mԃY`5Iad;"vܚE;(VC+:.M6[}J8YbDnY5 "NU/b494_{ջEY8 <9y< vL;@;8SS\2cOuQPNF=[>6х5e:9>xb$CIUSdepػ5(>6qLb=e%QPE_.9}ߠebߎ]Ž7p#5)LNeU=3G3z\dlAT}XI~zNTMe> LS3pZ %rPbf]Q.6P)mP^Nߌ~NFÕ`4k9yyet6dV`:N_ɑv5T쭇ZI5k aPϴ QW.enN'xxOZpJh],f~s5,K赁`uFm`6l.Ev;ߵ wX]PU"{X K~&fKE'8WQoi.8^a/XwCݠNTwvVLR~DDrLH~$c@ lw#͂k0WN`/7n4nPtnwXL"J٫Y%RJ4fDLILL!x'ZЌR͡ -MW<6Tʗ2*dyptwҪI`hz˴Oz W@Gw`X^>:[^~TZꅃ1@@4?E0?.imn5w)%8Q];|b6ay{zs5y,wXD ["E`}Hԯ ʗp]ʷEPdO԰gL{o~x#~owUaL~֪R~z0;~Ƽ~~gpwH@F5wiװ٫g:]J]:e Dh"ƌ7rΣ,Y 9rbl) ڸt9`IWRsW^Λ@k$hǤM۽JnEEZLlf֑j+܎$'Wnv,]vAM+l7Q/uBk4 <.mtg#HB5֯Wˆ v;{X{vޫYfA[xpෑ/W9z;oԯ7^]5V|n[v?vG^}5)cq c<y. zjn(89TY ~蘃Nťy}2ǩ*:綾ޙ^{k2yC1ZW+G!aPZl~!E-jfضւ;nKCK1vk޷ m"B^»./ <0|0 +0 ;0K<1[|1k1{1!<2%|2)2-21<35|393=3A =4E}4I+4M;4QK=5U[}5Yk5]{5a=6e}6i6m6q=7u}7y7}7 >8~8+8;8K>9[~9k9{9衋>:饛~:ꩫ:뭻:>;~;;; ?<<+<;>c, >?????(P~( 2|/ j=(q}% !P!a^J \sT Fu QF<"%2N|"xD!BV" f^bF#nQc<#{58,(%Rшȡ*h=q`-q>,$"x61|$$HpJbQE'j2()ILR|&I n|4+`CP;@"19Kt]- *Rj"#@[ =kl$=.ck㐼l~t9 sI1[^pbMDՓs5Õ H;]d:`r Ds%=Н!/yWB#)i团%=W(`=yq1Y\XyOE` X|x}yQ WRV5N!.YX޵nW46XWGx|@ B͟S~ٍYm=&qWE`+!"]ՖkWٝtr Dq%rYA0Ÿ)_͘.\= p')aePi@3@ 9-;+B yE tU(!'X ^+ @ᔙ) *\ ~TIU09s@uԕ]*!pma0*❂*m(R`Z#Q'V$ |C4DPT?*[B1d+zQ >'[R UQ! BQՔ*$B!-Q4=]8Zy0QEW`Su&D1Uٔ^i$.Q?fUR^*FSg8Z]XNcN2PS&(T#%p*W'y VfPbT" kbVRٙ"BC%TBy""T p`Q)D$(]ꥎ==$cX^߰gePj }a,5=9/,@dƞ !Wubt6h!3]8!gXa!.U2X ~:fo:c"]oI=)!0D)rpT&Bqg!d&9h>QoZ)V.|r ՘!PR#Bt#-$~ҀE(҈q! "f#hV*t!eq~`)f]ji$I'U]r/B^ v @.$.@P$P5b89Mv&aYfbM1+nR֓8ZQ"Yo~!-kv$y"`!jy-X*ZFEdbI9E>ICY"ZfװTqj@*8!.m$+] ٕ'ĥkkBF ~.y f뢒ai̞}cQ+i--h\';6+!mIb]R%&cE€H!g)dA4̗Sr(T]ZbhZW*,%KFCuvF}U %۰kږҙBO/!m,؟AVҗ=M)j~ƒjQX6l?2F&fj.Λ.2d#韷^nZN'L™[ZY(|uk.% oNbI Xvm>F.cIhބ%mm*)!}yv,T^^{~)M #m1 9-VfaNE1L&5WWJ 2,"0i*!yI!"'_V)Qm0"T2Vta2zbHbh kB%rqĽ)~f{IA=uQbbIQ@O=O>觪hG"ޠ+Zgu'dӫRbR+B)H|b(po*eqibGB++!&DD0ZZX wJ48FWM''+*ykV W!1)"R9_!SLWY,L{y &DB*䚅)'~b¢PއrOpqZ*Q7W i.Oe=VB4l b7(l& `.Y \'_",yu-c>F_|TLMg%3FrQa4as{UyI*| T.>foP/V?%ؓf׳j!p%A"\u+Qs)Z)m*G[4J[}-0%҂Q" ft6%XϳY8qwB+dqQ{ kAS?Uz)2"Uic4!C0 15V=+ОQ;!3Q7sϖv}aM[юSly#9a7Pde@fyECA>@7LiR)x9G9R:>K+% $C:7wC;:mRcc0:$`B{&X 7GCW{3{SKg;˜;w;7$;/{ܺ;}g$MG$(7{I;;s;?F̃) ~H/D!=lp>tg 2S«~t>\E cD/$j>y=$ F}]zp#DlHUO\F.1m5Qchad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,)"1;($".;1"""942 ,EMVR'g#v;r1l1]yDrP.WD3DNY*Ti5i1r;t#h5VGzFh(Ns8HLYYYLNMTfnssskkng`X *2=/<%OANR2X&i6i6i&%R%]%R%R5T:R*R%o%f%z:o5AWRKSrExMrSrTLrcxzrrxP[WRDMeSw\wf.Uprvoy[Ҙ\ΔMגpwo{ݦsALN*Y;l1j/knMnixPz $ :/$Y$O/j3 J V l]`.((*+:'m|JWRm_fVJyqچ:rSdlhsnz[sc.چΗʥ贎⛣ʳѰ岬튑Ҙƕ΢ԧδóСؗմ΋芧κқȒϩƑ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|)`3s\Q(L<~r%o@s-zQNZų<P; R1AG;CfN*M(r ;0j r#-8NyE] r s95Jv{C2q/k7rxG!ԊEF.cP0c75 1$0KY,af^Oe\è@̸Ro0GKޡY¢ 08ӎ|[f6Yqm",%61^%/"lÐg?zOhMBІ:glD[L=E3щGnYG61%.p)`(9\3pQ B+]i.qkt<-F2'P-NiY,/O n Xj:Z I7xH>(2 &B[w\M:Zֲ {_+7TtceY*U&cMKKJ8 ddf5WxHQ~j;!X/ 969(`E'UsPܲWmasoempGrX.Q.qݱ#A΋ P#F'X"]@jC[ u`osk=060r3 &Ha Be9L* V`q}@Mӻ݂7'-&#j%`8X#?FH2|Y2Ql:w'[=J-`A %y\"JUf G*LH2#-.UDWpha e]gUV6l Y=éY@3VQPN±E5 pB_@Ձc=ka( '*KYZnsW ].dy[纬D֑ &, LD g@jbzֵ:p]iօ-} 6R.slY fBNNy'.i1Iw|<PG(4 H&fXxtXᱎ1&q^`V9i89mp񰺶cW`wAm "|Ysώ Y2Q[*g%1dU5/{U݀(j_4 6)#ͯqK_m̢kumk8F0"ke[w3f9b~90ƀ gW:0 PUze5:0cjeU~'YGHXx WC ?!pZ]q- k9p*3(7ufE{E qU`;57b&`Y^X uE$ݐ[؅^h`(0(Mw} rf0Bj&z=0xm 7Hsj9Pw`56+gVA7*Df Z=_W3X(f\3y#9Bh84|UbVwha0^ à9~9tO6WX8;'uBjVk3r\hԒ}0#>tXw ֎r[eUYqGf>f\ǏklWVG[Ψ(dwB6I]3(r31[I\vkY(o||5mu勻X(ᐾ1g}&Q{7 t5bf_e6wUW6UƇχUy`+gS}k)VWh ֠ װndv `p@[0[~@pא;lh]@I}9e4l\XjR /zȌə_璂p@V7z՘aїyeh}Gה%'^ZpU`,tb9ǔqZN)~~ZupymeUj{Ț tZqX|{- ( 6EWYgP9ywFf;šf UZΩPq/`XQطY} ੔< dE!c~nJ nP,'Xw{PC[+oF@V `0ܐG'0U6+j  0 T 3}U+K[ߩ7 2GsѯZyZe41uz`PVdmH3 {U o8TiwCk w<[e w=нnʫvC ;(w=,ٿ{˲1{ދ‹נ  N d$<-+ZD $y*ꀀWxarke5ȳR6D:yXҪX@2,iCvȑ,X)\yM{v,1U}(X{yXeM}P9s/8P Y|ݴyXi~_TT\eòEWu\^,}eA@ W@ :; AIUMmʍBNn.eg>RM_.ʽ8=j]ى֊ >^(+EUa蜾V]"Qu^~ꨞꪾ>^~븞뺾>^~Ȟʾ>^~؞ھ>^~Q ^~?_ ?n O $_&(,.0 0?4_68:<4/>B_0HJ/ENPIR_VXZ ư`9b_fd T? gr?: MO/ x|OH?:3'`Z 5?woU ) J U}. B' _]_ /` GO[ q C [UXU_ 8pP-O`: ol @, V 0OA, 4J ^ <QO ~8QF=~A%MD@ J (F,V@b&Np(P)UV,T X>rA)X qnJ*C. Z8I+- !y\DWp*ڑT?(`1P o P@WњT2vw\rE&1k"(,X5W"\΂`h+Fnё!xYD Q3V)ȁ&@U-"sX cL-p|Q4b84 )~)@#&EXCPjQ[CY0r1o4ˑ> )⨢G"N6%[8T#+t]e ,dDbѾ 4(*`)&җY iݸuL(,|JX|/[\WaLnsFM*Zþ$,D7mP12bu+UApiWzUR4@(n!(TXH]7cG. "x Yr3PpIXb"C %}5?9:{:>cy#3GH@"y=(w۹` C&091QM1 .Xj+!h<1IP 0#);!ts:;B1 qcHhT脅 Yx<_B623<"es 3z? DIp\H&/8jk)J*PJ |@ 4PPTl z zbeZY*p1ڈ-1ҍHRd UHAc r :6+JW r4>B1J'"=Z²mḢh%ꊔf (ùIԼIG.sF(5&`?C2-8H)+J*C• | 7F@ ?AC4)c p.1' tC2k¢ p2SkX&d6(MK0CP8 JJk sI$?{K;<:"kIT[0 zL)*:+$-VMK;١'y9IʧX5,,LQ1LTc#+^bHXhMg2؟ꬍ m3Y6ۼa k $<ΥDEaIx\.EJ3<Tt"{T`DAqN)Pdchad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,=(8);1(((333848;1"& DNZmQ)u9i)E33[33C/,m33uDNB1pJ2OABO[+O33F33X..Am1r;u-k33m5VFw/Hs$DRAAAMLK[[[SSQWhnorrd]X3A3. 2=(5$OBTJ3V3Y3W-h5i%R%]%R3S3R%o%f*x5ARSsGnMtKNrkuryWOWRDMjUwjy.SsrvnyYҘ\̓Pϗmwoժty.AMQ3L3C3W0[8k/ji0s_OoHwap $ :/$X%j3 L l]`(()4+nJVmkhUu:tV]Tkoy\.OSlto.ϗڿճв綌⛣̴飡ĘʔҙכďǷԧ۹Ϭ帗ωևْϰͰ琢ιПܴԑ۽ȫ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPދJիXjݪ՗' s9V9OV0uʕ}ѭ W=ALV؟z"[.ǐ#KLr29Gz,tZs'fj&C`Ҷ{wpNX._`κ#[xO<] 3pvೆioHW sg6=LtpX Р"1{4_}'Qv_3A(4=@膆:|4MafGP]7ۀeĤd>WR<9@pQ %uЕYhx'OPpAdT#AK@o>fxIYRH7 @ :CL$vZ`{*무ֺ0d$A3h4OPO2[іZ:ҶXmHA,A`f,DJO^B*֛=w72*]r0PC.B ,,0 t@β&&bPiB~$O ;- ;r'# Vo w-sfA+TWTJ/!VskPb7p%{Uv*½+df ${r)=fP5G;w3G 47u Դx?n砇.K{N1/?7ޖ71i31LAWQnBꭶ8(jh]nU6&_"LƑd8:ޔՖĖwI8 :9"/1I!pCӅ`ri\_|t8s1F1>hbXHN?IFr14' 92Z[o\BS| _C k#5ب5ev*Ct^8?xs> 2)r.3 >p3%հf1kj\.v8`Wvʅ3p,gGJ.W״Wmd͔"v$ʗB[3L6pv Bp! ewfLV% < (3-G9HCo 8"8dr{|axAı5  NnG{9pd}Xy܂892%0՗چ5x|Cls`&Iw%RusZz kh n_lx s!>p8KD9>ϼu <$7ֻ& ڸ@bG}z$-oxdf6q/۱;O[Ͼ{OO?x4_mϿw 7PwN ؀w ͰXw h؁ "X&x(*($XoԂ6:%(<@؀>xW"P:X XЁHXSX! ͠F`d LX,8chhqXs: 3M tzA 4pZE͍ۆؤmp-ȸ -; [;} l ƍqˈ@ t2h˃r}AKlzq-tM'x~fkԍ gk+Ϧ=b- {XӔ#MQhbpAp) vފ| = ݸ}Zhy˪mEЌ\Ci(E | (牎yL:Mk ,MHVV. %mF ֓x(y<0 ;}Ⱦ}n ή ( { 䞼} sj pȾ m ~ 0mRaM^N{  紐 XΗ(숡y8%p ! |>KL  M/ތ Ù  ;rY(˵/~{uV/pҊ+_ԃi?P OQ]; DPB >QD-dŪ=~DG]T(crudfΩyՑЎl%42Œι(\vXl6^zhBhtO풮Ynz([i2"x7kHXgr'/mJ0聡hu)hw,Mܞ*f7ynFL咙߂3tV]sx7AqZKkcnMQ0bw"z9swdlݬ+ݮӷ zP1++dtꁤ 2b* /0C 70jF`D<`/D4 <CPL!ϊ#'FܹΠZ7zvif8lZlaGFRc>g̟z. +H,IҠj0 b|#a  .Rk?-_Rot3P7{H(’D P#ZGQT1K-Q!|53GGjյ k,p %<T/% t9sXS3ϥ̮lgdgAZPWŮ=W4qKZ*j2^y祷ބ2ܐ&+L5r1 '* p0S\;HI|Y#5by颣RdĜ(E-ڡ̩5Z6k&2G.y薌5P0M-}/6t4JԈln!4X1O,]; N:zN;aY#-&?+^@} A8E*ZuANv9j6\1l):b 28hFdd|Y6|D>eQ"G׸v$6 IH(mpN8嫄 ɻ '$TqDŽ0a%zq{8ǼcA6wd҈ + R+.NSF dG0l"Ց G&І''nc>[2 q$eGIm]؀x)7\Ԁ丒sÖK#9 IJ;ʳqIL0%:]Q)l *cJE,4#BC' ,3I.$IP- n cZMmf#Cj94A ܝGS~#fOjYD'|΃w 'V݆/tz(D,u-bjwlO٠9y` kRT109UF ^mUr$ڐl)G$ElHR#Y1al7P~38R U jb-NUnmZbԫ實N lHV2G^ןC1 |ہ֐E% g${*{< Ki>AA~DmI,J/X%ک0k)3v,?LT$11AD \+,g ,XkB %VI/僧RR"%f3+L.6VOND:^p$ .=pP<#:"yܘiگbޕ[vfwQDs͒pQOP#(hV YYHI$F QHM?ݐ O%W.1 BAݎԕb=BWfu$G< (:ζYm9$vfbfR>@K&Y_JKcwHr GmZ<'n9`aj;bWx Lhf;!H;/8#-UMnKR),Te,-S# y7rϺ$bGXaw 5EъTld k\ 5!ws!۸1lKv'!5)4 GBv?ox#68}6s`c{6ؾCzؿ !*>ѮYᛈ?b%)$ϐXTp8@046@䐂a;@ c!B* C#$6KB2yq 9`xi)/+"2d_h3T5d6tCx58T׹cȈ4>?̈[C@$BTf6̗[P[DEC:,cH5dZtECDCd\F5TFClhnFJdTq$r4GoRFD stwGpdCuVF5GPp4}l8GxHoDXȃDUDlSÀtDH|ƉwѩL#%e&u'5MJmx_ȗDԆdO/01˦dMk`k6=M/%9:;MIL|)KLC\lͯS<5CEDQR|=FD\M 8ULM%˼C@4DDD#NeVuWuN3J>dDDpEkNB_`Vl͇ne͒Mٜٛ5PLS9@JTR5ڣEtاVĐECe$UKMګڬMՔpMCAt>vڐZ5۳E[ J,D6ŇMۻۼKDdǧeeĻJE]JՔluZnf=Dd| UEJ[l\ؿmUխɥSڋ\m{h\eեA">CDc0BE^lS,QM^S[E4D=[DN 3GI}J%_ MfCḊr[HvkH<, M,ZFuJؙVa2uXL4<KS^"6b&]=Cn6e$#*^OLD4DCH\)1&c mJ8Ň<>x^\M1.84߻UFSlO?dPJTU{Q Fv5OPDR ebzHR?~N`DCRTȭFOVU.MeZDD\VLeV\vL=v9Ub6f,|XCV=e[>ifteG|ӌ8xjpK^Ue^F=S͈ԇowZdc N_D }ЊGE~F脞v|4lTӕfbO|]f&hv&霌d}˺u璆&3gLM̗鞆PƇn=jZʊgbYenߝC=gEXj|sF_IaT&\vIވmEy鲖pNWnSzHLqPeJmt5_D߈DRϱF|:hHL[?Pжmj_ߔfQ[kԇ֮j٦fa-`|8UJcus|(d@LٮoX |Q%U{U PNa.H]͒Eݗj,ΐl0CCI{B`1alhGhvx,Nvi :(r*;|r.׃/0Dr׎񥌇@q7vT7<Һ.d|ITl 4O1s.DŽ rDփBwm;Hރ@Pex:ys?Pms=4[^Vq*pupDW4Gv2ILDŽlmDVI{8J_nB`o'rb#Ec5Ǚ*%ftz`mDpf?vGWv~/s^eg_H$x&`Ox&8WhIn?JPtkr0_:;>T4|c9n׆y v|HId|\:؃G:X z؁/0K7WIP:d5d,E䌠5!.0y |:0vy{x푬: [GY|e`IkmI7j>ʿHIfwK\e-]{lw=nI{Շrɼԇkv@]>|P}'-QfsV$tpɶׇFO~퐴__x-*xO-x''px<|zns? 7OAvdŪY5V jkթ":*.^:4CQ=-MƔQ$|%=QBw jONc>MՅ Ǐ:R%+ذbǒ-k,ڴjײm-ܸrҭk.޼zEx͗A_K4=mv/H|%OIcgdC1Ǝ5,O`]6,eb3 5>[{nm9ҧSn:ڷsΝ,CVתUCŞ7-cθYgGRֱÓegLCSݴ}X1,7Vt30#u!!8"%x")xV;Zyɨb-^>GOᤙh>&;}uLڏUƠ^L8oaQ0RT!P%a9&ey&b6PLHy3J^d'_G+G$>H;QCZؑ,tXI^! a 00XB '"o@0̠ erR0j 7,6++8 p~Nl;fGjh/XLP" dF0  rO 9`Ph$ z[1GB,T0B@AB ChBYȯ0c!IALR/s2H 0RT#>('nK1^+*tWhӝՑ:djZb]L1brdf7H3)gO GÏk H|xsl 'FRf+ KEѕO׬r8f'/K꾢0}eRU@d}[U:' y^Uwq#2Grj-q' hnFFŻ=s@6?93CI.@dnp!9~S#HU{fI| mSXt9=4ha-^yZ>Li0l}k·ҠB+- [Rj 1@w]ik|D5 =[Ӏ@ mP $:mO)~&mŖt+$mqТkeܝ"!fO!# / pKʈȁgd/ .w`=x.ޓxJ^,6HC؃GP6n$V}BdC@ O&btedCKXW½)hSP3R/6C|lw 4b,ݕ8q!:CbHw_BA7_=mdLQ>$Y q!na~z'83"'2ZrȃXف/r`%2h8 .` VPf3ld}ȈZ2?,oTe qS>[ 8=\rPq]XTTǔMh<(d7YMf`!Pղ1UqWc!PT;fDY Z5SM^LȠdDK&P`9_OU+UMXv@aeRXWYs=_&huE!<)ZeE^̑ZO  OL[]` JAZ|Q!FtR>"t]Fu""a)1F9@ pQ5`X/Ra>H1#]/D6R8%ZV%a@U=BԛDh=RčDf"D8-@&͑V&KD%)#6(5`67])eGz}CC8ȓYVGj/$ ] 3*eDJRJXp[aL/+HIjInQbO,F*űu bOZuESdIWY%Kp^\/6^?=[8eT%>tlmUY$6e;ڔLIe*R,^45?3Z!:@jC7lQRevDj!>A >@  }< )#DO%#&g< 8<`8Qı^NদQ] w>ZuFgVL/vX~R%'-೽^X|Ё&GBBh\JcɄfF!gv<,Ej dkzjŸeVflliX -8'\B M#q$x՘~#\8v/xX2.Xi'T)h6A Q21sUUDkA2  5QRP|=xPZg8HR.[n&($>`ӌfL5"~،@XiDu<@}̍feE8@Zj̹,IVQ>y EȄ8XݦAW!Cn E52x*뜖)c9M#&2H.SrdôU j.iOHcngeķb+8N)K|)A4#Z`N*ȋ`MB`Vpju\/ЩBSđ<unjl6U&DʪšrfEE=<8.親lo^X`zo-RePbiRsðY4NZ XI Umy"%5"'/5nUA-ߚ+FR4mhd5<l"YTQR*/BlFuF&(Z,jcљjănDJvZR.U"KT&^F6*Aa)v79P!/ҾPn;ljLp9RhX.K`^:6o_púo&R#=@ o탆b*_܎tL17dD"PD;(JB@9=@Ez$pB'"ͥI$^;a,^41n>1Ke)6!@71U5@c&Z5xdóLIiXe- Az$YʝC<qq1S16H,XoR@2nF5;lCfFh{%1#sbk㑃/2ۓ2k1r+0*,Eȣ4 >Hu\$@3up8's O@_ljʅ.˦7٨D|-cnh"!ٚvŽѐ1%+0Arn1(Bg-:[٭>'@no9M vVP*1tj+4ծ#2'N߶ɛ,,{ow\:RtpX0HTǵ CYYp$lC6@e}6h;+C9`6lÏg-P6j\8tC ͸6d?G87xc87` ċky9@8S<|h6yw{D˴mA4 KB 88< S:_z@OG::[zszzI-W:{z ::;;x<\ l= {栋TDY TբGG? : TπKz;߻{Ӏ#A |;C?/|; $;{ w#A‹<Ó'| `6:π h+<@>NǪX DasDɟ{<|#=/{8+}_ < Ӏ߻g=ӓS=C>T{ |KAw;LK+=XBa KC̭+7;㣺l;'{J?o~:Oc[ w>W;C:[~C0$AG{){oNN/bC_{ 9yO+DWo?'87X2@?O?S?G;$-踭yS#NL` z4 @7`A&TaC!F8bE1fԸcG }9dI'QTeK/sg/_{X,gΝ>UF3=w`&UiSOF:jUWfٮ]|4yLl3dͲլ&|Gƕ;n]wջo_2g-:$Q}HF4[qG!7:fB w7Юd.b2'7qTX` mWo$A{+ف!XCX/uZ7v)Yumft %0IY,CE,2_Z*Q--n(NZꩩ~QK 7Yr([ָIy>{`&[ͳݺN -~[ -1'%2E.\)k\Ffv+]ѕBLESRVMsta]xm eف^xd" B9e"w硏~ F3/֗_+oS0¼/۱h:.popAԹ<{[KsKFH-aB%*qE+A5c:0y;APj"0E6=k8K6EM$UcmmpKuX?'n_U@ʶ .{},hpScG+D!Msz4!O- M6 .dI04.JQfdîet%-FS_K]> ehI,~ 41cq*J< LiNS6oc!7Bc&(NubJ7 B:Ϻ 4'*iG}Wδ㝲-*C!ڔM+g9͈nA8 aqIQJ\a՗R4#;'EI4O?jHӜ4OԘ1p<ȣ*J)r=Wj2`=ZVWކ IJ,ؠfi G_X5aX.uc!YNe1YngAZю5iQZZCXka[^C5hkږmo7[VkqY&75mk~յus nw^F]/f]Zg彮_Ηmo} _Z`l.L{`/8g vp~ax/$a ?x~%vw%61~I_✘qac3&7buPuVҋsSy]Y]$7M.o!rN4q_ ܊0_u ~wTq*<}n  ZP63PmH|V\aD}' ~F+N1Qs N0A)r Wppv:T`w]hdnlMa],96"jhYvwm9{Vԑ[ v{o~6@n(LqPCQc᫸+ٮn@_ՠXGp^|\0: k D 쵀8]]O\Du+ҐNݶ7Ig(@o!-@t~۬uQƅp|+ k`xWn<ȗߩſ %*.P4YL (}Pu#9mQ@E&]\ԤKƁZ8}OGs@٪}]e'Z>a{漿r~s˿EqFEjRo 4-0/ ֢U`(--*O4l Kox &лp6 XnNV.uZOo20FZa D Vzz"K0D[!:`\AP"~n2H7t"^NRC4ڂP6\`67 R sb-Vfp:>QEq٭ %FDSG -q :L `dݫPMD#/ͺn!w L0ҋK,o1"Va Ln41] q$Y -O0,Mgര4'zW+'q Q 7g~:Y12#5r#s8/XP Ś@Ď%arVAE{BI0ZX`N!uZ:A0Ta)7Br+\V2u+Y:mDcPA\xbH rNX.f'2N0SSrn 0m1w ^4ĴK2)R7g8Q2_`HL!qdHؚaf#}738#C3$SgsIΫ9nfa90'z`;T-Ȍp:EM.rsb= / O" N,q~Fj1KrDc{Al3 ~.=%L ݠԈ Gc2EqRP 0oA9 eD[~5۬S'BP!CuQ8H4I8Y8FTFK' nO^K |L˓Ms ts/!w`9G2' | XP >l 2+!QoP͔ 'nA 1ZnnVEF[E  k Jm`qIkPk`sٸ-̮'4/hTI5Yu#3O3o6 @2LR\O[Oҽo\ V1'FAP!E0ɲsG'4\cAt/.^ rNS(o ]`(MZp4D7gJ4pZ۴R#:FU!_ 2i2S0Ua 4X!_$_4Ekoe cXg%ՖTO1'/U5lvlYQZJEcɊԓ A-@`$naպbpZZ`D{"S+5N'UAֳ rKfRq!/ZCS5gpZR|:P:`T7vNdۀcrO*ZqzSrt%~ v XWW$0W"fR@_r"l7~+e}~Y7mкB|,g\A-KSb0O̚܏0cpz׻{}5Z @xP4lhPV J h!ؖib|oH,p7T7y\8/IauRKɎ ln!ӯW+Tw 4wsWb6UmuLWX2HSf nd R ԌV|yXxUdTF.ԺӐ[w )@mSD`>o:{ZqX, t%VW㱝.}ϻʭ<+̑wCDȕ48Dq[!W8+mAV'[ a͎-r;vb'<11Y=f!+Pc{N:d.+wp_JMs) R)PovS @:@ER4V!·r}j0;`=NN` < FAÇ_Q-ɘQ?Ic$H o5 #V[}\9@Nfd$0KG6cr!FZ 'R$I6رd˚=6ڵlۖ=6nZrK^4Y&6JO&R:n{)WMYjZ}k@WO8.g9u4J3ANLd;K5u2Ѡ*R@)S1l*eZmUڕl0 r ?ӿ_>}X|Tm%\xYE`"Z\P1UXNZԇҌ,iؖhWW+$.8RTMc:c>xV=(@d8@{gtBei$Dnaj %|,cQ j$lu_CXe~(܉ŏt z-(J*nX6]N2Jn%~*VyB@ _lJ*jf ιr Nz4ޱa%֨*'`R+WƧ-*Ibu$G $=~J2xl_ދoo pLppp3pOLq_qoq r"/Lr*rr2Ls6ߌs:O> tBMtFtJ/tN? uROMuV_uZou^ vbMvfvjvn wrMwvߍwzw~ xNxx/x?yONyۓO>ac9Иksyǃ5yꪯz뮿v<i;KF|m AO;>_w+ lc6{_}ړ rЁ߼K@8=ˏO-HdT>@6hX@.31 dK,dZѳpD@p`1p Pg <A c p4 v}$H;A_D |ȼ7<* 942_\!mxS\C4mp(41*hS3"d;Jy`(&=G: evn9OB2hsԣ/ `fox`&ark<IǸ#83J+g:$tşqgG uD)xsD<1'FC1mhF@)D>16سxd (@f_Fq4 7|=cDgE1*ӍNH9ARf)''HО# 8awWJh'zKݵdk= ׸ʵm̈76g|ayLByo%dX_3;f-YFg`H pmPY |سU+ hZTkl⣲+)4Kp{h١mu\[}fVhFKum\jj#>. BΞ1#'{q}&2A{o7r\`%|!H\gL"zk/ . KђH@{{D4^tոn @LX$V8-|d D=b!"=L,`=8%2xDq~- H<9G,ѐ`XAFċwj0NX|P9e4ËN󚁌X!s.ڛ UZ8$QtԜ^k"d4+?xZ|DF xi,ƐyN1Q}4W3 c44kXh394j{Q_?oݑl us[rJgr ĭa\lb9 t I:]]׺>n?pLt$hsc%84i9z7q 0CQl1qQp|=y$yUmFyX1Zexׂ]G8zcIݽ wC5E+rȒO⢜SpM݊F7{s}+vߡ;d^òKy`XcCL!{x f,rFy3"B'](xP3ZoOv<&2Rci 'd7]'} X7iEs}]DWIݗ>RcvoWBG4 ֆv'vt&!~wg{>#_wI1 84e&E0kfxOntGl}V{%ms{3HU5s_vF ZLp=# H n8(VWs3fuԆv7vcՃ@xu4:@TIUsKxQHhYx_W}p sj4XmLlH~gu5(vCe_gh4vFpLb>CrzM#s#؇=>kx74ptGD$ F3C`7]3 p?xNyg ` H,aHV8cS̀Q0@>QX >ew斋g61<}rr  *Qa !`{5  ɊHGjb!V4xV͐|4er:P E@ZD)S2s7Xs%DYEo7qPpЕE)Fd Ȗm| ;`8@Cp[\8@hm9{in|~[4Eb˃.Ɋ50Y4`ߣBP;+(^Y+F9QE>o?7@p$>; F I)7nInɛkp~+wm%TR[3` #_3vsHf W`t2&Ȥ~9~h 8yYII% /` 3@3A>ӈg4=#&j <(kIV> chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,=)7.";1%%%942&DNZfsR(v;r1k*D/-rBcI+BO[,Mfu1r;t.l2SEs$IaRSSmYJnss]ed.A.. $2=(5OCW\R2Z*i6w.o/\.%R%]%R3S4R%o%f%z:q5AWRKSsGpQrOOqdywqryO[WRDMkVwjy.Tortpy[ҙ\˒Mјnwo֦my.HAOK\T9l/ki/uZNnJwkw $ :/$X%j3 L l]`(((5+lJVmkfUu:rWlhnz[OHOjnuc.ҏΗͭ緋⛣Ͳ䴭ʔҙ՘ŌǶէέĚϓԱ͇簸痒ιЙѬב H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\R"sѓ'sgִ9fxJѣH*]ʴӧPJҜ9Bc꤉էNXϝJٳhӪ]˶۷pG3Nl ݫSlܿ LÈKZoc8ӯ˘3k̹lrͩw4^2Zͺװc˞ 1X6MSXX NqV's3gĞMSdzkνIǔS4Sϝe7e ώ]ИB)뙂sĤ<F(gV NC-x 1$Uh(bDM)iXf%a)(3)еg 4alGٶ<:s-B 4qh s$)蠄jBw<9!3衘f@Z<8{H`ΤY%YW]-) j< +lkrӀrjrx\:VkZ§g-זk)_jK) oFzzlzI'hԨFIpX*l n4ꨇKC-Afp(Gρn{d|+kf5k/m<'kW0G9-u2Xgq-v5ӿ g/ d[ڴЎxjxƍu{J~d{5:ވ'_68jԯыgS٦MsZq^1<12ٖ&$&U(1m ^KmNi?p~x!:IOtSP @]wV}*5І:*t md=P|F7Jf&G 4cXr(EUԱRJgJŘcn$z@ Asrz+ą9:թ踊؈H ,}VϹRTޫ(Fn˞#<='zz?Mֺ.y( 1Pv l-KRT2Uip&s}?kңT񅱎ͬ6L=@d)j&=HQT~iQK4^& pG ,O(O*:3!$ֹح!ҏT>bvǛZ)j֞;!䍯o[pGfΪ@+OVm^H  >>gV뢽h[XybHH6sU OY}ZO,;_LSgD w8sL̕T|I.K5 LOG2둧;aބPACThN.M)6Nބ(C;SgM)%=l03{#I)Az*SsVLLު^7Mjy1tci&7,:԰ƗvPوe|uwm.yfyMlU(Fux9]* zPA&)Jr20D;sܛRkg*37m(ILWL~:a)W3cP8kTA+Z_-I 6{䭺m5([@D7E\hRy⣊k煂' [7ݽaD1r1ŞZ[o2L`Ou9kX~; +([(VAFFuq^7\c'e/P  r6GrLNfa AURһ>?IK 0 Oq_"A2XFؾ 1OhkWTOYlM/^8VO(+/}AkrP?k:I6'eEf3}۴RGB ȀSG~WX`57؁&h6Ue:tw0QUd`:HFvmهc;X$ao#=n@1FepJfX$ GPC#Y7$t$! s0 'Gq`qE&'QAolp k tPr"r=|1C%| k 8q*7A"3dc G!  Xxas6/RI2?Ł᠊'t=w0l%A!H!oMgONHk(0l@0 gx@1  880ȇsD{} w@ߐ&'UE?l | |ȇʰ8ހɇqّqɇЎ)q H09X1I&v،W]bV!)9ؑ xgHMY)l - 5Y 0/YP ~9v>8`G/!hr0䁒q~IQH{hAgIzpB(th yw]}s)z;1נ 隮ꪮ@yژ 0)@tУQ\|ϔBϷJSsHw!0 jl *Qt` /is 6ɣCewv}Rv~$: K ) *Ax|`.{dz&gx%#q!ٞtڡؑ~ȭYZP9$k0 SAO$|p O'ހ R;P b&iGiԳ$;ո᱔Ki`q!1.R`R7xZ8k 4,g+/6:}P+EEa16ɛFB)uҫF"$CսۃVY |RT Hx+7,F+')SdX;^ >3,ѓ0 0 S  +T`( @ a T+aTЉP๛ +35|E19; = <: \p(uH=– Z\8LPiP$ 8`6 6pS}`}6p]xlk/~{dlm ~ Gqg|lƎj,E tK6c脙D jZalqpV:<6v<Zl{MIfE7̅Pƚќ$kCЌ͘@˻lur[*ѻ._/ R 0a,ƶ=0i,  *l"m` m'm)G%MћusBd܋lذ}E} =˵,0;pz4}.ݸa !eg}]]8I9"5EF Y| z$y( M'&M`vnj|i}qS1QYcmZэ*\hDwJ  PY k Ga` R{ y߈ #ŒzSy %p! y,1uL`E`F` } 99m=`  HEPQQ/n.A]H}@?z~l. HP?uJ)qpy0`~/6P}fp9N&.fʮ` ';x9^}q ] IE(BCC PѲl0  Pꓰ  bϞJ] N .0 Q Y 40EqJ<PҞ|min=\N-^ .,ηĠ؃,.~O L 7Pn.@f|/n 9v O^k q >^hœ%*gN[Ы $f`Ry- >B+[` q  @pf,oƦo/Zf . 1 ׬ Q*l< ` 6qy HƏQ]"~l bl)`c_6r A^ !dEy/S/ )1-ER8"2jC%^&5s->"aЊ@w.Ć9ruǸytla< 6sk@,kt.ʶk,͵A-?s=>s/·~-=键$;t6[*-L`ZKNӣ,8Yu7cS!Z:3$5{XcE6Yee6Ysб yS$4[[ˠf$H,ţ$Ց"f2#x\ Ʌꂮxnd͐\zՀ#`y&h&#kNSĴ^a;QC'/[AXtSmcAbe0pN8A6j8+Jҵ4Ul{ LVJQ:)"`! m聬_ŞdSΔ;;mpG~H g|bW\,n ڳYnZҪw\5f}c&zGhcbKr7o\E8Bq0q'lan[˖ rn# !"] ;h@ tjע$)Q!VAӘKB`&2 c"g4Bx6H~ lcHp)1V씮,JeDz#F '@}ROj4Fb䩮=lR#rIXdO\xa k8KZҖ| z`+[ք:N vP93#K9`|-wI@E 6cy> ц*C2 NVg5/Ix8Q8Q BPPv2QK`lP@f}z(:?x!GX!))#k ϴr Z2(eP:T2ZYTbT  oiZPGр؁/iV2yjv!R8E(tU Dңc`'`~l$i>]"!+W:i9[Cꁵ0"]M _eώpti\ؓbtN<,FeEnp;5B )-nIМTm9~&je籎!R ?@i dEEワ(f~Ty u,N{)mFܠOUpYXAd G?gNF+Z1`!JzRp: †%X/ @YYb[o ym 1ߧw#a1`x*-=G8rgS\+9k}hsǤDodC 1CZ5\lVd1mX aC\=XB>!fe/1 PPzXƣ׋ʉbTo Xh9ЋoD҃8%v*pPL|-`_-vu4x ء6Olԯ05k#m+<] ԡ*&uhP#bVY`;|dP0.v`Z0稆-;[gõ6wy־b4p<$F鞸9{9.ň7=kso/u8zZ*M!yp8HF 2ȗB[31*r/ tCHtnY j$TJ؂\@1fP(xj$[?|CE)bRv06{57Gx06{Ј=`=K~+W??z+ċp 'R%y| ǵ,kU+[.Ⱦgd5ʅT(bb?p@' τ֮Cu,+z"HsJuנ.U8'30ي߉># X=(H@QY ,LH2d#X7ثЁ$C=8@)d4$QIس߀4\05 Qy,-m;6B;Ciz^rҖaR* wP*fPۑjxop,i{8lS4Vuxi<j@PRcUDIT\VRTzE;\GdtF&&'EH'M``Gx+ǮlDLMNu9|j mِ^2A]%_2sM.?m.2-%.3ė D1sXg D ڕ^\ؕ<XfvK㊾} f=D[֥5&F ]eNn$Wa ^ 0 6^䥧*Z92{`V!v'=D*S82`(/[ms%s.5fc%hl>b6<ϥgP.ipc=6CXxl BFJzقgg&R6eUxpY>R>Xex1]-U`CTY_ֱeUdVfWW]fbޔd^^jfA%v>՜iFpDQ<=]tdjvvglF-/S3#~|eTs\}&肎Kž\`J6舖X]T9i-Sz勴:vfr؇fs>gm"`ie-&jeyښ-i#g&vNeiئrV>1~kFmhFԖm럍QHnV^Ti>R]vj]jieYF6fkkevgjK=6o_Ve>SVAhfdZ׮z'7GWgw '7GWgwgHphxgqqr!G"p$7r'W_(W'r)+./01H1?V2G4Gs Q6'sY7s/?9.;=>R?@GtS_us0BoFsGwW9Kt1?Nt8OuNr?Mr@,TVsVuCX1GtAWYu]_sY'^B;?:bgv곅esmv7Wik^Jk?u06^Xt4P(Lmsp/tRr6u>msazg?BW.bX=Ok9uEA>}x9']{wsRx0s}'yM?rO-7P/'!Q^(y7LDV?L2ؐtϹus(isLvbp7y2V9vSI4A1DGGP hUsR&z4  | ;?(Wu~|=Ȯ|1lAS&zC{4DŽMpBPm}bȄSXMtQx0. rw5DŽ/Gg^LCU}Z J @:P. `74}SL(e B*A!ĈmAF7!p$ M1$ ^Ҭi&Μ:w'Н-j(Ҥ;#Ezl"WٲXC!,e48$%ODPjb#"=zhG^Ĥ __)Ȓ=95( ^ݾ/mI-8~`Nbf~m`Yj1ϖ0GFELieXztSi؋Sn:vs;SQ!աVsL3STܿVj8QcDMqx_t%a5PDJ%PH" J)FL8NY0J) @Ai)d )2]Djo3bˍmHIU^QBtJc'FZPBB419qfWuy'? F=!y)SydiJ֨~tdTRJ(a:A@S QePexuЫ3ӛ!W)bܱ (Z 9&UjY&F啣mF!fV'/ $2MWI8J)N! 9@Ă1d2&8T ",&q8lG̋bOmN Tך;!r6krcg< j_mD4;kMBl.##/2d)Z+=fAEMN EЌEy']|H>18YH`P#ʍjF q3{{mw x %Khk3r29ЇB&3"qDʉ$8G%+neEm/ܙ63{d8IRDvָMUBei$^¹ye책$#X-(3w1!|݊!T8Ha&,Y-E@J -h@8lj"tvg /O&5+Mv,>M4\{ϝ? v&Nh_J4*ۻ nwi} (U?=c<˹]W~F[J}R#MV ycYǾ\ZQ_EܟTy`\_6`RQ5)Ћ 4[@ rQAQ^Y|Si-(]ϋ)Rي#ݾ%pNiITp ^u1E<C@C(]]gx_:uE(xyA؂ A``}Iؐ *"w**YJ%T B ]Y@ xqE8i_Rل +XAB!yB8Wr!z"PKFC…HP BWtAD D`v(ؒE_ Y C1`Ț왂{aW56F~]l@ Jut K+A";>)d]", AgxNc)8øWG@RHU-޲ G! ’> +pRĨ[{Pp)0-O"M*@Fp1yod+dl~@dXy "2"(dt),udʁjJ*fDJ$n`n&F#K!@~H!i g*L -iymx5cpgYAvdˡfc[("#7D( !Fn^ܔC a( yƪ&ZVoVS=MܦNFUd!x#M EXb(k؀²Qd!ʇGħ(0E$B/0YD!aLI6ŋ7vF {X~ PKF$V? /(GsB<5eL L-ppT{TWU[V{[ sC7u 66=XdQr5hgd1e5 C _Rۈjp.+2$06 t)5k7Iöc׶*6 ' p<0tspw6tSt4/vn0;G /s6h%8Hr [&,*g4|S{p6LOŒsp67<%;$8CC{O&C~$B7<%s8oppLs<70:9930DkC}˸sp;D(\:sKs<$ {4p9sC4W91C/t[q}Zo0t{w|{p<؂}C xY9Ͻ.tdku,1ߴ<$}<\ÄhKd@?=gp.#{gd\@7>CS㓾7~`{㷼0c==@ @S8oVb 1hB… X[6jw+-Ǣ`N` 7o[Sy@U!-IJ1D J&UiSOF:!.:*zJ5(8b<[ySSv. JK2^ȅ[,ֵj:M3  k Z,+R 7dxqǃh@MU̷1֭7-` ]x27k (J/soaWjVҦf RԻ^=Ne% H e\$僚N|7zUH S;l o *`D,H>H7Ê) *0$ᬹkS +нk KzR5JJȂ2 sKQ?;oJ3z 3Zǁ5UK>l 0? TAJ Fa-0K̑<Pczi*7E/DJtvJ+HSz$ixn΂0Xf[ +S@ U[|U\z`'m XaP+gYz% LLtTu pdx@jhTV8 En/V3KGYGfh^,(L]w!I[y V5>HKCA MxRE :.Ԛu%'= eU跂Y#.*ী~gSʙx䡇 dSM=G bމ'cڂgiC^hZ@{)7.zܦj1pXX!j5Skmi뼦wgnQc ,OZ <5S2x[́ j<߁^X|YzH6OPgTzȨo=Lx^VWUߤֿ n!Vf(OK?@ 'r1рBB<*D].bYRC +jU _.$$-ذ 5D=A* zr; ŸQy-GR%M~C " wP ֘xD0"q,RAD~0bIMx/)ӸǾ-/ich]\x,!*6 dR2F4 #'/N9d^w(D)Bl1l>Ļ:xv׼&-|L6ݔ֗m:b NsnzGK&W%j"Y0v]>Ԓ7 J wGj,f qWU]q$nC vuj[|Z6 "lafL6%EpqI+H*)͚BW%DYkUy&~nR#4H1} ŁZDK0Se\rf>zLֱ#d6!u[#q%$0I`é6{`sMhhR##E([> 4ŦuZ Y>j ;Wj*HL5r 8QO2e68𨨉Y6mԢڹIo Lp;っ㧍 9^g^d9&3r⌹$Q{;\<$%j:+۶eIkKb1Cք XDGQʭ+ÇS*wuލҮŮuʍ E策Ko:It#=ߐ.ۂ' C7v)"r-/y0w}j?Sh gy?MijWQOxPe8BUb)Հ4"T%>yA=ϨIc+tɭ٪!n/ s-\]YOq y[;[|}dYU+:"^HC_d0m|ok$@Vܰo=VH *Ư0!IM<K6,B1qЀB>Dv$ r(0L$&呧0X4K$w&NV)K+Ÿ`9q$)5 $ !*uWJo 2 "NB.2Ǧ`2q$z!*.#m*='K+pQd(ۦV)sVla܏d(&268l ʁA $+p1 +9 @& -!T1G<3BE)*2&.287TS11f W3:] N35bR(w2O&/9H&ϐL<+(m,x#O~11:ht"ʳ— %ԽnM&bJ 4mCT@t@1L)q%ze޴ g0tPGDDaSMcEE$ u#0NW%LePEq܂ScLE'$<&l1R':2&4)>ήIfSCUxZ&Ҁ(K b[b| 69PL.#)A,PY%ZKcZBMK|Y7`# @.B[G3ZYb 2a$aҮ ^cUQ\"ČC| Zi)pa&" 6q8 _bLԕ]uU  vpt]']h RYH!tqBO+pY!dPVVvu H@PrdeGV!5_$\+rЖX7X(dS6m5Vq"2xvC_"d6&-c)5\ `3^)bum m9b.vv#o2, S\oUj!krXMWzaFK)at5vcw"anOt]"wv8a|)Сv9H]@acf%uW aylw7)w=Brn})ء7Q~}7.~7zTa|E  $0"b7"W[QxxPP.bI)}yy[tx9utugx!p88Wx 6xq78x8%$x@ z8^7oGi-XJkqa٘D$T\!9>5).-3o#a1=YA@D` UV8yat!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,Woy"1;3'";1""111EMT["g"t7l;|EgM"EMV;E"["d6g1r;t;EIIz"MzEFFgYHsss||wgrwV^c *'$!'9)%)*2>*4MV"V,a3l6r;#M%R%]%R%R3M%R&R;R:R0M%o%e%w(y:k(G5AJRWReHqNyJbVWoIqbwlyybw}bfJ]WRdTs\_hTeufVarwlzgݔlגqwy|T"[;l1i;r"gJuQpWz%3<:%l}JWUirW}TMnwl՚籍ʳݾͫĖ΢Ӧܧγɶʞױϗ⨸觸랯 H*\ȰS8HŋSǏQɓEnDɲTb$P˛-+q - +WxVbСPK*)A$j UE̺$4^6x(*OHAU_y$J?Ap" _ ңNPPDFϞv3,V8 5OVQyv dtVPU}v$*(Bm_ģSZAp䁷ESV4J2O`i̦v(53 #@Rh1XUQP3^XWj(aBfj` &ߑ@ɈC,s\8oK9_CMyd8@ŢF3` ^%9 $Ngi7(C&1 }hv< Z@NГ-&”q!3t={je^Q QTG AS+8Ӫ@JꞨVcR#+D6Q4+L #:8@8Prq  dSc:kݾ<3Y/ rjcZmDOBd]:d AcjxT,/;DM g}0D%EBG(C2=v@ӵ.M/fDv)34E'% !4 QB'y+x7.9_n 7`B &.x; +z%nH>+z0 @ &K/<;C% O>掋_>Sn v㟷 #H/9!*!'I̠7z GH(L W0 gH8̡w@ H"HL&:PH*ZX̢.z` H2H6pH:x#w> IBL"F:򑐌$'IE̤&#YG4x$&2AH0\4$* HL@Z@@ b@HJBj‘$ K4! "5%j 5 Lt@Ŕ%`Ni.b: Z!d # & d6 @Zsf:#ILX9@%e@%&zAޢByQ(4g) Ipz4!s0yt 1a2Rp(D ӒRB@EJUxAF*'U@jb4fCS&Ҧ,i9NtlU@SjKEV5I\ i`vFZVE$ 0U2u(d VCuO2#֖ՐzS8VtERZAbU+rZ|-(nIZ*ͫA]qޚDusLl nu3u}+2-%JKC4ba $|JS@rԜ/E S $Y^ 8bMA/рVk}-!| C6S]i Z "(xʴr&@q%87D#(^zxDEE1Q5L8*^/`v$A&4WZ&0 ڎP"W[Y@d\`N A2K5` vLn ]RjD%(aC"Di @P%!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,."8.";1333848$#"'CO\TsfQ*u9h+E33Z33m33tCJB0mH1BO[-M33F33Xtf3s-i33m3YFv/HpCTAAAMLL[[[UNQmYMXgpnpqaaa3A3.. 2=(5$DOD\T\iV3X2Q0g3p/%R%]%R3S4R%n*x5ARSsGnOsKoqryRdWRDMkVwjy.Qstnvҙ\ˑNјmwשpx..AOAQ3J1X7k/i\fo0sfNpGy^k $ :/$[' L l]`(((5+uJVmkc`vWQknxKQmrvc.ЎڿԳϲ蹈⛣ͶڞÚ̔әԘċɷɨԧڹҰ૓ˉևڒί˜ϫܵёٵ˷ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjEF vA_-TUTJv-Ussv!ZlZeʔ\)e໱X=VS&[͚vg+9gzÙ!eeͽv Ray`*wXf  ڲQnhp`k6~wnݻۗՀt|@x(3}="Q``91# #'^~$!y! 18݆ d (ӈ}# 0#`w-y'hdKzʚu|<09a]3'eh +жt;*O7ZpA>zQ<=K7xJ8ʀHIP[q%d>N;\T{m?k*k/BcX'r '$rB *lK)2^  IO@?4qӟ T5IW=5 4Qs4Ke7 FӶ"̝gVߩ/;H4vLu4s!t?GmA\}stlA9D(uS2".!;CpK;dOLP;ȭ|B@slWnLg cjyVGy7U! < ,.H``0Bv0wBV+DQ#!phECS"2Ĺ$m.2FvpM2G99q3D |s4 dP.b %tjIT۬¬q1DHܺ&OIDXcGpG*g5s!]Bym94$ r rh xN1Fv<#4LM NĦCύ*̟H:Y^GRzbd ńKZӞOK)ZcJ'Ӧӎ :04",};TN}tʴ 8*Pt"8Egٕ!lu4h[X<~C`HB5"} .Vc,>~YR6Q3*GD;KUB!~CR }a֩b V#Mi%>U&pD@G;"5aXrV C ``hR~@]x~͊2W !l(X;'.WsgEO!L֬\Ԏ { Fxju";nmvxo\qBJӬЫ7$a Im#3O|=24NСChA1{IXLU Ee!2z3.IƇ 62,+{pf<'$ t*,V5G*dRĈi@;~NsB}@hlfMӚ׉,0\L8jNj=ykH9!xH_:)s5fzk֜yUg<.ƐIco M l#Ҡ @>լ7|TFb}&nvpjD7x3 -k9]զљ} @%SM;gׂ{5Njfy C NRc6o %uP-T9r:ҡި 8wrzSso(&xQR-nw}5 (O۩v~>Oiɀi]tO N|3dg.0 "Ո.,]ԕM}FiG,է!ַ: =ϡnd uF#5kZ|i}~5fj9.i8S'Xg1~5!w~D{7}Wuw7vcŷ8\XB847 ~!uNxc} ]P_6!7(5d{g9+T-y5q%'0azAVi"'L}rNG-PPfg0xǷQlWV%r .LR{Ç@C=srmuoHqRYxwy_v|taa8}zNz AMskl紈]5|/hoϑWo[ Pf(kGg҈kx{xGs,z7g+?RaCtxxf\F1xwg,\`d?aktxzqePh ،8ׇx21PHk?.wTvT5JaoqH(cy0X^ ɍ 3vX0Ò֏X{q6|:9^SUH5.9i h0MH-.()]xC 1MB94@&jGk{kp39DjeVaO-֎!?'))s)ט!.8( :) YAᚉəcR4TvRi_%6V&$q;UlgV:iu qrћih#f|vHCIKmOB90p5eS_^QGitG Xy*ه!8h7ʜM‘ BrÓhHIHz]S JQ9HV9  8.ܩ ={4r$s( 6cBmf AchP/ϱ EhfjxOeoe 1;-kmdpځF1x$!nrf5wl$A)*Ej~Xbv;)w5U(gEa1Tsʡ񪜳y`˲a\GfF'[ E&;CK<.P<R<%T ;ckfC,efE);N<&1&:aa]\dL\ܑƢj#i 2'~lc l\4&*kV @B,3:oH!`0` ) Kibl'a%AaQv @ ̼\,* Z a& [lЄ1%'1q $1 ]MNa*=wծYaI#ܡ},[|y~t,x-ͽir,+wzm2p=Nؗ}Iqk]AYLVaQ8Jݿ !ۏ@% Fa`ݚ=- *!|Zr:J8`s \-lܭp ;AM* ˝^߁|fSh-@ڂ`/ N^٠ >2 "Nca(ޱ*Ω0P6<>@B>D^F~HJLNPR>T^V~XZ\^`b>d q kGwq!ay]b"1< qa{1T3az;qja5^8w5q没Ƕr^^FP9?b=1$-4";) 8=T LW;`6Y.+ (t~"61""1 b;ܕ"rQU^+p+ (lb)'\'VQxN+#+XR2)BD)e",4!9țxn'')RK qzr&*/RIl 0F0;k.cEv=N41e!Cf' u:1(0L,kfȠ0i?'a7qG2ZPH8;Ns[\kVMt)Q'@jU(Tt'&!AF>&#@D>R[3!:Ƴ]qsOt;,o*e>U*a:O)h&>J1C:EAN9|\@&>I rѢŋEݫho4 +V$]0I[o"BcyBI9O+P_ 36Bu0†#b| 9o$ 1mc /)5#Qn+2) ZT(J{[t]iI"IRfѽ0'Es~Bg'PzG}^gC601'>ir'g*^%!sۢQ;ckp]**dog`hlh蝬E3zխ+kx'nNNBH-NJ1ۨ#l{)1DG$qBxxM6 pAh,B>-YGθCM@y B$JM'.Z,ѵS̉G. FeQG|GҌ"+;r&뼳ˆ~'`к ʘ'3!dM8q {>` 6!@@Q5q bZԯ:4QGĴ 3,M?OM5'-bէXMK6]5~UH$+ͲX 4oq\"կ_峢jW* R8`ĔHp@1 QVMQ젆 W$1 lmex!`xADqM-BXG2I1x).FfN&O`sʫG\eqht h4Xdۊz%+9 Fyv"P֔UO9qLh WنE@,cn-]ϭ%=]z>:Fk nci17d^4i{` vx{, F/ti8!:>o@,@#XjHPS-MfAH~_i:!r萨{0CHD`U}>Ȧ-|kHBH@p  2:-ʬU\Q<A?p2J@ë%5ca ?:,)wLH$q*e7`ȥ8l. y f@}kJ)HL#,%2e.܈]ZD1 䔊bȐl4۟zYo{IYnw{ H"^-AIc[`ԚDxq3ʰXS6 @,o JxBOaTD}ǻLhH$cJB ҜPLbUGP Et_gN?ޙ(X@ilXÎJYbx:ӡ MqfNxZ\f~: :ְWWT@NhZOܓEӸ k^ݲ&uu{@t W,=] Lb~WF5$ QetHd@]J ]}"2..gacAYV- Bɑot\У@#!rEپǣhpLH0WD:G ya 6 1K`3D]Hiұg=WUI4Cdi̊fޞi]u$|! ܒ/<2{z,ZqwVrO=Dׁ>m‡v^e$ }L_tXǼ_Ϡ׽AA- !Z}JRl|# ۻ%H9?98 7K31^z'  Tܳt n8/_tSI!ua[ $?h5@@*9}W1>?A\ •h( / AAB–~7a :5 7 5S ɔ"&!C%CCdY[3ȳ 0=ij pX"1"3~a˺,>QRyĨ:D{D ŹE9<=چbBiIt% ?QE![DJE8>.yBM;)Ƈ)!|+ ’hEP<"xk Ui_p ?TqLgD|hH;y{T y3fD3.MTiEwFw[HUlđ R۽@'{P,ӽ zo( Y1d]o;unH1Iz \|!7zɜID :SJi|*rئu8H4o AQ™|pJIIBK(ʣ-4GJ˘MH;–y*\I$s\$'!zl,ˠ;*Jrˊ04L5Q0A\NxKHЅbJ1lK˨(x!< NhqئnJb<$ c{ HJQ,?OőLQ PDaLK`Nv֫`P 9p`W`a2yabS՘!a&'jSbah b{0b$.)^b== /c- .bc1F bm]-kh;F F Ri: @=>6xdG&IUdQb=&dxCwK6LMC6K_]$qpd{`F[lHUH_`\e^abed]]efhijklmnopq&r6sFtVufvvvtw{|}T&6&i(fhdK艦dօfih>&ThTdv>^藦iօ過铮g>.hi.iVNv꧆ꨖhgThTh6Niitnh,kVkfKh>h~긮h]H&ivdžȦuXq&6ζVf^vmؖڶn&6lFfvvhnVnmF&.VmrllllnlmkЅ6J@a p>o XgVpa qpjdojpm pʖqlkT0}nwpn`r#Gr6ޅ #l]rO;PuȅwV'$ qq3_!Ou@6 PXxr9g@ܖq _s̖CwpuXtF6:M%7n /Hr֮O'2FsSp.7XT]/^Fs6nuRr. /^Foc_vST3PmtOWu uB6*GblR _u֖9Wrr7wtvնYu$/xFubqpo?rvpIlo u*N]xxp]؂ VuZ_n(vOww)Ȁzo{v"Ξx7zvKprwF(vXoJwpbmvshznH#Gz?hz'xx Hhl7xonq;h_W?'qkz&ouwmo @ o 5ׅMDŽ .sM}N}s-hzX kWiG}LЄv⿆g߄bh[7)ЮZlMk0aEn„ҴiӨn ǵB@5])DmZqG,i$ʑt T %̖lti´I)jqئZ*jAL)ؘ3YʬZ]OEyq@T*PUβ*۴isV+֮^,@i ڐk"0Xװ2jo*xia xeuov-H>C716MB x];vZّZrn:ڷs]aWWE9 wU,id],ZL@Ia/(?r05_pMq@B H4#8Pzi݇kMY2N61!EuB_# G +X4B% I(+&P#BEWV EA >X$LFudM3\F2 B`=Hĸ_­XY)`b1](" @_ )#}v ߡ4bjhX(BYR/j!ҞiBfGZE%|ם~WÞ{f|"0bH\6RYKڐ3(;.7^xe9," 1F 0'`}%PCu&κQulпQ+z'΅H`th0BJb(w , r3SKbl8p .iQ# MF'$͗@κ&d%Vt2ԁ#"i1k py&Ba9A|Ud2 _X A?YOyvXx%aQpGS# BJħX#IU#W3$E{H>|"yP/%ZI"M laUHTTГwvjAMȸ0JٍaV!mfr 4+S&H}#b@{D8UR At!טr=N>"RL%q豋%0y#av^QZO2qnc ; h41T 8qLע-e3c 3BN=ret|A3A ]Yl F2"hۄ"924m-;D =0$A4Ѭ.PS&&)S ϐdv ` G:QOM>>hbPҧ9Nʊ$@[(Aj&sч@dN38bP`뙓&S)R6;Y)TYUB8E1撍nog2B=MKu-bC)5 Qɉ]T X#Yi JW݋VR5nc0/h#'*7tJ: mTnR!E(hR ް{ISU"Ej M*jc+7ᯜx5+)L1k|0DZ Do";1QEh4&#;"_Q엪 %ꮿ aoKj9IjTW+FV\jL̝1/-!rn ߵ VІ>:SQM"\*K5i2MW m%UמUZ8NRΣg2U{e$Ra6ӆ#(ٚ}m5&d?u1J͆ٚC{۽jV QilX1L'W78+;6#7oڑvX);Q<LȿU]F_a-//R˞^Y ; P׵hq* u:rMYZE4c Ps9 79k4s %4I{'V_ &W:h!g3Æ1/CT'w;Eu@%.?5jj{{]f|˞tDtގ[ۺsb@X:| wG+&—[fZQ"oxOHCMF.yA4\>zMئm hF ߝձӯ~/$J77BAucc^xuB(Jd 1Hd(\ E}N|]ѮIIHg)aEDPdd`')ߺ^']Ւ] jP6Bf uؠI4Ye}DJ lƎdCIP_`diTyg S0WRG4ͧ<8K<"\â )Bm|h?At6M@ʄ(mf`UfO6P"9U.tTJD_|UC't~A_**5h*= A#c SXFyDre3&)JM?#QAĪǻPd"Gyè2<͎`avJ|1N\HXZōJG؋ɳD8d5T<\+B#*Ӏ>}\U ߻r4JlItA1fWv"FH"O}f Dİ6`,*]}I|$œ7l2´ŢsX Lp[J`C =&WʦFuCR1T( ,AalXd$LR"1 扴txHxȈꪺ X [Q-|#DUXΦ85)hVHhuDG5\sS7P5\5sFn5nZ|no̥VX4.;lV$"_TCN.@RV6Tq8.5;.bG;43+33S;,L,2׳@)` } sG27?>@*Ks3/tS=2/4?u?:52י;s\,;M;/uRcVt24`4-+=. 3O@cu*Z+=su*-6;Gt<5Pd:6j6kv+U4>6m׶m6nn6oo6pp7qq7r'r/7s7s?7tGtO7uWu_7vgvo7wwp;=>w>x7>zy>x|7}׷}7~~77{xwyv>wz=wy7;ÀW_8go8w88u#ÁwyCwCx>LǸ8׸8縎p7{xGxx8'/97?9G7+xG=998B x/xۃ/9׹9繞繰D'W=:'/:7z}Sw{+8> ;o:wyS8::Ǻ9w˺:;qz:8|;GO;7:7yo9;C;Cx[~M5{zx׻;;}Sw_<G^X[y;'/<ﶏ7S'3?|W_=w8r;yS0sBwv17>m#DTrZt#8;o>|}d'~秾~{Ku^~cO>;ry>?6/x[KFw9O?W?_k)3[?9>>^Йc7g~ǿ|r?=رc8dI'QTeK/aƔ9fM7qԹgO?:vރx1#FL-BhUWfպkW_;l٘M^ӌ骖lD|ջo_zuױD .e?ݘQ";C0ce?~}'"FUqS"9/|f%@O ) Zg"ǔ{,# M'qģdB aQiʓ /b} )qa|Z|'R)qK̞B<7>fMԑnB|!_ @DVXv͑B e`_Rl1R:UB GQmyX@}!ۘ+fB~0I6@*o D"Ca!STj-SaaP1HUQak^AmlSçx2t=.3}/AΓ^f%YV`#Z㪇,rp!') ]'0֍$"bc0A|A,teŜ|(tOFZ3bSRb%GEP])#X/e$ .'!DS} @;tI4^NqS>G .bfGSrҔ9r]Nt0En$-: Zb+:q #w-&Ch(R6DDLCG8_sA`=c˙^P YHX2$X1Qʃ0hC0a]WHepp9sC=Jdvl̐A\)>]&3C! V.ZGpcñbaZuC OE^IlH\QQtԞ|#w.*`l멍mq{v#"X2GR1%*ga q ]G8[NA (yP\+5yћ jRƫLc ˉ}(x>ru`66ceoE򒁷!0o4"68;saĝяp+#ƒgac%x̒WǺH*z@i )NBvlXJ5s W c*]c5^r =\Omv'H 8LKUq0]-|z?.> `#kX^졋)!Q|1k$a ZP1u - fէN5V`}YDPCmBDeCP-{s?[_ZO]/1u $TNЂܤpĶR#VB{!޷F7Vč$ \(Bp8(l߬34H& *CB~l eG_0ĉ= D I_:n+ I=p`a THBõq7־>}ٱndџ!,-5;j ԊQ}@`* $?6 Wlp:<jΒ/7ҙAwwzA}-9w֫Ou({$UF=>RvJȖOGs`uy# I` ƺ Ku'$RuO#jˏND": 6RA-V3|!Pď'N` k .M +| %@ F%:&NOPRoo!&=`.F(cbfO,b ^An` aҀ~a  PWv i8  %lOÂi. ^k 5L8dCa   . ;1 q.8!IBL lpBd &wؖ p@qOb?1JUMQ# `Sm͡  YlAq r%R$#)4b:`x`Fk6#@A@A HAd2-AW%%cR6!m${N ܰ($`L*%5. N:,O0.anܰ0+)Q $l,+˲4$, !x뎡R]/../ѭp.5܎n rn s 3@) $H10S".3n' @5 .xA2R8+]` *_"1,-? Pl,6oN-2A$gb ֓==@B 2!s<`$`fn TJhArʯ&"A-ATnCOVBBCA1B+u4!F`n iHPGG@R F46/B@XdTyq XMFDO$JJB%T놴CN}4bkDtN:.P2 h"p+(!/`:TXXXU[`f @JUYUY5bu A ?O ~&!>0oX`ZQ!' m8=> (51O58PZ^V$4c m] PEu]]4@WIQ]3jc\]5%F`J6_C HuPOd[+B Ȁ5_\ӵRcpآpR#.$+>54 @< e @rpO|Ov$?(U u%+w.2.n'a !m+@oHP[Bnׇn` %6nWt4 Q:c[5p$4NHq WCuOb߶PVO;QoRnXXwDA[bchWgCxT"p@,h; ڔii<`lv@xoB[ 4O&524BT\@OqAʮ.+spH!B;8b!n|V!eI7808B5fIGreuPputTP'xEa "wrwxvw!wfT$(؂yV.HðS<|w!MH=b@8! Tv.|]xQDx]J8w3 9;X2!bsK)\B߲/oy w VlM-@83!/4`QEvՕy9x%"!Y8U>mxbh2tapI8b:vVY.  ֔in쨔ubRPђ:'@ Gx]}pI[΢-jDCN.EݍbUY B$l]T!hG:3~: YrCnsaJWaoy9""bZf)*B,,f $Micj6kI&a=\/H@ށ|ti~S^Ʃ{-ޅ838`umnQbF7-ta ѭ ^aEHEn f8oaQf7Wbu!Y))=";Y`;S>@ &|B)#X?@=! >=#AG z+U 2W=w*3 Ssȝ2a^ 5^ӕ#K;0B|0a*F*Z(mH.VH]B{N8Ō+]^|&O6ϜN 81 9@AF u`7:V͔Zr M0ޕ 2)M%2r>x$$v#$b((- SȔE&v X{EUH8gSSqDV.CGGY >-BPt sPdZRH VBL!=G(|1(^ELJYAx/^-vCaE(^^1\݉gzg~)X;$>l6Mf鲙3A4RPC-s 5؍.I1~j6T>`s5f5ִ)~ي5ͯNB¬кc5`3mBĂ6lKNơ" vᄬ#L84jq\ dB˨.+F2t ]8J|›8 `-Ʊ;1[ٸ,G1-C&L`d:.Yr%mHDeR .R,)OT卪l+?HC2RT2f=22+ ` s,1؎U*\3PG⎉ljs7w#e2RAfNP7 xs&#|,Qh,:"ks-AP魣& _>̜=ƄjtG?.fМ'N mK_ Ә3:T!͊#2O ԠƱo2fBmS ըzkHN^e`T ְu!= e˜B% yutSГU{>j vBOla J֕Ge8=]zoN' Њv &gL2*[ݩJv U)j>HY w% ,^(JwԭnBJr.UwaB&j^w/]g0biG͕w.SMo3.nSP7ZYCa54 MQ.OMӞ2)JS(oLP kBxD.23N*Q (+42MVl8wJy\EIE눽4]kRGY(TӤ.jI\ mX˺4z!Q3bZ}r?fQ`+{>,ndTQ5m3fTll{Ľg+Oo_f93 o./3B*R 5x+|OdVZCf/SR|_񐋜== h|k cGԬh z jP2lqF8A+}4mU-kTԘ8Zk}4 T/L:ώp*UiN#iKyY1ռgM_} VߏFlo홨3b1Z_kn*1N/v\MgOvlޏ7쑞ϓ_} +R^q7}ńP<{[g L|F<-ߒ/2f1k3O&Ih|ngw^җ{}GMs}xu2{F.{ȁzg8A&tU%jց'xz*&yu3;((v_tV(p3ȃ`r;lփGxwF~m'p|H(\f6hzE}8]_a(cHehgiȅՠmoq(sHuhwy{lvX ~H ȇhuHH舏(h 088]h^w舦8h8xҊ8ȉH}8芽(،xȌȘHx٘ȅ>Q4 kPN`(qՎhxKx VhDtN8 `?F9H Y8 J Y9`%) А"i) i$ J)9),"N 9'?,i(8 yB-c_WNa8+ C )X2i@j'ՔٖZ8(P(E[ѓ@YBYcyqx ɒ \Lgh.<9 *YxaLVxiH8 ilHɏَyL_~ω"ٚ yx hyy~ɉr ٜaٓhy驔)hl)i Iix@F8 hl@ P ȔyKQM U_)jՏ)1*yYxiRբ Qy=K2=ڡ3 i ɞ,G8+c҉ ^٥ʐZ>LdZikʦmj J x P(` *`Y Y .swiU0II w Y89 ~z#px)n6[ w)@ `Y`P j My  0 8 *Ы h*ઢꙸz $`ЭHƥyz 7gjŮ\J 9 jO P iԧ     ɒ #@8_J ЩU': ` 0 9  PT в)= PꓟЁQwQ[j:pP a^`YڲjQ ZP>K`j:˒dڠk qj=;+-z Q@D +`RjA;™P۲6d0 `N0pKQ ' & #dDY P1 P8妥@'۲(nzۻM{ '@ !,:|;j€ y;Qv*9лl@(۾0 Q ƸR 5+kR'3[/01֊ "6૤u(@ Y Pp.| @? w1Z' i ۲V=lຝ /[Pbls&ɍ`lXʣX,Ll̗ .܎h陧{@|,L99ǝ$_Ny sbhwW[uPK!q@̒ -0n3nm=Ps6i  lQˣ˭y ˋ ڌB,V:gk -$ϛ o˜ EOը/0 h +HFJ9Ǐ՟Mc[']\ tjڴO @u0@Dz`bx0Á(j./O*G1eΤYM9SyR1Nx`'R"eJU40`r'>=paNa.pcCKѪ"/71vjUQR8 dHSnHb,4ʜeۦ@,F ںs>^qɕ/gsWG^.MԨ z*pYBV\h6⛖/Ҵ}MM ܫ"U6@xɶǒK :JFUia~8 CtTq$n:S!Ī. zd&h DNA*RTX!V +3  Xd>;-~#;#OPTL+4 s/7mR(zh.,;SPCuTRq:RSNAfϪHDjb GHM@P)O_ 3}*@OjH%hFE5jN./R SR ;;H5JQ4cuR90HDKqdXƑLib⛃$ Yř qHv4$o6;O}K*".7ԙ:5%2bPէ2nG&LPܙV>Ga+;ÞP#%iIMzl3.XDK'nB`n'HXFj=z@pD(bt5:uQ7We bhJiP5KYKD&=TC#03=^EHK"@OlQVm+qDI$4jjzcre4 G4?D7Cf2OW &D6V"(x[w*-!A4TrvȒ&ѪqMbY , E{[Tw"̨-3G;`r5*0iYn0I"c)4H<(LE qJ˹0SJT H;`?s䠍L۝\TxK*Z2 OAˈ$c'@D=S: DÚ$ќ$) ~@ %+?؋Pzsz(((DO1I(ɳ4D86CCPO̘3td7M@RDVchad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,=";1&"".;1"""632(EMVR'f#v;r1l1]yDrP.WC4DNY+Vi5j1r;t#h5VGzCi/KbQSRsgUuutjknT^d *$2>'4(&OAMR2W%b4l8i&%R%]%R%R6T:R,R%o%f%z:o5ANZJRWRMVsFoQqSOqdyysryWfWRfSv\vi(Uorvoy[Ҙ\ΔMܕnԑrwo|ݦsDN'Z8k0knNogxP{ $ :/$Y$O/j3 J V l]`.(((+:'l|JWRl^dUu:rRlhly[h.ڏΗ˥鴎⛣ʳа嵭Ҙƕ΢ӦجδóСԗնȰҋ犧͹ЙϩƑ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\RsɃ*LSMӨS^M%D 'X5{fͻ `g =;lϜENسg9&E-ZϢ;˟tUKcuMh&{{\N'ay4$W fv\ƩYL(y8݇,0Xq5$:&XM@)$|4>O9JX l6I7PF)唐qgaB_ "`)d2eh3mɥ7dp)t2d\Ld4Ou*蠄y7xzBdF*Zϣ4^)̫{XU>Wo}^W^s 49"><ب |fHk Yt'K`5Ńr UTz̠%~9*ek ȎB0aph mIUY0(p1lLB=?LAt/d{AHE96\THX.z*{ tN}hQ2L_>bHG@'#YQ% u?[sUD>''2C$'6}g{K)ID/rT_\*9i)c4˟NZrVByYLrI[ҋa ̤LV!O!2eb~Gnqp<ܸ!ӛԠ㼢˯3`f9bFgIp%)fҧ@:LB;zNQLB'z?)OJю.۞;%ђV/{O4Jp#ZcNU$ &ũPI0o]f<wR u0&Y^vubfM%zN^5>NpI& _Ua.,4ЖdG'~ZHHT&U[L)5(`[ɢ;(vP۴#;YL(0˜'[Fe%$|Wt3K죢Jtx2LXKgn%4Q,HѐVM[U7M䘆 Ӻ l7MM5rfYVcىonFGZwu`m^㥳cXbpB"jfGFul\ijgDQakk{*WUQf"zK>h<7J& Ҁ o|W۩%*~Qo$n& 05%bdϸ/_rz٘ҸAĕ8vٹG0X2F:(=8@s1asw:> >C28 ˘K,r&6,gz m`P[6bF|cĠK,nuo3%=@l!@d{ >aɛ7Չb:#Q{_spGOzP7 h#W~~A#}+,\r+e!~G]CaoI" [`zJjW^0wzhjv7_WL1TzqjG6"gzd{ʧ}VyVNMvF8g0ڕ{?Zj6SaQ Pr `` ( ` 1 pЫ D "zjj !Aƪʫ ttt#UV H蚮gp )*۠8=P Lv| ZvȰ 9 ! [!Kq hZJpldЅ%г) OE?^jP0B@DP`kdkhq9 gi[t۶!qykn{`Q;:c6?0   10 \MA`u`@SѺS ˟` 8{KzNѻк;6;E,k])KK˴ ?`z[w۵^{![|[+ DxHܖ&ᾋ'kiKb[[KW˵q3 4̻7%2|%',);M dҳtSq k p]ĜP V q El^~`ju' gQ)~q +qKL`  ~ A ` NK!=ؐɊ Ȑ\BlȈȌ  Oఄ`ɠ<Pȇʡli ;VG uZʧ \Kʴ N!ñlȉ̷ l1̲ϵɝЅ9 ~ pB}<ذ2P.U-<# :;#[,)<<8[jͲ8"r Sֵwl=j h@@ɫrm ;9rt-F ]j}z}8` Q9 [kڡ|#[{\׊]G Q"7#"E]  B͞0`ܝ`!  0pA0mP-\б0 ̿?58 @ ɰ Gp_+كP )Kա%|.Ơ `-n+\âӰ.|.B0 0 ^W` 9PwN ^C8~IL^O>W=.dRx٠ؖ@ ;P]([R.>#~"Z`z I%%^皮hWnǙn.􍮊PE-) 29< ^ ;pcS4lNH+m a!>APZW֮i ku'Ka.֞w+Rpw٩i  1ln~ -~OL/) !^fAF}`!be, ԋ`L.-N<م° 8g9` ;>WKčmpN!a{my,Q/0murj/O?U۰ ^?^Ip~3 qɮI~֍/n>e/^8`V-?y_TP4X?S5۠A]J W?߼O 0 2nun€|)nn0 @ @? k~// :!O@s<,u' @ԦYǏr lF"YdA) ᠁b@[sL3EO,(s"@.N˸q(O.W#$J&Akw$5֖]X?.m4jqTX`… FXbƍ?&|x*˃93*Тe AF͒  L D@f%<ܺ_@8۹%\6Uڶy&] ڐS)KЦv=p2v@" -8^> Q_U ﭴ -kmě%X #i',(.$ \c! p#H$ĻˤA1x:1$S2J)J+K.S,L1bhӲTl5 h::6m:8ވ xj*A_:Kl4 #+9)0) `"TQ d* SFT-R89ίm XG)UOquP yg"%" ’gE~(Ŀxhc ˗v핉nfe֒V kOG-HG_ D_8`!#ML2P%$CNڡ9T90fPPf,'Օ\b!TҦ50]Aj7!X61 yޝ9co*F*hy >  #i\~i8tUa>]:k6)ܾqzi{#vvOVmyZ5 ?Goz6HZ\gc%Gꦟ/<˛SMJ%;zdW'ZFAvЃd:CaQ$:O` 8uHO0lbnS0S8-e#9<;X_]z=]/&~$[g<R[{"Hqa.I3SǮ棐NX D̪6BLZKp'kůErr0am;Бn`Ƀ!'ʢ S rd$\C&V,-STlh!AM W?7unTx,IOU't=GL(ZB(YV8`1=+vxGP-Ղߜ0@ua5UH8g9}S驙u;(vu8Uyx5d~_A63\ unFk5uD#87 CTũoy\<?!d>~_6\7~_XtG6e*f >›$%1S7훾vp@@? l?@c?` @d$sރ(3 sсB [2+=#=$$=;&4#$'h?c$°0Cǐ c0A18k0c+",BC;? D;;A,DBijkiB(kغHIDX&/=HZ2P0Q4SDE,) ̌r6LYź+Z\E(vp5Yb4cDdTFɩ0͡'[ejkl;#br4sDtAcӌ5>uz{G[E9)W|ȁ$Ȃ4Hي<ȇȈȉf<)` NrȏɐIeD*,ɖtɗJԽˡTHC8ɝɞĆT.?ɤTʥdJd!/FWdu@ʦʫʬD#0aJ$˲4˳YCGID˸˹sX̌K*H̑dG/GEdUy8L^IǴt;  YPP4D-K3ÿDؔ Â?GRLN⫝̸H̀FH d\9rDt?$غHڢA(KLtO;AԒDhMh254J M-Gqhy PL^LUQT_9 Ld+CMTl RXMyQ$!u'uʬ0P-R\ʈAyHR1g..U5ft2thh0ISe>SFoS.DEeԃ,7풃1ʋ22a4mLTjGn ~?H8>SEcLȷ(*=?olT[E7}AL45U\%bĒt2V%*CTKZ5hVIe}74WVio5eQ4nBFpevmAɰ>Ĕ^uS,uyJw~Jdd|ۚRBu2hׅeXcJWE`5qՎֆ،Q+("O;PXEٔ}AY]} B͔Uٚ*.EAV~kƛڡmsH4]J\_%ڨ(*ڐkڣکگ D;)ː- ۵eHH'+Y0dKڶۯMOU#M[2Qۼ%\RtՐ_J…՗E[= X+{X\­Z$ y_5W?i Koƽ'S]oU,=Rs]%^c]E2_LW3S,YтJt]U-۵K^5_F ʁ-2D=eݭߋ԰$~%f'bv()+V, b#/^b0a1 6c#^c5F01>7/4bh=@a"8UPEFLldNLCThELVMG6La@dUHeehTFteOeΨA!ldSvJ JfQdheGdNebVd0eT6fUenGFfnlfPnifmd hɄds`.GeUDY^dV~TfSeeO焉fNdcfU8Md``>eptfTwGnRFwfievTTfbތ}gUiUV =envwXfEd [~iDv6gSie0F飮e\i?c ^VnjfjfNjLNeJihhVSvG佄Y֌6p6hlNh\VhX0hvesWvj咦o봆jfV6lWFԜFfl6ǶVd^f~6eDMw\g1yk_NgjfffgLZdm|&eg]epgɶkeΨrFgfgcPkWN÷Mn.jFfk l.N>hSl璖kkeannm]>gFNj.gԞ¾G~jҶiVdGdPnKvĶV?Fnfo^UQɂ P&i g^iq /voJVMIofrz>m~^/8TFIvr~VgVlF1l3sMTko8rgOe.fBdzUNMdSJeϼDkWtV}qk#iR_mH`VVnjBqVn0sDa`sEoh eu_gi__dQou GuV-mruWh&rbGRfUd~twp֜E!wXv!i.e x0\njc^onxTx/hxGydb'y6y&q`ueQ+e? 7wa:'m?NFt5ojhgve|/rt0Wz'Mt4W chEfL$(8{ςM@'eM's&otifZhV/loHI8N䂻L|Zfr^/gf]n>rBľv/nAg_'`fJ6JJ`E&"oocXMb+h@էyuoubf,p kT8NyW+EPpƮn>E+,R*hJaCT9𢪄>1UBY$#I y\ȑ&L!igʕ[>|1&̚n*)&ɟ-U(eL325PP4&jaяzrXTMJBEZq*+)Ӈ~1a`[W]BWV#*$rܳ:%IͨUa ޟT m(Y`'Ť8ļQY*5+vhw?H`'c` aD$j@r E)4CnU }Ji0WYY}fXKVŕ,zR 8xrWŕD,:tZ~U&JlY0-V=TPF|wA#Pw)q"%\@(A_U4)6fu_ \aD( DB.`CUaKjTOJ,%f~nY%OljQ|vDWQgB6ukfCP]uNm]t*x[a)_HجߴY T3꧆ޙbmbJ.jnZC!Kن[5~U4#YP'=F&;Ĭ_-)Oh\iѣNլ s6'иR 1[լwa l}&ed9M-; sFj=#L+-IU421b& ؐ s-x6x7f{'WtI \gw*1XX,2%8/E @B_uor8i˚@(J6i_讂:R&MoEFY:gӖ:΋}OcM_:o_awrυ}x_F㭽\(/d# &Q*,%#á,[/di+z cĥٝ!N !iQ i_ĩ^d Pv)?UAW s^?:$$d@CK!u 26"LE̎(I1Z"̍wӌ̜@eX0IV⮜daK>"#@^ʊ ]XGИ8V_)*l)x \oL%ŀ JqY \ՓB@R v@͂)EL_i \b"Y%C u@ح%)%ӌN^ ]tޠEd`t*D X KD,aIU$Q0 8{|=ʔLJ$en+(}I6O4AQ-H)X.uM #2mX nYa)Fg\@ֽ[x),ci @+yv5(PµM T}NAxO+tԅk*"c [)Š ad!p\E`JI0PfNLj1+$ӀZ}GtduF` S Eİg̔}eb uH ȀWgK*\[o)E\@1, _-5@4̩BamIYB\+$cXP$фH SaȮ0eԂQX j R, ÌM[+뽜*4I;:/VͤȊz*l6́GHc\ &$^ @Kdb Lj M#*!qIq5&wnыX ܍N2jzM7dž*63+990OGȍ KTJ ]-zP5pr!cƊEsoS)Wꪬ/2AwB7T 9K+DSP,m=BD,U@qqXKoPu #_,'M>1]P,,x_4F`PVe!EFEgE%2NRcXbE8;."WCH*h$gΠ6_W|5 G/{QmiIf}ɐ"ݱ`p1Y"G:8B:u ٛ(PlpX66L6uoc,Aoh(A(Y. kO2_Kaw0We RGP)&ו,tA}5dLײ1=P$T=ZSQjKǝ18f,nq;!ٌ$*Q-S1!8qX&%C-]5L>8/8GQ`3Q.݊Iح-OVğJdBAAz( ŌީW8%E*$3N,kDLn0lI:*nZ hS"sigE Ny*`(D6)6maO %~\_,q',0vn?bPPT ,xj>O,N9*ή`[71vಏQ_J4V8&B8KJ`yV Sڏj*]JM8/% ()7Y$ X(9u_6.dZ@l¨jp*dtAgDNV6Z+5sh<>f#(M# +/iŸVD  4 ȉjT7uwH} Ky=ܗaQp닂4ΐrܲYdR=$ЕypooY/%':\K ςaKIw`(@"HGJ[ <PQ4!o* ƠfⓣJ{iR\+R RuXD)njP꽱%KKB⓱jAcPca"@L*l T4h$IbEPJÊ*rXc PdK'1BCeH1Ra&<SgR$J54cd(OQE @(B200޼2Б*hs,r @F"DW/ESRPDTJٔS&H-}),ϛ3NzgoL#2S{vڐ%f+wF4VsSVjh3}&lWS }R:Q/W93`)Ldg,6i[O|ۋ^l4ٶki)DbҕSHAv!/hpK2᥃`މqOLḂ=NwCJy!`ƃ~91ؙtɄB" ظ9 sHЇ8W9bu➆t R<"U:AW3&<8)#NOvl߈" 1ӈd(Pv~v/ }P6@.qiLg XgfgZ(`@p r2{!f%x@0`-M Q"ie[@ 0qULtل2/zbl* 3eYIKlb%fa9++͢^fr8D~+U#a  OQ"ʤV|Li0 02a QP z@&Ig=#в'@ "*B6x *UbFU|j ĝYj|挙*UDT1aTu#51nX%ZI'fSMU8Y'jHѮRl&Rlh/&"Ί!l/4D` K9U({d_UȢ'yX#*򚖭fѩY%\C͆ & X/,Ml\X-wE1{ b8\ZݨLxڬJVw9tsv EZgn"uYQ8 h pP%FUd(aFA q۔(< R$Tȣ͈jkrȹb9!vTBx1~xMgƠž%\5d8<YJi9T0L .gSBʦ~V$DeG_1K| `mSܙdS%ھ*|p+M͐%t9pvT_sx˹Cr:aio7QB`vsZfelY[wSO[M4Ɣk%S;cNKJFr;p8/'4//'JO<+ #|qŤ? ɹv0< f;oːB±07 Il2TDC_fs>ObF7>Y Ǔ?fmm 2Z0D?ut?MG7DΦ\]V&<"bKKKKL!bLL4M4LմM"LtN4"NNTOTNM4NOOTP MPOuNOT&QմQMQQ9RRtT=QtRET5UOWU4V%V]RVe5T Vg5RwM}UX{UW5OXqTPY uXXLV?uP4SASYu[Z/[5U1UUuWM͕RU\]4^gUXVەRZu\LuYYu`a^?^v^bXOu_UbYU4vc9c=cA6dEvdIdMdQ6eUveYe]ea6fevfifmfq6guvgyg}g6hvhhh6iviii6jvjjj6kvkkk6lvlɶll6mvmٶmm6nvnnn6ovooo7pwp p p7qwqqq!7r%wr)r-r17s5ws9s=sA7tEwtItMtQ7uUwuYu]ua7vewvivmvq7wuwwyw}w7xwxxx7ywyyy7zwzzz7{w{{{7|w|ɷ||7}w6}ٷ}}7~w~~~7w8x 8x}!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,V y";1";1""""EMUX(g"i3v;r1azErT/QE6EMU"["E"f5i1r;tS8EHGxMg*MrEFFMVQsssww|nnr[ca *'!2>*0OW'b2g7r;%N%R%]%R&R:R(R:R2O%o%f(w%z9o'M5A(FJ]JRWRrEzMnSoRWoJobwl|y}~fsWfWReTu[_hjcWMlrwhzܔnדrw|P"c;l1i3o"[MqM{%::%i}zJWWhn}WupUMilgtrlz[͗Ҧ鴍ʳܾͫꯣĖל΢ΫӦ֫ʳĻ̣ƞذϬ垯ɻι H*\ȰÇ#JHbWXȱǏ CQȓ(S\rcɖ0cʜIs˚8 +œ粃zi0[('ݶSO7֤ÆUoVjR"a5QWm|z2jؙW1bہٲȥkd82[wnݻ"ݾ ::U"\Uyd95sN(2hХ;d4ɪmc6 g["SO42'Q䉶z&媓HN-ĺ6`;Lޔ64h,}zn\)S 7\WQxi'\巍1s, *|' /4we3ExHJeXb/b4RW4bZEPc!6*`Gdh\Ch7<#PV`A01U?((&UD?J`5yXI86 E@ԐR 2  @@„ / f xU U|Cm6eQUb,-jA8ǟQscJ":ؠR"ͤ@j670@vChـtu QQ>vM2d`@A Zrd[y룽q)$ble:xL`΋)AƑ9#VU/U1MkqͳjMn6gCAұ2/1aCۤyG!]/öL]ZqC ~%tApAس _4ڐ,]Ԡ DoYY`ǬnlYRܗ0 5$6ܲMͱ܇o -:d̥m߈R5۰iOW!V.cЬ0DUk+/TMU>me%bW\#(lT`ՠF @aI3Bëեzx쳟Mg`; Q' Nx8@~}mcqei.Qx!]&% `!RuLNWHvËڨoXVAV!C ,0eЁU{jQq¤j1a 2P0AT5ӣӬ&D_$WV5nJ3#B.35K"n3Vえ6G5p}P7jv4D"&j8fsLH rKdOsX6֨ x*""Y1-dZj6Hp s RJa1`ڌ-kFrsbVPa(=&HDo?7 QZ N`cAES4 ,H(]^pi>q! \N-A`0b! pKo>6w>"OzFeGͫWiYCiZH=̎#%i/(l^9@3 ye`Z¢ER-Z(ase8wyC^=$\  f @o|>1 @s V;uc8@~s~`8=aPCOןy&`~3B'3_sh}sP~~D~sb Jpzs4'P GyWu0|7؀503Ђsy}A 1}9r0si s><s"H3g8'{E'|z,40 x^sKyMsZyCXsx' HM 0`}`-x/W \`&p %`|}` so QP'z\؀g(s`X Ƨ 0 rv 0p0qHsms  I#4G0W7s0gj x}HsxzpG,8wP Ũtt@~.s=s9#H|{W6G0$pz y$@6x fs`H$P~|X psx|8ssSxy@ 7s/ 5 3Qs_yMQX'p%_y K@s $&wx~F wK07ig8gW|yrhC׏LGyerMYs^ X} yAXg#WuXgW pxpx ysP藜 Iȗ iy y͈1wـHy)9V'xsQH0)/i4 } 0 W @x ~`],irȗNxYgw 8sH8kX#472ם/0 X} )[GyYZiv'}#*  jנX4GxXM$ٜ0 yY)ǡirs`؇CQ'{W;W٥` yX1xpr x1CtuZse wQYrs y>ؠ9Ty7{XX):G)ZA5 0נ T0g/ >IGz'r X2Ȭ )IP @ s wz ɉ::7`'pPu}qv谐ij"b Ȅ۹xP iW @ : r ;1whY ˙i 詹:/g {iz أ0wvڎ03s ڪ=XZ kKr,{k'{  KyG,Zns(~Z⇯}w@y;׫_ s\D ꍰ~p p AKvk!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,=)8*;1333848''&&DNZsfR)u9k+E33Z33C/,n33rBoJ2QC,BO[,O33F33X..Aet4s-l33n5V3FOEs0IsA\CCCWWVlYLtkVThpmssKVl2A2.; 2>'4&OCUI3V3X2X.h6t._%R%]%R6T4R%n*w5ARRsGnNtKOqluryWPWRkVviy.[Qssnvҙ\˒OΙnwoӨry.HAOIZ3J2X7k/ji0t^NoGwkv $ :/$X%j3 L l]`(((5+oJVljc]tV]Tloy[OIPksub.ΏΗڿԳϲ緋⛣̴譨×˔ҙ՘ōȷէڸά૕ΉֈّЯ͇篸痒͹ПڲՑڽȫ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjEʫ9 `+wUoW5JݻxW- +P3# 1E(ғ{}3k̹ϠCE1W i7,g6_*0>C8 N|( EX24yA m`_ Цf0Ox;! @zį}(XT0@ 4@bTEwfg ($N`k~ tcPamz8> + )ayndAie"JddI0#BI>R sXA<`shxDx.1P.A{hBjK`QZe$s& ˣ0+@aڞj:A*! CyC#E_XD+bp ͦ*A(P0F;e+nl8i`r\u{``7ԫ| @%A͢\`p)0Ia50eh{al#< 1$K@KEO~Xkp=2zP@,>2{Ǜ>-'̠U?ua*mDex5}:Z$ijk-롥L|6ʧp%MB.yn޹ʈq 6ع|.{F&FyʸTbTGЧ;~'8ӏ²oWrt`C1KBQ?#H5>V=FJ@tIz]""{ ҟK @,6=~iQQ2Ppz,f#$x tjcXx?C ! Շy.DYQ%ȅƑ#)izP5Qv d-,cGKHC:12(@#y1:]klg[۳J̴ pO !x2H5Qi.Z<cp-M~p`1!yћ|6xQftw$/LN;&< [0Q7{nF-@L0q*Na^00*8&1*L<w8>p}Ld 1&#+vb)[7ryAc-{MޱdeXhN6xlv\8XF&sd>~q3aBǘ> hr4<7ũ04kHL]LǸҞ&t0jkpk9 "*ʁY|PFwСʦ{ z:yj|}ʡut$4 tkx9u J :L˷3@y#kZ6#HyWzZӐoTo|ʱk+8hl8˷73gߧ]1{L .tj:ySFk`ꓜ9y}z}?Ԑoz/ B`ݐ>Ұfh0hW{cx7gڐvo`z0UD|mۙ]|k;y%-R0( j k+@y"/$0LwI T[7xIIy%X+lK%}RlHn}ʺV[F#ʍK}ЪWl| !t-;,}W1'h˼ & pK+ "˫ gKG{Ir70XGys1B{8 P Q ptphI rm{I9)@ w4 6ktr@ܐqw j ZP 0lP}s'fJ, K@|N<\y*@LW}u(‰ @}`X(_G6ٮpq:ו_L Pܡʴۍ rtl q7m͐t" [@y[u`qp t G8V4:wk-i0/y|۪P;r]( Xm0Ӑl\k!l ) il础+&ʼn@wWw֫Ū|%0 l˾V` mQ;{ {o,ݢ6x }tk[< fȹ&`Wb7quZWZ ;4z}֫;ے ʮ(wꗔG$쑺y0Yّl;L6̔g|6L̃nY| 'ظ}(“ >mʋh(Vz1mI;aq ި@b}Ɩs"Igijk3kzukAk \FYk -9pl@9!ުYZ<$q$9džKA{ZخBxl[IOl %#^ (kACzБ lW^O[D_)|.gl<: nL[Wu쪉$Ҫݥ}mޭB|FIĩz; Iᦫ]qߌo8g\ i Z8`[[u 7ު K ЭjfhB[I}ZwMSr%l`?x&y퇃Ekxk prkLPkzǁ,|B~3:=vnH:l/7'3ܾXˑޡhh*8JkP\ڜ-B; ^ĸ>*L젢w0qR"'a@F,z&\ΝB%\.ҥ9>׏ᭂmFkB.a@cč\d,ڦ2PpC1]{HwUAU͈xK͉Z 3`Ν=ZhҥABt&R-ȌȄ5'W!kN}0yT0/&cmtpӯRpŅ^ fnEB{ jxq@G-;pM.7PJ +*;A{ǢZn+m{ǧ ϔˀAC$ GqH+H >x6cp8v̗ JAL@(.Tw|`Hr'@`{N͆Z0 -sP RK/4RSKQtn m~@(?B Lx٪A4S< zfͭ.T#b=&=42f['@/+NZmsqiJ΄Qȋzx(h F Y`J}/s'M(rWb] .Όt4:kS; "6ݵSyDI|]g(Ekðl:"n"WPqD7h3Ga}6L͵ cյRtV=\Y>o(Z nlpPחʰܛj^C:p(=ת ,HF7VUsQƀ oe"J?f0DBd8Ck5<8Q@Es.4<11;@B5ʢP mB +QHpd(` m#OpHy,3Apyr +ŕ νj|rBu$0a<xd$ѱ74. celd[#CЁ84T^FYLQFfh'^0 xpȆ'>m/!1HC=`N%LaD<.vQa_M4Ɛl>ԏ׉.CD*ٍy0ƪ&hP_,^>xfΎ/M2T /<B܍oaCED%iNexk]fP%uf|" !n ]Kd)% &x&T h.-|T˴A*C.r.刭RqKVASwh2sbD 1E2΅mqK`SLig9]b0:K#bNFy؍Ye%8Y2jwaT$E2䲎 l<1"=: Skڶ)8b0 ּ]M]X2%O9LU pE]hH6Ep`1.Qc_ 1B"Cl瞈 #(HJ+'^g\|w.H#"a `P})O F(}\xj0C;ExyqW|;XdYeC # Kܲ$#ڠنD QC29"-4+=?@[; ?M; 8CNc 8C@,EDK;\AC@GCKlUD=D::4^ZZD;f EFCSXpQhDHE0]EL:F ;DWU4dTFU>le^\HLZ@,xDXdF:4ZY EeJF,JkFUP9|FN`SyG]G}>lFhnbD4ȃDH9LDŽdH<džTFThHnu4~TifHET,THFHeS 8<ɆlU(ɍn\Z0kHJCh^HǕÖF<IL䔞\F{TJ9ɩI$I^D 4FJc 89IDFfIɎtʨJ˸K8dʹK:TЇ˾˿$4DTdtDŽȔɤʴ$\Lć}HM|Ї܇lٴM~4$4DT,(|~tԬM~$4DTOMtM}ȇׄxX%]LTNMMO }܇؜OڜUeudP\M}QE !%!լ|M~")*+lU%uMU}0Ԝ3E4U5e)'MMQR~06=>?OṘO1ezS@HIJ=MxO\MEK֜|ȇR5SETRTQxl^P7QRU]^1MbImpQ}_ughVN|Zf0V~`Wi%r5sEWœQFNmH_ۗ IUk^cM4VcmL KZ5;uQ|GY}^B6=R}N~@ZU:>JdbڱC,XBOn[>^,@gBnOž͟lkkڎEh﹮\H^fHĝՖ["gF^jN!&bn<׵V LGb%cLkϼ:h(OW>`c?לt}8r:>p('M$edflENGn먭T:˼tD-;qE|Vlˆɖv5de@rKЇs:ȃj=VN~0KHaOM97uЇG=ue8BB1rӮ@v> wpwbD@T|r<$O$Grjr:cwy:w˵{˻dyf{WZVTwr$߇xDȗW{yD^P%h&x%&okOׇ;gzxuԸ7}Hct@/Vl%_cKMX}y%T|:ЃMv8\(0K>ckO܇>}h!Gb `G'_|}هv.4DÆt@BhYg#ojid-W@wOvid B$%РB-j(ҤJ2m)ԨRRj*֬Zr+ذӷYcxUU[^x2J?}嵈;t4 Op ZtX'ǿrz/c΄y[>>#Z,ԪWn5زgӮm6ww[UR;5U ^d &<0?Đ0" %o^(Z@E=/PZ#J>" } C4n * : J8!HYE\(̇Y3b^g_6BQB 9Dg-aDETYQ#<c!RO2-4K5g2Zy%Yj%]zeRfyؖ\Uˈ#O>#B2hA!TAeT+J(6ڨ+ }!+մϔSM`:*z*y^xաty8kS>EWh`,=q9!T`H9xѠ;"_X擁”8 >ي{.骻.O}2⬵(g׬zge,u]!dhXjk0@/N!1!<2%sfŏrEp͕2^s2 AhA~VQ5ldX4 SG8&[}5Yk5nu}81 '/zKc[9~N9ܔ1}7 z問\VeӪJ}:8[~9W~!>J?h:뭻:YzW_pˉx;/6y ?<y鵠mL-d=k>l\26ܻ>o*UZ˞(a1ET m 3 ev =j.gsr5.| ԍyc /ȗ|(!(!kRdhฌlM^G)RVφo g+f<C]\`_%6M\a^-_( Bȕ4(I_䀊+ $Gȑ5lE""JK G6FrH4{aċF&+%%dC* YZ jBB@7gj  =)isRd5oY:OyF$lkiS=4@{Zs 28@άZUAU *Pct YHG?.@ >pMIt(U!;JL0 PN(5jUJe@ IQGMݘT+ bUAjLyχ9<UbEQ 'g9ic"IBK| 2BN"=,U*E epZEvBR$Kj[bZzhi%vG+[ߗE|r+6XHU >[@֥^igv6"8gܢVc/K+2J8opkb E]rvAҋba(k*Ȓt+==,o{"a٪6!f}-"ڒT` 5lbBҼy%_DX_d?b+< ,몘Vr [j@db@1aB}O/TK`zXe=l'8=0FDክ @4JOlNt G!鄩ĝ.RQJS Q4mjzЅġ"B  !akn$R: m;ؖEƨb(\35c_8AӁp^3ŴA 4=CCf25 _E'VV 7]Q;"R>@&Ʀ߾_5_F8"#lX~䀤! &G(4 f@(̛q4nE`.sX>pQg\GYb2&/|ݑs˫_ԠXObG.)GTÍkFAnE4Pvǽt_rSO$p${B3o!@ |BFQ*3\oNzs5^Γ^GxV npSįQ|m & dI :Jkod$C` <#w s@I~:}p\hԟ1ć> A+® J垟)#|y>B6>!Ŭu5Q HX C7(^P85A`-R K5A+(Wr B5E*V RME^P:ħB!hA `+lCJ eD!."A(l~m ]! RA_5+ FCXtC@ b+CDIAb++T"_KYFZ$@t5`,2^SgQ!!zv 61"zZ|EaQtfGCevi^VĊ (@~qx!4J8a{#C`Rp p΁U>& ;&")BaG#CL Ed"B#P>(P3̼^l"cєb|PMv1$0.vy1ARc9EP=" Ԕ΍PTD|cU5VIV# =HA4%S%C_ʣ>ѝ}!8.M $^ b^ PaZ7Z$CYc9`ddA1WݗO՝z]l^~LODEN<ł_EDiRBXDPC(wr%'BEcD `xR_YW2 *(2`C6do>5j8TSµ pC~g=qnbd]R(RS 'jI+: ƒBm2$G ~A.(aQ!Hj jÊ֓E(6i2:摲dOuymA"o>}4tYDIb%^iPtCQ$iy&{"LBVHC=XhAYn^#Ce9ʃS RQ4U<E 2DN̓Uf\Cnf#z`aaDĪu EC.(֖!ڪ^֑BLkYrDZ0 Cl@(ZK>ȩ)=X=KB ~Dk19©THj+HfZF/>Tc8[AWHlQÆAYz[?b]XƝN b 5:f]a@ Z=%-l*zNVhUD+T!-ʏopZ`bp4蕂`=yDv~n.%UlP> Z"**l=eΨ%5MYP/`Ŷɤ&^.8H2nW/P]_Iz,AhA4CeϲlЮji AZDۑ&S.! FJz&>>K0Ԡ"C=b1UfF>/nʫXa h+ꀤ  3O JБ>F@18dA *̅p1~'BB4B9p\8{3ss"ܜDB[:4>q#g WMAgE:<ĥ0!^N^8"6R#~f7LNP/ Hߘ>tEGS$Pc3YLR-|H>tOOM4HRmP5C^3&eZ? Cj2.cA^:fdyQ ނʘE G7L_hM9W  rfC}&?z>D:Ĉèjv[>7쀍O`"8qW<jq6 4Q6l:8V8+hI _SrPDfCjC<;jd;{SWDd6;Kp{†X=k=w؟g}@W=Ӏ ۗ7}N4=Ox\i8=՛} |_}s<@_>g>[~?Ws= =Տ>cϲ *]>(ct'x%sgsՏw \@a;_O|?6wk6W}۽=?@8!" 7'/$-lHĈ1fԸcGA9dI'QTeKۧ_}xjU3^x5h3U4#փi}F:jUWf*2em;RެY#=Q-څfݶe wڋr]*;paÇ'. fm6y(Qc>c~K=tiӧQVukׯag}LBeOlx7 Ǒ'WysϡG1M|*FtѧW}{o?th>O ,LPA1rkƚZnºA QITn6l'?j8 yJqQIl0"(U$Š8l'Rbz6~܌ R1,3mhl2^8U'L4S=쓵˧3,URU$G!TIE:t2 zLyʣTQI-T)I*(xi[qU]{'}'!'P8Y$^Vi5,ꋈc2'W3sMW]Դ t[2UR^$ u}HLjTtN|!*qWTeݴPFAYTM(X( EjrIYiN.``UŇK/a'Oy桉.hmM}^YS;꫱z*kRBUPi>%Z>dM~l[[C.b4ˠZ$Lo|ZKcUV7^bf9sR: jYo͘ ,1SHTy CP7s,3݌Tߙoy)|)! {`o2}HcS"#W=8ۧ!QyɰY@5A-}"NA Np*UMpUIX> %4 cS2Czv\&Bΐ5ljw-7DbA͆E4".hrܢlU""~\y)5f^e]7}hC'*҅!ęu䝥R4|߱RA;koa( F=BNmؕv kpxxWIQhoI me=V+RΒ1S"Ai<<ɪՒt/+Lcr7cN2`Ɠiq7ɫq1P-r1tӜQj2wfM&Hi P: vL9E EmĘ4xTfbΊb%St`?{&}hRDh `]j&bD(Mh&6N.IbNFqsMU_4ڤVQN37#y<ď;OۚWbZI=a{5ar`eDHM#Y"; $.-)^-ZDYi=g *hukGbSFN. ^g[])̐V[-oWA.8Nw8L-aȩS[w)  s@wd'W˪Dz]R8笉`6`/ v!a O0qacCAb%6q9|b-F06Rb c2FecOX;&0Uc{*Ά|`$'Mv?K.r|d,/%ʼf1ckc6ќf5mvg99Vs6 Qzy;υ =hnI&y^!Ec3#ӝ6*A{z]FQD6oԭv;-$X֕2i̹4*Z6Vؤ[=ldzfM85j65hGvUQRXzxզsfgsyyV,;˻B*\lxzas n9B6瓂#77p+7`ZP Ffc|BhGc{ʎsՌLdHųLr@ r;ۢ(Q{9 =Q3:+g؄&X,p`꾎5ml`>gsvp6yXoh|kk'@ى<~B(sF`1. +BcA>?" i~;B;?g-j߉ Ǟ)ڇ) (;r c _통'PϺOAC-No@N.,5p'2̀OGL0͔%!Xa0 ` o wǹP?0xoD9~ 8`6@ OOܬJnDb` j iTApp@V&֮ ͌/ pmlb0 A1Eq`j / Q0 ό-!gq4 ٰQpHg O2|0MDQP vNVi ` v 3z8J @pHֱCϚTa (PNLmLaf N"~/E  S!  QACSِrKE 'v*!O "'[Wirs,qQX}nh3s2n5!'|e"!wHtV2|7Kge _T~xxԎej%M\t͐NE(Xa6 y!uaTnuCa0aSG"JwFh!mF#^ ܶvښDǍ 1 u!k!pmKz183Tyn?6V` A%9uLw.XUy!|C!ĔOg/!qOV(2!z)#zMjKAYL ." cBrРV[L3z/Hz20'rz~FJRIbŌ%P2M"OyeNtk5V؎sc ~r/י(:htOSVaEyg ӸCW@u'NNyPR g-i/S-{,z퀶K)i!PPANـK>99xSH]yG>֗CtL6R0ȑ^T.1pZ"ߠ>+.,1Q(z8e(RMG5Z0]Y_ROX4Ҿ;[55Q$/Mix|!?y[9V!> LxG)$~(QU-#{el S0w LqokKE_2w2VqHa'/$2tWe Ìa[El}f27,W}!]Τw E#nV}N_M`t_~']jU{%o럞$eRq{{o]^jQ^3> L҇Mk,(j] }">3yAmTO5GE؈P TzC/8H Q%T\3‡e7޽=1g8M <0… :|1ĉ Q51ƍ;z2ȃ0]* Z0TM-("/#$eNU(0Ж"hf jQq֧Li6Vj ۔&ؖc>܅ ĄsMAS &lVJKGQ+ ·C?nA)܄I/ --5j.0G]deӁPl p9s+Ԛ*R:B^ `˛/ۻcɓ y]jZt,@J| sI_q-571U SUe֒d)R(ep@P d {b\<@XP*04P-*E`1 K- WD"tZLNTaȘ @4c5š)Q@?R6 NH-% ˵@yF5Qw%u<ǚa5^ƑFM^i hAi*I(1 '/dɋ b$*HrJ)\ +*PD**9dJ)p(mɓNDp2RRtv-&$KPnm94DIKr+T+,CHB;ALc Ckoir<)* C/.FߊDr/Q31j3HoX3Ǹ)G\PϣMQü<;PEQ Ip)ӝXc(JqT,jq\0qd,ψ4qll8qt"7!KqИV&YcR&)8U",VlP71.m"}\3㙴CKmˤG7 *K 8: Q3D)XA2Vl) MiPZhEGZɪJ[Ӛ8,wԜq7yd;s+Küs;ƺ:ֱ(r1ֳ"A-KqD淛|O!)rƚx!W8͖1hgҘS C?[1Ow-4'^U &2.p[ 79mʣwE2bT[a9{튃p1~[@rL_hQ|xDOuL@W>*'3_Л.c{ǝ+ۡHMo]dW`X Eq F({KEG)ޘM䟨K N}lH>DFc-i{u1p51KUEDހ$1QyzE&!Eawxvd}x'}PA}yau7}dyt#x!E~@W>!-?V`U`Gzx= (bcFh7W,pQzGE``= sXVxVNpQp6PV"`(%ErHdf'8s>剄Q-,EU &U@E_d;hEv(Uf_x~'--f[!Pu% O$ԈE ](tk(V),lHfٸ%'%P HUw iw^x>-q`Od[-xh\5MV$)~v8xE*pH8WI PĎ1upTD@iXՔ0錕5 ic^c-1 P~cV\g0f X 8/KXnA9Zhkmi1!cFk q}FRQUǗvP|"bu~i l > 烄dGbI$}*R UGE E^߀֕b^v{USO`}EZ ù|\XZWPYY@dT4n8 0u։*9O 1"y& q\#p[ta)]`4rP\e^AYU`]EDЩ)lСɑiUd209p IèL^%ZgƢ U$uw§}緔i&R YdiFH^l:EXTkME &X`ёt*pv@q\IT"wL)E{VV$^kEpکG;)QZMn EmF}hBـ1Ak*F픪yɒN ZE)󵈰09*ED*R^OE`^j¹ =٠Z$ gXw LYm&SDQ4^yk-Q:Y*EHNzP^UXtKS\U(ƺjZ hZ4 iFbrJb-aZAePIEtU$;ٴQIWQJ^V{^Y(68 ZwEPwPkO7 {GetuQOdP FwWq~% o(Rp PQ ڰ Ȩ`˭=^8rNjKUbPZ˹;BxbG P6 kEK];۹oۼBhOދvU7KjU(Zf[}KaPUD{+Z;m'oAZ۔ uUד"Y^EN~T&UVhEW{TW,TH.6ՠكE[˪ZԎۮl܁<͜]DmȬJ ٌZf7|KZs뾡]猓smO-o|Hy~>]X mXtkpሥ.k;y ĐmP vEm͡]){߉EjZ$Zڽ [y_bj#|zN5TjF v2Al\U>;I_T̩1LNftEv.EXʔ['{͕~wkh$ LPk5Xfdv0 lê5 305|@vVXDn5,Q C9@hhҁ?2xnZ>nj"@͆\pFo]P3Y uAd3"G'^qɕ/s.Ôpz@CtWP{}h@o],aԨX򉳳oonڏ=6"cD3򙯡KpB`d$ F,z( K. F@lЋBڑ1r3+@ŬΡPG2Á6H2Ԉ6%"u9Z6Mh150s<(ļb|.B70,(P#|$ŲBe8"m/N?:W`v|~i8I&۬8X؄(@Q 1ks' /lcDӖ[o5"wj)$)]pR%Ϛw s-ijce h@kV^zV+ 6x{ѬB8cK8o.KOwub_) "GYe}@0aEFPGlYna"ajԋy Fk̉anxROΎ(дLnRFک)Xgr-$ qni9E@u9g{T|Gkc.tQˈˬB+$#:'\0C1xmiYܙK7kwX裗~Řl)GWIm>qg|)|GtBN}t?NGm.wcá;yÀg]kd={<'yp~ T0 CcXG0eSL:q!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,,=";1&"".;1"""754 ,EMVR(f#v;r1k1]yDrP.WC4DNX*Vh#h5j1r;u5VGyCi/J`YYYJLLTfntstjkng`Y**/OANR2X&h7i&%R%]%R%R:V:R+R%o%f%y:pNZJRWRWRMUrExNqSqTOpdyzrqxWfWRYUfSv\vf*-XGqrvoy[Ҙ\ΔMܕnԑqwo{ݦsALN8k/kfMnP{ix $ :/$Y$O/j3 J V l]`.(((+:'Tl|JWRlhbVJyr׆:sRclhsnz[h.ڏϗ̥鴎ʳа䴬⛢ƗҘ‰͢ӦجδóϡԗնȰя犧̺ЙϩƑ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\Rbvbګ'=|ƠܵJѣH*]ʴӧPJڲ8gĺS֛7JٳhӪ]˶۷pGUL8ݣ5f=w LÈ+^%̞_ΔWck̹ϠCf;֝jѰc˞Mۄ_fkvǒȓ+_*ݞfF4jۓ8Oaj{Ӳ܎/^`Ͽ?xC |—MN94k5F(!Zݤzf=݄ ($4^5^_>zf4h-_|Di䑆Xπ+&$TViXV_؞ ړYihɐnud,7tiDVWMJ1xj衈">}GK !Vj饘V]nހӄ5ijꩂ6WXӔ*무5i^^ 6+k=)Rf[)Nچ+jr!.N37Y% !;+,K 78yY E'gƹm | isl(Sb}&%,4ۺv%f=N=5-)գ=pGPG4s\w-s\SM{.;=[{3k,e-5oU6|l߄/1u_ڂ]> --}.z[v|1>ꬣJpNX׾=(7nc `{'?$z6yJ^Y%J˝w}~8VqoؚВWǣ/b:|,:yhwH H:hҢ]8h>ґX wi ߞ%x _>A $%eM5Ĥ&G?zwh$*h [¹*g 4.E' f$nmeL&6Rʌ2oF9C61:W+ۦ8E#::fe@8Z8I1o#d*OˍI}ςM+,L:qCZ@}ćZЋz8L)t~S 3 CL6l>!gӧM1^OӐ҅^$(Q*1)S.+p$Uʱ0NٞRJ֪ XVgfZJWaqOuU<T׾ޫ+4gcC]xl%HĊKkf-HRKL7KZ_I둅XΊ3dOږVVuO+,Ky}LֽsYztan=:a SX;xyFҫ[ػ+^A( ([xwj7`%PX5^aX6*J[Z ?NwU³Jxr]eR2bzPhjȡ2*b0y6b&t=35M-GαZߖ|π[g[b9Ј]1]ЉRƫǒδS&Rƚ[$e_᫨W *j YM뒜j-ԬkkVldWb%# 줴2N ԠN 8PkF2l*e5>68c-mrtB]g^w]h_&H9q[wr+ N9C[hJGnh/5L7)~[t&B"1e(G duy(d+7}n#ytԃCuc5P0vܰom2蜓(wArWb h%}r(A C̽ 7􀇭ox88^x_#!{N d 4oM>rnr{{rӡ%7|( Ƴ;UWw2C>lgÛ"_m=\>(#O_ 5zb@XtAzws`-oU.i~W?Ev07~| BpIp xKЀG  gH7}wGV"+<#Pz&6Jw'H~tp}.hs 0Ѓ>=ק{q xn`w x3+ rDl7An ,|ln0eH}wr[P prާnG [' ;1|x QpvƅvnzxC\h@}xG~ }H[c&F)wGo(zhHfhX`ƈ Cwxd(nDŽ U8UAC#W7m7p}<( q8xx간WuF؍Cd7uUjUhl03Xn(g1  #I {Q0ɍ1xwyDl]&xzlhn wmІe0㐓)HI!O° }`xnP:F59e?مw svXnHQx' 'Oc)Sʭ aJJz*ZJ+:@KðFE  g+Ȫ#QA@=p_@OA\~ 77@&\\8I `Y^ / P1x- 4H<*Dap=$8gbq.Mw`v0 g 0@g˻˿ g Tq{3 elď m쩟ǯ7 4@(\k z ̨L; ʷP`χ*Ǫr M␲!ͨp ͨ<0 q|-⠵ 6<Ьz|@m/=1}V/4yUga$#i:pJ, ʬL ho hZ Ϳ%+jm~` P\*JP ${>@ 0I4!t{'=  z|ـٟ 1tZMA}کtm 5ϯ]-@Sͨ>p ;5M 4@ Lwנ[4݃tbΕ,L gͨ N-ߢJ!aj\ 1g* zp%Ph)n DK*~,/~ \@'Nt*:zڭA JDu:J± ۼϺ1J4|}_=S4VNg.e~>- @A#G{vNy@zNcN)snsM}\Ҡ.~4 KݡΣf9`o%֨7ʐ{ׇz˝(qN񬌺*{)[wͻz\ƝznM5p t{Ψ0Dp!]pWwz׷<گƁݽZj! Q~ꑝpl^NG!M cl̓ʎ!eh~+v0r |dkN V րu/] ;UЬ}p5`-+` p 0;n[Pf vjߨN3z poѝ>)ӥno ` ) 7`>Eo:[ȟKiO׺}boRYP a}$k V_{O @o@{  C s $xB -^x^=5 Cc:x9hhp# @ BCL?n14^t&ǖW͘T%Q釜R%O,x)Ղd̑VQeU#Sl-!s=xqjΆ>GEzp`I%./`tM]`XW/&_7rKX5lЊ"BŵmƝ[n޽}\xv?noڴV˝?~z ^0'xv/†-Znv3TnLp\A @CSÁlcDwRs#braH% 0ґ$0D8%&2 }\'Ð@LpH ;PGM1.cՑlPSijz k\37+C6`0Y7ԒŰE.iˆaf1, hJr,y s0ن]NlqE)y'NxԤ>~GG:o荛7錪Gx lC3Ѱ a3ѫRnt}wWr~Oy.>wף.{־\8Vɗ-_/ZdjSƤ 25V |~PD;/#;W'5l:B5={wHF24{лoǢ|ߦć>1~j9 z}w,#8n}|Tg]5~ղGSIM$|(L8LN< vp䨔zY> 4DT89?;jAtX[!$"4#dW@$()Hi::&+*/0A Vhl78lƫWp'?@DSB|h@NFtGD;?EԿ?LMĞA;lN4SDTDB=tLTYZ<-D!^_DܓJE`DdT*ĿCR\ijڼ],6!e&m#DNKtOit+R9OQ,1m%,#E2u7eliT&fgiT陶C$ߟKN~hn\e!^g&fynf6vj.\ggmE_h>fm}ni]|.an_16\MGܲ&]Fk8dKZLb)FgW^ˬ8SxfeSXt޸8VcancH^>Ol(f4 =M}Wmy.dfhDjaiV &\F eaankƅvFnk-fߗfͽmݛNcmfifPg%` d]_^ĝbC-g16]m%^lv[F^ָd\>`a>v_a.g ? O\3 qDqpgEpci]dM۬cfp^>b>\icv.p ]f\N,_f&6~~Gr*&fK]58Ui RnO83b>75gFmM`&hzfZKXLX@e\o[VbLno.^_nnHfk~9n$XkbFLPvX0e6 gVeZ XY_>Ņ\HZa-Fta.]!fS6mdܱh<px4=b6wwNl'ąoO\~h?s1>v;po1xɵxx&߬.H&ye[~f_cRy+ܥvb=^ɽy^Rno?c[t\s>tL]hn !wf<'_nUs6kW;oZiuhbPoWg&0vNxN | ent>p\"qoN5妾ktGŵnnET|77~߽l/\pn䅮cP0Q@`W H3xVA(GR`πDqDf5ls=VZe@5j!dӦ"8DW.F Æ [mcH+8jĘ J6@:$t@V d2*"iOC:HPhL4KJtzdVT6ԡc x X}mJsƘfŢf۬XvX7,޲O}0&ȱ4',X,&Xfl쐦D=cɒ\ ^Lr`ScN4ZpCW]ʨ+H7$Mvs*%KԨQ@1?D+HIW%}Uֻ$- Ty5hJh Q xɂ[HuE`- DZYW s-` !S heB=et2=[VؘLT`Vy$ &l(XMM$04@+ʸJR=UF8@+jD/qzfo֑Sj'W9KWEp%ht+FN7M1)-DRiq5!El5xe Rja*p9vX%IJV:)Ex&^T9G֙C:VlxUI7.QpH$k>ۛۺBɫ(hn[9TڔmW*ߑ2%yS):K@$BCY u""BP1HHa -Y] $E/hhxe{ZlCSDK&hϓT%8VHdm%%d4$$'F1.`2g,5E 0 ?lJy"Uԭŭx'%` qv"ӂFJG+'–'xCD^{_o} (]&Lx^"^Iil]>ZpOv!)&H|두Z'KDlfC\V=ow!0">%i=倉M#1$b6#Q PҰ\ JnŚ ;ƒjL,"B $>=pA.sU2QaEB,K  w"=(yraaTb%F0KR+9506cXSh\59 2Ǣ(J̐)DQ5X|Dɓ$ɑ!L$SP1)I (Wb$cǶ lzdb(U` 0̞1L(Z 3+Mf /&kEV>F 둚ҥap3~/s7'mz)STK>%ɏ&tŇnl! lQtW| YIV( $7D @,g%RP.yX&2aDs*T5Pa9[ ` d-,p N$+hYo3/vX>ROSTX0'WM|ӽ0F(4戁lSX^VpoܤY+.27b( !P*\ʻxsH&zlBspՊY-&3WB)*" f$TB$2VɅ6b*xw͊xuVN$kz=^/}1'2FD zASxq1R_l:ڲp 3 P̍jmJ"D V.9QT! +ƴZ2UpJVG9^yY 1XDH N+t PDg/".Ȑ 0 l=*h@F$@HTXG*+*E*D|~Z 2%A7G Pʄ=h*}5ڞX5 b4yʤ$FS 2&RJBȠ#K:8X%l;GLjݦB(NBL$_ 6&KڢU8eeʫ 7&#}I9tM703>Rqv[C@<$&!Ir'r<3(Eѧ99 !b%JiQUfC zIj裍d@>; U`FXKhw.c hJ|I{$"G,YJp& tH=&WwzPlKd= OTyxxϚ:ǥ6>(:mn4O(XbٍdF!RF %HJn⹏요jY)iuqʯQo_Hd߿Ҧ'aj^T(Tɽ= q$FX|"A)uE*^bEb}Ǡ!) RLHŸ G@}LJ7[E+L (p1L PtI U̚5&Ǥ iŨ0X!m?ERdD#|I*|4ǀp ,[LLJ4ɤ8N8kJH( jkxN#Ea "X$#]"]UD+ѸE(D2ߤȔXtlB&-0ʥl$T5Xt4,a)a-PKY|[9J#D9FQQ]ĈRrı^.K f7?Z5q,$˯i54]4DoiY*BR4x)5-(؆*ĤMUž=\CM$^y{"M A) tT=BL:?)M$eB]VTC*|eKtb˟iKVlNOw{ovMh@̷} ln>CL6EL$@e B۱ZN' ӷjMC"& pDH)BQnK@׷*d8Ĥmpn+B5<]*JA9r`]jR)d^+9 9s4>9󔈔۟ 4ySr9L&RddCO~\ K#=xOyӉ=ҞCX \BjFp(_幀BKhυ-DhP+5jgRDUʎ^ Z%0rIC(DB(b$/g-IXT1XЅG?NLtwXRJS0&X%'OJ_sPp Ej4"JØ,P ֖)nM)ؖGNc` Ol4L[XOsvXĴa}-3mc YD7LʻTs_z)W6QcO(8f%l,F:%L@ {{^F;ki} o4DOIx 4T!wZYu cOL)_L)%UKix,W:)rh/LͱJU^UJ,#[)Ytb$+m{AJ@m̠Vy_\.56۱ [T*o=q+lZIVR<-,EW% gzhNI+&U4$,S$Ux v2Bi JiEeeejRZI0JZM8XN)ɂ 3`S8oDL-, S"d(d60e!*5̢QH Ψ' [4j1oJ%0Ր<#K#?xe#)+Ld o/74`l0-ٛ ڡn QeGlPMh3'X)J/ܓ>O5b4Og VqnV4E%B]j$YK׽΅Z O lhCP @% `%fDI^ΓUDD/onNq XA\`|¬|kjWnE7"x>2 AjCޫ * M 91F%"M&L\!$啧(RbG0**at&F@k[1 /HS(F NAEPBܖA^QUV sBFi) !AYRjRS &udvҘ f2t hBRԗ,vip1bC@>VL Q8MJs6\g;{&1h^e1ZT#QLkؗYR. 6Êp/H /ܮd#9&ϢAUf~ȡRv '5!d/*Qۉ\ 4JzJ2B!;V<\ 9XQPu$*+tR VLI ζBU[E_`MW֓`", 2SCwƃ*-JSJ,KCXPw~6%QO'qR*mmFi)M5-4ld Aֲ$hFJA_QԀydr-ł NœNh5}sWNY!eLEU(VTt;ຂ<`Kt rR KsſbL3 DK)U=̏5]P,\'b'DҾ8)s-Mlhp cYVWR71q|'g؀Rcܾd(Qg%  :%s47]ȥ,ft6q)a8H + \CJxURfIk`>*jASĊkYwͫ5P4Gs 뜰Zi~鞣k{UWqg]XSTL֗;JRW[Ugne C.*L%dzchad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,l x>z Ⓡ!JM}fO|;Bw~}wٵfg;-wt xpїv֍q67q5 R}BcfG^< Yb֤&! -jN`&9ݘNWhlo aeelydfo:j{򉧡h'HY&s:hs~)h~z_Bz/{ ii&z)R讑J::>hzhjZ**Hf:kbk`.ʬo6'tjiމ)©nV)z&Z&r :*B+p +zj1g'{W챲"o1 /{a,+[ 1(ܳ2%#,V/OoM3_jQ,H|tf,b)i7as3x{]rD4+7w-7*Cݶc3}q ι[-4ʻE]ᤷ. ;ߓk_>h{J:IJߊ<ֲ̮N7 =Ǎb;Gwx蔯M:97,/oj~75L:pe UQ w . ~uD"`4<ͅ0aP=t@O7!1"Fl %~LR(| ϊR9E%6:$,N"b2эO_7=glLHnxc}H@5ѐw4ߘG.*84ژFI~d9r3v2w bISjxa+D3~2t*KJ[|gJeHYznj,i2#*xm:2|d!Igқĥ.Kuќ\:Yx;hhZ=kMeg2Ocӟ%5:O1"혦#5e R@7"! k@ܛ5D ()BΣY#p `j k<0MP-l(Qi@sTA`nԢ$f# Lu]*XEYά5LШS`j, Q3m]A GaREWҔImVZX,1>"#L§{]jA;iJTŬ׷ŝ,SYS̅u\VӼ]-x+ g&5Dvr+޾oOWX}[8PEּư M=Hb1'b=A /qIUtXILΚ¡.=x4D%:bwŮq 񎙬a&YU2wZ3L岣HE*aalRH-fY+KHnG7n idQrT1,݅2:MBo(y?-31zW]3~\ #ateEgˈng)[Z4) "D%aR,HI\4D\_'#v6=̂X6ZuiBy\ftXKn+,vY=v\#,` aZ#1x f Uyxd- pzS_r^>kGZbJw U^vknrZ7:_tZ曦vUdvvsZdbmX'8;5C;]?Yx(~K?rNb/QCwHy+D!sk88#}}LMx{.w$wZxG}uך&so{2~s/1~#qNf gЖpc9~~`;vcX8d&fwzx5x } O@ys~8Pq xׁ"8G\|(H*,(y-8j#({ĥ~vw~Fc{ X {m׃mv0 8 z}H `zP 4x78@Kׅgzϗ{g1{p L z4  Dž6|gx68}hH[`(+}X8}~gW炓8{ցHXJh|ux1h 7k=H~u`[dݷKvz0&gZ{e<Lj*+H{1hWS#&gahHy<K^p7h^ ` hK` Ӱ18 @ 0 Ў0s L珫` pf H ƂΨaШ؉njوz̈!ى&xh.ɐ)!)&ۈhָ:XiHx-) Kmh, ֋!V v 2T YC9}ڨK٩|) _ ČSک𹩧:>: w~zʨuݖ3Jvv`W[Qה?]gZky麣)@9Znyxɛ:SʇJj^@ |p 1y@ <0' Spt X ɱy/x  KڛxP p@p,:گLj:Z Κ`_cz mw0L p"6G.u$v : c7'a.ǘ>@ʼ|^ .oܻd^ܟ\ /0xI`ɰXxu 9 ׿ݰ,8{PƟlN5L^oO5?Bn[N Do^:o]\gh7~aΏwv愒 ,J~ 4j?tG麮wC0 :pM/@_ հ տ)գ*@ y`ʟx|~ƀO//᧟ ~-Z= 7a^'lm/ΐڗۆO?a- `gyY M pϏə`*AM%,LFUav`"-iZ&,X4d!M4ʓ*YSL,]ęSNj7yJgˊp@4)$MN * 4 *$L:GM]uIʎ֨MjE5WVzސyk5eO]PtwWlpY:E y9Ō`զ]8×W=%mڮѼ_IϠZG%/$5l[٨(~|Yc# زڕ,dˬe˫6@+lq2 "J)VkBVpC's"/Щ až;o#3Bڬ,z Q1#1 oh;VHcT#'<ҸcWmMh DHX`j^ z#?P!q3Z妹d[$d`6^zu_u _h^\]ݙ?nR_̬iOeEߤۚ:%u]}n/޴vg b;lS m䦻n;nę}y㞛+oțmo-V;zo|a+t qS`ϚzgtGhT=ku3,G hw=ug~b%v7>z٣ sWx}ug?mmǞh`=ݟ/_]bR 8+Rq4usEPo] ֪ V8\Vudk`Ft(TW`>!}퇄Ç ",i O5Q(:1Ut"xҤx,'?׆U$lLW64XOu=zvehX5YE:+ִ 4+k7YV=%nk+[,,!ZX֟&Fe:SҸr+XGҥjz&EM5 p{N7VWx}.c]vm%OE_?ӥif泒edB/ ?sUol] sq=q#SI6q3G;cx o~|긣]1d&3a?XVG{^Оx,d&8ʥudJ)ɖ|cƶ9e);yVt)lg?,o`+'yˊD7ь!]?R3^ks:ԼCY?Oz}iS5-iBxִ}EhL:ةf5_M:ơWid&{}8gۗV1[b[ۥF\sxvl7nOcژew j~gw%]5s$bS\kw#Qe!`K{6ɎMpjSfw[o]iʑ}[k˻ޤILX4<5Ozԥ>u;Uz֩tw_z*Rth\w=J;ڟvE}+{~˽W;ӽeݾxƿ{y7Uný<ooMzַ}e?ؓ_i/UgH{{'~a{~/?}Wз~7~_|BGy}~o~G$4DTdt@ @ @d$A4Tdt !$"4#D$T%d&t'(tAo0RC A B+Bz5d6t7X8<yo`<DC:C<D10D8HIDBCa(zȃ4$ Ѐ94EAnhHRVlE_@Y:l'E0O4@MlN$mHEZb4cDF&ED EStg2EDE(,f|Aj,i\zAFoLudvtG\Fu @p^plFsL@z a|ǂ4ȃDGgz{TGDlǁdƄȏI\FbVE(+G3lN/CE](t?A}@xC^п,\e?|h ؃(|І(|IIIu?9T3 KhkLǐt˷I\fH@$JJ؄?N-C<}H94Fm? DP˺`ÅLE(9`HLXL#jL/L@˽dDK{LyM!kh<$Fw^`x&lNd{BD\kLk[4~c=Oc5duekT[>'uD>jnVEF0\tβ}H5d&Sw*7q3r~UgRGvWCJ@QhL_f\[@޿^Br`cXMٝО@2'dwr$fFtVofԽ%VRf6kC\[T[YeXholc1%ß3x{4{O@n7+[ ηa%M5SJ@LD5{tV5|QDSN@] <T$e-g`3IGlB& 'II|dEbӀb $Dޙ:Oiff!HAFq7=zڟ!~(ڪ=fHE #8Lb00, Ԫ" L5 7N|j퍱0Je*T(sOG3E4qmoނnH Vbx6k,^=ޢ@E:EW pɛAbQ٪|u K"2r( Έ<+&0QKyW9nQ$at+zqif=Fk|dz226XР(61<;A4z L@#,p)2$zNȈx 4|N"w03|Ȓ/WYҷWpGzXaA1Ҭ _@nU;i+a%*H=a $40C,&>1S.~1c,Ӹ61s^h ɓ[=p^A*e| En|[4pAiTqhxp`s BT> 4E1uT+B K-Ib5ФF*bu"@]Qr)O!Ҵ&c굜%p/ZR ɤ4D2Sq e`Iãa |ߵNPR$9.VbT %{I7ZKn 5/jZ~Bdhk6:Pԭ&" !-r^E濆9Tnx $]_J.pDN"E*PT]?ˁ"OpIrSqzUx"Ѓ#(F I2 )dE#>ʓ;}_Xt l݃:.ƈI턂C֠3*F@ 6.=B#NB渤]B4aSPdDbԙ$igVXp%nQhڴ1T`(UcFDьY( x*K#Ild86603lӟTԪD\|f{'bDՄUFcUkdF0Fь.$(c>)*B,z%NxS0<3&6-5~@B|/p>(Om~ȫM "W/C7l,$E%rs-PgdWɭ'z)Npaq@b~,,N870vRZq.c =6 lQ)(X(HYyQ+i@CfJĨ@$A!%J<644%Xx/]&3cNb%A>(|sDf( cN80.$c &1Cp=4>[~=P5KݳbR~FaENF" 1-?I0#2Lhۄ1AE0A#@`^A1q@. UU6&p`zCx޷ 'MDFPpsA:򫅾CF= 6`<Ȫ I/@dti{dV# W*Zga P[MLbipͰqX.eX1m5߹ ?Ϊ+1*lJ<@8"wt%yp&DHhHGރ `@적%=P86⢡ FL1K.;,n3 4<Е:#T*+ F5D X"Ⱟ!yAr :(K?LWW􃨩l a<鋓AN70Lu-_E1CLiqiP:)o@epho ,T֕@&c"rc %{VٯL8LĩlHaHnLM 2,/TA' t9+ IGs a}r.I&Ƀ9^ЩOP/!1I5ĩ+kʡ` _*6|>\AJpv,˾HEnť;R :4A=XWb5 1%#e}jc#)ՔePDK:nX8`&{hC%LkZԞ,-K쨏8ZQ[[EavV77|[fvgmƅ mnr#;m8bu$k^hڈ{m#m%[X.-pՉ2\Aw I(jQuӟk4x3CW",;dXr& VXWF|P rФ:|@u'8=V} 1:0 z0PW$9(V̘QK B2&Ru*&=2e47 =hd 1oC?n$arb<_:ƈ7V-0KV Y|̼"UγA,2o It1،B׽Δϰ!tYQM!DRФYڞI\X7OW Սb\}k~!i,koX4?j[FؖV]n%NoQ?M(q p<0MoL:vWDq6mvЦ&ȹJoj{. 15yu".^.BC>pdݡVxeCPKq%&>9x]`'O\t&yøw y̩GobY>"I.\RX_GpîgO;&~5*U/>x? I^Mf/l= k5|ϥӘ5bR_~؞o 峣RW>@aͿx##{t%|B pϏKo9=Zc>pIB@RBHj!= epi#y7B)!t  v^Ʞ 7ڇ*Rxc S ʬ^D ' נA9Ax qRaa |aq)p-15q9=A1EqIMQ1UqY]a1eqimq1uh \aIZ@.v1R ٖ1q InH1]Q+*1q;1q1qC+Бr 8 r!8!%r")j4"5r#9y5'#I$%"""Mr%Y!D%er&%+&i2'u2m3pr'2(%KC%( ')#)*r2%2++3)g+,ђ("#2. 0Bh$r/ X/s0G,b0s1Io2!$1-21335s393=3A3`4 4M44K5Y5C5]36es.Z6g37g(6IS75|8Gs84oŐs53:M7:=:3;;;L9,>+s?3(o#? t&œ<ݳ@4'A$=tA%#s48'4Cg2B5C)C=4D@ DED@DQEױA3A]tFQ>Ci4GEuGG}4HHHktedHA!GtJuFIJtKT!LtLɴLL4MtMٴMM4NtNLNMNatP P P5QuQP0LN!RRR5uO'uSQ=P4LwS4RALM5T4O%5R5O5UɔV!U۔VmPwTkW5X7RtRVTVUz2R!n!Z5ZZS[[[[ŕZÕZu\\5|[ە[[u]^[][Z}aZu[_]Zoa^va^[_A]Uab`_b9V]cu_%d+vd!^5c^c_ea6c]vdCdoZmg5ccyvhUhb!v_[_AihSAi[dv^6jvjkR6ZkUl96kmͶZVj6aV_ǵ\6_}!_lg5L!V`i9oPAZ5^_!a7!HampraojqLqUsV5svltU[6qsI@7cEl–c=7Zguu[lkwhucs5ah *V 1]Worzp`!RpA6,kWww$7Z!w]WgCa(!Je^&[ wZe!j_}-VnA!#Xwkg{swmZW: ՊjxaGRA,|a?vX앇6"X[oaXTX\w~a3B8O6@`~w\1!n# @U@8*(x$) @[W\v[5XIV[wJ89dA`c[UA 5jN`Ux@:Zx `hk*}[d}!(9wn"Su(Z.bS&&Ҡ}_A 𸓹U׸![c5}+!@[x۹z\cxfSA%zbo nRP!#& wjS\6{Ÿi9yt6lGڟzx֊[qu U|g#84ʕ ֡pxl?*pS▏I_VrWwZP7٦:LY)[oxU JnAobfڙ@`!\UiS6eAq#u٫ukZV!@tyuVxW :*jVm;ZUZ}_o5a ~~y5>;cie:55a T`~Ub;j_b:!ux3o"NAlC&<{ASA81x(ñ5Qad^-A`\ $=so!o$zx\ǫ7Z8ZqڷxQYOX+x*! r 8|S!IZG!s`[ۗC!^|zAx֖Y6WZM[X>fw[?f+ !>fŢԙSd"uMp٢J_!S"Dۖ9`8{[w{ C7aA8^V`lAxLOp_B<{՗zX}obu*SA :i<}0-!gG[ZG',Z=X ZZۼ޼SAKGnF[U2UZk qqzҧy?>ZOauO\5jh9Bͷ:4o!V@ .4@S w/ p A#a_a!1I6/[3~7^㦢啣(g鵫 `9=h 8p} {u~_֣K`Grݧ6ɹq|a<[dw+ 5}-Up; ƍsl`MuW Z^20+$B0*+)0Bt20g!=4ҥJ_1EөTZ(֧:rYף xbIųh_ 5jUniHN!G}ЭUne]X(XS* aJ`c90-3wN2hi$Eh@r*Jx𢆕= 3O- \qgN=:д*>=&Ff͊O=TQ}y12Fȝ'JPV'!Ty9ukH^[-vna}+2tJYy&{ +mlhHa2*T"Ic)1ДW&`B&Ejg(Chk$B&04Bl0wT|3FBgv!BA)7Ǔ֙hMP A2 y8͉e*Jj-Dp)*򊜣LBgHjDFuq+`Vu>ap&lȂ R#eZlRo[d| jՂEh>g.k14[Vf^B%&EyˮܡJ*5bU/&{ e=b )!JB(U&IHb uYR^+0)eiBθhX%1 '/1ġR↦SC0'mFqu^VHit!]*\SbSC5EM;l"A|b&4-T/Ocr)J8^UvD>8QN_*Ydg*4Ehm['_ݱ/OWz6 d(K4 9qƋ۲GS k4,P1ki4&)&* -l0ܙJր{2"p&Hָ)&"Z jp>mbd'G@#\O;nl%) .ҿ -Ex:br m} ^H; ;L)UM`D>DTOQn>9Cv'""AcRg`)4{ZE`p*jr4< @/ /X R\cSx*;#)a*k_i(6+p: Q6F5*M qLx 2WD#^a?)Bnx׷>^̂[h (EhTpE&*T1vbg!fH^i΢I'u 40kmSf$颼,dhՒ @ (MEzTa% Q46\̠ᄥnzU':)vIVH*g +U ikQŨoYMYe|CtHpŜR J8ByJjN)k[T`v`8\3 QJ1UQ+( Br[1`SWOʟC֥# 4edS YI,dO)g<9u})O7([8 qW㋲ '`Kv 6Va1{`H橿W\]{bOEl»%/B/6gg0J8~Nw}^W~Ȕt?J?Ñ?UoYq[1oE}wFP}\FnVx8vxx>҇yvB'5&}ɂNW~(Ȃf)Hu."4gA3zhG,D=xFC(HXAN?!_ UYYx[[( _XЅbhghdk8eȆonpHUhxoh k8z{` X_^x@}8h~h\8Yȉg aXuH؉{H^؊(X]`8HHh(Hh爎騎Ȏ(Hhȏ)Ii ɐ  )Iiɑ !)#I%ip+ɒ-/ 1ْ P*)9;ɓ=  @`8Q)SIUi!4IJ906)Wigi ܡ Ȕ6  Q} Uٖ1suYeIIi"0\ٍ а wɍ0 ppȀ P H :R ܸm@ y 9!  A*NKyɍ90X!).cPɟm)xޘy 5@AOٍu)vy0Q.y71pm 1*)` ỳpMRp*ɘPٕ5 Ѝ$$ߴX 9cJem _z`Gؔ?zHZٔep bXU*y ݸ 0 Qf *RpٔOYH)G u噣؝ @ @ dɍ :꫿z 7*_کx vZ*a O ٩qjH.κR*q JⲨa ٩0 ܘjJPucyڔՙـd[y4⨫!+#kJP;M*yjJ੎J9JA+C{ɪ1ک; z1٤бXFz*DKeKbکP[p J2}XBP@ K`8 N:@/j z? N,бzۘ3 (K y4EٍD QKڡ[c)ܨ 7 yzWQ9 ]'A|cี˽ @ Ԁ H )⸾밽k˿ ,Ll  ,!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,l(8';1&&)./1$ EN\ToP(f*u9k2I1*wDhL.OCYl1r;t.i !VFkNNNDFDUUUQTTrPNLNvqqsxx}lmqcf`O.A+*OBQR2X&R2h6io2%R%]*S(q/RNMSVQSsGkMsPjstmNqWRnXSrwotӘ\ʎLn֝p.H?Z?H?H?n?I?AKQ,\7l hQSKmsluvHYHYJPLvMjluqT $ :/$X$K,n, J VjIqLNZcPusa((=..SkewNvmSdVLpqmȎ:Pkrjw/NTmrr`.͖̬֡⛣ͮ泬ܩ՛ӖʒĨкӼЭᴥҔүˏ̴қȒЫ֒ױͽ *\hP>~ BxPĉ 1bG,$őM,Ira+Oz|f̊#m\)R|<_ęrI>~)ȍIv, 4I +> R 3"rW#?kW7w*ݛbe[7ӾLp` аǾ{#VJǍߕlYc;#<:n璞ҧGCWͷA,D˫wp'79s㛋#w}ʡOv۷'^;u?.N\<߹[?Ν߀F|tYW zXup!u-x !_"{}mW:r|s."G*NF)MH$IR)F٥Vj9"6R!S &dYf`n^ \$gjJv)'A(}>)'#Zr秚 Nz&er:*u))>X**)gJg-@o]6F+Vkfv뭴k覫վ/kqޫ򛯲p LƓY+p&<?뱜C,[ ?wr,q$3\04kbLe=#t m O3-KGϜ0R_-!_5y=6`O5[sF] Ol=wU7#cvIM7Swn7bCNއS"+|# n9iN7܍ MMrJu期yo;lS%%@B +$|&PC#l|&֗I)ۨ;Kx58 xʮMC?uÚ~=ulC٭m{`?u+[@ς˟>=MP\EIhs$J Os'$ϕ2](y_RF )ǢFΦ%=Lkҧ*E 0qlȼ JOk+ *lf@Y[JM([jM(&S\c>'%yu;ETMJ,~}6'ԧZ2_<0g5@F44P7ղ&1p@13NS?R\lI?6b5 A%ܙ"w\dek[4ݮU#7a6R-+tUM9]B[X eY FխP"6M4/d]F*#յ]hB/,a W AlHx"*8 +T؆`D׍x 9miwM:*Epj'C7#(8(sx>銃]m:0 IӏmaMZָεw^Қ`:;?Q =5vWe_Zp6}lzaSafp׍ik0pa+$=@ O[SpFI >3qN _6;?z&t4ghx:MP\~ e>x4uw>+|bDU-JmCT@H mن9 B[G4Yvav_>Nuc9y.wv|u6^Ns“ծ-W0KP &iÆZ\ ~7~w'aW_̇s| ||#w|G8s8|'w zǀ ؁&x XwƧ{gxG}w#x X _q`DhqGyEܶNGrNqW?`8ar{Fa(|0xHѷ(ǁ}maws |o({ !~~eCb*v~bPjj0vHt ~jwh~IWZq[}5ӇX|u/'zgRI 9xٞzKWꪚ LTwIJJJrUvDD#MNzW+:ݖ`%ФXWm_qل ^`sjY@j:zgɏZS꯻ 9(\v&cqJZy۠ CZI`~HN*੨c [5P  r麯Y:iT9@;7AC zzViMɪL+Zʮ0Z'FqIПEfg\莄V jk Fʊr FT ʤHYژj9JWksj˳;jKȩ (ktPr u 띣% '@}uIxQ ـ;lzWK8ۀ~k;;ZzKͫ໼L뫸:Z9+ʸ{ـx x^gMPyYU]yy{L;;zWlLOj[\  $ǻ"L#l&Z)Hwck'` D>ɧ :x[Qk 9{,L!, W _ƎyƨZ Ž+L^¯)Q\ Z <\|4+Ӑaq X!Y &^xۅo<@E}IlӐw 4 cl[¢ ǫ<{Aҧ էڀ c\0nJ$b v 0ĕcٰq3  u:@ }LdL˰j_<ȗ[踳$2{|ɻΐ~|ʅ٦_^V ; GlЃh&Κh\IxN ϓQJ' 2=)=x.M8=9͛[ο@r܀jef:iа#p 9F<@jܦ%{1P pd ү7^ߛڷኍ~Ӻ;tYb(A<ܿ V[ќ 5 {(׀ͨFDͯs4ה.^6n4A&_%#o._6on(o}:^8CŇ#.C h%/~5%ut/?*NԗN paOn;~>.v^>22N|?{OTOUn>=דaڐPmWЦ]jb% @i--fN=ݣ|/V7zo>fmjoT-/-@ jvP` >Lx0Cl 6\XƋ !HmDMA]L)SJȤɓ hM[J&XyL(2ۈTi&қmTMÒ@JEgԱl*|*RdI<4M۝⭈RoBҭ81Bh2,"6{O{PeltvZř/W\`Z6Zi5M[_`6E@ Gim.gnC[;Z{ X!C]osaވ=9/MbJH(Rtf8j#N |IAeS>ۦi6KK"nϲƦ.?bT0LH:h5+/. [ϱƲh5Q*}fk j q<CM"Q!Ll<,U.? )|33G:%*2bstlN;UTTWL%Qr.*TN<Ͱ "_`?S @QL}'hen*D=8B`b dHfY!\?k} LbEElڣĒ_!ٜH)"`?`5E؝,>Ulv[db &lR07ydE c W$>Ued(%5*_D&Ϊ !ٷ />Oeg#]"keӢb.=HKϗ x'K1&o5D\Қ{(}/Nɴ%0;sF04+]Wfs%9%jJ3y Lܧ yM3/Lb@ Jr <&vq␘򡦻t@S˂hA҅T=WXR̊(5i}z);62`'BQHڹxJfkR,dIF ԛBl9P[VGP;#^:W9TMkXAOVhU\KXjխ*4wZն`;ԵfoMdMX5|5f=W┯b(iZW9e,\;UYbumg:ZUkpCJR- x[dUkzsR7,]ifݝ[e_ MvC=mUкEc)^kk#7]amf`ߥ&~j,X foe\U6 6[]=^0YN5-+}1| WqkRN7?'bd&ǦM^2e]BSrla,/]s<%[x2ɼf,oɫ(ٜejLis/y{s=hBz_25lhCיT~tgIϓ|i6;zʨ5YR5CmPժvOjV:֥ue]j]׿vm] [zFQ}cبusl^5-dwn6=d:ڢf6QnuCFsֶns]nSvw=ot#GE+Mn\zx5qwyE>r'GyUr/ye>s7yus?zЅ>tGGzҕt7Ozԥ>uWWzֵuw_1ac {ڡp!w1<6u!mT(ܘ>>x9`g,?%{ @5&T^|sNl7`g }eqś"?  pc_ `|@O>w8f?~QC.3,g?/t+=|Uˇ8~8dtK?<3s>?DT\@@@̼s8zA  d"4#4D38AB{0ś}5hø(,  p<_ۿX'X8;FRЇ^E&ȼH؇]xK8˾ ?DLM:~f(ɓ'`4XJ=s+< ֔MQ098z #KBSKĐ̼?p$L h˳8ڳǪ4u@MkM4δʓOԸ<Ӹ$L^H,TCTTK8 EԏKcRlVL?3SPdJRM7m?=ד՛OJ|(<7SbN&zNHC=>gmΌ[ANm؉uNV K$WS4 WΌXWXxPNP8WՒM EG̳}]z̼+0(m֋{VK98o@C$&? Xj! ?ڭ=<%U3S7H~a@vXr=UL3s0u@zKR~p <}͸a5,_ȅh(eRLԄ Pj4̳_|ot+?pՓ[U:=ӬExdGsmtGk9;[,Ɯ ? H܁eV3XM?@A&B^Aps0EfL: b(0=mLn~>>b0⏓:/lz`! xLM>:\>[> <0#ޑ,ZF:\;JNjfCD?Q8n?{b@i?`?8OVd{afj26gt&g:j:ffg|`itVVPegs{y@Fexk_U1y&.ef\b6;|8:(lEk_ Ypfwꀶ|8Խ8fgNia8CF퐫be\mE gV@_~8 wtfg^V2`nR^n\j-}gX߇2WZ+ne׸9]o'pSB}kKwsvhw,jծ&L\~{jFHupPynTds~fE?XpC^YGv}@mpgrq8|}_~@H߸~8ˆj ;p79^xpy&h'CJ/||?~wmff_Yhpbg }%l!Ĉ'Rh"ƌ7r#Ȑ"G,i$ʔ*Wl%̘2gҬi&Μ:w'РB-j(ҤJ2m)ԨRRj*֬Zr+ذbǒ-k,ڴj6]KsnB[k.޼z3cYC~0Ċb!8rn,tm(33轎OdᏦp5WGS\ֲw'Y7ʗomdfPC~ 19 v 2o=\sܬ6,_ #`0u9L~W# .,|ZxbD9FX0j0&z!P!5|P/7Iv!q1F! cf-P81(7z%L!}8ImܶiU&ؐ 6OxWAa'wPxj&zѳ–Z+~Z[r1NC,,>&(3/NWXV皶=DK.[:rp ۢ3&k/^2_f̡[Sh[h Wf@c9 3Qc%0"䮊T6lbarR{~E_ O?'=ٽOyar~2Bl+8 K>9[~9k9{9衋>:饛~:ꩫ:뭻:>;~;S[p 9nɻ;Cj<71*Z-gƞt'X2=3Qg͐NFVw[*a=311R3H_= j12E3mZFsҘ:/ <98b0URTV^+(HvPQ"n Q0)E*xs0:lP}4>8TU3HzzQ,6 L:7sxh>&Y=$,V}QrI:̡}Xtu%\뭾 =,b2},d#+R,f3rlIT"r0hN$(6%B(J;~X[-ؖ ,W lh#b[veAX 3ݑz \K%O8cdX0?~/};X)HA [}k<7Ov!2'HaLjqןG8pDrKY7eP*LDVნx[f)^H OpLA[g2\EB{^&[D؞ 2vo}"3r&J2 $Hp+>Pa"b$W}`XZ78.PhQ.0e4nb 0]+b. $L,ػd`>щE*U+9'mJpmLayxe OX6Q=jcOBRk:"pijt 0H`u{m=4ԒQ'0jevo ȶ=}!8ŭ#mlH*hI> ПwSixB!!Jyih0-(|8",zX; .F(HYdp7>f!{TO1thLkrGCvb`VC>"ACmӅ(&%,lD Bڑ=/d)"B(8 A5B>t_B](`BYy9BB$l]C]Ñĸ|!TɡE,\48D/@ Ү-y 4B>TPC5H> I, V.[BAQm@C Ct W--yۥy!?MZ\DaBx1Zĩ56D8؁z ?i D@X  AGAI=mcCd p$)~*"Y Šc = $Cߵ:&Dzۃy!=aHxDB}#V:! -C, $yCt nHrF>_IV ,:D D !9Bd+i=Q_k1#mdc3U%D72 55lC-B8"^z*aFDNn$PЇC04P.z.E p Odb0Ic (=*$AN?C C$XQA,IAh&6C=w_ѡR7ڍl¡zU6V gVFDċs"8oZėy`YDڮhy2qH3ÓbwfD7L0hfC$B&Đjb (̒_BJd鲠/ݵ>d4̂SҖl6C*<^=l1EA; #=Wb*'JjAX7@2L%D/éxl_' (GЃ[rz`K&MXFzE<ӸiJ邲$BMEC,fZkЃ0XWCvՂ9jFrPS:*7dp^r[ChEd;qXGCqH4$D=@n)\b`Zd~BdǶiC^p:?GñABw[$ޠ &AmEBfaPV= e 7>Q&qftV ~`Ɗޢ(dܶ<Q: =Gc8LE.aӺnAx]yEgAN>CJSR.jӞW4V>pn^"8P5"la,HÆ4j}>@Ρ-F<ӜL|m) E 0o<_ DJF=0r߁QbI:C#rn/>lD6[JqNƌ((CnN,2l5C-pY_nøQEB090>C ٷb (5L 80&7L6=P)Ј"*QͭPBC[@Щgo wuFA_Z|A]@AύǶCda ٯnHX7ʏ<az:[)rM8"ښ5dD})BDoDºYHp>(>n f )]uDCUGҜsD+<ȭe9CC3jj>dC2eCȃ6KnLC "v8L)<8l6Ci6M/tJxtL8uI[<=pFJpFl-@_>< t5P$,rT3u ؝JG=MG]]U5O\7pԪ5CuG,X=uWx P&T 66tM_GXC-z K'̀ A+GD>>z/D8o@qCNgfW&4U]CwAkDm$HLIJ;:?H{ĿC;LB*c1l 4&luӎ!έWS93{'˿{B9&K wEt+tI|:wD= 8 ڼC̳-tB'$TBB'A%py##ñ9-9 :tG?|G9\H#}߽ }f6$]_a3678B]z?_@ۧO`A!4JEVO v󫵫@[| [#w+`z`c-F[A7EJW PגNZp蠑͚EYnnʓt|BI}!1DezvQ,`z?0QJ>zĩ y$$ApKoe'"9L}-;h⇽(aqǣI,QD$h­ۧI ab aXɍ`܇V3>)1Qa*qʅ?b(f]^ѡj033"ۧ0,&1έnhLC :kWzP!`XmTEFJ)5/ n' %!g 20!)4((+n ܃ȿiE>-V? #2- w\{[D߄ ^ն.nEEL!XbrE* %҇cr4cI$$2&P}VT`BR*=r..p!~Hhb-3*p⪁|֢Bj>u+k$p⢁馽(3G @ ŨV(=PjY`~(}vRu8 |Pf)e )i=yX:IٺMh G.Hh q/Hx!s a;WcBxӟtuPܕ' \sO.|w+ ;t`$_Wd1>% ڀ2Ce"VFZ]YvBB0">~faI"M'zMHB;ekÇB!ؠȡh& /xǏ|el@D:L}G 7q&>RIN"(bH/>8\-k'9NfY{p`Mw<| rGA|=Oxo$()=A'#,2 ݘ H0\"9>`Odz9 KŲAx,^?pԅQv4+<;/&}(A+7(0B:Ak}`MVVhxAaNOY=y.7x>k T@([P6LUQCzHU橾9\)F.FJ'<1 T%HB(zN>op LB1VRI| 06 $@k#G|od5Y1P۸6z#e"8n~4c!|TbP&E1h%4y0g U !B(zTn-mVP&+yTĈ`-+ZD'#Z1en$%=5TVƌ΅ VQ+ {:2$JD$xUS8nMtH"'A\ .PjًH򞀡z'AvȐ=8bl !Eȹ%@k]X'"l"c;|D2{@ 1JI3H#΂mns>wƉ1:K(<9О=]#pM*л Jks@6Zxy+84 vknsr1즀 n⫤`&2|-N !%a#0.r-X If% X\'X %b L*3bn,n$дbJ1 1 2P4b {GJ 5 5 5c (9 z^h #Zp[? be`p'*zN#>ƀ T)MMJMuDP ,g5#6iVifSDۖ6jIZuPvؤ#&ikvlaUvm.!]!avnnn6ovooo7pwp p p7qwqqq!7r%wr)r-r17gA>`F/sItMt' uewvira@ vk7xwx pWw#vxyn7w-"zyzwfy?w7{7|7Q{{7}w}o{-By}w~wzѷ~wwDܷ"x  x~+z8%x|˷ x18)"5AXv9x"<8M+ׁ)Q]qUiw%mxy8oc8gxu;8x8ga6a7Xi닂P=v `ɸ5^(ٸ1֍8xbU`U O 3B9%A'9Y6a0YEa6@Gy+Y9e혖m9XRyu8J{6AP٘i! ř]nY 9͙{yϹ#Xyy8噞yyy}zQ zxYWO9!١-z5Ax:IrGQqaVO:apc!Wђ_}zp{j:z:z:z:Zz:zګ/:z麮za: a!;%aXA&;5{9{.;E{IMQ;U{E[XBG[R0[q۱?;s{hS![o{;۷[S[[/X!Sg{]ۻ/۷ۻIsu{S;;'a\۽۶=7y`/;>T!]W‹|[;Y{Saa;5\S;ܲQY%}{`N͍Ga5. ;/{= '={6i~O2yS- [i]|:FuMY$͍qݷMY8`V{AקmE|Yb2`Q[m}E̓՜᝶ObD=F'[L!VAD>WIg4> S!4:`-=W#6UV4|q=K)`ܱ] }z=̕C] C-/@LɇE>.`W!懾E~֧chm~{>a^!& [@@[b1eE4@S>&_Abb^uAWܫS P#Xփ`'[WwN+;YD/[[~ܯA[g?k?忾={ޱ gAhBUW0B RTQÿT Zh.SyJ¨.fPEqcAfY $ t lEXɔ=R,U+sĨ#ǨRWY5U9SH8S&RjS_-*I H B1)g=D$PŌWjcQF= pŇY)ҫG=o9sU+YfMzX`* (%R{0YƁ*v~QRrd͝% `M+Q)^N Uㆺď.#OTο\]ovvQGj;ʎ^Gm5ݛ Wn&Ӡr/DRH" ĽB`V* 1|$(@g@"i 9!$Fn}iG-R>ÊYD20ygᝰ+Y ӨgV)| gf y(/~Š1,5.6M$JAttTTd%K*jc_@ OpFtBaQzNEK 'g'OL6;R1pIUf쓹mdRic)T1hԊO1<$,YRWr/+ԧG0–cߒHQvﬢbILh^@BHt$XV҃%>w3Jϕ U'Ř20*ee2CCTpRWF&J ϧHj,I&YX # ʵo{gHVH(85!N*6; '%E.0XT8H˚4d'i"21v=D(uIplE'QdyY` ܟ-K&4^JQ QBDkv5ޅ L`VSy2[f?zDtz)B6R^4^4+/U;Wy*6 T\2!fVz͂~ F6|£X/k k?V$2q\6Q L}ord×+,@AkF|eAJ\(c<"D"!Wnk`q Ag!j@#0A\Æ!#M B'. T IăOu]dKAE(<`YHÚ&)MfC8?|ƘLU"L6 Dɓ/(ِ:4&g5/ص\,"8u 5+Bq}D2"ilR or+7|l!pPM@X,i>%*RO֑q Q/׳IlOZg:㎜3D|Bb>0BOVg0U^s {Wk WĀCR-}eK DAW/l(E G!e2ӋjHwAMC3! BzO'!5r.rr`Wia&p+0sDv$Ec'SO*v5*3e:΅G OB4 955(u W/W7&"X !:\` 6.bR (39h'-qJqV53 @ff:bA7rsj>tGaBd$V!O#w ?2m[}'8I p'<8v vWC38Bv@CvW|UT73AA1t9(>DBۃHJap5,AslB BH6{SGEeHuaR?e#1OChCD@V6!8. W{8C CIiuH#C_U 30j1pDx$ :D(?ʣF)j5v<>a`@e-W9qG!#REJ4W1\V= :cApx,!.3B_)i;C(VUH$ -ۦR5æ*C1i ARUvq`X@(НW#TDcH%4əHæj?mm.IVP %P2p# .wU@iN.S Xa .66wGx"R1 ze`I24jNRsG+ I;a 5xt`=S֔b cV 2$Vꊪ01D1 C(0!J "C $+6Y I=*;M? /;$)rAF\d$F]9=!5# su h 篮qr&i\9"9QDE]wA/Eql+F awek/T_[tvJ+;c$sYAQ je/u|S1CE[ 0B>}daҘFq8]۪GCqfI+;bKFgPSkp5LAwҼ34q2ϻk0;z½iY0T4; {S1gA{Rk˽AE'[˾kp[ҩp͛ pVB" ˙Iv("\B&T?K!¶D49k E]0 Iν@" P-cMeR 0Jp/J]η`umwfC,  0 ` ZտLڠ p׿,_ڀ ױ-۳M ,YEM6hsMP@LX˫L܀] -,Wޝ38C='3 G 8tm\m@ - &@n@=]$@H1 Z .]N r Kp@p Z=0\~B̽PE=\̸A.e-WY^P-1m=1mMnj4ۿ ra޽=ik>M33Č ppZ փ @2 ؠ [ݶlNn p<>|H`] n >A˒ܗ빮s>^I\ 0$XŒ ģ4쀃>~뻮<mC祾h Al xn>̶ݮ< s١~^VG^̻ &pgꃞ[>-N=qn]Z؎`99V=  .[VŎ-m n=60 4m ;ogoN= ?Am~U`P=A<Ah}r͢q>ڧԂ}<Lv~ٌ R@eƌِ e ǏO/Oo׏ٯ/O;haskell-mode-17.1/doc/anim/font-lock-types.gif000066400000000000000000002166641360223321700212430ustar00rootroot00000000000000GIF89adl."8.";1%%(//1( CO\TfpyK,Y,f+u9m1I1*uCuVUA/pN.VABO\T.K+\ft1r;t-i0aA\Cq,Ik3DHNNNDEF\\\QQQWTSqUQqjZMMyLWpYfjllqppqxx}jllj_dO.A..*DOB\T\hY)h4s.j/NNXNtHkPwLylyfOurwkx\ćHˑLҙ\ܟ\ΘTОi٪ow..HAOAY,X8k0k\fpf/vfLULuOl||mwLvQxywPlhshx\.OF\Nppw\.ͱ弇˻˜‡Ǖ͓ҙמ͉ʲȧٯœĘԊϪʇՉٱͽ!d! NETSCAPE2.0! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,dl XϞA{!AIXС=NR&͔9 TŒ[$] V~cxՕ`xuo{^b'OyQBҁsOƠXymx"x&ɸw߇9ס..NX?*""b#WTc[\%Xju%8&}YYrHPWe;gebif W=8i%=B&j2eefZ)n@Fz% :_| ZijJkz> , 6++8+b[ۦG*ÒR,b^"B{kjk:ҫ>+.p:k+p+: ꪳѺ1+{[2IJ:_|t竫C-*,j|'uw+\-1_#-dT-}6nݶx6~7{mpnvbέ7ڇwC+N䊃/Lxڞ?݋]8} 8˗ӾyG0γmo8ٔO[{ N2N8޴㤷o >ꢧC/: {_=oo|8t4B9zύJ,(Hk֓(=MSYd"O"tH}2YbUYݥI)Q54=ix4-* R<"8!hեt8 Q5{%_eJPNӑE#WF2 NWf?)`_)NrVTmg׭Vs R5MruEUSvOh.ڮr3X3[ʜ6a'i\ַPsmڞ NUOPNZ=iSI֛N;IہV^lZo=t7/gU鰢5$q;@~#ID#fJhD),i(1ۡ'Ju"6SZOԹG%kmcdV)FҁCLъ\#-C\zmW*^qP*_pJScwڤU╲TMFe&7@es,P"t e&ھku=OT8NE1٭.3`MFfjLҥoW`:b-뎩 ANS>/G([ّTBӳv$l oQl 6* uۻvoS'w~ꮾAW/T4\Գ_>6vZnP>jDe3aX ql2Vwraurqvrw16x' vpkڤ G.oEpe hv~38jT6erm}6H7~nsoŀh}æv mgvwo?L|- Sc4`|{gvĐtV~ ^mCȄ?vBuW_NV2gsC0woVhhugQ'I}(؈xv}H9uo`|XhcR`р $c"6npذ6 8&c8Ѡnmp( (bHθcXDXk渎8vH刎D8z81`0P⠁-|s`|p7qmxȎ"9h( َ+I/ 'َ9 5I<)6y?k8u(b& EippIymM$8nJe5i6h@ VnYa֕n8Ey0iQrEYjXQTiz9sØ`CPneS ~2)ɖ9 ɘUSy M10|mt - |/0Ұ -)vנ{0^ى78YIl霣ɏ T)i>)) ɉU ̹ةMgnɝ)F_ ?NxmΉ vT ٘0yzIȝF֙牝J` pȘڈx_١ƋgiF*Ip-ΐn j*Sۙ>ɖir)}iɤ1 aVO:EZۙYJj&阐?XDkʠypy9HDq*X*7|-(÷{ɗ*'  ` ԰ ` PX:r0P @ sӸ pa:(zZFu z eZPzM{9azĥy)Ij^ɬљLjVJzxjD*Z_٠犠3:5٬~Z&w. զf0p:p*kf Y9x yoY#k8 cM  K*뮿ڳ2z ip٘k+J'J rI 8eOIVzq;yejB۳*[;L*@rޚX˴)_ z yN4-P94 [*zҐАp ڐ-m` y O0|k"ˤ,?{M[kJklJuJ&i暙^ y ~ٳ!X8Izۜe+Sɤ٬K۠k@ VKk˦kL廷 Xiܲ *[`KkO{ju*{kF -{eb L)-Hæ>)L  )K9RYºj꘠Z[ʳ Nl",v W{g ŐN|QƵuzY; *|ٯX  e0-@ỹ-| @5WG}*LА˷| @z{j hPk$\Yz\\Tx<ł;l۬a IH{~ Vqqzpil:JC{i۵;jz,1z{r +Mzg~'P.-vW*&;chiw \K`gyďNIv0)ڋM7ی:{{P .LOK;xJݜCj!Pl*̄t={B-Jۭkۘ+ |p lɨLؾ 0 zѷ|ɤېӗV-{-ذ-]0@` |[;meR @۳jRӏe[Roۗz=8{u\ ݺNݵi-S [l̀ 曾Oeh) oݺtPZʛ;ݭ?=R{ԛ*vh*}7DkhYw8Xշ80n(2k΍Siu Rmz8n4+ 8LK ˳K7}XZԋmuk#n{庍@.V8NV+fNbKbnKapݘz{xY>0~ӆ; < [ - yҀ]V`I 0|+ kMqD䷭ K   s1T7]xͶ@.K~0=Ł[GKXb笼S? P^m~RޫE}p{|cc>;N;R߻Wяn6s ]6]IM`_hO>p2 a/iaiiyEJdhIh&`+j4f><#Ri*-뫨7جZI+PL.!rOXz ʢm~Ji>bVh$T˫3$&"5 2)@q'=$("Ӥi-MP#陋Ds62.ʔJJ Gy G ,$Xy$ٺS S8SWZ.'A5G" 3I 5㒽['JXr{*zMn2Ϧj ԥpKWS+13ܘ811(5o0nԟ]鸨&B:ET_cG [ [@2v(fDNfeO.:M׶Nr$(+ 9sw*NT<{(XG%O^Be[G2U3 tۇ -|X@FW9xDŲ8';ų;.Ӡ/&J"5GpspB|գhAH 5V;By=ո}D3gpʭxTsD%ӞVu^{Ī".bu(cOg_(( $y=;p[BUa25f-p RLdz!a$P U:41ڼ J ,CŒm }NsG̀S!jD3h.-1sDR#畧oVׇ9-nOĪI(6)" TcؿKmR ֵ:yi~gq -w3&j8CA^Xe+`$/ck )&ZbQ}1GU@O[I86Q|fx.ru" HBgp A 2P00!i P60#7ㅿlA'Ȃ hs^+ p k)Dm#٫fV ƅ; 4ǼmZ!)ğ2"$g6i#0wN(0PSn?j5zuYXְE,aIXB&MQ |FVPpELViTRP06 @P!34YK ,4NvoOXrb> w}H,] VŮZFUƃ[FҰ$+U.8hyq0,koq4]N<`-o"0فQ l.<_GC#-C/` o" 6q!c?2L! Ͽ0I;wDHA"S$ƒJ%D_|e+!| J.v\f#׹Hs Ld*rqw*?}&3ͼ<g.3 =gHGCf3mi+olBֿ>م_4ThY : 9En!c SKúP{!*gb1Mיm9i[Ewn< W+gvopS6p{D{aWv.qw詑涺 hp9ɷﴥfZIK[?|*p2޳o=?|֯描_GqjܬV^V̠ P`1a$?kۢ ib9ݺPh; AjS>KS+2C{+}7|;,?kADATS=[#>(lSs7'3=kL9;fX?!BkHGO/DKCF fC2-|HCADAB,CDC) DBC4Dk+DEdDH\;D4 MAKBN$ELdD[jfx3VttK4JsfhhG#EaCP.c\FbtHlRDI? lBe`FicD[F{F#doElEԽ3Dt?CihPh2xPN#jhV;l},4Scl(H|d3G~4n~,xDGql?FuȌGELȎDH&ǑDEFLDS$l?SIZd>QLHJLFI`O<ɔƋLBkHɠBIlIF ?JDFmaJDɯ$$I'ɤDw=SALUmSLONP=TQSO JmTK%UH]dVXYLFFZ[UURUX ,9_FicMTgUFM_VehejVݼk5Smp}VBVq5sUpW8rVtx Wu5sWyUwaV@UL~EFhHVeL5X2[MXmW{ihUh؆ X$sVMhU̐X؁օ]Yu`\ؗ `EX\MY2UXuٖYݴXYdu ڡe٤XاUٞ5if%ٕ-خگEZUYښ?YDX5[eہ٧՝-ٝ-؊-VZYّ ۨ-׊ۣك-SwwY[Mڵm\ZcE\EcMXm[ٿMY˝XMۓYkcMbX%]UwW]]Mfe]eٸkW5ZٍZą\̕-ۆV [\ YZu]V2ּ\ um5=l^ޓ޹5ܳܣV&6~E^Lfv^`~ >g ` & F` V` `& VaWl^`aNa~anaf  !6# ."F&vb!fF]T`g0U0,,b-/Uc1bR0c/&./0c4fcRb5b1N.V9cRp,c:+@d1fcAcRd7b;&2b=<.d:fG^cGVK&d;fcC;6cEVcJ.cDdMC;cND7f16veL6XEve3dSeTUN,~RfeOF9fGeVfhcgeflcj^f4cF>frJUINn4dKfwbIFibogKvZVnfVdfdjg}eq>hbheShv&cR~vPg&6FVfv闆阖陦隶&6FVfv꧆ꨖꩦꪶ&6FVfv뎾6[|N^n0x- +tlЁPlxpVxƁxs 쐞Vfv^yȃymHm^ 3얎fnvmZaxnmH0ynJJPj{n^i{px؁9mֆn'7pnNi6isjZlB.mGiwpvov7jfqpvxXvhj*v30i"7r$w%W'q(p=!*"g0)z(xFz Hl\Hxzh:s&ipq(됶s= \&tCDi($?sn/KȁSy;/KlNsN=zl5\?DdWej]xƅ gvMLIvJxtih*n(n&x6y0l{6lhsĿ_鯗{y0zXne{Hˎ|<|^ v?WgF}.qg9pw&x~_Ǘn@'yvN`{Pmo{Ex}wZBs9 `D &1B7BHhd=`e&\aDo~D%Pz nbŋAQz@\+dBDmk Fm dBv!Ǝ=.k.޼z/.l0Ċ3^ ӌߖ+Ŗ02R[bNp0,Y3f34yrg!#̍zr-Xu7٨#.:/˴1Hlw.r<"3z Dxs) : J8! oMKQlŦYF~hlz&%TI#Ɍ4O! W &VTiU׉F{!4D43xEYFu 1CDDULZ̓RQ^9Hb]lG 8ATR#DDSchbEQ$5Qb>hZ(J:)ZzQE Q"i}]<2yꩳɕW6$A1}%(aBHD]=d$ Ku mJM{4ŇC,!wz8sjTe)/+!f3RSoGЍ#-vQP5%QfۉsЪJeF /"yWqn\<&,'xXWt0DT.UF3B" s$Չ(Q=/e}6i_[^AJ67rӽxav/t$C?hGd81C쯾e%P"n92`-Q}Վ*Nru VsJM-UR; ?<{qsn&HNCA S6[1ޥndlփ%va*u`O_^pMy~x'. BW RJSyx{<48yD>cB* m„$:XㆤZ:JR -6L2@F啄.7 YT DOKY$ڥ\(V䓢oq\lD!Yh1(x㌾=~#[` -|)@cˀzt(`"H $B9PHb хs0]I"Hr(Er_VHOf`I@/an\b`SQD:| c&sh3X"đ?|CMLf:%< N'@Ŏee{Lk: MЄ$`ٳKiEE0#t*RQ@D_.2jB Ԁr^ꂺq4O=A|" <JlukzC1M"cׇPFIjX AMBB m컌: %G(ZiYp/[wT+Q wԕ[Nu3ݬ*EMHk25Aى`#rċ:1 θn1  깇:Ao:ú[ŋwũ޵tZ]Jjh8ع>0`L朒\CS0{HKP6&> 8.(+bӸ618!~s,!B#t_"= ,)SVFL-s^2,1f>3Ӭ5n~3,9ӹv3z SYajLcY3>9t=+74pjmD ` vtUgz+lӖjGBӽ6P5Y=:L8RHu3]M.@$tPQD8B };-TVxWmKM[~a_]*f-fS4uD#""HLR_ v uR6)$ƚJDn fvp< #/z/llZT6^$ 8jNaFd `4IA= ߾p潔jd}*{`alr )8Qt?7;\S+ޗw} [;oDzc;,;A Z`=Pi'Q? X ;@(7&C ]SFHA{=!"G :oX a) )q!A{aϏG ЋU =ra`8?YT[?סSM@ CP̃<D74R YBPO]^ hy^6!D@D^CPJC^5G2.H NX``߽-Dlf\T`H <PABt@>0j4C PeĖPk$իY3,iR L&`&,'+P1lOBDT7ᾑ !""NYGC|O_*2K C%&aC&bb(ua ]Phfp! ~a UBB@00H  yE٩[@`!+,, "+b$ -7a0}T' WB `B &%X@ lSG8/IGitM5@AB|T 'LOLD3%TRQAC"Dp<;BJR91:eFvD|qU_(KBNH_R#$P1͓=E>dw Do?A( d|$BTZB5CxDJdBVR* BeB_FD>UcV6W=|%e=Ki BF|BD|(7$K DA@5CS1XH` KIDFGj-ye474 @BL HGE=MKՍ EtV\g9gd'[/JtP?AQZ(TyR'B զat /"hb|Q H(l @M#SoD0T~DH!V&C(\De_`eZVE|g(If>TE(BJNATvTs.<nGrVh^M|Cqy͛ʫHG]`4D`]`5 j+(ƞ*8$hB,_<[Z&DVfƠXdioTQnw|)ࠣ ŧKҧ^hQG[͊P‹TBD) ΋j"T*83L0`F :i~bZՈ/Ξ-Jd͡R5.+s #p]EhF@ ~ Y*BT#HD)Zf E VεN53@I^aI1EP ( 6Jd*+gJ;|b̊Д-.1 Md="92~ȊLCCSE gżGe^ZO؎mKEҦ^l=AZA|i %-˨1mLmJ"۪n-B`A|ó`!UnT+ ЪK߶ъ|tŴGiG ǠlEaf `lOhIIdO+IZ_C*IeoFS8-2 = 0G., q(CvC sFD:%+G0Z%ܮ:P-D}B6%Y_k_σ1H?_G*)^3Ao]VI"q7CT\7vn6v_63U㋦F NGO>W_>go>w>臾>闾>ꧾ>뷾>Ǿ>׾>>>??'/?7??GO?W_?go?w?????ǿ?׿???@8`A&TaC!F8bE1fԸcGA9dI'QTeK/aƔ9fM7qԹgϐרhB/{>ֻFѤ=M&iUWfպU)BW/v38O:8nЁ\Yvก^;|$uї1`!G<2E0a밪4 ^1X 0]Y¯ l" VvyP\qʚxqǑodSqz3^\bJ"eRFV:{_=$țGf'M_ n& dI$AF "h!(ݘY5o=P8B1" "QE\4LSoVk6v‘ ,Xrj! .Bk+,^E5d?S x@i dE)Nq$B:ZA( {Kl4ldgEsх\6@c`X(F1:gF3[ԆG aV`P  d!XG OU[$B@i+ QJUnĊbHȥ3I͊4#5 GXUI|`1yzla=^Z"롡Chnu ub[$A(l#A2%h=74,΍l3b`U/QF#6V0BU-Ɠ9o[H) mIQʊ_ȭ:$* HlH(bGRO}Hv>P˒(4@ #y `()J}TAKh ,jp9iU.X\S\1KaLLDMt:,K ,r|Hz"! A*n,ΪN֍%f lN*.ak/p ՎX&loXYfi.J "P ݈6,DfJdRF!bUrD%t9`c;_c̘pN^fO5 g b`l!H ,aIqpl,bĀL}BBi~ ,ut!vrsgs:KL HGNG. ,<J ~`j$P%,Qw. Lk`pĕh. XzM!#" "D/!OZ b`(o#NHp g1J (}A1,b&fa U(}D7B$&"*Gl%y䔾0  !6f$L 0J G })2a6/BӇ&&SK ^v F-b!!IJ:42/=$;? q.qr Xk)$ ,5(u|2b//v J34836>9gn/1S!V,%#K A>HA"` V!:lv4碫Q5́Q `'?l/AlJ3bD!X>QVRU2-ieT2,T.nLـLᤂa"HX.!!T}Â&k!!!5[D[C^Mw_aZ8oa-?[A1˓26FjfbA6[挣a*6dUveYe]ea6fevfifmfq6guvgyg}g6hon%nT6#?x", +@J$Y ;*A?}?6 D9`X6IB)DRF##(Dr}$~Q"GD &ء $%x"X"o?^.oɦ} v#zJ#'֫>X!ZT?P -sX" 2$ (.NY>3!^qBL$N1—d*y9WjW~7!A%NL< ,V`k]БMI0T;0"\ā 4sq#0! = SPQJrR@i]Y <e(v`YZ^ 9pW 1OO—!h_,:e@d\  ]a@Eq?,!k_ȅW/6&[%d6 MP&e!^"y!"Nb!! #øst6* cB줒媲+b82v#X(EYXeF> v$\l4(4>_^`F,rZ5@Gh ۺְ :e& bŅ\‘!ī3 CдKk=>9"۶d{d{UCDkkC!YS7ybEg -L#4+BVᐜ4,Bc;lt,T)X\1 zF#vkb=N#9'6Bjfj,?&4P5.Di.IqB,;Eк+p/ P~aBΠ rR"`gV"ɸp }tbb`ERr#aܺ BIz*zNrgO)T:jFzn6,},{;؉#&r.G1g(u^[kNn ze1flשzu[QG~v~>Bw]JAU$ "6hc}.,e۱IQG y=!bZj~^4g rVq!" \<,H -W19x HA r1gO.d6&A.+/YCm}o)ujì<{$9[ƉÝuXQKnb2 m}CG6"P>e E[Ƒq^oy!w"|B0Ji}C=`x  IԀb_CS^(0_r %>9:Lj# ŒňFHDr%+J(1bMKkϜ9rpz0ޖ&J䢐GZ yH{+anb;Oڼ9Qq 4С%|KQ'x:91VI<z_ #z2ɴb=q%MA<6^"<O>\O͔Nn\("K÷( M ƤH m7r0'[g5N 9r͓ cKtiƞKCj|OZ<`h!a-bȓs8~<i?u1ДxB6ݱH4* +%Hh3e뛛/{nѤES`c=ntUh]GTjw. b[MH-cS_SO`b98eDaTOKD6*zFapvJZ/半MBlP8'cC)BvΑ ݀REHp>$v։P=@_ %ئLA!dFhm7өN~]=ct(s.ʨ9ҕjnQ-}gni>ilL 5zӔ Dٌ"7 Fk(yڛmb,s ;/cZdaXT@p NoDA,K[TBU,^7hyCte/ٜe/iʺs%Tq: w*D2NCoy rÞ`NKCjfjl[ZBD (֗.Ų=. ΀m]IŁ>%ޔx= P״DJkKq6&d7_3_~9!̶;_tYhi@;Xdas?Evm{9k#^o~6*~`v3kpY#΂S.;=)Ӌ.d_-Т->S!CҤt;6FD7QMs,֎% j>ߜ)t 5@F h?1 }aPA{V:e<#&7CDAX$^.uDǕ(([KV8X1FY|h\CL$‰ ?\0 azb.^B%1|ړvT*N; W%^#7CĞTDtU6C_C C qpcxxDS|5CRiHEhGhW COQ(z1 0N8[ȅ](ZcHeh9hikXhȆoqhn(uhw}Oꐅ燇| t(uz |(Hr艟yщHa臦ȊX W؇犵hЄx苂81HHhɨO8ܰ&׈" V-(爎"|$e(Hh||@ȏ)( B |@i iɑ|ّ!)L8'2 )/!s0I5i79;9/ɓ?Y@I'YXI)HJO Q)SI YY%9Z󸒓В_I(XYikɖmo qM|(w鋄р}i~)Iirɘia Y٘ə䙣əIɚ際 Y)i ) Iyyyҙ)͉ɜɝ9靌yyTI鉛ٚ yYɚ֩PٞyɟYJ ii*:yꙙIʘ } / 3 p: 5 3u`? 3 E ;*0 Jw 03 Wʥ`VTʣ]z:F R |0zPz 5ZB8Zb dLjv:p:[jY /ZHʧ/jSMʥZ}*Pʥz/*H:c:-Tꨕjkʥ < b*Sʨcz <@`|o6 zO3nzqw^* | Yzk ͊p⺤}`JT;| 6ъĚʧ t*{.gJjߪt:`e(j2ZڦH)OzdŪ $: \*|ꩇ*/:zZJ0k3ڳ|:ZjJd oZO |J[۵ZZ۵9}V{+NK/*vplaڨ? r۪?ڲZڢ劮+c{E+Z nHF _Pz{M]d ۭ;ᄦ b:x{6+v |kl qKp嚻ۻlk9:T;/0**sʬo:\ ڣ У˸ч '/{׊[=kZ5zK +ڢ [}۶B<\z  ?z ꦆK/ܭ#|.>ڹ Qk/¯|?r˪{1۹P<oZ?Qz+ U<z]{5 ۫s.@@DzxǜJ` FӚ@ lX̩ժ{SZP `[\,0M m6 *|Z˦v+4 U} ~( j*#: @ P \j"P > ?KE:z `P»/ } I:ZZ: ,]Ll,V̦ʛK4 -7 P̷@+ܵb7 r\a̯O--_  ӠW*ͳ }Χ@L+^˧0c'` -)۫ btT[G}n̯l8 ꣧Z pΕz pYPL؍M͕ W Ij=}p 0U-t?z`ٌ[q&p | ϖ])]/ÙTz_Qi}6dLM%銮e;Sz|JQ:3K2Z @[n-=S`|TGz  c /z tW0 ً\H ̦찇:\, em5:[ Qв  &ħ0L}`C~p ; "Ӈ~կ0Μv: Jҭ0", @;k{ A/,<纝 `Yn^ m<\o\_ mƅM }\B뮚*ǐ>VlGz*ZzJJJ ^ߌ.^YQÍ0 =PHqN*Y<ŭ|ýޥI\{0 F|Y. ~} sp Pt+m|O|,^$t;ڻ篊/j<?U^+И;[|Lݗd0~Sn]J>_ƿ cMjK /ߥC*1_uiߠm z -w WPHa4uP Yz T1u`[40c_~Uе\&Ll-y2 5۪[- 5~l@S>vJ|P /%: г =KQ"K|E?E}#"4S3Qi;D76D;:qϨi[({:݆^1{6x3SV!$59*zI(j*:da{2a, }ȹ,Z-±=.teKVR "cf,[mY64@ȢYs)-KԈUڜ4`Fi@fQk;0!S*?@ʄR+bR2[E É}OE|EK S.IT@RB@׹$p`-rgv JϦ)o3VTvOQ`@TE'5zK^Ӄ(F5Sf:j`7\!9ȍ$&!ro#5P Q$TPIL2XAHd2CY2՜Q+E$$QaARر:hX 0C,b|!I(8OSt u@M 8A +6 !yёBEBradpz"AP3Y(^7"/X}8qS֓E *Zp+$'I"l[pğ(5,@/r ďؼ~գ̇F Y<қWr, wt !/<ʿ\9@ b5f7HV"B6%'i2J*R0N/D^0:EM~RT[:P<gY+K#E+`sBG$%EgY~$d0J(' i!.TdP9)6L&K0R$& JH"3!@谲*Hfjv/Ek!Kw)m(@ ULVSKZqPE p2o@Z̤89Ms bU| ts/:#/ݼzJir .ЉK Hl5஍~`{72_g82Z =(ǫ8 C<XȎ Z@p![ BIWג 1i:I >B=R@62= 1~IR#LRM0 t4tCPB,۽@p@G)=cH<=Ij$3U,O:xa#knFK P Գ:>9QhTA@^ә5 ,PPU@H2PȣG*Mx Z<3y>Ċ{9RCĐW3;Ѧhý \2?薳ѩx4|ŽP) V+J; 꺨d;ň֫: `!;i:̒ Hd=1c#˰N9Fڷ޸Є{ ÿ *QZR=)K2AB$3H'fĉ< :;ƻƂGpK?Юuf|!sMOT_5>ꈏP2+I+#?8x"(҉/i^( <Īl/߈̙ZČI% D,\9?$A%TJbƅ(ؚKpԫk:&L:82ǁ k (*O)}*'I˻TZTp:Y>  )d<<%˽yʿC3A6&383Q‰0KHd XN *Љ@$IzD1z,HW(Q3?+TJ'['@|)(CE }lUU&EHzS*!Q!AYiأ ɩ$5ַ `y-C-Xo-k*9+UqLͤJI=L1G uh*AD_4=57ЦS@[x@8_xE' QP> BܕĚ`؄CY8[/ #,`D0-^0i5%ݹbC9Vר O5] ]CYݲu@iD%@\Sb_40dTC$ [. a {W0Nu@]'Fث] fەfd |6 !P;kF,m\|'i jN㨉u.8hEK S''T餕`84[\ fD`%;j+/X=l&;f,{Z aNš*Ov.J=%\.{]ڟ[Xb qmҁxRfhD.-H&(~I`pc$`J[0 VC(` פjljPZXҽq;g4Z4(e_S엞a:J z8ָ6PgVy®.-Nif'h)vD(nK˧Q`fV^;˔AP*hGΐ %!^ 5*+a?QERv-Ȇ "n潊Ӿ hP`G! $BZn쉪aKϘ2IvB} (JF'Xq4l_mWzpgr(oցZbFj qhW."O\P^m7FZm|Zq/s;r[!l5'~4lqAו,pC/D+bZ3& ]b@Wj5gqSؕcÑ>sQG@VSkS `chbwIk'1!abuqp(u铼uZ/%=Qg(ޮfl-]v\/ Tprw^wozs_g͘v{Gxvln3xao`vwRF6+iyygyyyyy?Hyos/zyIpJxgz_zzz+6w{FHzz?zO{{zWI0|?FHgJ`y|/OGz(|G|W}'}g׷zOˏyƷ~zՇzߧg}z7}y/'p "Lp!ÆB(q"Ŋ/b̨q#ǎ? )r$ɒ&OLr%˖._Œ)s&͚6o̩s'Ϟ> *t(ѢF"Mt)ӦNB*u*ժVbͪu+׮^ +v,ٲfϢMv-۶n+w.ݺvͫw/߾~,x0†#Nx1ƎC,y2ʖ/cάy3Ξ?-z4ҦONz5֮_Î-{6ڶoέ{7޾.|8Ə#O|9ΟC.}:֯cϮ};޿/~<ϣO~k@!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,dl'8'9%%(//1" DNYR)u9f)krHKXp3s-h WGpMMNEFFSSTTORrPMMNvuuymlpcfb+*MMR2]2X&S2V2h5hl2{2]2NNSYRGqJmZwPRmxjrh|R(*06R+k,(U*leffg,*;Rsovbՙ[ʎOӼd֫oiЩ\s%FN7k cNnx{LvNO $ :/$X$F(m( J V h u/kSOZcNurvnhnM((<--gvqNi_Wn8VJuqp(++Rknwe1NPUHsrduvĺӒά⛣ͳϳ⩢Ĩß՚̳̑ҳǙϔƮқɓҬƔҲՑ /v̧!= B(Qa> flgaLJAȈ/2\#&W y0%BzPҬѤń73&CW,LL:uyφeTQdԧ^H㽰3zlڟk!&E*F$6̉޸uM›`R%ٔp;=IfB)7^ś|=EY4cmO/5 bɡ*}s9#.J 2^r=}KK].Uqz'zBub?軫}9uݓןm'vg_D8}=;v*T!I(_{Zx{m;&a(b`˙a48c~Gsh]s( $HR8KX"J)I${=X xYp{cޘՕ^jfffr)vjGdqyv(n&pf^J饎)~iv袃#ʪ jy"z&fji裉뮱jjJ,t&{tIR騗 m:z )F+,* K슛 L0jl.B+ c lG,q 31Oq<2$*)i0[2:s?@ռ0;ی2 +* t{n{[P;'Yv3MZsԢ}֮2aM^2bq$ۭw-;<8>$~G.Wngw砇.褗n/ꬷ.n^Gij/u&?mb/}ߏy'GﯿNjOk_>~ڴ@ͯr ws 5Au/x \B>| +(@>Ѐ ǎˤ0S3 ](a }H S`xFqUl Eb(%QelW*&WD! [|cX 0y  U&KT(ECL$hF+bcXHEpt%H-r(62#W3"a58z|ء>c%=ACiy@ٹPҕE(+{dh::͇v0(HRD,iHjP#  G8⚒F¡BQ$U%9M"zAMT> U[T4ՎicC!z´&R KIDrd^WLzG+&z-2r58EbDb׵V` ;O.GLJV>trd+'z˦jZA֪l,/Mwd[!{ukVunKс*L #:Ptmll4/$@ĖUڨyQ Dx;RqU %X"e$~`Hv&+z GV59TleՑX q[/YKt.e=\b:[D ʎix0bo,_s ōnh$/a;5# ZX'~rl+o֯d2a#lhC8zNqw#_IXU$YUx% B"Y2\+StpaHt!^kMÌn'LMO+dt[a]_5ײ"AE8f873sY 1k \v-4 p plk dȃ-[QEۤ^3fp{{~d@e߹v XǶbimqgv kl/ wᴧ]j;6\mavEElfšԓ - ke$'QJwEA(`cC>ߠ+{-8yteNf?9ks, [x8յ,wqWss_d_*.`olCB,.p$|:vjyCZ|]7zE۩Kflo=L'!Ajnб LԷ>O>S{ u}OϿ@7e0W'KƐto ؁ "8$~NW} ~]0 7 ug}G |'-t5H}%h{ExHH̖Gohnplw@F o\{LxhNnG}CW}<`5t&}FtA8~0 2F2W a~STXi8hɧGyplD@y U ` @ P og7  ` (cP  n}xlѸ(n׆WMh\At~ `u [X^t06HHNS=B_i☉0 iI[0eYّɍ(h)s85!Y!)값/yx4y82501pnXxxv`e g Fn xxБ@BaIycE@А4Y59Iw|h>998 >`]P*IeIӐ[抱#˧ ) s:%˰9"+z>Yd+@xCnSH h HKyŐy #NJyӰxp0 x+;:s&kI5 y-07{r+@ٷ=K!u[;9/z۲91 ˙}˸*ws'VsSYPLWy뺯K H;ַYL˸ۺ ȋ(˹kKۻ2IK{?kV@h35Y ExW6V S{)VD`nT` P+ž .ګ+.˽q[;+/4KA [>--݌28m 6|(*];mӓ ;+5M،\ÃY ~U؏xG k` |(ؕm4Lž{ۼ]ڼwM=ܽ}tMܗ۶}mϝ]KǾLeK EJ]-@ ԶQM'޾+Uˆ7]}t]ҝ͙ ғM9༝M.-mܺM>~^'m H;~4ϐ- K kw}h%^J&N%k">} ~U0 JI'; ?Mвcʞ SxЀ|$PO ;}NN[޺ؖ䗎.+ 38}H~K ͤxiLϐ@ ¾Ww}Ԯ'^~ޅwؕ (0|nOe[޾|k D͟ޱ~ OҞ _@n-S5.>-Hk?4_6~. UMd+$lj A$ EPX߱׾!m4 Xp 5 &|aÆ':i'S)u$Ik׵X=HRTOhU5kb?3JLJQ*YN]=xP;,TsR3LӰ㨔irqi.dZ qZ7 2hڪZpA[)H5tjԜkӹjioR)ө7**:&Nd*1įP#5EC|60F|LH"flH"Ԑ 4IDR% }&*wBr E+̒I(wT9 ɺԮئ)+U_ 2EjRJifn Tۧj`P."khj, 0f(GȆ4tT2>h)2&Ms`2؞\(3\YVuɧ%ZcUT5!0MȨg$ , ySu wg )ܭr\6(V\GM|~WUj>_aY!xk~=2Uamʘdb%*Gvam hyE3Ym\hiVdئi咅vafC%WjQhbUk֚ٞ:kvcdǖOrpG(ic !!DߑVJ)GLVԢgE/PJtiHE:R1,)D9RuKejψԦ--sИ"t5}iOY*TԨ:](QJӣ*UN]jJc Տ2W})BU *DJұ_*ZպP^c=[*VvmиZk^;X*a[CZ5 Nv-,f!Pn֮oM 4װUgh# .JkA4R^m+^FV*mCۅe[&W~-oO(& v;YW',o\F-ckbW& ,s{vo P]oy;~׿nlK^B8nl]Vgm)wpyږpu;C~w\wؾ%r{ٛfzɝsv [HF"]3V:njZ֮~5g]?/pg֬YΎMl^Ǧu=Xض6g-mdOgܖ5kVlncݭvwutݴ7i߻^6Moo[7+=n8m3cO\ v}|{S񜕜Ϩk;89pC#D(Bt7OOӑtSb`ӛ^ ;=Zz)uO}W:طue?{ٱ~uuv0u]`/ګ^x]w<>d?o>Z<)x 陗g=|^wc;k>O|'{Þ߻Ov3|{{kj>;ǾNc_d___x|?|?{4DTdt@ $4DTdt !@k_ o&leHBԇ#|(+,T5PtXA] 3 243`,`C6yaC3C3 04H(?@AD@UH5B9 ă6D6<ԃ,1`/ HD64B>$R4SD?4DD?:H8D 6,\\\8E/E1 3 .hC2PFe<QC?Lhi\DԿ|pEXY<|? l_ F 6<|(AkCnxy Vf?m|E rPu?q?rT}lvM؄[H| v`<ɔ|<ȅm Hw9BkLӜ|n܌k`>MMl{BV`TM8_tIkT?oF,/N|d7dK\e؂6D|qxHNOLcKL$[C,$ğlaZH'k8\kChBl?CM>PC5THѐtVHQlM>dMPN}Q܄MX̆MQ_!_#Iƽ ǪĂ0DohCHL]KpHy4M6uK3SZĂd9O I|9m5D/07u?D6S@ŌMy}`DElMX>l=m`WQ|=NG^U̇}ElQPT%K~PՔ7M^ |=M|EL?o3<^xsdCES>eC0IrӨxDMqM6 EFRpm?.R;g^V?eCK^-Gx8K`zfTMn?,WU3RfPd ?Ir(C̄U]ca旆i`p萤]W|@N8dNJ1@O6O%爦d?D`|CDH.+6hH^ 8jhptX\wB>N5V4c=Q,i c&@].YYzHο*?C&d,}j(jEK^=Xc'n?u?vdHdAE vIm|mb %@'cu4 z?q4@MZMpZ. c5jiD4b4X9F8 Oe5CN]Pe*M]pDždFnOlC^&^xwC?o\}?;{w\G~6r6 gC^Mp(q,KNX?']4HQUUaȇ|ІNs_Murw0,p紖P`$*VNpa]ѻ>f}lN+/掦1\wA}8oƇ9N( k8oT$?D(DR3={(X6ÉDO,`ê5}S)Ƃ,qD0h]6,W?jHDw wE.(|mw!k]DB90Q&ʜN>x]GAi`Lup?vRn㙷?'ql4y0O$qfyrzhy plOzz[+R{Az;WA Ж?gG&G|/EB{H4_e"'wB{z^e|'7GWgwׇؗ٧ڷܴWYpcH@*uX/lo'##v~>P}m>}x8333GC5t?a'C2xg,H /| 2l!Ĉ'Rh"ƌ7r|@p̑I@O:N1:I0rc&< 2(A62mRڨgLZVzҌ3lGomVx5+ܼz]^]*\ߎ#kvغvL0_`>E-?ČC3 ʅLT/s!x͢1RWf[:ac"8rt!3}:^n:Pcl0g7\TCwϰw郄E^Òv[<) yVFxǐ;9K]xQ{La>ؠS7l)Xb h__3~Q"A ]`XprO-y84O-9,\O>h8ȑ BI=Ð,y&(Q;F)u擛$` Ť%.*38`k2{64:1SiD>:H^2N;JRR^ $lbB KE7<0fٶC}W>T[ ٓG.yhʐ.qApv<ʳN!捻 FUV j)y$p"yo.JCq0b< i Ҋh 2=稁BJ=<ĂCFjLcsә P:4B6o86ġB}P;(>SE+Ƀ+B9L(S9g.bvo} e-6I\+ Iʄ $ D9 {2C<"[.p.1K`;-QmX̳_lyLqQ!tո0m Ʌ U9_?UݳlF<ǰBĞ|2W: Iе<R+@x r*K 6Aa@Whbfb#͌Đ9)#[oN Q/TM!C(@Dnpk,—:d>쑼'&D Bxc*Zt <6F Qd H![hzJ&7rQ 丐IF<ؖ> d Lem!֤' p[1O&PQ~4)1!F|b(LBljyȰB0`xY) ZQ*![9cHQqΕ`w.݈=j# !JTF u&iyakA+b/| )*b|aFTPS*C4E/U*YkTjWD撦Mh|8=%O)~1%I %*:'i&8ͼYɡ )ey9+Ccb;F0Fd=&ZTKIB(NICdRJ(\ AIR#oJ܈:F|e"2VX =H;܈\# ]\džu*%kjC-/%`IjړCxɅ\WtUH* ف&a=pmV#r}V/l߻R6Sƍ8Cu.^kk+ɧMR{53e4h!J@:OI^FYxa̶!^. ,tRgŸ(issgYh;# d iIjƇ6۹!VS6ޯj.M%ƃ0^)2M+]:zg[RֹX^^-/vȍJ\a)5־KC5%39{Uf+d NCd&0CVyߒ {ʵr :&Á'4!$ D߲!'7$!$E؊W ^qay브׹є][?`z[LV5p~.'27OyTS+j-`ۆ̈nt :}!p"3k|wG{}Vވ5V!ыt Hw9fǰD|XǍvөFx3x9Y|%?=z'}exG+.~kL"}N\M S&v;{Nޙ;o|y!ℳ9yY}81DS D$C$YM:K9D4[x  !۱D;BtCFDOT쭚TC*L)+D,D3OY` !Hp2+퍟JVMIǽE݃8]}9ieIJуۅ vA~va e!W>9] b|Ef\aA]TD8\_GYY>DX^BV+1qrЉ8uGjF>0MNP!㔡jez4~,Q;T1D]#$BIytь1`ƃH=2D;:W@T>,fAH?vD-Ԁ DԂ݂G BT.J߭yb& p"GCrf|B" \8$O%UF,8-UHUHÌ$E,b7pDdXݤHI"V ܸ­cɠY>X CicjdhCv> [Z6`Yu Ѓ-D %]1viʛAEa&l "6 md,գC>d- < F<,RD$P^|"@ G."1 H.D1Z;hG&NG(D0 PJB/Qf$ޤ/;g\=Dm,MT=;qGQ:DXabg|J\`gz5q"'T%s.LVvhXJ䄗JЃitO!\`]lHc7BѠD gB&b<]Wc֐D#͗ԑDg=hnN)DF(0 rZe8WHGĂ F Q.]O0*RB|Uύzš+EW')\dDρE\Z URR]QNxf Yݤau,9dݐ0C 57懀h``\W@Ò BZ)!Ҍ;&^ Ÿ+D(+jC`=` JC@bʓ2O@=\aSyG"eR xEG`)-J~FraAk܍(``b/'D5ĆkuDܱMEDTFĺCv,n*S>h>%HiD5=CIN>T>ÇT,+: >lqm:>C$m:0mH-EԦC2:d$E;+Ph+v7t;dֽ7FGÄm޾9݊9n>nBV$.|^#fnp`]Uv.6.nu;Z%u.nhf^GWXJ.V&EsF*EE" ./VoF$f~DDaG 2Cn///Ư/֯///00'/07?0GO0W_0go0w00 0 0 0 ǰ 0 װ 00011'/17?1GO1W_1go1w11111DZ1ױ111  r C.AY.C/v\ݒ82&{|bl$0`* A0[öF*D+g2X(eˆ-SF )[R8Wx$E0YV0-?"C ^[Xu^eG4o撆ilkPl=UOJDs8{itl4wLXC7w7TTGHBs=o1&ź3GL/D"VD3//:SCAK gGBl Tʼn K.C|iÐ)ÿ؆}C$u2\3\| @'D`O|X .GȬ~C.$P3DW,O lIFS搎0t^_D.!')&0I`a/xPD>Bfg6R"bBLTЀ"wLj'bU\ۄ]ٞ=B-U[pO;fOLzC6 զWGGSDGM8VTw[(*ŘED`9M|qh푘Q=X fClCwSd9nx6 U0qCE*%q,F9F-Y%1E_EfvyC,MZ5 Aw]u4>,8\HRBSj~{^]'X,CM"Y՚RDsK902LHmhZtڳ\$x~{ {s{cGE9L,*t!X-=!.^ cD-‡C;+ i|S!z2'C1|?[G)p.3D "Ƀ.Gd8zzE`*\'GUTe˹d[y7;لՃu>܏tG8D$CD.|bQG`KUK=` 6էa!cZe=;ЋT e& ,`Zy"6hu;||['o`6t* =f@sFXIkGD(@`Í 9|m<|޴,TtbE rӵp`laz/.-.Ɣ9fM7qԹgO?:hQG&U\H]FŢ(/bY$; 1̰cO,Ij̮Jʊq ̊w.''^DaN( Q=gƗu+Ů_Rׯaǖ=vm۷q.5p 腽.lXe6'0,_<_<uevrrn1XDe qb0(,8ӈ 粅դB$@|,C4*N2M 9A QDᆜ`gV߉MQ2CfmFFav饗s@qș)+R-;+. S1,3LK{<{ԌS9;ӵܻ0= TA -CCD2DG!TI)ez&J9OA UQI-SQMUUYmWaUYi[qU]y_ Va-cP;8x+vWpB& RW0ljHC/җCV 4{ ]7`E.^0$?XD,b(w Xcl@0Nq4L @xkP `mfC9bk^>\_L0Bu B@3A8EӖ,$K[p6">\QhYAБY$GxwK].'PaF@B)d4I_1ƇBENsj&X3&En:9e*(8\1ŘeLJZMKB?\{m>E,CPWMN4MqKI,I"b  ̑4 ⬈޺Ί /z-,A 5q.1xgM"3Us0)B Qq_qǃТ{U*&jg!Ad7rh%5'( ``4q}t_ˊT@#]YF4X"-LYZi穟7$ 4er ,],vPAuš~ҎqHb[.v5*m&"^f{Ya1JZŊ<4,w'(3\jk*C5E j` K!&LöyT<̋X5ol΅PX!&qK*WnEqvbHk˛Ja "-=qw&PO@x,F~բ|S І[T$Mvk|H)(67q(j['xˆ cDcMK õq#y™1:(*4hAn}[T0Xb>ҕf epK)V6Y3&c6ra"z6dZޅqk=(F: (p( L#5>.ZDfN"Z{ 7 p,WƈLWQxBl1DPِu@>,Hoe);+FT"~Bfcv0܄Mn<uǝlF*!ΧiI,q&bPvy!Н{b`y "|pniHrj[]z~Z R;AWp>QRwqLn|C]{CJҘ=3'A"a.CAӽg?\rp"DF`,r ZQAГ,ޠ Vbd1`9*,`.b4:h.>z.0تgJ@)3I3{R)"+BAgpAQZ>b좒;{"( 0! j"Q +=ZI@ZE"@BX'V1ĕ'&&T()!X1+R2"Cyf!x,xǚh@8Q( ʒ(Pz*_&J &_,4a4h <PH{)I6Tg fyM+`&Y5]. i "erBU?b!ZU.z!VGaҵH)5A4x U)d'"z( p81RQZWO G:P[I^`Г6>t,P5V*J!WHU@,,Ty"rL(K-ȶ'Ε&!H3Q[ka1+R_pl@l@wI`'P1*L1 1!;| il Lo Rİ l6pHi&DwXSCXi Cn,M=cdYǢMgu?q1s&HX'tt"usd'jAjt Eqn݀ہ~'OwAtq 'ZVF o^n2,=#3 {0|11J23 4 oCi5`OUX&h lv 3$%p&An%f m3-*^!bX ǀ j)i&)@T h zY&Tڹ&Y3~Of`_޷ȉ sJfn,`IJR%фWcBrWiJ3d!z,N!J-'~uC&i)dA.`PtG?JUZs{wO9Ndvh=(#GL=zŗH1Nǫ}Z6txyxk~Yt6 f~KJJ."Md"8fSQİs"䃳lH9ZV"bjQ>*rPqv5O`VԊ^x"4{0ڵ صa[_U*͂]2m±Xv3y13zr,ޘx#5hN! %Z;h973־A%jJKL;G;Nb/r8+QA%ex5@ɞ"l!Hf:2j(aFMiJ"ԍ"'ZTm%_WcL;ueapm 2ZYq;z1Dž ֽRi`^|eJ|'`;l?cstX"hK}zIEksDٍ2l}b|\5C*@Q"a528 x_l/b? ^JҫȍJ\}ܺby'l-H"h (g;`a.C; E]=Fu(x+Bk@ۇsvj<6]֜"ڕUJJ{ E\"r٨>b93GiLK މUڶR4>KB D<+b.-"+҂9&l-cwiY˺j@|}DAAu"-E[=:W>5Dh}̻?q,E "r[zĂq1@{w>Y|\ܗa(ߗuxPv<<?)j ~ѷnJJjhc몙[1'Di)@&+"$*/X&x峌Yz=C d[\ʞ}!Q8bWi"2ɵ&3rZRʛfYBa8Q^b]ωݷl'H/$DŽċy j(aō;z e-$6$īnH(Y|*DB(1BC'Єn, $Z5+-X E˱bYZ1XXEiÊ˸l׼an-;X } J"ENxM_%ժrparח#  3UÆp( ޲#T&1 xH8>w,fyȐo|~q7*yspl_r8~ц:ҒHQo%d>TuD4QE4~ Q yCMOS=%"QM`#W|hvX}&-P)$dejbKiEXsM\@aeFJUj6UFMnHYm>N fG@aZMMb!Fܔ7jsElm2g|UoQ G7PAB4M*(1UcM5T 4L3 %XB H`CyJŠRAO5<M "qr/-+"/oTP7ED7/PHB 4P l"%%S13& s) >Vhq&o8jZ''^Axxm:l{GgxMlgHOprn)rE$=g;9}o7,qX!67qmK$ Ⴠ0guwS29 `~Z%d5+ V܆KțP(+dxډJ-|XjXT9%dB) J`#;LD浓)Φk y#-̭g/ TtphIpFF^PzA/h!# rGc@ڒ2ftN&>|Sx$Bc@&~_ ZrDʑ0#GPRKXVbņ4Mڥ %#e&i&Fi+facg<r |L-2֌ְ4ԁ9á_Bc u"4!,h|RAV6Gz#+4!t4pXMjF5:JujHCv{*dPkZw^֡q*wPRJ1퓫]j! P*^BEn*@m,^Warle@ʚұ-5_Y=ѣOh39k2%m`iյ5*E"ֶ"ݭoT4Hq|<no A &bntކ ´ ^f /o%P*R܀w^bhxC" | `#.0d![1>XvK"YzTȵ)JaNx$.xŷ2z! x4ox< y$C@$+yLno|d$?yTeF9\ +rό4y'B3yt,WiPB @ zЄ:A?Ќn?CzҔ{,KkzӜy1L{zԤ.fOJԧn_ k}fuo\Z9Vu ` dnefC{ԮׁuZMjTύncږv xs򮷽Oz{wd <+{;ի~/qtǏ|9OrK:&O_NYS0+M S7zя+}Lo!K}CЩ̵טώ#QO޶}t~s|_S ~u5ĿK~>rh9bX;际dh 1S`8"Q(٨neYJYʫh F@{Y6_:h ,anɨىb"`qٟb Qp `ɡ9H:؛)Hئ] ߚ8} +Y;H CS ɍ1ɊJ {>: J| > ,&1ɆSHج" 6D ʗNb`i=(øK(TX,Zڲ0@ * o:y0 C` c"aI_ Q{ PW`1= hy Y`z9 j@hڃP)^7)KسZ ((l8)h|X;G(8,.@X^kjjA Lk@Q[ԁi ۊ; ;+\5ꯤ`sy p 1`>m%K:g-~io _= ъ=͂)` LڵɄ5,QSY;F؄:ЛTۺ!:r R5H悠ԃŢ?D aw8 `Fݙ;i)2A, Զ ڎ(LА2 10^Ialhː А 9> zYŢ` 84>i Q;Moڂ?X ,0⹜Z݅m3*iL,9ݏh K@pM.`晛 iʮNN]t˹хm*\_mڄ ɼHߧZɠIqރ8M n؈J=  ͗@æp yH 9 ']hAX.[0Q(y> *k'R͉*K Eh=H蚔,` tJϐig|ۈ -]<6|yRЯ.` 2X"QIoЦ%{ ӁN3)AR.dC EȊ_.bh#GР-u8)9q _$I)X5Kc=J̘Ac&Y:E %J:HQ1W (&?>Px5D)@o\v_bRL<<ӭ Ȫ4H^xrƮw#"d輕@%/s @]TPYNE-t֯dM(J0\gK16×Ii޾1'aY+6/YS j(:XV @̍c"5 Rh$|r6dHr%C}|#N "nH\)*.H*׀ω2-܎+3ɭ+\ZG?͘,άJfp f(Dq@vŨgV"dՋij'ϊ.M & ˠx֝Y\:Drh% D0$ƸŃnWp+] S "8bX:<|ʉOK\AĉAxxħ3+8/Ƙ3ӉT ŦX-/GJJx)_rۖGP ILL ('BP i,h)pXr[*Vqq\)Y@2-k({PTŠZ=s'ACmaɻȨ֚)8Ać$ yf9\U>"{9CT2'lHN{˜b ũ$IF `Y3zg*~BVtl0E;h.39)3AK#(tP@#eQ$LP(ƱTBPx"d:IN* ⚬$ JR= X*0xD'(Aj:`bԦ;KX!T2 V)+ D+eu %g:߈ |o{h Q< GiX/ ŝZlLC5 ۢcD1:DdQ݉q+W1,g@L'V138(-fKc4&\К%ddC >8'ViX'fp]\HcԷh "L# )ΒQtz4䒖QτB=HxFA7Ak%62hŢ̵^B?WTsD am'$m^g[UYZFWt]cgQ_HO>};`+!*LSJ"TEgK0 c2PcvuN]Am̠4)'ekm]Whq \Ʀ+\M5˱1p**hW! P40g6ݲ,Kb'+7 |ײW?T$sK"RR imrNKJeWQ\rEt5,*~+Ns> F[x0/v1~E5ވH[D#s5,p:R aYkUȑ+ΓcR9돗꽿r7A֒:!drU&f BM6.f %'6҇9W|AQxX}֒p4qx&66,+%XfQfR,ˋ WP(-d"+6*ծ֗]gv6_$_FBLQ Q%l@w!MM)deɤ+uXu{!"s}! k) H4z'"y4* t0#hE\DTg4DM蕄{ b VŠ(ナe~҇% N8/}"⠿K|;8 PZ =( " 18T$єBy*tؔSag;Y@ qt;Ћ7$ш_@K"`L2!eJKΠn (һ2#$$$ɿ8'Cjۺ6^۔&RCÂC{?KBq s+v-"@ T) ʠn5&|B&l sl B=DDp 63]r :{iEk$y AL0X)qE^l[e%@j?tKchad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,jl ]v*a†18!v 16xG1ő&Szp$Ɨ*cYʎ2srѦΟ)yJaO"*<@P:d MDC E5֗}\ 6A`!:eHF]q^+7V }4lr7lr)&!cƒ?,/˗-cnd9Cy3͞v3eͨE/x6c֮eÎ}zrmέ{߶M<xd.8p`~^Cwޝ<g^S7ܽafymr@ W}<V!Ih܅i!faa6`v+n6"xً&0x#=cA~ht&itvI"d/^%Vg)>f"Ry%TC!1(I*&h#u*h:(J裄*^餕n(䩙٩o2#uj**:9霠Z+>c'骳b+ފ饳8֪YJ)~2ϖm,虮*bm曫K/|/*6o nvJ/7Wp6=,0,4l8- g]>i< gזHېgZ `Lbkb-1ko,1o΃3RI@4-M<̳sL:ΡV lNvzЦruqYeח9PDO_nOMXWfk/peޞ6Ghx;ӨmmnL ݂xmKGҁ&'9¹gb9k-j 0Em&OSpuRp3ygru;9rPzy}۽m_0oGH?"؝Gzя^ݩsU׹ɯ.a W1A -sY_Vһ8Zy=N&][O|Ʒ68j.u+KoVq v<<ҍ4c~{wyco:]ٴ/y< p~ ZЇbnݗ6r@C>bJiD#+wF46 S}- '@X'< hӭ0)_z~[+~~{W{'vohoWxqycN"$B][nu -EmUP^Vw[z^=U`zZc Zu'u N㶀>XctAcRGn 8q@wP E5V"$DHB8{5v00sSHpt. ͷ=vht@ ȷa`-|o=80 oȇ>'|t sM8qUXu8{XSńOQh焽rX&CTX{(J~ wOp8(f{U]D ؁_$^nE8kut~s9zz88^L*D6LZI M(RH-ʯ+A *T_H) 0 ΰ  wjho~*-p"k`~Z6 kVwT[%_KA;~>J:E뢙;ÚF9nT ˷˯gMy 0nPLKVjn( kA˯ֿx:I+,nh~G kϠ}0V[ 3PWM(- -PӐoGwнc N bXf, W5 g+7̿;+c @kgK=Ĕ:eX:B0L{ ˹ >ڹ™HÛ7 NcD=Y3+K;E׿ׁbִ؀]ɍT - u5Zyt| ԍ:uU;U܄-y:<]~~ͻ}Bצj э&wf9=.P-b n]#v3G: =GRNꪎ~]֍^: g>Mn u: ^@諎 ;`f_8 :njt}?SK?~NxB~8kފ^;h *Ьmt|v[ЌzާMOEYۄoï /7_~N> vS>e[; o]]/nM3gΞ ,S==Q#=;@H@h3~G$YWĈRfK3IlR#Kg ˁsҢFVhᢅ\fpڪb*d4)-tJўٲx%$c:TQnО5\1qΘu\MmDxX MIN91uLҤL]ܬrg֩Yn%5MBS(GE/RT"ei`F=.i͓ w:c|ŏ^|t 3ϊKhKۭ 0C6hQFdjPB aF3=κb1<<$SP)I;~$%ȠjˎHHAsFNn:Ax3!?SrAE:E"cEdP835 QˌoA;Ϭ0QL2%J{t4O-cB$>y僧]x̗>zW\yޭG^ߞx/WGvه?~?_~뷿sk'@@6xr F[4^-AvЃaE8BЄ',4f, ZAZطy1peÓ0?PȎ(Cp"a9̝|(2ыCX>F=ΐ" B)1n .QLN$^lcG5pt$$82J`:$"G e\ahH t / %D95"[*kiK2bR\% 9&{ rLXklH?](]x+4=@*$C3DC>;O#=e32O;o.D;H,CG,=88KB D84o@44BP./ f16,eBCB+8V$?LDNOtE&dF 5*Ɖ9f8.֫OEh4$$(4@r$=KGxGx8Uv{G4N+3#AEEx`BpBx[lO{|QGrCU(|@EOAts,43pu,4P[9bHuHlƣ0'0R8*<*m$@-C,{pŕ.#(C#: p|HKE7DċtVa.H ƸA#ArĹ,¿;`37C`LC.\E7FDLDInCIdMK8*8iT7'udk Tl߬IJ@K@$u6LXˎʹ.D缿DNxôKDB#<ɌJY 4ADt6y8!n0MZ7 -Ss M.\M H>7JTO"K9h=D&#-9.|lNpMNm/.t( R.K;]ݱ™5Wf.lZ<XT Wx@N}MP.D3g܂EX XZIbuKM|}S,mLZ u/ /UQdVːU/q [smB3Uz6{n.8/ TcUJf .ʼnU`Nnr>Tc< ?>yH}kEN}\꓆f h>[S i MgOޢ$ea*G&1a8;㠪fkm: \pۙ4/;/^/}J/{~(]Wj_sxpitC7S7njlцؖ4[:v*t.Mae87@fiֽv.nYoMζ8߆6$x^xmVjr`h{cJ)lᇂّ2f9m0rlH=he]nVo%ۯծ)>{8Nե,؁<hHxȆ4D/[b +A\緓Ͱ?l͔ @{q[j`X4s`O+"QrYVcSN0lӶ@DxWNHhDdG;A/gHYp?ط)sE{1;iLޗݰӵDW|dUWB,=t@;s+lN|4Q"g .t8V2qsܾc|sܻH:=CۻܳkS&/[3<@hjkG/PGtΟxx.5]su'>>RnM[dſܿADuTWv7ZsgEجd3r?7(u8;nY;-ZJ0DƻO3F\o"ȈaB2SWkp 1uC(3`|SUe-4`>ϻDBo_e/nQ'j.5xX-9֛ 5nM\ECSOϯg̳Hor~:|/ҍúlt@o_W"ox;l7xKO6ɗU>|x{BˇՇ~swQfm6%%Ue4 RӏU-}^++/{NYKF-:6Q0x@s4*DGD`H<.H$ʔ*Wl$A$aB*$!=pfN(ҤJ2m)ԨRRju*rŃU.dt)ClٴfƋ'OJ 4Z!Dk("/Cڥpժ0ez:apwɣ]'3ТG. vlꒅֽԞյm\t*d q أey{<4$8buVBg;kB*k5դg,4;Ã4.;RZ)SJȴն;9q{CZw(|Km,| }x-fAl E> C(d;m881{#|! c ./{Z52* ЫcQ؝ Dc1 S R~ȥʼn J6 emY"h(no^1k|,0E2UTb#aج,Z,em4He<2ЉGZS[$(C6Iꃖx8m|%,r8bY#Xg{Ԩ&!.Tt0 P[(yPD"jyAR9:則-hЂ aA$"` :,gJ"Y=d_r3+Y `ש~ jyjPQ!:U1)R|̉]YPا)߀R UqjT8 \"!g?!9Y}ˈ5ҩrQtO|bJ"\1c3A Em͍B^0 +3L !!Ad*Ff%\!ǎj-OZ&%"$t[MutҋNhd?zaajAVR tD0U¤=j B*ܒVh<-~'oAG6k.0 LxZR Tt>0%ْ$EWƔ0d[*h-6p\?!Eʿb.0plG<_yS&͑["=csY+4U- r-s}@"~$0g sL;Pف\_$׼6q|Ӑk' e+ujvADH͖ $iYK!1> T^Fd=?R *T.URD4"u#Q -#vBo[^싡/l)m#vX+yԞ BU tJUc; _CY@sECv Cղ ?5 ֤`#Yĝmd**RY:"tjB̈ F.}s<|<i]ZR&\]p)D\2Cu5^E/U:(ξ*ĐÃ1+;t;G*B))[YTk#`.5=M>5h|nxq @CTQ=16-xhߪAݵbW{_<3~Sa"!yy͓cPJ7K!B ȚI 6 ݿ~[`,?)^j=n p>cyG{#AM1/Z,*{|4 B*" Z\!-$JC,x)B=``HD]=VhsIC J  aX `=J #\R!)Jd4I1`O@D dP%xP~-Ě1&K! (;.a޹HtSKD"%,Ւ FLMgx"`"Jl9ņP J134F3AS(&L%bP[YHIS  =*@Ut#L#1 58#4%L#Tu@G0CF":ꄏJ PgOJtuJP#L̔%ܔ_T(kCUGAK{  @ TNHGddINFUHȁU<ؕd+=Na)Db5 Yh!"Tl+x`S/N:$繠JEEʂ5h4J-E!@rQLSnWZUy)EU^W0WeXZSe$a6ܗF}U/Jцh%%SJPB "EԘbV:_B^֌^Vf]eNknA0!ashbh䛙V-XpLFzfX*f ag ţep"nZrB) P \=gă.J@8"GNJk1P18*2FRV^9}F.v|), Q͊,{MrPZC;ȃ6L~#N$U$1x05B$@B$~cylg U TW^ Fb|bQ¦FD_R/RUlVfE͆y0p0ɞ BTHsʨ#M]HQPȽTٌF4YHylDy0R+)gƒ8D /#5qd"5ehSh*4*ʹ0Xf>IuՊ~'|Q艩d58ej\(~D'37L}x]VTUC;_D0^~KA[u{ -< -Q^rtJF(C2AL,xKNܦw#y1}JR0)u[~cC{5ݛ] ӟ|̼կD+/|ʩmgă~F=mFDJX~KxܫW2Go<E)Z+9୞{0 @$<^Dp7m2.lD$QH 9mYP!lY ȇӖ E8x Sۑo|B\thQ5TOG_sJ$ʈUȵ+f,dALGhjGf/eʼ=${v<eMAZkMYs;h cy2yY$[RU+2: vün'r/kKp!r Z #xrC+Z3 T3-7wjWXH qItZ`੔cf;qIk'In3uXIIQjK;\`0,*mه"9]VA1k7{VİqnmdAو:0&rQkgՊgq$md1+]Il_gq܅y܈֚&h@B屝ia7\r݌Z\ANYe%w%DRIjryMĞxa'%V2Q襙nzh}.^ViN&CˤV p7Tb[ry.jYȮ:/gw"3 o"úUdі9u~s\tgga]{$Gyl9Yt=sk;Y<{6y]O^\xeZƙ^^吡]k&oAnv۫m3@ZYw$H!A NPuܐ@!#JAB:e՘$n'sSaCΐ:P+ e>me[Ƞ;^Xx(zѿx8 >YF)@A(0)v ԋ§Zj7kplcbld)A5e.9̡Z8bndғ$J..k! JIl@1 $!IX*{}!a_1 =7I;BEB0K:d'94)9NR[JqQວLX~Qӣ;Dv[ B݌bݡU.d&] n }}=G]"dbSm;Y2,!4E$wC;;9|;i~/DuE‡??e\`c0J;i?P# )/ 굂1[砄Hp," AEܐnta"$ A ;pD/0-0&-jL0>¯&bxG,b A` Îpi>fcIbY+k!0.$L .&BA؅Y gȆjI6o.Pp։H"c'j=n"!d0-K3F< D ᡯ-B %!BF1&N% ϦzB8#[|ax.jF9[TǦ z1U*!lbN61hGJHb/ , Z2+\<jJpBPG$bm'B ; аbGBHq1Ȫ90p,m&#@q2Q*&VQ.p«Ρ(y@Q*@q:,/ $5( n*C!o2'c*+7C+Br!4q&Q21Pw[$j$r&*i6 "+"L<c /iq҃B0s$"C,u3*m"T0B2L^%4S .g:S=!e5O1S.zʇ[b+9 $&FKP+%AJ&:3L'.m$XJMa^3%r3+{%7o!DQKS4N O`A<B r!%O+x3 At# ,1)SH(#@ޭ?b3"Qq@POr',C^-&6;(`\EbBb(.6D8]ҎYy#n6N8F2Jag \LG"fl /inwdJ9\Z7@B:{4mwyl҆骯'tQW`I[6蘒Cvz4w\i!qw0F|S[tGy[Y~e9 VCJUN}xsx^Zf|}5x9JPZ׶{;Q8y9a|8I^opՃPBlXT8ux?HlFDRqx5X%Q9cIbxIlo¤9bxE]krh8mD;E%[GoTpࡎ89,hr(}$&WP.y9y}yEj؆;yYyyu[l9o:H}4y={fh9f搫ؗj&G9ͧȦ8XUٙG{:eِwٛٹU&r'8|W:.ݹY\ j~thikfNtiy:GF8Ggܶ5zqu{ :9Q:-T!jGsY:1ES9Zz%mѹ٤q7ZFyhJaȦ9Zpgydi$ڪڙ_9#9u(q1zueFi'[6VjhgI,) v|`ѹ{16*XvJ9b=蘨3Xsuou?[Biێ7xWY[J88tٴk;z&{ Wve[0%s\:[x9;7أ9&z;8}c٧{AH{7$ %!wYZ\X9^Vc;%vr~|<['|Ó88ٸ(z9W[]{q!Q#H%dm+ ƅ.ug9ae84ȇvfFvV|`9YvJ948gx{mq9L <:Iم>yy}MkJ8y#Z9Ż{^*==7 {'=(YM]{䧃lF+we}{R[SsVwge}]{y<E'`וuw(^Z|:E¹ʧ[,ͽqxìWzz}n[R7.6:f#f}|ݑ!h5Jwӡe/98]G7wfzJ[QwM(AgJ慞a8/]8|wޡ=<98nrYp>.ރs-]]jL膀H9~::݄8Lɼ067=qf>d &od]~Iw]@?EIMQ?UY]a?eimq!ya}?!?]?a?kg?nK?]7u׿_՟vܟ??۟_*+0aƒ "+k."h1c) KI G#ryQʒ)KJ3)R1ʌpŞ$Qת:i43iDH4:p*Ԗ@JT*1U-JZJ׺}-ܹt~$[7Fx1'.`}>W,1̉u5X6ZKQ&40= մDӝ:hz9?x$">d/A\)SHl|~u^B!%N8^'p\$rW0RB 5#Sa @ [La˙ ňScb%Iif7Ul7-JichX} @5 ԋʶن:$8 d.[&Sr$(lsj cA(YX^z5xj’rzrYhpT_ ݟ=KvIAL`1OJ*R'`Gf,D@O!bA ⓝŊ fg/t'_^"i YE7+6Aq.ގ j^U$KVqj!DZ*t| rl',d K K,X I ո\KzwC-%VX7>. xĩdj 1S-s/VA8byEUY)'6cd*q~`!=suB*')^=낧rw.|cd᥺ F@OB e$1 "9Ln&x,V,tvYqT)o8@. uC@JL֒lTA3"aRZp*C*6O-9LQ,W\HyGHAaP ])N1C0>tW8@8!ctlOM*ջ%x+|'}$RG1 1E*W7?KJ#&gb6ce;FAC#7eh)qR(%:(.C&ugriU)? R0xE*d* Os(%$*t[ < CH|zw$,RA76Ȯt a@Wa烕aGTa;pNgK\!:(JTO|@|!@kնI-Ndz4р/Z ts2gsQ!u]?D|$EHr^'NB/QpB>.f9ZR-ODapR\n*%@^@0`ܯ_@5E Wěh쨼65- 5m“Zp(O5$ %ű&$>]Ti?N *;2Q fuE%W"B{p* YFj#ԅEj~$!Lg'F HuJqu45>) W֍A4_T#Yf: `|0V8X0y cA ,T*)7oJ8<2ڋԨ 0L#f3 RMFuu55!P&^5+;GXjuqag#uDo;5VW< >fte>h6iSGW^-V7 &? sږdi3HA%6 mj>iP‚a?@ki6NGfƙF.>%E4a/b2%Rqq}) *.@7iM0ޣ[ʢ3Y50яѨ)1KXDtfmTl #i)P+J!Bdh -(48"_gB(jcQy-LgDA $* y ymiFh!$v%<ʆ8ʃo0i|@9A$T*0S K7Q{Z8ʢ@1K u+Өb pYFuw@+$ tZs ˩KaًxSXSw`Scg  kyiV jҠ E>%&5'PmMLUFP01\ԳzH7t!If%PrUKuct=Ļ`3[= ,'LP]}FJ5YaH@ƫ<0&L59|Su (WAB/@7`'BQ#%QOe[IGBfNVfMDL^$eY8}qdhw sS7l+zpi3 YI$T@ oiM`w1;-MN6:v1CJҗFn4 pC!c3jma grӈ ETj->JӼuC' j`ˣEܯ.S+t6ȭ9CnJ 8Nq Pu&R vJ~aaM @巹2J6%QU qʋjo1O&rb9(.Wvdk'k^KA/5,q^uQV@ @d .XN4F5F>##li~kER^wZgǡڿ|cXY!6C -R,JC.BHIg(WCCNBcKqz]P4>꺕)Ȯ9)1}&#"Tɢ@!#AEL~)\~aŠtGJa3@<~r/3WA=qq꦳\)|g QP#0B@A(G؟R1ҹ&{*{%Y;a*Á)$;Ja]` x12Ip5H+’!REgaU5liD24f@ 1oLrO@ S]sF"D5B@cRl;A+4(69." &|#n4eY/4)i!Q:bK~˄reM Q+@󲺭_ftںjQo1I߳n=#`-O$Q^ O 6p}6~d\Ü}]=IWJtj.,pBY K58URJG*ZtqɉMHR%"R!L6k9P.:q*DI\4e–0K! *I"[L2dYyZBY3 9vYh*R\8JWb߷EJTpEnĄVزƗ/g0gωC/홲iǕ)FtD,ڱ!HD= m/+X4Ñ[Nls~e7|ѧL5ts_~y-7Wm9[μ3AF0 k  3pC;CCqDK4DSTqE[tEcqFkFsqG{G rH"4H$TrI&tI(rJ*J,rK.K0sL24L4TsM6tM8sN:NO@tPB 5PDUtQFuQH#tRJ+RL3tSN;SPCuTRK5TTSUuUV[uUXcuVZkV\suW^{W`vXb5XdUvYfuYhvZjZlv[n !d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,0.# H\gsAVA!OA\.RmfAT\\\QPOea^.OATR2\.`&k2%R%]%R%R:T:R+R%f%o%z:sQVWRWRKSmVWoWfKqbwg~jlpxh[WRgSw\zk(*24l+T*(eruo[,0yXҘ\ܚ\ΔNܖmҍnwoӶf|y̸Us.ALOk#hTr $ :/$Y$O/j3 J V l]`%(((;(::.RPkuy{JWKKRmduXXk~:qȝVJyj(/g1MVqsdoԟЖΦ鶐˘⛣ĥŨʳӱ嵮⛞Ǘҙؘ͎ȯΡӦثɶ̸ӿ۳ͪˎԔˣӔӷɱы橰芩ƨ˹қȒ̮Ƒحȱ HtM‡#JHŋ3jXqR H8Iɓ&uP c5jb&68sɓb54IѣzʠP y5Vȹileʵٳ Ụ̃Gjq.Ix&4k$E6˷#-ŨXë*A52Ex2[>YϠejQcE$hkvnµs(Ɔ yblz@t<@Ms }PF 1(5vū] w@2y.oH| u#FcJefQ,ɰy CKMO*ҴVi[Vrb0Ϡ,R34FphH56Si Bt2@( tJ A7&9"Wd](Ȅ(3 Q/ %)GyJq"j3ѐK1 & 1yhd0)t;,(,pZ 4Ԥ mĪi.y"`عR$6y)¬q}3=g}EXq]!헏nԢ؅ 1nd Zi/}YGjAK}d.# 1pxBIO >zpA|| 8ܠss:W \GVX!р#@U {:{זgcV頂ׂ!zg`{: )zǁ&hZ!p }p[~]P }shDsU Xs\pհ,Q` g4HgOzGt'GuT@O8y2%x1Rs xX!hh*3|hwvr0y(rw|tzxu }Gx؇Ha|Q}x g؋fA(tr7Wǁ<}ȊP;WHi(hgqhXnhsԷ7G(|h:sT0qW)wÈtHxǁsɊs8(XYҗ(6X QWwu9xؑH1& i(3I GI(7)u%9cɀ'y[I-)HgWi=w;镱(:x )pɘa18؉az l(ǁx)I X*IX )(0h") `W  "Ts!! gHgluiU)XFy9_)Հ+c h7vtaaǜP埵ɝǓ}s^qJ8Y)S%` 6xA stioI,tIt Lg0 ɉ2:  zy I,9qt`0 K W:vZ:Vt{70JnZq`Ձvzxz|ڧ~:Zzqr$oPui _*zX?r jZw|$ڪꪇ:MZJʢW g}؇S}އ ~~}~]~@&0uPsj)` d:p|()[X8 h;G1 c* ¯[z xEH!MS}먰Y]hЯ *kͰ xBhuٷ}T+Fd)sԘ"w p) 6 jb겟u^ZP} ɍ  [t))gh  O&+-v )XgA{i܈Hb `+x)_wڱ_ 5|;ܙsȊЏ˳a K `dyN1k>[yF:S:p [1ī*ٝ];@Y 0;@0g+[ M7]y돊K$˗hЭQʿ85 ڲw蹑Ȼ~Iϋ @ `8|Ô x۹B<0# z%̕'| Y ڠX UrN+  :  gM SJîK0a{ `_\KKn\TPʗK pJ:Ǹ:c:8.ڦ d \#ʶ˺˼˾<\|Ȝʼ̹| un Ph\ 0 06, ZSGq``q +r @"ѐ|@6 E0\6 "0[tK+5р,A"*Um v "= -( "ρ~ M<DNnS"> <*]߸ X a} η XE%}R}ߛ̠  c kF`AӋ`!q t P k$ %>Mk׉-4M0VSB Ŷ/<3!13/0fah;+R31hMS MBx?d0P )04Nl;CWt&L^$ >E_2T .}u> p rS%Ld,֛uoqTf(!?e!0Mi0;1:!ЛU埿0^4=H@40>dTiAd//0RQĉ4hxEQƂF.a;%Mh˛ S}Rl'40c8/uI\<_5{ܸ*Pv(`ʸ"8"WRY-N+AV(X\A6oPpPNӨB z@LmjBEfE ƊlAzΞᢆ itj68OŘ})6iu tl&^"hMyAɁ*r61q>O?&x%+2`c TxKxj] =6k"+ CgTMGrPKdRV[$`/}}])?Hk UfL`h8mH5USc*+."af8y-9 f#4֣o:@f&͘cFt`' I;0#>[iSKPf!4*DH%S塦!)j9gyHغgXi<ꆔꐅЉ5: bF]"9fVs58$u B FHxwG;_ɮl5N8r RicxxzTy &097kzӺ &ReՖh""Jr d:Y wf>_*- {V/Hߺ'gq/yaqǰ t<*< *)I.7`cTF@ cHPNBv1j5@,T$4U75|P#q+c8w4<‡>4E$~ aLqn9EX0 Y'7+HnĐΝf!W7,CfT5>$\C̣,t;$0Lpp"7=ȤC6yD"~dJ9j, cieVI% >‰89I7Y+Ƃtԣ-[2EZ8Z $6@twMPCgyR-A$vR:}g~ G J5M[AopFcUB^ 3U¿Z^[`bV8uf#r6_VhQ?ty6WAf]`ŬTIZKDq]E b~iQ`=5)AwU-pJ*r `cQh+$9)7NMakJ.mlF 8oS<͆䜹Uxh2&-qTN%,3$ݛ@r3JbΚoH:i NwqmX69$X;f (KhF9efDB82DNw}X9"m,mS:e4Ì/|1ox )E?zexUz'3[@bIc{^}')G~wz7:XAH;w+H^P?~wտ~?{]Ѕ\0ނs`dM˄L8M]MPQ @ ]ЄPM@LH3J)7ɑdPHxq{ӰjcI%lB5pX(1B0#%1841=xH5[9,:Oȡ7:Jz{x("CB*`@̆Adx@8l=tؘ H`tȌX!1<Ƃjƀ<{A+͹G350܏ƔO !,a*xI3 ѤAyd8$icMш +<"@(٘ , hHK蔓0Z-1(.(Tєe *mdi*]X]40) X1HwfA$Y)m6AخD y=QEb1JC!ijl6E ȶqȷIeL@v|ڋd6 !e+{4)~ɭJSS1)lj)="Ӣ9ӝi1AXЂS ˚YiBK#>9Z҂qhպžG T wyIux71a4ҘqCғ0(ɂ@RxpCOֹ.[ٝrY`Y8_>9i+&zEB=y\hd:눞)YP`aD xMu>jz ,;12 p ݲDj'?͐ĸTDEr!sP*RG8K\-$ZyVRlj0 HՈdEqEٛEFd@SS*m>=ڣY8At=bX<HI"2S6?T/,zُź=-.r:ًA%aY %U[j-:j1e 0ූjb8W؉Xb/B1q4 m6G|{-Y˙xdH]Bљh(]ԍ(4`Zc)I]1X"E!#**1I[E/2[[݅"]V**Bp$hX % ڈ+'D/} 房 ,F.]hge[ Eܡ/ `F5EȘކ_j:p y0~A=-nRru骮iix ڝ]E㤴ݒXb!/i/^m/0S*d8)Id䜘dw2l63xmx1ʭkx Sl@spZ0UneZ Y(OUk";i2&s)5]+;gnoZ./+M?4W &5 4YN"8٘S^?; mkX4uN7i4eeRY8Dg& [i40cx5V1yZ3i7c(\c@Tdd;!fm6@h?Cr!Q'ٶ.q3;ijΤf XjKkF7~9)h޻ G]=h tA9kufHi)+?,[[*C\[G̹4䟻o9FV;A3jllc:y]Fk֞ÛIۆ,Uv lPJ}nh3s;fn;K3<ۿN[4vIꠇSgca>ee`p?! {.r);7߈vq;g;haskell-mode-17.1/doc/anim/string-escape-highlight.gif000066400000000000000000002214711360223321700227060ustar00rootroot00000000000000GIF89aj"1;&""1;"""942 *EMT[R'g"g2v;r1I1*zEsQ.TE8EMU(V"g6i1r;t'NGzIj%Jo;JONNNEGHQQQXXZMSRzMMkPNwfRMM{MMrMPnSfmmmqqquzz~ssymkoPjP*LX"R2X.b4i7r;r;NNMMPPrEvMmQyLoZ{oqcXNrchyrtty[ŸxHT*Z;l1j5n;rMMKuOk||u|hxMrM| $ :/$Z$M5q+ J V^lMLkee:Vpp]rUOdglhutywzMsq/à˳̴Ź×ťζվüغ٣˪ˋқȍЮԸԤٻԒ!d! NETSCAPE2.0! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,j (0]:t*\ 5Tċ +"P"FzdD#Q4QHSD'1d˗ms͟2iO@9(vH.|ȴRCҼQՍ'ijeN1g[v \Ջvֽ\[z^8ᾅ 7x/bǂ/8o]P.Nogk4CT2~/kk˽۴K|Z7Ȁ)+]" <=f~z#諧_/^}ُ okzܽ~u{z*w`Q-(jXyh"&"G} NH#~bn4a@?Ib?${r(@GOViwQSnɟ0%(dD%-(|Mzyex%A'W6$qBv٧{)irz(:)LRh楍^ixVj1ZJУj뭸뮼+Dj6F+V+`O/:Ҋ&Ͱ#0ѺU3֤ AZM5ל\0s7"v²,ɂ5j,A9SRԚ +fW_%&$ zװXhTvJԺ-͡ ܵpP79 f-1Ė{hn! /P^R7or+'mvma7,q]ޮk-U׸W U(~Mlb X\8!҂X.CوC@K5F8= !%Π c,Dzp=Wb.LQJƪDWR"8@ՆN|aXo6E!CKmg7&4wd԰1%- F.K1w9^MlVπ&qM`-8di ټhD0`srEوlܣ#c.F\^}l,X _Sՠ51nPC5jAv_7pA[qu4`! QO|Dߌg|Mt:x j7cE{-`?߿Г5D}'~({X~  |io^|uA&_;Q}R?P?FJ$t-J@& x8noRC Puaʧ}P`' Pa̓ EP E}}`W|'})ugg|gww#x}|Rl}y2G|%؂ p见;|.yPB8rr(eep%L\B7g*gATA}cA?gswftu4lH'`T}'}Huȃyx{VyBPx0 3vupWgX8fWwT. zX0x`wp10u\X(awGcۇ23h(|h׋t}Ƅ7_3cto$(q@Lȇx|ghHRчw{PUzS{%8|p`pf7gB_n6hI8{Anh刀~ȋC؍'L9ȃ}lw'RWdY'4/ K^ v) `0wuX j q'lh| 19'cu%p W%鷄؍ՈՈ0ؔJ)lAȍӸۈIǁ<ݗ(|y4nA7n4@)x Fx fƅFgeag9_>gg֎n2Ё zXx|7IHIyynY|A?~舡w *@~ )xPkWPܐx y WVǖRѰ~'c%Yz@7@h58YY]iwuIe8Y)fHm )əɂyE z('V }5 nUǗ6t6t),z≠0Zldp o0v ֜`)@ ׀PLꈂ1oȀP)c @P~k?:cpUX^  p:yi?ءw4x z-r8Z ڞc wy)X|3Pm#:u ]`АxlGՎ:ږGЕB𸠟9o9'**੢1:+ɫZkhʤ@`v P) @ `-0 /k^W`%`b*qH/` 58||z;ڬ)`ثګ:͊ڟ~؇jlף5DS%ԙ NXzPVh fxh::{Iɫ:;[ KúkТ z Q`א|PJZq`Vj_XPpP pذ~g~w EI&uΉِرʴ[*'2 +.JJ+Rk{)[D˴M_O{ | Y j[[VgvV{:zXz`Zdm[GXQ+۴{;}5c@ Pez 0 ]W |j Y{Ѐs ,ok;e++ ;%, Z-<#L׋G$“[+ *sTpÝ 1\`M7/keő+J{+`, +!i\.lQ^z0 v{ `6ɐ`. L0Yij8נ@ u|Kd,ۻ.Fk!Wk k}^acHL 6k˷nM\J+\<8[nMns]6˼R߬˅Ɔh5P&P _J Q\+s[]k 5F<]}L2\Eezϵ Que]9 &ݲz\#6}8@7e eyW_hKǐcȅ*tG P_;K@ t|al- hjl}%sSrY۴rMׅJS6UTK^`Xœ ږ~ ߩKܫ4; x\nKBN&DYR+Yc0* \i a=b]: en(d)n]-jnc vk}rf^̅A5P- 4J9S4K #TŘ. ׬ w-qwK]ڨ7Nꩋ }޴ӝzpp.*~狽P+K o"5UBC`&߻(*?98oK9LJTN _H[o vjgc]k f lpS+Zhw_x|o^yVWK /__;9 PU1  E_, :s @n/m-¿丹_^Nko*ُկ~/ q@$B ^S B7VXbƅ$n)eʑ-Ml0&F eZ F44+ylB8f̑N,3&Y\NOv9߇MWfwjݟZn ݪ5zskjx]7W z.h45\l5;j?j@ kz\ٔGj&vcgb}vww>xᇷ}xG>ymg^y矇>⣧zvs>|ϾzVG?}IQEq?~營?e~ϟ`> p_ط6Ё D g4`A o|E(/Wn},<7-d:tC0=b8D"шGDbD&6?tb8E*VъW!hE(nы_4b8F2ьgDcոF6эoc8G:юwcG>яd 9HBҐDd"HF6ґd$%9IJVҒd&5INvғe(E9JRҔDe*UJVҕe,e9KZҖe.uK^җf09LbӘDf2Lf6әτf49MjVӚf6Mnvӛg89NrӜDg:չNvӝg<9OzӞg>O~ӟh@:PԠ5 z6ԡH\(C:Q0D/Qt@?Rs%E)>ORs-;_SVt :Q2 b@C@ii`p_c3iV! #e`FPy*Jz֤ j\)Uu VOonX:jV8H-Q(F)bU=$]{ޕe`US1U:ІMc!ZAu n2ֱceh%Y -"/0\! =n, W67WuݰVADt_jFWtf-jZF E\C\kbϑƮ%]Bqņv7 _ `uvm9ImvAmr1>^r[ȵ0 Gvގ|x>pC6@Lj p@^%NHl<<8 с&gyE΍'|'#5n w]>s47yusSڜ?"̩t7(zғXrt(OzԥEt |S(G]zסgG{g^vm'sw3w|?xG|x7|%?yW|5xD b}Ef~3.zӷ}y}u{~?|x/|7O?}W~dBGq_ ~3?{>[Q":W?CC>X(4WP@]x@쓿W d@#@c_ t>V T>?+xTȽ'pAOX>KЂ=-V`C0L(ӽJA>%\dp=H>(B. >INVкGA;FhL@X0?s;AC2= >_h X$-=/D:< >[AݫA<2WD#LHJ_8LO|&;hS>Zx+E(fAUJX-dBGܾd P ̽)B:FWx p,;?Kp G,H,ԀFtDJXWݛ/VlZPD0c'dkHXWHHFߛ lPGuIxJxʆ<KQdJȂ ;D0I.ųJJ[5A]H<^ؽLĪJ+XL C>pԀO=uKJZL=KD-,MнK<>;+pӅzܿ"lGMߤcSķ=]HSƀW(ܛC[ʥ>,O CM=شVxTHXHJUh | B-l[#eLdQUVPLC]E|H}OK&mKlJ޼H,I4π3Ľ&A,ЊB_hL4SM@u>+CPM@81Q܃CDEJ`ӹ\?cW ETLH`?E>&w̽܌HRUReԽ,ߓsHkVP!uœ=#=Vx$`$$T3C!grl\W[S O0=ì G0=&p$T?"W-W3W>l0ΌLYhaQyƒսx5XļIps-G0KFpmKK=gT-O*I>FG+վdT<tTGQj}@SJL"JVEa\YSKiw}w@KpV,M TDWLuPJԅdpXȴͤEFW8+xJ8YƼnL[ܛ M,M!L-C]UVٜZ"DBսP]yХH<-4S(p \pLu['DJSHJۛH|G,ݲ=]\SuϷ=w `H/ ?x0W^Sɑ_R=&W]l!FP@t G<=I-ۻNuJXZ`HNY߱-pͽѨO U<о$5HVbڷ"5c<DXV ZxZUaV(N`{Sa%ESZe:UPYK@EQ$Z0i=CQ̃dX;NqMӦeM CD̽YhP@WPNB=Z ߣ$U][a)_́M~M\ P^et<V\m%BlMFxԅ_K4pEԂ>&fF =]Ym@RP=l#hBRhG@GpC7|GX|^<(#D`vv nQ`DLaNٽ\-mZՀ _ߕOg+'hK\Mamol=,0ג=X8jcT+d;PK0K:^5eÕ }=HQOֽ[=ܻ=pdk-w3"hª$e&ӆiVHC6\BAB% ̷BBJ,eEZ,Jf\d=O|FDΥeLc=tƀk5v=S?cJn\ G uiRd-iVGN\Ǵ˙=no+6AMtW|lĭm_pLn֜LM2\&KfuOlۨ= <$>}q~L/kQ oR%`S=lfPD*~]cviZZ :tAOp< =GhGd( /;8Ig4XN8USd2s=>?0gf܃]U_@uMWDn KU=4M>W VLR{/`Z?\wX/ZAZIXv~Gp ]x}nKCg B\S;t{|/H e6Mc $&aFU W,h „ "BYV8P,"t<d G,9{J ZR𰪕:u %EJL<ժ$@iWhz8jQk Gb*l5)" AK2(*_%RrS V(f %@cI>LPr/ZMKf`5aCWf1滹V^v2  OB]up"j]]J!jjd\-E`<*j?-<_@'?'GeT0 X]`A<um*J-E)5T2SF ƙATATV!)gx!wE)+zZ)凊%a^+FT5+AK5x)$A) 1!$g"v^G|҅ݍ2(2J(AjHh(XAa%Ptp I]ʼn" t1nJV/N:Z j+" )(ZX8(( ,tܛ#ګB8 p~[еA-p-u%cAn8V[һ~kк+V ܿӺyݼK -8HVNyL,\2 )G-21(YD|(Y(;\)6ˮr-F?Pi\5YKG/<0KC,.iZ6ܯv.ۊqCy7}7 >8~xm"8 K>9[n9{9衋>: 9逳޺ጼ{7>;|۞Ͼ ?<<+<;>髿>>?????(< 2| #( R 3 r C(&!(!F<"%2N|"()RV"-r^"(1f<#Ө5n|#(9ұv#=~# )A2!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,ZLY"1;"""1;"""""""888EMT[T"T1I/e"l"e1u;r1I1*wE|ETE1aM1zX1wM"EMT[;E"I"[;["g"l1l;g1r;u;T[EwE|M|Mg"IoEEEMMTTTTVVY|g[oaTM[a[hhgjassrplu *)#)5MTM"Y"[1c8j8r;r;=HrE|MzTgExI|TwaITR\]fv~aj[[Xbeghzrr|wMT"[1g;l4l;r"g;rOucrl|w|M|Mw|zoMW[fdlljsv|} H? *\ȰÇ#JHŋ3j0Ə CII_O\ɲ˗)_ʜIJ]8͟@ mH[ЧPÇ._XjQׯ`-fr WQ ˶ہf5YoZ\Z>»a\NK|2YuQ30&ϠUzMѦSzםž5ۡm-Y7z}V8R#_.T95CR:'c.R;_Q<ͣ_P=˟OϿ(h& 6F(Vhfv ($h(-,0(4h8<@)DiH&b,L6PF)TViXf\v`)dihUp:)ri'2E%@i˖ +yb1L* W>2'N2!\ @%*|J [J"' $ ʂ G}D*0&[YJQF[PJ"hg@蠅ji- +jn,$; 8 }BAJB9n v$ JzL&,&쯃nL%|`p,`  `>(3 ɵ۸X @OV1_X>%$]W7IDP]Gα:@&GB vbq4 xӒ#pXXl^ObZD>QCMi\؁ [ ןC@$}%:*K!v7Y(K9M}p'~t-~0bu< =[lP6 f#XxjmK|;ij=IwL^ ;-qP[dAw(DĄؤQ V6+ސftR+8>2I *.1H.MLj$QJы䔶5.={.eaPm).__X72X8aɤdKt^BhD<6I)R.!rQX !*jpph@98F,@ **=x+yL(IoMr46>J V " "%dK`bzcJIA@ĒF3@hLVqP *W)A*.ݨTfZxyTJjU&(HT4,fZ$eL-$Jjhת +?]~%$K TT٢ 3'd:LQaW0l_6TIK4G(i1%nI&Y6lzE(BA/N#(m ˙Ll&gA,!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,hL\"1;"";*"1;"*/,,EMT["V1I*f"l"g3r1v;I1*zERE4xX4jM'EMT[;E"H"[;["d"l8h1r;t;JOEwH|Mg%MrEFFUUVMSRj[IveTVgmsssww|olqM[a*QX"[1M"a1e;i6r;%R%]%R:]:R%R:R%o%f%w%:fJ]RRuHzVhNzJl]Jqeyzop{WRdRxiWjbeghruw|w[ֈiwozTM"[;l1j;s"e;rGvRneuw|Mz:%%lJWkWrTWQeldllgtyyҙѥ糒ʳĚѨỗӗ˲а垡Ӿľμ H*\H #JHŋ3jȱǏ Cz|Qɓ(S\ɲ˗ IœI͛8sϟ@쵫hg݅"OPJ= 꺚U `Vpװ@۷p2h+1&LY;p)uPǐN*&lpf#M滖1S!kۖM|^Fn냞.i =֭3+a<]urʿ"VO?[ynsBXg ?{'Ͽ\KX}(KXƔ5k Ԍ}@$q2R~eaPC8X=@Շ1"AiGWլD`<}$5 +VWYbv՘wa1:h)u 1\L] cf2B4$p L{(P@R%xɑgIY^dX &L2{ ̝zF*D4R1vzU@CbPNꪢRVh5  (l& G5'+j6:WfIW@*^Y)s%dYذ+cR-զ!n%&Xc3g|SfS1fLXd5dՠk)fTZօqAGV 3,2rR6Ms {zr†){}pYa^#L4(L+9#2GLG-DPOm \/Tu`ud;vhzvlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.1/o'7G/Wogw|-/o觯>Ǽ/O2 -_HLOX?Z|7^$-j1B}l,@P ,Q ,FaWz|4L ׊-A11'Q_+LGp")dacBmHb;c \cY 0}@ 28ĄHK E@@0͂$BJK$)M|%/`?$Q )>[&`|@%7AI r@ YOЁioVf\T &O80 Kyc4Bei>zb 7 ,sl8~p6(/>ZH9} 1z3AG2r(U))>,s=%BҕO?CjRӨV4@'V(>tsF6GaOe"f7,zZ"V\z @d0? 4sQϦaU*>4['9ZLŠ`!tY (@O4-8kznS+V}D-Vϸ Fo[Cu ok?^Q-Z>>ЩgxR_}n-ԠAZ3btFhB`gؗ<>Y8E#  p|׽>mfvNqӗⶏo) `RָX#0  hN,Q [0P ȄĕZuȁHC "v!\l$H%|HԘbUTU ?[q_%L\f/peeZ>KTӂA=#oA1Kf|:):Q]dࢸ R+x%I0㫳hqi]G ^o0l-m5@v|䎳ki`':|e1@ 9h+b򩺌ůZ};,UպҀ-iԱT,,qC}ٵ@T~  > "^B/s-_bφ%\υsJ6oUL&^/7$EXucRdXbn'Yn`EgxnXE tnqmSE|c?̷LW 6vq4 ^WjNwP%WO0?bfpe?`{:Fg(Zo{#Vl0BǗH+c*lhE` QOhSVe`Eq@E?wQ`]){EfX L+ V *Wp vd@wsn'E{x7'vRAf~P$S 0`h( 8$u(Kf puQZSlWHgeEB{ d_tqJs mu?V6}'>/kXjNzdz^CxcWK 5f8D SKpx9uQ cT?v>xYx :gE jIxH@咈 0pQwǎmgr^fJpvypwK8F XgET't 6~(\I>t#OmX1Vw{0i7>R4_E aY%/E7iW-I(/yyF  .ٍFPK&Y p i 0Tl5vBrpD2m5?wI)HCrEvX S׃cCCy{i?gh_6ZDryF 0i^@.iDIVK`Y7l?9[e!W6lExYR%vpG  Upm_&WikP|?U?fC6ECviWh_B4WבX$wxjTX: ')Qd؆1䒨E~/8 mw`ugEڞr6A&uO@ |E ETl>4xE y,T T P E~I3xy_JnR\5_W~S, 0 Df Ic O01Jj ` `pGfu6 yO函䉫|zOg(@ 5Fpfk՜OXWzD~g@b%RP|%RnDWAC)Z q6Q&R(w?`i!@TyQ$|_ Z :C%T&lG~*zT?nF+n D  R,erg>|0CcT@*cgxr*b/'R0Mp"%4Y~ZTl E] KsU P m6?XT$AUK?3+V#}f @_ K>'>i tZ(@r>igJtEAaŞT ?@I$GU&@ p  P 2dZa% L}#jJSJPW$j>K4k@Wz@;>F$W@Lyʋ?EI N`F>`#VS[׫@ A_D[@kAkJ` ЗXr5ruD \5? 0A!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,LX";1;1"1;"""""1;;EMT[M;i"u;r1g1M1"yEqR,TE1EMT[;E"["E"g6j;s1rGzMg"MoEEETTToaTM[a[aassrplug[M*TMT"j6r;a1%R%]%R%R:U%R%R:R%f%o%{:kJRWRWRQXtKzMb]|TTql{uizllJ]WRfRu]ziYaagjrrw{։hݗkυfow١{wQ"[1g;l4l;r"gMrlwMz%::Se}JWb}oMXfglgsz쾗鳍ʳƫྱқΡӦ֩ɶֳĚƙӗԔʞ׬Ҟ఻槳ȼι H*\XЅC #JHŋ3F|QǏ C)#ɓ(Shr˗$(թP!8Ԯi-g )MFӨcD@cM0)GW$(K͂QZtjG 15|ĉuFSÇ5d[ƏgxPJ{V/C~ ,s3W}4ⓓ+OcjPf\y+ZN:jȭ_ 'FbpJ\#79J-Hle\޻ij$8,5V|NGhv07ZX`AHcrlF5O0 5.HU.l@VBHtf4X-a`/VC dUn)b $%dfWa4}\3*ȋ4B G5貖 ؗKaGv5" Չx+H)k\v9,`֐]W(@\ucW16+ v^@:$zrUSo1iP{ C)&n)] WUg 'WͺP(RTicrva)XfUtXs!.Ki n@6^k VuRsdtPWI3WKCѻYd(н <^X7\5}=#3@.j DS+%#0;-,1MYqĭ5φ V9ĆҜIy胛b|X\‰zU=B͓®L3L02tx2 >.9'IN Yiy N aꬷ.n/o'7G/Wogwo觯/oܯHL :$`#H ZD (.GHZ oA& gSp @C> -A AP"/%>A&:рb!;E@C B.2Oq -`PPw@'4Fe  xE X\`& ($P5*pL19II | e`F.2(dH``BPx ) @a 00@LI `4C= p )L*∙X~@SaDN’ Np, IA+LR4 @{/)qSD$D' F~HHE2'f`"j} /@AHA"69fBК8Hhd)DP  -j9IE%T I8B/ŀ9Շ&01ZH`6Tk3LBW)WЪLQ-W.X:V?*@`4 BCUj6 ``p @mj/ 'QUԐP-2 X2}U (&v4P nV>me@|Db+9If } '+R[P֐s% &?Y3¦0&Qx MRNH'6A^O, S 01x}k `m7qjojUϮƴ/Jchad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,\LY"1;*%"1;"""344"EMTN(h"f3u;r1I1*zErO*TE1EMU*T"k7j1r;tSFzMg"Ms;T[UUVMMTvdX[hhssrlkmZ[W*QY"T*j6k9o%R%]%R%R:[:R%R%R:R:R%f%o%w%:hJ]JRWRWRQXuFpMoROqfyvpgypqWRbRlRu]yiYcxrrgz[ֈiݗmυfwo١{zTM"[;l1i/l;rRueuw|M{,:%Th}JWbo}pTegljtuxҘѣ뻗粍ʳ˳ɭྸĚ΢Ӧ֩д㺖ƘӖʞ׶ʮӰ姳䞨ӾǷȹ H*\ȰÇ#6\Aqċ3jȱǏ Vɓ(SL9r˗0crMNv͘l&}DA:UJ;`]@VWhȐѫgZRJ:vvX7 ҵ{7oj<ʋ \5Y2tEh`Œ}LV`ׯ7 L4ZՄԸ\ J$X:~ Nb[n҄Ș:5qv۹zi"详a_Σu wW;G<^V]xYfgą =Ķ G]A!|M5Qf^uډb`!`L W mD8ڈ'ц )Q2Lpvr͂$dCD@5tcS8KDVpI@8P2Mؕs=iUC v152|2o~IXv!rJvqyq840DL԰@7uqjJ֒!`ڎ9) ,oxX Zi^:q2Ev i!dczQ4bJe1$iA .Ǥ9-ׄ5qp 16#] cd]"*$귡iW <k @]`GnADd4k,`3bٜvŒWZ c-и&13I+1\™gc PWԡ)*RT(PH%ժZ!OVխz` XJֲhMZֶp\J׺xͫ^׾ `KMb:d'KZͬf7z h ҚMjWֺlgKͭnw-pK\`Mr:tKZ؅'zwx]Mz 'K6wʕxߛw) Z7q^E tKaZ}8Ї$ K bw/щŜh'0X|X.& `c@UD  {W ;Yƞn8ǠrD1E!,2rKT[i020>A ݰ ]Hr';BA@h-gX1Px `ep.Fg2B%<1=K"OՃSC45~|= ʜi螺p ^D|I,2r]NvkEKk8[;Ȗs% <.wϙHqǽ\D ܝB 2AXuA@0WC A"0nmsP`% \xKArkr@_ɛ;cML``p ]`s<fCrEnZ{p/@ wj<3,]R]tE#^^|g0~ԓ뉮@>of޹6tk!raNٓkh$@\$ˆqw'[gkoVǮ= cXVrwQ;-ïkvzD '7?y|Wf| |{p xabP({ٗ]PqW g{ɵaVݶ\f{ U8]\;6jPax` gk\|UgtVrWgw`ve iP \]hk_ b&8`\\"(o)d\10jcpgw @ %a 3hX,rvWpgW uVuf{Dg7Ekgy%h~6{elyz`rZah ~dwg{f\o(|ǥ`W ]~{ aEpv_fط]0! `fv|h} }W 8_Xwh膗e}Weט]BV|6W}h _@|` \^up Gr }8hJؑeH kШi8h fhuQ &u\n˗\5qkǕCrϨh9|B(a~`y ܕ|:? 'bҕhoHVfɔԅ v ؍l ]RiF|i^_\\y\Wjlh|@kiy F Xm(nAI aXx( `>i%* ~v ]Uwqu E|E\ߘpi7]Pʵ|v q8d{oևV JX n $gty9b~醓 y r@kPdy1\h?u}a('\&ɓXf! yu ` Ug"` ǕnfPv͖ eg8g#6J^K8 )NPj\{ՙCukh\\gu}g06X}f1dzfz Ty } θ:a7xz_7_>j"\Va pj\{U Yjhyql&wy6`\\ .bǕ . g]qK %vaǬdhW]{\`b!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,LY";1"1;"";1EMTl"g"u;r1g1M1"yETE1qR,EMV;E"L9i;s"gHzMg"MoTTToaT[aassrqlsZ[W'5'-****&*7RM"X"j6r;a1%J%R%\%R(R7U3U'R&R;R%f%o6f)v&z'M&Q(D(JVRWRGSzJrOmVSllgoJ]WReTp[{hZaahrrp{ݕl҅fwo١sw|Q"[1g;l1l/mJsMyw|-:UG}JVYcglxoVMfglgtz긒ʳ˳ȬྶҡόĚӦܧɶӬ׷˜Ԕʱϛ嚯ȷɹSLa*\ȰÇ#JHb-jȱǏ1Iɓ\ɲK"_ZשSM$VAU5Yy ̣0š9jxغՍψ\hhVW_Yimj 竭HJV9_!zK5([q!jQXu4 <<> S3B#=9^PH[]QC3Ş#6VY Og6LHۈs `X8>M6{A"[OZ _ՃĹ 7B ~*'L0qVY ^Y y3p+[P@!!W\r+&3Z\^A-TLrjEHfO5p,hh\=00|/ط.H,1CE_Y6̰#ÕhfA,$g4ae l5bx4iGCx:#>Q-& pE hA+5{x:%raj!FC^~n%UA_`~Z&wZBŠOx1q B`KAF3s sڊ:Bq[" 4- հg FVג 40&ͪ;~P,"Ʃԕp)֐U:/c%mޥ_xlB&CY4X(삼7@u1AVׯ -rK3] iz,^ [P1[6cKL0 SAz΀*HpEalh*g]sKG`ig0W Z$r7ެ0k 5SS7 DV xЪL/D 0AU";D 0T2[ƾJ'o7GW/gw/o觯/o HL:ˆ'H Z̠7z GH(LG0 gHQbE w@ H"(&:P(\ R,8bE%BX|!?pe!"00 *^bD8Kb8.Qsa((p!h40CD mE!&@J @D!J0A$/?R`dJBF•3ą&U" (J@g&rK2 , 22+P6 y&P@ 2V 7"& OfY}@aD/rDPN E =F!D@G2B xi|%?g$'ІПh`a(DtRC@POhPvH҂p5aUs: M*P#)T&&"23TU v2aY!:Eh:D_xQ|M$R1frNQ+CaT!Vø:(Dv!bcX' dؔFօ/-Y]ȋUС7kSom5GQjG!R zaj۷0- Pɻ4$k^*.5 d),щFT2*nJcHT4VRP0}{b! ""~[L2~M ;Z # d4eʢX+vv; F@EEv,J s0Bc P0_J"9?%* R``ȸBV#e J@y}jTf)_paŋeBy0*KdӐb ] 5 B:v QBBA@I2Z`})Q ܀ZҟvRl&qBtB[k]z$fW,b.8ep-u[raUڢEup ag+!RDD/Rê'[kڢ-Y6!)mGchad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,LY"7"1;""61EMTj"u;r1g1M1"yEqR,TE1EMV"P7j9s"g;EHzMg"MoTTTdXIlaTI[jttr||wplu[aa'5'- **)%(()53?QV"M"a4j6r;%J%R%\%R(R7U3U'R&R;R%f%o6f)v&z'M&Q;F(FVRGSpLyJe[SlszgoJ]WRS^DOeTp[\e{hemwYarrkzgݕl҅fwou|١Q"[1g;l1l;r"gQthwMz-:P}JVYcglyxnVMfellgsy긒ʳȬ깵ҡʓӦܧϰ׷™ӗՔʱϛ嚯觳ȷɹ H+ *\ȰÇ#JHE^ȱǏ ;f Iɓ(Lɲ˗ Y )7QdJX֍P4.LDی0۬=r c4ۀ;cp&Yb .e/PǍgIk0YH26Oepam۔,=l*01vįnV-0'/y1Z۔(mi;[bKC#Ò=zlgO,scB-1DC3d}Avn l]`Zpy޽T98(I# IBL"F:򑐌$'IJZȸ&h ?⓽ؤ(GIR`>a(B HGhd&M"E!7KEPpd&MHa0r0@?z\e"d .K #7!pdΉ8\+W{Z&+ T ~9Гkg!a* |z5@g%)X42Q8D)Fs""!VA6!%MWYq~E+@O7'->MHuD JLi"gT$#@j!{QPr(ը2Ы!*VE>h"P֑ԨC NEv( @YT$+@A>Z-$VF6C)UC+I:" -EJ[er ]WZCT]$$XB*/pO4#HJRݧY\ r@Z*r' 3~$j&X r@5$ش{XO.&GRᜃx9 D5'"0YyʌpmǾ~9afZV"bW\DF$@P ؔd$E|NEq [Yщ'wHVxq(*ىN&N r}tXlӏ;]MG9$ .2qiG⸭ d3Va  `QX" ]rU9a\`I`Jr\XHC OhBxg4A _ rxI}5؜6 J\!d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,LY"1;"1;"";1EMVj"u;r1g1yEfI*IV;E"Ta;t*gHzMg"Mo1EEssrplug[M'5'-***)*&*7QV"M"j6r;a1%J%R%\%R%R*R7U3U%R*R&R;R%f%o6f)v&{'M&Q(D(JIRVRJRyMmVSlgo[nWReTw\{hfnZaagrn{rˈiՈfܕlݛwo١sw|M"[;l1i,lMwMz%6:UG}}JVYgluyxoUMfellgtry괊鷔ʳȬྶ͗όĚ͢Ӧܧɶ۳ζ׷ĘԔʞկЛ嚯觱ȷɹ H# *\ȰÇ#JHŁ^ȱǏ f IɓG\ɲ%K]|effm *SeịD6V5h(!x뚞M`2\]ҷ xjz65'<lD./vvWfז2A \KdcUGlw_,6jT;lk:쓥OOT=Zb^[^"kI{zr=*{c VkY]_бT5tU3!{C%&p ]JH Q kԊiڜGW@PX}/J~m\!cC~]BІ/\CLhKOIs#w~•' C;Xs rd̔;b\2Їta&9v !c#2QKz%. l pK6`pƉUU-==ȝu/ s82 s0]"4c°۝aW hРjhWsF .ˋ/ 0g)#W f!,"n]HgaU07,[[f'0IZPk-2%\oLc$&LBJZS4ChBtÉ]Ytdfg irC() en.~Xpu@#h@Ӫ4Z?†>T4kXL7XU=%W4fW0"g cq(T=ݲ$Y62ߒMM@ tLWls+,ؒ@L1iWRD~i32Uvŋc@\ly6#a~c}%4Sbޑҁ@+Ǭ@x:j,)zgNVs62LQ1 IBL"F:L$1"IJZ̤&7IKb' PfL*? HV KY6D sK\b(%%QKxBD'"pTe+_EN(.CQ!YO` H)H<o^)YME" @J | AYH e-IQB $?mQF ? a &%` EgE+zoA EGPH4(I\8?e$-E$5Ud jPx`$9wHPF :@8HFua U)9* G(>" TD*bd$`yWG$$6`FTEl(Mf RgԶ:E' =D@\,B]-:P>Up!Hjr lFWճW*!P쵫ln'3iuk]Bn"=BAa|-$5PW*n'\Ӷl ZH$p yYT { D 1 k(,a2$݊bmwR,aAB .qaH1"b$eHb|BE) ȕNxq ;bwȦ>̰ԦKeA:\R̀+ay\y%HSTX17 s~p}Yb9B:Rۇ3#@vB DZV4!g B%6uxKȶ -b:jB2Bԟjk S@MnGdgR}Yun" gf١&,P|cŔy=NԄye 2O& $͑ I _+%OEۙ 8oFhHӒc挌n#pɖ˕ !d! ICCRGBG10124applmntrRGB XYZ 5,acspAPPL-appldescPbdscmcprt#wtptrXYZgXYZbXYZ0rTRCD aargP vcgtp0ndin>chad,mmod (bTRCD gTRCD aabgP aaggP descDisplaymluc" hrHRkoKR nbNOidhuHUcsCZdaDKukUA2arNitITbroROvesESvheILnlNLfiFIzhTW viVNskSKzhCN ruRU$frFRms.caES@thTH XesXLvdeDEdenUStptBRplPLelGR"svSEtrTRjaJPptPTLCD u boji LCDFarge-LCDLCD WarnaSznes LCDBarevn LCDLCD-farveskrm>;L>@>289 LCD LCD EDHF)LCD coloriLCD color LCD Kleuren-LCDVri-LCD_ir LCDLCD MuFarebn LCD&25B=>9 -48A?;59LCD couleurWarna LCDLCD en colorLCD *5Farb-LCDColor LCDLCD ColoridoKolor LCD  LCDFrg-LCDRenkli LCD000 LCDLCD a CorestextCopyright Apple Inc., 2016XYZ XYZ q9gXYZ a#XYZ # curv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtndin6@UL% PT@333333sf32 rCrqmmod.,LY";1"1;**/*EMTj"u;r1j1M*yErQ-TE1IV*R7j;s"gSH{Ij"MoXXXreTVchssrpluZ[W'5'-***)6)%QT"j5r;a1%J%R%\%R%R*R7U3U%R'R&R:RpZ u (ZQZ G8\VҀy34fv8u3@ũX3`|-ӫj6- v% ^Û><kxq%g[oV$ Z̻J.k]@ q QiCF%qX281ث߽Q Ѐ#T2ZYLcuT6jh x1z*ÛygIbW~]ZA<`o,:$VicIIjXMkC V ^j51l8!6 v-V=k JJꍺKyV E̙hUÌs-4nzI|9cnP8W/f v U6ojMًd1lWP ?p67Z 4<. ?X`P7˔D>ejl9 4{!<+` 4絽`_X aJK\Ҡ@leQ!;> kȳ!7k@ACH486x)9)ۡ\81N8lݐ IA4gJF6^Bhb]Bb|!0`q%Ҋ#Y`{T]od$) K0f/zYi2BT^phnHU1V+E3t(P"?(J4-#sIL$)3'@(,;}AUDBK0 =}`׃&U%BQ SS$@%J! #F2 D:t=BoЅ:4m }DщZ*FUэz HGJҒ(MJWҖ0LgJӚ8ͩNwӞ@ PJԢHMRԦ:PTJժZEVծz` XJֲhMZֶp\x)׾ `KMb:~Ed N֮D]-WP'ZqW*kf?QOc5Z [b'ʋVt(D%hK ¸Dr a |Fa;!|n?@@$QWCL %@f" #LHvX,mn+V֯X6N0`[ H^`fmۊyu[WԒ6.&ja aP|1X0_vȕP[Px嫁^e.bhܚAw^{NbB_Tpv|V~DhYɄera~{cxm'Bmsk^zٯq:z]Ůk&V:Սq"0OmiDV`An`2¶k '` ('R ж !FCu]L]k czbkl 9c`u9щ˦4W24֐?mO`ں]!|9@@C%N>+ÙvPUҞ~6^y2y9Y6' DB&덯?c|k|]7X캹iP&_\߹xppZskyxg:u^$/i\ ' \{} \; find "manual/${DOCDIR}" -name '*~' -exec rm \{} \; git add "manual/${DOCDIR}" if [[ ${GITHUB_DEPLOY_KEY_PASSPHRASE:-} != "skip" ]]; then (git commit -m "Update manual for '${DOCDIR}' from haskell/haskell-mode@${HEAD_COMMIT}" && git push origin gh-pages) || true else echo "Update manual for '${DOCDIR}' from haskell/haskell-mode@${HEAD_COMMIT}" fi cd .. if [[ ${GITHUB_DEPLOY_KEY_PASSPHRASE:-} != "skip" ]]; then rm -fr gh-pages-deploy eval $(ssh-agent -k) fi echo Done! haskell-mode-17.1/doc/gifcasts/000077500000000000000000000000001360223321700163565ustar00rootroot00000000000000haskell-mode-17.1/doc/gifcasts/get-window-id.m000066400000000000000000000011521360223321700212110ustar00rootroot00000000000000 #include #include int main(int argc, char **argv) { NSArray *windows = (NSArray *)CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements,kCGNullWindowID); for(NSDictionary *window in windows) { if ([[window objectForKey:(NSString *)kCGWindowOwnerPID] isEqual:[NSNumber numberWithLongLong:atoi(argv[1])]]) { if ([[window objectForKey:(NSString *)kCGWindowName] isEqual:[NSString stringWithUTF8String:argv[2]]]) { printf("%d\n", [[window objectForKey:(NSString *)kCGWindowNumber] intValue]); } } } } haskell-mode-17.1/doc/gifcasts/haskell-gifcasts.el000066400000000000000000000162701360223321700221320ustar00rootroot00000000000000;; ;; ;; This files is supposed to be run from command line like this: ;; ;; $EMACS -l haskell-gifcasts.el -f gifcast-generate-batch-and-exit ;; (require 'gifcast) (require 'company) (require 'shakespeare-mode) (setq load-path `("../.." ,@load-path)) (require 'haskell-mode-autoloads) (require 'haskell-mode) (require 'haskell-interactive-mode) (setq debug-on-error t) (gifcast-animation font-lock (progn (set-frame-size (window-frame (get-buffer-window)) 40 10) (when (get-buffer "Main.hs") (kill-buffer "Main.hs")) (switch-to-buffer (get-buffer-create "Main.hs")) (delete-other-windows) (tabbar-mode -1) (tool-bar-mode -1) (linum-mode -1) (message nil) (scroll-bar-mode -1) (haskell-mode) (insert (concat "-- | Program entry point\n" "main :: IO ()\n" "main = do\n" " if flag\n" " then putStrLn \"Flag is True\"\n" " else putStrLn \"Flag is False\"\n" ))) (global-font-lock-mode -1) (gifcast-capture) (global-font-lock-mode t) (gifcast-capture) (gifcast-generate "../anim/font-lock.gif") (kill-buffer "Main.hs")) (gifcast-animation font-lock-types (progn (set-frame-size (window-frame (get-buffer-window)) 60 10) (when (get-buffer "Main.hs") (kill-buffer "Main.hs")) (switch-to-buffer (get-buffer-create "Main.hs")) (delete-other-windows) (tabbar-mode -1) (tool-bar-mode -1) (linum-mode -1) (message nil) (scroll-bar-mode -1) (haskell-mode) (insert "data ExampleType a where\n" " ExampleConstructor :: Int -> ExampleType Int\n" "\n" "fun :: Maybe a -> IO Int\n" "fun (Just x) = do\n" " y :: Int <- (Prelude.++ 1) `fmap` readInt (_ :: Proxy Int)\n") (custom-set-faces '(haskell-type-face ((t :inherit font-lock-function-name-face))))) (global-font-lock-mode -1) (gifcast-capture) (global-font-lock-mode t) (gifcast-capture) (gifcast-generate "../anim/font-lock-types.gif") (kill-buffer "Main.hs")) (gifcast-animation font-lock-quasi-quotes (progn (set-frame-size (window-frame (get-buffer-window)) 50 10) (when (get-buffer "Main.hs") (kill-buffer "Main.hs")) (switch-to-buffer (get-buffer-create "Main.hs")) (delete-other-windows) (tabbar-mode -1) (tool-bar-mode -1) (linum-mode -1) (message nil) (scroll-bar-mode -1) (haskell-mode) (insert "html = [shamlet|\n" " $doctype 5\n" " \n" " \n" " #{pageTitle} - My Site\n" " <link rel=stylesheet href=@{Stylesheet}>\n" " |]\n") (custom-set-faces '(haskell-type-face ((t :inherit font-lock-function-name-face))))) (global-font-lock-mode -1) (gifcast-capture) (global-font-lock-mode t) (gifcast-capture) (gifcast-generate "../anim/font-lock-quasi-quotes.gif") (kill-buffer "Main.hs")) (gifcast-animation company-mode-language-pragma (set-frame-size (window-frame (get-buffer-window)) 40 10) (progn (when (get-buffer "Main.hs") (kill-buffer "Main.hs")) (switch-to-buffer (get-buffer-create "Main.hs")) (delete-other-windows) (tabbar-mode -1) (tool-bar-mode -1) (linum-mode -1) (blink-cursor-mode -1) (message nil) (scroll-bar-mode -1) (haskell-mode) (interactive-haskell-mode) (company-mode) (setq company-idle-delay 0.01) (linum-mode -1) (insert (concat "{-# LANGUAGE #-}\n" "main :: IO ()\n" "main = return ()\n")) (goto-char (+ 13 (point-min)))) (gifcast-capture) (gifcast-keys "F") (gifcast-capture) (gifcast-keys "l") (gifcast-capture) (gifcast-keys "e") (gifcast-capture) (gifcast-keys (kbd "<down>")) (gifcast-capture) (gifcast-keys "\C-m") (gifcast-capture) (gifcast-generate "../anim/company-mode-language-pragma.gif") (kill-buffer "Main.hs") nil) (gifcast-animation company-mode-import-statement (progn (set-frame-size (window-frame (get-buffer-window)) 70 15) (when (get-buffer "Main.hs") (kill-buffer "Main.hs")) (switch-to-buffer (set-buffer (get-buffer-create "Main.hs"))) (set-visited-file-name "Main.hs" t) (delete-other-windows) (tabbar-mode -1) (tool-bar-mode -1) (linum-mode -1) (blink-cursor-mode -1) (message nil) (scroll-bar-mode -1) (haskell-mode) (interactive-haskell-mode) (company-mode) (setq company-idle-delay 0.01) (linum-mode -1) (insert (concat "\n\n\n" "main :: IO ()\n" "main = return ()\n")) (save-buffer) (haskell-process-load-file) (sit-for 2) (select-window (get-buffer-window "Main.hs")) (goto-char (+ 1 (point-min)))) (gifcast-keys "") (gifcast-capture) (gifcast-keys "import") (gifcast-capture) (gifcast-keys " Control.") (gifcast-capture) (gifcast-keys "A") (gifcast-capture) (gifcast-keys "\C-m") (gifcast-capture) (gifcast-generate "../anim/company-mode-import-statement.gif") (haskell-kill-session-process) (set-buffer-modified-p nil) (kill-buffer "Main.hs")) (gifcast-animation string-escape-highlight (progn (set-frame-size (window-frame (get-buffer-window)) 40 5) (when (get-buffer "Main.hs") (kill-buffer "Main.hs")) (switch-to-buffer (set-buffer (get-buffer-create "Main.hs"))) (delete-other-windows) (tabbar-mode -1) (tool-bar-mode -1) (linum-mode -1) (blink-cursor-mode -1) (message nil) (scroll-bar-mode -1) (haskell-mode) (linum-mode -1)) (gifcast-keys "\nmsg = ") (gifcast-capture 10) (gifcast-keys "\"") (gifcast-capture 10) (gifcast-keys "Hello") (gifcast-capture 10) (gifcast-keys "World") (gifcast-capture 10) (gifcast-keys "\"") (gifcast-capture 10) (gifcast-keys (kbd "<left><left><left><left><left><left>")) (gifcast-capture 10) (gifcast-keys "\\") (gifcast-capture 10) (gifcast-keys "x") (gifcast-capture 10) (gifcast-keys "20") (gifcast-capture 500) (gifcast-generate "../anim/string-escape-highlight.gif") (kill-buffer "Main.hs") nil) (gifcast-animation flyspell-prog-mode (progn (set-frame-size (window-frame (get-buffer-window)) 70 10) (when (get-buffer "Main.hs") (kill-buffer "Main.hs")) (switch-to-buffer (get-buffer-create "Main.hs")) (delete-other-windows) (tabbar-mode -1) (tool-bar-mode -1) (linum-mode -1) (message nil) (scroll-bar-mode -1) (haskell-mode) (insert "\n\n\n\n" "main = do\n" " putStrLn \"Heskell is a realy nice lanuage\"\n" "\n\n\n\n\n\n\n\n\n") (goto-char (point-min))) (gifcast-capture) (gifcast-keys (kbd "M-x")) (gifcast-capture) (gifcast-keys "flyspell-prog-mode") (gifcast-capture) (gifcast-keys (kbd "RET")) (progn (flyspell-prog-mode) (flyspell-region (point-min) (point-max))) (gifcast-capture) (re-search-forward "Heskell") (gifcast-capture) (gifcast-keys (kbd "M-$")) (gifcast-capture) (gifcast-keys "0") (gifcast-capture) (re-search-forward "real") (gifcast-capture) (gifcast-keys (kbd "M-$")) (gifcast-capture) (gifcast-keys "0") (gifcast-capture) (re-search-forward "lan") (gifcast-capture) (gifcast-keys (kbd "M-$")) (gifcast-capture) (gifcast-keys "0") (gifcast-capture) (gifcast-generate "../anim/flyspell-prog-mode.gif") (kill-buffer "Main.hs")) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/doc/haskell-manual-fixups.el������������������������������������������������������0000664�0000000�0000000�00000005633�13602233217�0021316�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ (defun get-gif-dimensions (filename) "Get GIF dimensions, return a cons of (w,h). Get GIF dimensions directly from binary. Does not need external tools. GIF Header Offset Length Contents 0 3 bytes \"GIF\" 3 3 bytes \"87a\" or \"89a\" 6 2 bytes <Logical Screen Width> 8 2 bytes <Logical Screen Height> 10 1 byte bit 0: Global Color Table Flag (GCTF) bit 1..3: Color Resolution bit 4: Sort Flag to Global Color Table bit 5..7: Size of Global Color Table: 2^(1+n) 11 1 byte <Background Color Index> 12 1 byte <Pixel Aspect Ratio> 13 ? bytes <Global Color Table(0..255 x 3 bytes) if GCTF is one> ? bytes <Blocks> 1 bytes <Trailer> (0x3b)" (interactive "fFile name:") (with-current-buffer (get-buffer-create "*GIF*") (set-buffer-multibyte nil) (insert-file-contents-literally filename nil 0 10 t) (when (not (looking-at-p "GIF8[79]a")) (error "File '%s' is not a GIF" filename)) (let ((result (cons (+ (char-after 7) (* 256 (char-after 8))) (+ (char-after 9) (* 256 (char-after 10)))))) (if (called-interactively-p) (message "Dimensions: %dx%d" (car result) (cdr result))) result))) (defun haskell-manual-fixup-buffer (&optional buffer) "Fix contents of HTML from makeinfo in a BUFFER. Currently it looks for image references and adds an explicit width and height. GIFs are generate on Retina so their resolution is double of what it should be. Here we halve it to compensate dimensions and to keep it crisp when viewed on Retina again." (interactive) (with-current-buffer (or buffer (current-buffer)) (save-excursion (goto-char (point-min)) (while (re-search-forward "<img src=\"\\(.*\\)\" alt=\"\\(.*\\)\">" nil t) (let* ((filename (match-string-no-properties 1)) (alttext (match-string-no-properties 2)) (default-directory (file-name-directory (buffer-file-name))) (dim (get-gif-dimensions filename)) (img (format "<img width=\"%d\" height=\"%d\" src=\"%s\" alt=\"%s\">" (/ (car dim) 2) (/ (cdr dim) 2) filename alttext))) (delete-region (match-beginning 0) (match-end 0)) (insert img)))))) (defun haskell-manual-fixup-file (filename) "Run `haskell-manual-fixup-buffer' on a file." (interactive "fFile name:") (with-temp-buffer (insert-file-contents filename t) (haskell-manual-fixup-buffer) (when (buffer-modified-p) (basic-save-buffer)))) (defun haskell-manual-fixups-batch-and-exit () "Run `haskell-manual-fixup-buffer' on files given as arguments. Should be invoked as: emacs -l haskell-manual-fixups.el -f haskell-manual-fixups-batch-and-exit doc/html/*.html" (dolist (filename command-line-args-left) (haskell-manual-fixup-file filename)) (kill-emacs 0)) �����������������������������������������������������������������������������������������������������haskell-mode-17.1/doc/haskell-mode-travis-deploy-key������������������������������������������������0000664�0000000�0000000�00000003346�13602233217�0022437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,9385B3F19E12C488ACF654D37A7B70B2 3ucmv5i37lwRejeFWTliQ9pfs8Vfq1G/30lnI7/GroClDiE2LAKm9tWzD8EAVdjx lAcD9gKy9g+5Gft/qj+ucXmh2OWhTz2veBIJzjuujoZBNbbgBhBGrkAzr0h2LK5u OE06F5Goz6rAjnyFbxTU9slZnWENHKpnwYBRriIq3KM1vS9Kr/0S3cYYfY5exITT Gy5uTLHDVzps5Bn7wjLgXRUoLbDRRDF6L4LPkaFyEHRt+1VjtqWc3jnMuY7P2Rru y8Mlr0cv9UzeJleTrN8AvcEtUCcl7FpieSZsGh0Q2/wEj3fEFk6Zf/q3aAqz0mn4 hdp3CvTRUeYv1JibdXSptd34dpxB+9IJIbZnZ4ixaj5Ay3oCj9PPHC+qDGsjeA6J ect9EzxuVr6j4gvJYR0nOKNH1KOBOAZDhCQG0kvZxXaQyUbu5NV+kh6XUCedzfJZ XyutuOF6frUjEkJlRj5aWdgtXUDKrPDO9jnV9jknoyaOQMjWt4vd8uhkWZo+SfZ8 bVO8pcx/YxNBKiHeDiLVUPc7h0Y1fI48RwLky+iLrYTe6hhMOPb8/PxZsbG+xVN5 +D2v08EhDzomxsPKBagHCb9Dffihi21F54ZeRBAx4Fr7O3KEHFE/67Oec5lz/seh yDw+ZhW9bLklO8nZWw4rJGKG7pCgb4pRVD4Rk3VFgVdolq9Z44YNCyHX+CsfuE7D KvHBOQWdpVD8EvP2sjqb7kIFOY9ZP5vOOZ10fm9XweCca4xJzwlr9aah0XXYza8S hCgkPYDQndLM4NH0UfGJPft7HhjUSF7vodL/0jKsTvRBeXnh5pgeTM576LnpfYd3 wzLKg4g2/bIMUGYKo4VRY6rXvQbf4MDvUlnGRMBnihbm+x0LU6U0/nxBzeKnv5D9 VR56xGwJHxIytNjqzAZVPk8+9nXw8Dyc0XmSkPsaYr5DgI/nacRbdvlVo2M8Rac8 72qcAqkUAB/JXl4Jbucw4nGBsdOnl6zGRqTMeG/bfR9ULM4u1wGzNeXghc5+Krk3 mMiZeCxfnAdw2eEM0aXieMD2QB882Cm5HVB+7tqQZcbpr8pt9uNQrr44rkBnNsqa LQdmbUN+1+uDXlFstkKBCN/i2cEX5NTo7yiebMZZ9/+uY1LWTPzV3wAwtJeYaMIB oJ5DunlxqpKULX8jL0k2qAuA57ah2DlsMj/2L9uNs84ZmkPnhtPpiDwsFCL+xxRo Sup6qrrBOP6WvGR8O4uWcKP/HH6x11cgD20NWcoSjslXBgJK5nV9uqiKE/vNjG9e /pDfvce4kdUQcp4hbJu+o8MrWLC9o3ijPZWfqikCt5dX8qMp364GZcyxYOy0gv9X g259f1GImJHcFMb88qqYdP9au+S96ZIXOGtlKH/nwfe/UFe9tO2jOQqNgVh+Akyu 3gcjuMyDQryXNNHMRlB76mFAUnSUQIQ3n84oMFn8ZscogDdA89FWOV0MUkSoiVmW 7uD2hlliYg269xDJH3FE4Txk95fKquJpsa+6hzpt2V7VqR6m0BzQ+yQmMFuWsLtI oTOUtdPYojZVWPgeskNCrxEg2/CJQ4lHGQhv8tab5HWleHCS75RjwlFpYE9Ie4K3 -----END RSA PRIVATE KEY----- ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/doc/haskell-mode.css��������������������������������������������������������������0000664�0000000�0000000�00000003710�13602233217�0017633�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@charset "UTF-8"; @import url("http://fonts.googleapis.com/css?family=Lato:400,400italic,700,700italic&subset=latin,latin-ext"); @import url("http://fonts.googleapis.com/css?family=Source Code Pro"); body { font-family: Lato, Arial, sans-serif; font-feature-settings: "kern", "liga", "clig", "calt"; font-size: 1em; line-height: 1.3em; } body { width: 800px; margin: 0 auto; } table.menu { width: 700px; margin-left: 50px; } /* makeinfo 5.2 */ div.header p { margin: 0; text-align: right; } div.header { background-color: #9a98bd; background: linear-gradient(#CDCCDE,#A9A7CD); } /* makeinfo 4.8 */ div.node { background-color: #9a98bd; background: linear-gradient(#CDCCDE,#A9A7CD); } div.node p { margin: 0; text-align: right; } div.node hr { margin: 0; } div.footnote h3 { display: inline; font-size: normal; } /* makeinfo up to 5.2 cannot pass on unicode characters without messing them up */ a[rel="up"]:before { content: " \2191 "; /* ↑ */ } a[rel="prev"]:before { content: " \2190 "; /* ← */ } a[rel="next"]:before { content: " \2192 "; /* → */ } code, kbd, samp, pre { font-size: 85%; font-family: "Source Code Pro", Menlo, Inconsolata, monospace; } code, pre, samp { background-color: rgba(0,0,0,0.04); border-radius: 3px; } kbd { display: inline-block; padding: 3px 5px; font-style:normal; line-height: 0.8em; color: #555; vertical-align: middle; background-color: #fcfcfc; border: solid 1px #ccc; border-bottom-color: #bbb; border-radius: 3px; box-shadow: inset 0 -1px 0 #bbb; } div.background { position: fixed; z-index: -1; right: 30px; bottom: 0px; width: 256px; height: 256px; opacity: 0.3; background-image: url("haskell-mode.svg"); background-repeat: no-repeat; background-size: 256px 256px; } img { /* same as div.smallexample in default rules */ margin-left: 3.2em; } ��������������������������������������������������������haskell-mode-17.1/doc/haskell-mode.texi�������������������������������������������������������������0000664�0000000�0000000�00000231454�13602233217�0020024�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename haskell-mode.info @documentencoding UTF-8 @settitle Haskell Mode 17.1 @c %**end of header @c Macro used to mark references of defcustom variables @macro defcustom{var} @vrindex \var\ @code{\var\} @end macro @dircategory Emacs @direntry * Haskell Mode: (haskell-mode). Haskell Development Environment for Emacs(en) @end direntry @copying This manual is for Haskell mode, version 17.1 Copyright @copyright{} 2013-2017 Haskell Mode contributors. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the @uref{http://www.gnu.org/licenses/fdl.html,GNU Free Documentation License}, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts. @end quotation @end copying @iftex @titlepage @title Haskell Mode @subtitle Haskell Development Environment for Emacs @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @end iftex @ifnottex @node Top @top Haskell Mode Haskell Mode is an Haskell development Environment for GNU Emacs version 25.1 or later. It provides syntax-based indentation, font locking, editing cabal files, and supports running an inferior Haskell interpreter (e.g. GHCi). @end ifnottex @menu * Introduction:: An introduction to Haskell Mode * Installation:: How to get started * Editing Haskell Code:: How to edit code * Syntax highlighting:: Haskell Mode has colors * Completion support:: Autocomplete * Unicode support:: How to use Unicode * Indentation:: Notes about indentation * External indentation:: Other ways to indent code * Autoformating:: Using external formatters * Module templates:: Module templates * Declaration scanning:: How to navigate in a source file * Compilation:: How to compile * Interactive Haskell:: How to interact with GHCi * Editing Cabal files:: Cabal support * Browsing Haddocks:: Using @code{w3m} to browse documentation * Spell checking strings and comments:: Using @code{flyspell-prog-mode} * Aligning code:: Aligning code using @code{align-regexp} * Rectangular commands:: Manage indentation manually * REPL:: GHCi REPL * Collapsing Haskell code:: View more code on screen * Getting Help and Reporting Bugs:: How to improve Haskell Mode * Concept index:: Index of Haskell Mode concepts * Function index:: Index of commands * Variable index:: Index of options and types @end menu @ifhtml @insertcopying @end ifhtml @node Introduction @chapter Introduction @dfn{Haskell Mode} is a major mode providing a convenient environment for editing @uref{http://www.haskell.org,Haskell} programs. Some of its major features are: @itemize @item Syntax highlighting (font lock), @item automatic semi-intelligent indentation, @item on-the-fly documentation, @item interaction with inferior GHCi/Hugs instance, @item project building with cabal and stack @item scanning declarations and placing them in a menu. @end itemize The name Haskell Mode refers to the whole collection of modules in this package. There is specifically a file @file{haskell-mode.el} which defines a major mode called @code{haskell-mode}. Generally, in this documentation they will be distinguished by normal font and title case (Haskell Mode) and code font (@code{haskell-mode}). @section History @code{haskell-mode} has a long history. It goes all the way back to 1992. Since then, it has received many contributions in many forms. Some design choices that remain in haskell-mode today are historical. Some modules are outdated or no longer used, or are used by a few people. Historically there hasn't been a single individual or set of individuals directing the package's architecture for a long period of time, rather, patches and new modules were accepted in liberally and we are left with a box full of interesting toys that may or may not work. As of 2016 Haskell Mode is coordinated using Github at @uref{https://github.com/haskell/haskell-mode}. @node Installation @chapter Installation Haskell Mode is distributed as a package in @uref{https://melpa.org,MELPA repository}. To use MELPA as Emacs package archive do the following: @enumerate @item Customize @code{package-archives} using @example M-x customize-option RET package-archives @end example @item Use @kbd{INS} to add new archive, use: @example Archive name: melpa-stable URL or directory name: http://stable.melpa.org/packages/ @end example @item Fetch new packages using: @example M-x package-refresh-contents @end example @item Install Haskell Mode using: @example M-x package-install RET haskell-mode RET @end example @end enumerate Voila! @code{haskell-mode} is installed! You should be able to edit Haskell source code in color now. The above steps should result in the following snippet in your @file{.emacs}: @lisp (require 'package) (custom-set-variables ;; custom-set-variables was added by Custom. ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right. '(package-archives (quote (("gnu" . "http://elpa.gnu.org/packages/") ("melpa-stable" . "http://stable.melpa.org/packages/"))))) @end lisp Haskell Mode is available from @uref{http://stable.melpa.org,melpa-stable (releases)} and @uref{http://melpa.org, melpa (git snapshots)}. Other means of obtaining @code{haskell-mode} include @uref{https://github.com/dimitri/el-get, el-get}, @uref{https://github.com/bbatsov/prelude, Emacs Prelude} and @uref{https://packages.debian.org/search?keywords=haskell-mode, Debian package}. @section Customizing @cindex customizing Most of Haskell Mode's settings are configurable via customizable variables (@pxref{Easy Customization,,,emacs}, for details). You can use @kbd{M-x customize-group @key{RET} haskell} to browse the @code{haskell} customization sub-tree. @vindex haskell-mode-hook One of the important setting you should customize is the @code{haskell-mode-hook} variable (@pxref{Hooks,,,emacs}) which gets run right after the @code{haskell-mode} major mode is initialized for a buffer. You can customize @code{haskell-mode-hook} by @example M-x customize-variable RET haskell-mode-hook @end example There you can enable or disable a couple of predefined options or add any function to the list. @node Editing Haskell Code @chapter Editing Haskell Code @findex haskell-mode @cindex @code{haskell-mode} Haskell Mode as one of its components provides a major mode for editing Haskell source code called @code{haskell-mode}, which gave the name to the whole project. There is a derived mode provided called @code{literate-haskell-mode} that support Literate Haskell source code both in Bird and in Latex forms. Haskell Mode supports files with the following extensions: @table @file @item .hs official file extension for Haskell files. Haskell Mode out of the box supports most of GHC extensions. @item .lhs official file extension for Literate Haskell files. Both Bird and Latex styles are supported. @item .hsc Haskell interfaces to C code used by @uref{http://www.haskell.org/ghc/docs/latest/html/users_guide/hsc2hs.html,hsc2hs} pre-processor. @item .cpphs Haskell source with CPP pragmas used with @uref{http://projects.haskell.org/cpphs,cpphs} pre-processor. @item .c2hs Haskell FFI bindings to C libraries used with @uref{https://github.com/haskell/c2hs,c2hs} pre-processor. @end table Haskell Mode offers many productivity tools described in following chapters in this manual. @section Managing imports There are a few functions for managing imports. @subsection Jump to imports To jump to your import list, run @kbd{M-x} @code{haskell-navigate-imports} It's nicer to have a keybinding to do this, for example: @lisp (define-key haskell-mode-map (kbd "<f8>") 'haskell-navigate-imports) @end lisp You can hit it repeatedly to jump between groups of imports. It will cycle. @subsection Format imports To generally format (sort, align) your imports, you can run @kbd{M-x} @code{haskell-mode-format-imports} Or @kbd{C-c C-,}. @subsection Sort imports To just sort imports, jump to an import section and run @kbd{M-x} @code{haskell-sort-imports} @subsection Align imports To just align imports, jump to an import section and run @kbd{M-x} @code{haskell-align-imports} @subsection stylish-haskell As an alternative to the elisp functions described above, haskell-mode can use the program @url{http://hackage.haskell.org/package/stylish-haskell, stylish-haskell} to format imports. You can set this behavior by typing: @kbd{M-x} @code{customize-variable} @kbd{RET} @code{haskell-stylish-on-save}. You can install @code{stylish-haskell} by running @code{stack install stylish-haskell}, or if you have not installed @code{stack}, @code{cabal install stylish-haskell}. @section Haskell Tags @code{haskell-mode} can generate tags when saving source files. To generate tags @code{haskell-mode} uses external program — @url{https://github.com/MarcWeber/hasktags, Hasktags} (@url{https://wiki.haskell.org/Tags, wiki-article}). To turn on tags generatation customize or set to @code{t} @code{haskell-tags-on-save} variable. Also, you may find useful to revert tags tables automatically, this can be done by customizing @code{tags-revert-without-query} variable (either globally or for Haskell buffers only). @section Profiling and Debugging support When profiling code with GHC, it is often useful to add @uref{https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html#cost-centres, cost centres} by hand. These allow finer-grained information about program behavior. @code{haskell-mode} provides the function @code{haskell-mode-toggle-scc-at-point} to make this more convenient. It will remove an SCC annotation at point if one is present, or add one if point is over whitespace. By default it is bound to @kbd{C-c C-s}. @node Syntax highlighting @chapter Syntax highlighting @code{haskell-mode} supports @dfn{syntax highlighting} via Emacs' Font Lock minor mode which should be enabled by default in current Emacsen. @xref{Font Lock,,,emacs}, for more information on how to control @code{font-lock-mode}. @ifhtml @image{anim/font-lock} @end ifhtml Syntax highlighting facilities parse strings and string escape sequences and are able to highlight unrecognized constructs. @ifhtml @image{anim/string-escape-highlight} @end ifhtml Haskell Mode shows keywords, identifiers, operators, constructors and types in different colors. @ifhtml @image{anim/font-lock-types} @end ifhtml There is also support to use mode-specific syntax highlighing for quasiquotes. @ifhtml @image{anim/font-lock-quasi-quotes} @end ifhtml At this point quasi quotes for HTML, XML, shell scripts, Hamlet templates and SQL are supported out of the box. Customize @code{haskell-font-lock-quasi-quote-modes} to make sure your quoters are supported. The following customization variables are responsible for faces applied: @itemize @code @item @defcustom{haskell-keyword-face}: for keywords @item @defcustom{haskell-type-face}: for type names and type class names @item @defcustom{haskell-constructor-face}: for constructors @item @defcustom{haskell-definition-face}: function and operator name at the definition place @item @defcustom{haskell-operator-face}: operators @item @defcustom{haskell-pragma-face}: GHC pragmas @item @defcustom{haskell-literate-comment-face}: literate comments @item @defcustom{haskell-quasi-quote-face}: quasi quotes unless using mode specific highlighting @item @defcustom{haskell-c2hs-hook-pair-face}: c2hs hooks @item @defcustom{haskell-c2hs-hook-name-face}: c2hs hook names @end itemize All the above are available for customization. GHC quasi quote syntax is ambiguous with list comprehension therefore syntax highlighting might get confused with situations like these: @example result = [html| html <- htmlList] result = [html| <html><body>...</body></html> |] @end example Please use spaces around a list comprehension variable to make this unambiguous. Any of the following will work: @example result = [ html| html <- htmlList] result = [html | html <- htmlList] @end example GHC's ambiguity is an accident of the past but it is unlikely to be fixed due to backward compatibility baggage. @node Completion support @chapter Completion support @code{haskell-mode} can complete symbols, pragma directives, language extensions, and language keywords out-of-box. @code{haskell-mode} completes identifiers (symbols) using tags (see ``Tags''), however you can get more precise completions with @code{haskell-interactive-mode}. In interactive mode completion candidates are produced by querying GHCi REPL. @ifhtml @image{anim/company-mode-language-pragma} @end ifhtml If @code{haskell-interactive-mode} is enabled and working Haskell mode provides completions for import statements taking into account currently loaded and available packages. Also it completes symbols querying REPL with @code{:complete} command, hence completion candidate list also includes symbols from imported modules. @ifhtml @image{anim/company-mode-import-statement} @end ifhtml Unfortunately, it is not possible to provide candidates for identifiers defined locally in @code{let} and @code{where} blocks even in interactive mode. But if you're using @url{http://company-mode.github.io/, company-mode} you can override @code{company-backends} variable for Haskell buffers to combine completion candidates from completion-at-point function (@code{company-capf} backend) and dynamic abbrevs. @code{company-mode} provides special backend for dabbrev code completions, namely @code{company-dabbrev-code}. To combine completions from different backends you can create grouped backends, it is very easy — a grouped backend is just a list of backends, for example: @lisp (add-hook 'haskell-mode-hook (lambda () (set (make-local-variable 'company-backends) (append '((company-capf company-dabbrev-code)) company-backends)))) @end lisp If you use a GHCi version prior to 8.0.1 you might want to set @code{haskell-completions-complete-operators} to @code{nil}, if you experience major slowdown while trying to complete after an Haskell operator (See @url{https://ghc.haskell.org/trac/ghc/ticket/10576, GHC-Bug 10576}). @node Unicode support @chapter Unicode support @cindex Unicode See the Haskell Wiki's entry on @uref{http://www.haskell.org/haskellwiki/Unicode-symbols, Unicode Symbols} for general information about Unicode support in Haskell. As Emacs supports editing files containing Unicode out of the box, so does Haskell Mode. As an add-on, Haskell Mode includes the @code{haskell-unicode} input method which allows you to easily type a number of Unicode symbols that are useful when writing Haskell code; @xref{Input Methods,,,emacs}, for more details. To automatically enable the @code{haskell-unicode} input method in haskell-mode buffers use @kbd{M-x customize-variable @key{RET} haskell-mode-hook} or put the following code in your @file{.emacs} file: @lisp (add-hook 'haskell-mode-hook 'turn-on-haskell-unicode-input-method) @end lisp @noindent To temporarily enable this input method for a single buffer you can use @kbd{M-x turn-on-haskell-unicode-input-method}. When the @code{haskell-unicode} input method is active, you can simply type @samp{->} and it is immediately replaced with @samp{→}. Use @kbd{C-\} to toggle the input method. To see a table of all key sequences use @kbd{M-x describe-input-method @key{RET} haskell-unicode}. A sequence like @samp{<=} is ambiguous and can mean either @samp{⇐} or @samp{≤}. Typing it presents you with a choice. Type @kbd{1} or @kbd{2} to select an option or keep typing to use the default option. Currently defined sequences are listed in the following table: @multitable @columnfractions .08 .15 .08 .15 .08 .15 .08 .15 @headitem Sequence @tab Unicode @tab Sequence @tab Unicode @tab Sequence @tab Unicode @tab Sequence @tab Unicode @item alpha @tab α @tab Alpha @tab Α @tab beta @tab β @tab Beta @tab Β @item gamma @tab γ @tab Gamma @tab Γ @tab delta @tab δ @tab Delta @tab Δ @item epsilon @tab ε @tab Epsilon @tab Ε @tab zeta @tab ζ @tab Zeta @tab Ζ @item eta @tab η @tab Eta @tab Η @tab theta @tab θ @tab Theta @tab Θ @item iota @tab ι @tab Iota @tab Ι @tab kappa @tab κ @tab Kappa @tab Κ @item lambda @tab λ @tab Lambda @tab Λ @tab lamda @tab λ @tab Lamda @tab Λ @item mu @tab μ @tab Mu @tab Μ @tab nu @tab ν @tab Nu @tab Ν @item xi @tab ξ @tab Xi @tab Ξ @tab omicron @tab ο @tab Omicron @tab Ο @item pi @tab π @tab Pi @tab Π @tab rho @tab ρ @tab Rho @tab Ρ @item sigma @tab σ @tab Sigma @tab Σ @tab tau @tab τ @tab Tau @tab Τ @item upsilon @tab υ @tab Upsilon @tab Υ @tab phi @tab φ @tab Phi @tab Φ @item chi @tab χ @tab Chi @tab Χ @tab psi @tab ψ @tab Psi @tab Ψ @item omega @tab ω @tab Omega @tab Ω @tab digamma @tab ϝ @tab Digamma @tab Ϝ @item san @tab ϻ @tab San @tab Ϻ @tab qoppa @tab ϙ @tab Qoppa @tab Ϙ @item sampi @tab ϡ @tab Sampi @tab Ϡ @tab stigma @tab ϛ @tab Stigma @tab Ϛ @item heta @tab ͱ @tab Heta @tab Ͱ @tab sho @tab ϸ @tab Sho @tab Ϸ @item |A| @tab 𝔸 @tab |B| @tab 𝔹 @tab |C| @tab ℂ @tab |D| @tab 𝔻 @item |E| @tab 𝔼 @tab |F| @tab 𝔽 @tab |G| @tab 𝔾 @tab |H| @tab ℍ @item |I| @tab 𝕀 @tab |J| @tab 𝕁 @tab |K| @tab 𝕂 @tab |L| @tab 𝕃 @item |M| @tab 𝕄 @tab |N| @tab ℕ @tab |O| @tab 𝕆 @tab |P| @tab ℙ @item |Q| @tab ℚ @tab |R| @tab ℝ @tab |S| @tab 𝕊 @tab |T| @tab 𝕋 @item |U| @tab 𝕌 @tab |V| @tab 𝕍 @tab |W| @tab 𝕎 @tab |X| @tab 𝕏 @item |Y| @tab 𝕐 @tab |Z| @tab ℤ @tab |gamma| @tab ℽ @tab |Gamma| @tab ℾ @item |pi| @tab ℼ @tab |Pi| @tab ℿ @tab :: @tab ∷ @tab forall @tab ∀ @item exists @tab ∃ @tab -> @tab → @tab <- @tab ← @tab => @tab ⇒ @item ~> @tab ⇝ @tab <~ @tab ⇜ @tab && @tab ∧ @tab || @tab ∨ @item == @tab ≡ @tab /= @tab ≢, ≠ @tab <= @tab ≤ @tab >= @tab ≥ @item /< @tab ≮ @tab /> @tab ≯ @tab * @tab ⋅ @tab elem @tab ∈ @item notElem @tab ∉ @tab member @tab ∈ @tab notMember @tab ∉ @tab union @tab ∪ @item intersection @tab ∩ @tab isSubsetOf @tab ⊆ @tab isProperSubsetOf @tab ⊂ @tab <<< @tab ⋘ @item >>> @tab ⋙ @tab <| @tab ⊲ @tab |> @tab ⊳ @tab >< @tab ⋈ @item mappend @tab ⊕ @tab . @tab ∘ @tab undefined @tab ⊥ @tab := @tab ≔ @item =: @tab ≕ @tab =def @tab ≝ @tab =? @tab ≟ @tab ... @tab … @item _0 @tab ₀ @tab _1 @tab ₁ @tab _2 @tab ₂ @tab _3 @tab ₃ @item _4 @tab ₄ @tab _5 @tab ₅ @tab _6 @tab ₆ @tab _7 @tab ₇ @item _8 @tab ₈ @tab _9 @tab ₉ @tab ^0 @tab ⁰ @tab ^1 @tab ¹ @item ^2 @tab ² @tab ^3 @tab ³ @tab ^4 @tab ⁴ @tab ^5 @tab ⁵ @item ^6 @tab ⁶ @tab ^7 @tab ⁷ @tab ^8 @tab ⁸ @tab ^9 @tab ⁹ @end multitable If you don't like the highlighting of partially matching tokens you can turn it off by setting @code{input-method-highlight-flag} to @code{nil} via @kbd{M-x customize-variable}. @node Indentation @chapter Indentation @cindex indentation @cindex layout rule @cindex off-side rule In Haskell, code indentation has semantic meaning as it defines the block structure. Haskell also supports braces and semicolons notation for conveying the block structure. However, most Haskell programs written by humans use indentation for block structuring. Haskell Mode ships with two indentation modes: @itemize @item @code{haskell-indentation-mode} (default). This is a semi-intelligent indentation mode doing a decent job at recognizing Haskell syntactical constructs. It is based on a recursive descent Haskell parser. @kbd{TAB} selects the next potential indentation position, @kbd{S-TAB} selects the previous one. If a block is selected you can use @kbd{TAB} to indent the block more and @kbd{S-TAB} to indent the block less. When @code{electric-indent-mode} is enabled or the variable @code{haskell-indentation-electric-flag} is non-nil, the insertion of some characters (by default @kbd{,} @kbd{;} @kbd{)} @kbd{@}} @kbd{]}) may trigger auto reindentation under appropriate conditions. See the documentation of @code{haskell-indentation-common-electric-command} for more details. @item @code{haskell-indent-mode} (optional). This is a semi-intelligent indentation mode doing a decent job at recognizing Haskell syntactical constructs. It is based on a decision table. Sadly it is no longer developed and does not recognize newer Haskell syntax. @kbd{TAB} cycles through all available indentation positions. To use @code{haskell-indent-mode}, add this to your @file{~/.emacs} file: @lisp (add-hook 'haskell-mode-hook 'turn-on-haskell-indent) @end lisp Note that @code{turn-on-haskell-indent} will disable @code{haskell-indentation-mode}. @end itemize For general information about indentation support in GNU Emacs, @pxref{Indentation,,,emacs}. @section Rectangle Commands @cindex rectangle @cindex CUA mode GNU Emacs provides so-called @dfn{rectangle commands} which operate on rectangular areas of text, which are particularly useful for languages with a layout rule such as Haskell. @xref{Rectangles,,,emacs}, to learn more about rectangle commands. Moreover, CUA mode (@pxref{CUA Bindings,,,emacs}) provides enhanced rectangle support with visible rectangle highlighting. When CUA mode is active, you can initiate a rectangle selection by @kbd{C-RET} and extend it simply by movement commands. You don't have to enable full CUA mode to benefit from these enhanced rectangle commands; you can activate CUA selection mode (without redefining @kbd{C-x},@kbd{C-c},@kbd{C-v}, and @kbd{C-z}) by calling @kbd{M-x cua-selection-mode} (or adding @code{(cua-selection-mode nil)} to your @code{haskell-mode-hook}). @section Region indent is a no-op There is a @code{indent-region} function that supposedly could be used to indent code region without changing its semantics. Sadly it does not work that way because usual use case for @code{indent-region} is: @enumerate @item Alter first line of code in region. @item Call @code{indent-region} to fix indentation for remaining lines. @end enumerate Note that between 1 and 2 program is already semantically broken and knowing how to indent it preserving semantic from before step 1 would require time travel. To stay on the safe side @code{indent-region-function} is bound to a no-op in @code{haskell-mode}. @node External indentation @chapter Other ways to indent code @section Indentation with tabs, not spaces Some projects require indenting code with tabs and forbid indenting it with spaces. For hacking on such projects, check out @uref{https://spwhitton.name/tech/code/haskell-tab-indent,haskell-tab-indent-mode}. @section Structured indentation Another alternative is to install @uref{https://github.com/chrisdone/structured-haskell-mode,structured-haskell-mode}. which indents code by parsing the code with a full Haskell parser and deciding where to indent based on that. @node Autoformating @chapter Using external formatters You can enable @uref{https://github.com/jaspervdj/stylish-haskell,stylish-haskell} by installing it: @example $ cabal install stylish-haskell @end example And by enabling it with a customization @lisp (custom-set-variables '(haskell-stylish-on-save t)) @end lisp Now when you run @code{save-buffer} (or @kbd{C-x C-s}) the module will be automatically formatted. Alternatively, you can run the function directly on demand with @kbd{M-x} @code{haskell-mode-stylish-buffer}. @node Module templates @chapter Module templates To enable auto-insertion of module templates, enable: @lisp (add-hook 'haskell-mode-hook 'haskell-auto-insert-module-template) @end lisp When you open a file called @file{Foo.hs}, it will auto-insert @example -- | module Foo where @end example And put your cursor in the comment section. @node Declaration scanning @chapter Declaration scannning @findex haskell-decl-scan-mode @vindex haskell-decl-scan-mode-hook @code{haskell-decl-scan-mode} is a minor mode which performs declaration scanning and provides @kbd{M-x imenu} support (@pxref{Imenu,,,emacs} for more information). For non-literate and @TeX{}-style literate scripts, the common convention that top-level declarations start at the first column is assumed. For Bird-style literate scripts, the common convention that top-level declarations start at the third column, ie. after @samp{> }, is assumed. When @code{haskell-decl-scan-mode} is active, the standard Emacs top-level definition movement commands (@pxref{Moving by Defuns,,,emacs}) are enabled to operate on Haskell declarations: @table @kbd @item C-M-a Move to beginning of current or preceding declaration (@code{beginning-of-defun}). @item C-M-e Move to end of current or following declaration (@code{end-of-defun}). @item C-M-h Select whole current or following declaration (@code{mark-defun}). @end table Moreover, if enabled via the option @code{haskell-decl-scan-add-to-menubar}, a menu item ``Declarations'' is added to the menu bar listing the scanned declarations and allowing to jump to declarations in the source buffer. It's recommended to have font lock mode enabled (@pxref{Font Lock,,,emacs}) as @code{haskell-decl-scan-mode} ignores text highlighted with @code{font-lock-comment-face}. As usual, in order to activate @code{haskell-decl-scan-mode} automatically for Haskell buffers, add @code{haskell-decl-scan-mode} to @code{haskell-mode-hook}: @lisp (add-hook 'haskell-mode-hook 'haskell-decl-scan-mode) @end lisp @code{haskell-decl-scan-mode} enables the use of features that build upon @code{imenu} support such as Speedbar Frames (@pxref{Speedbar,,,emacs}) or the global ``Which Function'' minor mode (@pxref{Which Function,,,emacs}). In order to enable @code{which-function-mode} for Haskell buffers you need to add the following to your Emacs initialization: @lisp (eval-after-load "which-func" '(add-to-list 'which-func-modes 'haskell-mode)) @end lisp @section Speedbar Haskell-mode comes with declaration scanning support. This means that if you enable Haskell support for speedbar: @lisp (speedbar-add-supported-extension ".hs") @end lisp And open speedbar with @code{M-x speedbar} It gives a listing of each module and under each module: @example Imports Instances Data types Classes Bindings @end example You will get a bar that looks like this: @verbatim ~/Projects/ace/src/ACE/ 0:<+> Types 0:[+] Combinators.hs 0:[-] Datalog.hs 1: {-} Classes 2: > ToTerm 1: {-} Imports 2: > ACE.Types.Syntax 2: > Database.Datalog 1: {-} Instances 2: {+} ToTerm A 2: {+} ToTerm Co to ToTerm Gen 2: {+} ToTerm Intransitive to ToTerm N 2: {+} ToTerm P 2: {+} ToTerm Quotation to ToTerm Un 2: {+} ToTerm V 0:[-] Html.hs 1: {+} Imports 1: {+} Instances 1: > mtoMarkup 1: > toMarkupm 1: > wrap 0:[-] Parsers.hs 1: {+} Imports 1: {-} Datatypes 2: > ACEParser 0:[+] Pretty.hs 0:[+] Tokenizer.hs @end verbatim The hierarchy is expandable/collapsible and each entry will jump to the line in the right file when clicked/selected. @node Compilation @chapter Compilation @findex haskell-compile Haskell mode comes equipped with a specialized @dfn{Compilation mode} tailored to GHC's compiler messages with optional support for Cabal projects. @xref{Compilation Mode,,,emacs}, for more information about the basic commands provided by the Compilation mode which are available in the Haskell compilation sub-mode as well. The additional features provided compared to Emacs' basic Compilation mode are: @itemize @item DWIM-style auto-detection of compile command (including support for CABAL projects) @item Support for GHC's compile messages and recognizing error, warning and info source locations (including @option{-ferror-spans} syntax) @item Support for filtering out GHC's uninteresting @samp{Loading package...} linker messages @end itemize In order to use it, invoke the @code{haskell-compile} command instead of @code{compile} as you would for the ordinary Compilation mode. It's recommended to bind @code{haskell-compile} to a convenient key binding. For instance, you can add the following to your Emacs initialization to bind @code{haskell-compile} to @kbd{C-c C-c}. @lisp (eval-after-load "haskell-mode" '(define-key haskell-mode-map (kbd "C-c C-c") 'haskell-compile)) (eval-after-load "haskell-cabal" '(define-key haskell-cabal-mode-map (kbd "C-c C-c") 'haskell-compile)) @end lisp @noindent The following description assumes that @code{haskell-compile} has been bound to @kbd{C-c C-c}. @vindex haskell-compile-cabal-build-command @vindex haskell-compile-cabal-build-command-alt @vindex haskell-compile-command When invoked, @code{haskell-compile} tries to guess how to compile the Haskell program your currently visited buffer belongs to, by searching for a @file{.cabal} file in the current of enclosing parent folders. If a @file{.cabal} file was found, the command defined in the @code{haskell-compile-cabal-build-command} option is used. Note that to compile a @code{stack} based project you will need to set this variable to @code{stack build}. As usual you can do it using @code{M-x customize-variable} or with: @lisp (setq haskell-compile-cabal-build-command "stack build") @end lisp Moreover, when requesting to compile a @file{.cabal}-file is detected and a negative prefix argument (e.g. @kbd{C-- C-c C-c}) was given, the alternative @code{haskell-compile-cabal-build-command-alt} is invoked. By default, @code{haskell-compile-cabal-build-command-alt} contains a @samp{cabal clean -s} command in order to force a full rebuild. Otherwise if no @file{.cabal} could be found, a single-module compilation is assumed and @code{haskell-compile-command} is used (@emph{if} the currently visited buffer contains Haskell source code). You can also inspect and modify the compile command to be invoked temporarily by invoking @code{haskell-compile} with a prefix argument (e.g. @kbd{C-u C-c C-c}). If later-on you want to recompile using the same customized compile command, invoke @code{recompile} (bound to @kbd{g}) inside the @samp{*haskell-compilation*} buffer. @section Keybindings @multitable 0.3 0.7 @headitem Key binding @tab Function @item TAB @tab compilation-next-error @item RET @tab compile-goto-error @item C-o @tab compilation-display-error @item SPC @tab scroll-up-command @item - @tab negative-argument @item 0 .. 9 @tab digit-argument @item < @tab beginning-of-buffer @item > @tab end-of-buffer @item ? @tab describe-mode @item g @tab recompile @item h @tab describe-mode @item q @tab quit-window @item DEL @tab scroll-down-command @item S-SPC @tab scroll-down-command @item <backtab> @tab compilation-previous-error @item <follow-link> @tab mouse-face @item <mouse-2> @tab compile-goto-error @item <remap> @tab Prefix Command @item M-n @tab compilation-next-error @item M-p @tab compilation-previous-error @item M-@{ @tab compilation-previous-file @item M-@} @tab compilation-next-file @item C-c C-c @tab compile-goto-error @item C-c C-f @tab next-error-follow-minor-mode @item C-c C-k @tab kill-compilation @end multitable @node Interactive Haskell @chapter Interactive Haskell @acronym{REPL, read–eval–print loop} is provided both via Comint (@code{inferior-haskell-mode}) and an adhoc way called @code{haskell-interactive-mode}. The Comint based @code{inferior-haskell-mode} is just the REPL, it comes with the standard key bindings(like @code{ielm} or @code{eshell}). @code{haskell-interactive-mode} comes with a different set of features: @itemize @item Separate sessions per Cabal project @file{haskell-session.el}. @item A new inferior Haskell process handling code @file{haskell-process.el}. @item New REPL implementation similar to SLIME/IELM @item Navigatable error overlays @file{haskell-interactive-mode.el}. @end itemize With @code{haskell-interactive-mode}, each Haskell source buffer is associated with at most one GHCi session, so when you call @code{haskell-process-load-file} for a Haskell source buffer which has no session associated yet, you're asked which GHCi session to create or associate with. @section Goto Error In a Haskell source buffer associated with a GHCi session, errors that prevent the file from loading are highlighted with @code{haskell-error-face}. You can move between these error lines with @table @kbd @item M-n is bound to @code{haskell-goto-next-error} @item M-p is bound to @code{haskell-goto-prev-error} @item C-c M-p is bound to @code{haskell-goto-first-error} @end table @section Using GHCi 8+ or GHCi-ng If you use either of the above, then you can use these functions: @lisp (define-key interactive-haskell-mode-map (kbd "M-.") 'haskell-mode-goto-loc) (define-key interactive-haskell-mode-map (kbd "C-c C-t") 'haskell-mode-show-type-at) @end lisp You have to load the module before it works, after that it will remember for the current GHCi session. @section Customizing @cindex customizing What kind of Haskell REPL @code{haskell-interactive-mode} will start up depends on the value of @code{haskell-process-type}. This can be one of the symbols @code{auto}, @code{ghci}, @code{cabal-repl}, @code{cabal-new-repl}, or @code{stack-ghci}. If it's @code{auto}, the directory contents and available programs will be used to make a best guess at the process type. The actual process type will then determine which variables @code{haskell-interactive-mode} will access to determine the program to start and its arguments: @itemize @item If it's @code{ghci}, @code{haskell-process-path-ghci} and @code{haskell-process-args-ghci} will be used. @item If it's @code{cabal-repl}, @code{haskell-process-path-cabal} and @code{haskell-process-args-cabal-repl}. @item If it's @code{cabal-new-repl}, @code{haskell-process-path-cabal} and @code{haskell-process-args-cabal-new-repl}. @item If it's @code{stack-ghci}, @code{haskell-process-path-stack} and @code{haskell-process-args-stack-ghci} will be used. @end itemize With each of these pairs, the the @code{haskell-process-path-...} variable needs to be a string specifying the program path, or a list of strings where the first element is the program path and the rest are initial arguments. The @code{haskell-process-args-...} is a list of strings specifying (further) command-line arguments. @vindex haskell-process-type @vindex haskell-process-path-ghci @vindex haskell-process-path-cabal @vindex haskell-process-path-stack @vindex haskell-process-args-ghci @vindex haskell-process-args-cabal-repl @vindex haskell-process-args-cabal-new-repl @vindex haskell-process-args-stack-ghci @section Haskell Interactive Mode Setup The most straight-forward way to get setup with Interactive Mode is to bind the right keybindings and set some customizations. This page contains a good base setup. To enable the minor mode which activates keybindings associated with interactive mode, use: @lisp (require 'haskell-interactive-mode) (require 'haskell-process) (add-hook 'haskell-mode-hook 'interactive-haskell-mode) @end lisp @subsection Customizations This enables some handy and benign features. @lisp (custom-set-variables '(haskell-process-suggest-remove-import-lines t) '(haskell-process-auto-import-loaded-modules t) '(haskell-process-log t)) @end lisp @subsection Haskell-mode bindings This gives the basic ways to start a session. In a Haskell buffer: @itemize @item Run @kbd{C-`} to make a REPL open, this will create a session, start GHCi, and open the REPL. @item Or: run @kbd{C-c C-l} to load the file. This will first try to start a session as the previous command does. @item Or: run any command which requires a running session. It will always prompt to create one if there isn't one already for the current project. @end itemize @lisp (define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-or-reload) (define-key haskell-mode-map (kbd "C-`") 'haskell-interactive-bring) (define-key haskell-mode-map (kbd "C-c C-t") 'haskell-process-do-type) (define-key haskell-mode-map (kbd "C-c C-i") 'haskell-process-do-info) (define-key haskell-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build) (define-key haskell-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear) (define-key haskell-mode-map (kbd "C-c c") 'haskell-process-cabal) @end lisp @subsection Cabal-mode bindings The below commands pretty much match the ones above, but are handy to have in cabal-mode, too: @lisp (define-key haskell-cabal-mode-map (kbd "C-`") 'haskell-interactive-bring) (define-key haskell-cabal-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear) (define-key haskell-cabal-mode-map (kbd "C-c C-c") 'haskell-process-cabal-build) (define-key haskell-cabal-mode-map (kbd "C-c c") 'haskell-process-cabal) @end lisp @subsection GHCi process type By default @code{haskell-process-type} is set to @code{auto}. It is smart enough to pick the right type based on your project structure and installed tools, but in case something goes funky or you want to explicitly set the process type and ignore the inferred type, you can customize this setting by running @kbd{M-x} @code{customize-variable} @kbd{RET} @code{haskell-process-type} @kbd{RET}, or by setting the code: @lisp (custom-set-variables '(haskell-process-type 'cabal-repl)) @end lisp Here is a list of available process types: @itemize @item ghci @item cabal-repl @item cabal-new-repl @item cabal-dev @item cabal-ghci @item stack-ghci @end itemize Please, check the documentation for @code{haskell-process-type} to see how the real type is guessed, when it's set to @code{auto}. @subsection Troubleshooting Launching your GHCi process can fail when you're first getting setup, depending on the type you choose. If it does fail to launch, switch to the buffer @code{*haskell-process-log*} and see what's up. The buffer contains a log of incoming/outgoing messages to the GHCi process. @section Haskell Interactive Mode Tags Using GHCi You can bind the following to use GHCi to find definitions of things: @lisp (define-key haskell-mode-map (kbd "M-.") 'haskell-mode-jump-to-def) @end lisp The one problem with this approach is that if your code doesn't compile, GHCi doesn't give any location info. So you need to make sure your code compiles and the modules you want to jump to are loaded byte-compiled. Note: I think that when you restart GHCi you lose location information, even if you have the @file{.o} and @file{.hi} files lying around. I'm not sure. But sometimes @code{:i foo} will give @code{foo is defined in Bar} rather than @code{foo is defined in /foo/Bar.hs:123:23}. Alternatively, you can use tags generation, which doesn't require a valid compile. @subsection Tags Setup Make sure to install @file{hasktags}. @example $ cabal install hasktags @end example Then add the customization variable to enable tags generation on save: @lisp (custom-set-variables '(haskell-tags-on-save t)) @end lisp And make sure @file{hasktags} is in your @code{$PATH} which Emacs can see. @subsection Generating tags Now, every time you run @code{save-buffer} (@kbd{C-x C-s}), there is a hook that will run and generate Emacs @xref{Tags,,,emacs}, for the whole project directory. The resulting file will be called @file{TAGS}. WARNING: You should be careful that your project root isn't your home directory or something, otherwise it will traverse all the way down and take an impossibly long time. @subsection Jumping to tags Bind the following keybinding: @lisp (define-key haskell-mode-map (kbd "M-.") 'haskell-mode-tag-find) @end lisp To jump to the location of the top-level identifier at point, run @kbd{M-x} @code{haskell-mode-tag-find} or @kbd{M-.}. @subsection Hybrid: GHCi and fallback to tags To use GHCi first and then if that fails to fallback to tags for jumping, use: @lisp (define-key haskell-mode-map (kbd "M-.") 'haskell-mode-jump-to-def-or-tag) @end lisp @subsection Troubleshooting tags Sometimes a @file{TAGS} file is deleted (by you or some other process). Emacs will complain that it doesn't exist anymore. To resolve this simply do @kbd{M-x} @code{tags-reset-tags-tables}. @section Sessions All commands in Haskell Interactive Mode work within a session. Consider it like a “project” or a “solution” in popular IDEs. It tracks the root of your project and an associated process and REPL. @subsection Start a session To start a session run the following steps: @itemize @item Open some Cabal or Haskell file. @item Run @kbd{C-`} to make a REPL open, this will create a session, start GHCi, and open the REPL. @item Or: run @kbd{C-c C-l} to load the file. This will first try to start a session as the previous command does. @item Or: run any command which requires a running session. It will always prompt to create one if there isn't one already for the current project. @end itemize It will prompt for a Cabal directory and a current directory. It figures out where the cabal directory is and defaults for the current directory, so you should be able to just hit RET twice. @subsection Switch a session Sometimes a particular file is used in two different sessions/projects. You can run @example M-x haskell-session-change @end example If it prompts you to make a new session, tell it no (that's a bug). It will ask you to choose from a list of sessions. @subsection Killing a session To kill a session you can run @example M-x haskell-session-kill @end example Which will prompt to kill all associated buffers, too. Hit `n` to retain them. Alternatively, you can switch to the REPL and just kill the buffer normally with @kbd{C-x k RET}. It will prompt @example Kill the whole session (y or n)? @end example You can choose @kbd{y} to kill the session itself, or @kbd{n} to just kill the REPL buffer. You can bring it back with @kbd{M-x} @code{haskell-interactive-bring}. @subsection Menu To see a list of all sessions you have open with some simple statistics about memory usage, etc. run @example M-x haskell-menu @end example For example: @example foo 14648 08:21:42 214MB /path/to/fpco/foo/ /path/to/fpco/foo/ ghci bar 29119 00:22:03 130MB /path/to/bar/ /path/to/bar/ ghci mu 22575 08:48:20 73MB /path/to/fpco/mu/ /path/to/fpco/mu/ ghci @end example @section Compiling There are a bunch of ways to compile Haskell modules. This page covers a few of them. @subsection Load into GHCi To compile and load a Haskell module into GHCi, run the following @example M-x haskell-process-load @end example Or @kbd{C-c C-l}. You'll see any compile errors in the REPL window. @subsection Build the Cabal project To compile the whole Cabal project, run the following @example M-x haskell-process-cabal-build @end example Or @kbd{C-c C-c}. You'll see any compile errors in the REPL window. @subsection Reloading modules To reload the current module, even when you're in other modules, you can run @kbd{C-u M-x} @code{haskell-process-load-or-reload} or @kbd{C-u C-c C-l}. It will now reload that module whenever you run @kbd{C-c C-l} in the future from whatever module you're in. To disable this mode, just run @kbd{C-u C-c C-l} again. @subsection Jumping to compile errors You can use the standard compile error navigation function @kbd{C-x `} — jump to the next error. Or you can move your cursor to an error in the REPL and hit @kbd{RET} to jump to it. @subsection Auto-removing imports If the customization variable @code{haskell-process-suggest-remove-import-lines} is enabled. @lisp (custom-set-variables '(haskell-process-suggest-remove-import-lines t)) @end lisp Building and loading modules which output warnings like, @example Warning: The import of `Control.Monad' is redundant except perhaps to import instances from `Control.Monad' To import instances alone, use: import Control.Monad() @end example will prompt the user with @example > The import line `Control.Monad' is redundant. Remove? (y, n, c: comment out) @end example If you answer @itemize @item @kbd{y}: it will delete the import, but leave the empty line remaining (this avoids messing with line positions in subsequent error messages). @item @kbd{n}: it will leave the import. @item @kbd{c}: it will comment out the import (this is handy for when you just want to temporarily hide an import). @end itemize @subsection Auto-adding of modules to import Enable the customization variable @code{haskell-process-suggest-hoogle-imports}. @lisp (custom-set-variables '(haskell-process-suggest-hoogle-imports t)) @end lisp Whenever GHC says something is not in scope, it will hoogle that symbol. If there are results, it will prompt to add one of the modules from Hoogle's results. You need to make sure you've generated your Hoogle database properly. @subsection Auto-adding of extensions It you use an extension which is not enabled, GHC will often inform you. For example, if you write: @example newtype X a = X (IO a) deriving (Monad) @end example Then you'll see a message like: @example x.hs:13:13: Can't make a derived instance of `Monad X': … `Monad' is not a derivable class Try -XGeneralizedNewtypeDeriving for GHC's newtype-deriving extension In the newtype declaration for `X' @end example This @code{-XFoo} pattern will be picked up and you will be prompted: @example > Add `@{-# LANGUAGE GeneralizedNewtypeDeriving #-@}` to the top of the > file? (y or n) @end example If you answer `y`, it will temporarily jump to the buffer and it to the top of the file. @subsection Orphan instances If GHC complains about orphan instances, you usually are doing it intentionally, so it prompts to add @code{-fno-warn-orphans} to the top of the file with an @kbd{OPTIONS} pragma. @subsection Auto-adding of dependencies When doing a build, you will sometimes get a message from GHC like: @example src/ACE/Tokenizer.hs:11:18: Could not find module `Data.Attoparsec.Text' … It is a member of the hidden package `attoparsec-0.11.1.0'. @end example This message contains all the necessary information to add this to your .cabal file, so you will be prompted to add it to your .cabal file: @example Add `attoparsec' to ace.cabal? (y or n) y @end example If you hit @kbd{y}, it will prompt with this: @example attoparsec >= 0.11.1.0 @end example Which you can edit (e.g. do some PVP decision or remove constraints entirely), and then it will open up your @file{.cabal} file and go through each section: @example Add to library? (y or n) y @end example This will add it to the top of the @code{build-depends} field in your library section. If you have any executables, it will go through each of those, prompting, too. Now you can rebuild with @kbd{C-c C-c} again. @section Haskell Interactive Mode REPL When GHCi has been launched, it works on a read-eval-print basis. So you will be presented with the prompt: @example The lambdas must flow. Changed directory: /path/to/your/project/ λ> @end example @subsection Changing REPL target @findex haskell-session-change-target @vindex haskell-interactive-mode-hook With @code{haskell-session-change-target} you can change the target for REPL session. After REPL session started, in @code{haskell-interactive-mode} buffer invoke the @code{haskell-session-change-target} and select from available targets for @cindex testing - Testing @cindex benchmarking - Benchmark - Executable - Library Answer ``yes'' to restart the session and run your tests, benchmarks, executables. TODO/WRITEME @subsection Bringing the REPL If you don't know where the REPL buffer is, you can always bring it with: @example M-x haskell-interactive-bring @end example Or @kbd{C-`}. @subsection Evaluating expressions To evaluate expressions, simply type one out and hit `RET`. @example λ> 123 123 @end example @subsection Evaluating multiline expressions GHCi features two ways to evaluate multiline expressions. You can use @code{:set +m} to enable @uref{https://www.haskell.org/ghc/docs/latest/html/users_guide/ghci.html#multiline-input, multiline input} for all expressions, or you can wrap your expression in @code{:@{} and @code{:@}} (they have to be on their own lines). The prompt will change to indicate that you're inputting a multiline expression: @example λ> :@{ λ| let a = 10 λ| b = 20 λ| c = 30 λ| :@} @end example You can also simulate multiline mode by having your input contain newline characters. You can input a literal newline character with @kbd{C-q C-j}, or you can use: @example M-x haskell-interactive-mode-newline-indent @end example which is bound to @kbd{C-j}. This command indents after the newline. You can simulate the above example like so: @example λ> let a = 10 b = 20 c = 30 @end example @subsection Type of expressions You can use normal @code{:type} which is part of GHCi to get the type of something: @example λ> :t id id :: a -> a @end example But you can also just write out the value directly, @example λ> id id :: a -> a @end example and because there's no @code{Show} instance for @code{(a -> a)}. This would normally yield a compile error: @example No instance for (Show (a0 -> a0)) arising from a use of `print' Possible fix: add an instance declaration for (Show (a0 -> a0)) In a stmt of an interactive GHCi command: print it @end example It will run @code{:type id} in the background and print out the result. The same is true for ambiguous things: @example λ> :t read "a" read "a" :: Read a => a @end example Because this would normally be an ambiguous constraint: @example Ambiguous type variable `a0' in the constraint: (Read a0) arising from a use of `read' Probable fix: add a type signature that fixes these type variable(s) In the expression: read \"a\" In an equation for `it': it = read \"a\" @end example Which is less useful than just printing the type out. You can disable this behaviour by disabling the customization option: @lisp (custom-set-variables '(haskell-interactive-types-for-show-ambiguous nil)) @end lisp @anchor{printing mode} @subsection Printing mode You can choose between printing modes used for the results of evaluating expressions. To do that, configure the variable @code{haskell-interactive-mode-eval-mode}. Example: @lisp (setq haskell-interactive-mode-eval-mode 'haskell-mode) @end lisp A handy function you can use is: @lisp (defun haskell-interactive-toggle-print-mode () (interactive) (setq haskell-interactive-mode-eval-mode (intern (ido-completing-read "Eval result mode: " '("fundamental-mode" "haskell-mode" "espresso-mode" "ghc-core-mode" "org-mode"))))) @end lisp (Add whichever modes you want to use.) And then run @example M-x haskell-interactive-toggle-print-mode @end example Or @kbd{C-c C-v}: @lisp (define-key haskell-interactive-mode-map (kbd "C-c C-v") 'haskell-interactive-toggle-print-mode) @end lisp There you can choose `haskell-mode`, for example, to pretty print the output as Haskell. @subsection @acronym{SVG} images rendering @cindex Rendering SVG images @cindex SVG images, rendering @cindex Images, rendering SVG images If you are working on @acronym{SVG} images, you can instruct Emacs to render the image as the output of an image producing command at the @acronym{REPL}@. The following example uses the @code{diamgrams} library with the default @acronym{SVG} backend to produce a circle: @example @{-# LANGUAGE OverloadedStrings #-@} import Diagrams.Prelude import Diagrams.Backend.SVG myCircle :: Diagram B myCircle = circle 1 # lc purple # fc yellow circle = renderDia SVG (SVGOptions (mkWidth 250) Nothing "" [] True) myCircle @end example @findex haskell-svg-toggle-render-images After enabling @acronym{SVG} rendering with @kbd{M-x haskell-svg-toggle-render-images}, if you load the above code and type @code{circle} at the @acronym{REPL}, you will see the rendered circle instead of the @acronym{XML} representation of the image. @vindex haskell-svg-render-images For this feature to work, it is required that the variable @code{haskell-interactive-mode-eval-mode} be set to a value different from @code{nil}, @pxref{printing mode}. This feature can be enabled by default by setting the customization variable @code{haskell-svg-render-images} to a non-nil value. @subsection Presentations If you have the @file{present} package installed, you can use the following syntax to print anything which is an instance of @code{Data}: @example λ> :present 123 123 @end example It will print data structures lazily: @example λ> :present [1..] [1 ,[Integer]] @end example It shows types when there is an unevaluated field in a constructor. You can click the @code{[Integer]} or press @kbd{RET} on it to expand further: @example λ> :present [1..] [1 ,2 ,[Integer]] @end example Etc. Remember: this only works for instances of @code{Data.Data.Data}. @subsection History A history is maintained for the duration of the REPL buffer. To go up and down in the history, run @kbd{M-p} for previous and @kbd{M-n} for next. @subsection Cancelling commands To cancel a running REPL command, run @kbd{C-c C-c}. @subsection Clear the REPL Run @kbd{C-c C-k} to clear the REPL. @subsection Trick: Put Interactive REPL in Separate Frame The following @code{create-haskell-interactive-frame} is a quick hack to move the repl to a separate frame, for those that want a more predictable layout of windows in Emacs. @lisp (defun create-unfocused-frame () (let* ((prv (window-frame)) (created (make-frame))) (select-frame-set-input-focus prv) created)) (defun create-haskell-interactive-frame () (interactive) (haskell-interactive-bring) (create-unfocused-frame) (delete-window)) @end lisp @subsection Troubleshooting If the REPL ever goes funny, you can clear the command queue via: @example M-x haskell-process-clear @end example Alternatively, you can just restart the process: @example M-x haskell-process-restart @end example You can also switch to the buffer @code{*haskell-process-log*}, which can be enabled and disabled with the customization variable `haskell-process-log`, to see what the cause of your troubles are. If the process fails and nothing unusual is in the process log, the following command can dump the @code{haskell-process} state: @example M-: (haskell-process) @end example The output can be copied from the @code{*Messages*} buffer. @section Haskell Interactive Mode Querying There a few ways GHCi lets you query information about your code. @subsection Get identifier type To print the type of the top-level identifier at point in the REPL and in the message buffer, run the following command: @example M-x haskell-process-do-type @end example or @kbd{C-c C-t}. @subsection Insert identifier's type as type signature To print the type of the top-level identifier at point, run the following command: @example C-u M-x haskell-process-do-type @end example or @kbd{C-u C-c C-t}. @subsection Get identifier info To print the info of the identifier at point, run the following command: @example M-x haskell-process-do-info @end example or @kbd{C-c C-i}. @subsection Presentation mode When using @kbd{C-c C-i} or @kbd{C-c C-t} it will open a buffer in haskell-presentation-mode. You can hit @kbd{q} to close the buffer. But you can also continue to use @kbd{C-c C-i} inside the buffer to drill further down data types and classes. E.g. if you go to @code{Ord} in your code buffer and @kbd{C-c C-i}, it will popup a buffer containing @example class Eq a => Ord a where compare :: a -> a -> Ordering (<) :: a -> a -> Bool (>=) :: a -> a -> Bool (>) :: a -> a -> Bool (<=) :: a -> a -> Bool max :: a -> a -> a min :: a -> a -> a -- Defined in `GHC.Classes' @end example And all the instances of that class. But then you can also move your cursor to @code{Ordering} and hit @kbd{C-c C-i} again to get another popup: @example data Ordering = LT | EQ | GT -- Defined in `GHC.Types' instance Bounded Ordering -- Defined in `GHC.Enum' instance Enum Ordering -- Defined in `GHC.Enum' instance Eq Ordering -- Defined in `GHC.Classes' instance Ord Ordering -- Defined in `GHC.Classes' instance Read Ordering -- Defined in `GHC.Read' instance Show Ordering -- Defined in `GHC.Show' @end example And so on. It's a very good way of exploring a new codebase. @subsection Browse import's module To print all exported identifiers of the module imported by the import line at point, run the following command: @example M-x haskell-process-do-info @end example or @kbd{C-c C-i}. It will print all exports by running @code{:browse The.Module} in the GHCi process. @section Haskell Interactive Mode Cabal integration There's some integration with Cabal in Haskell Interactive Mode. Once you've started a session, the features below are available. @subsection Cabal building The most common Cabal action is building, so that has a specific command: @example M-x haskell-process-cabal-build @end example Or @kbd{C-c C-c}. When building, it will hide unnecessary output. For example, to build the `ace` package, the output is simply: @example Compiling: ACE.Types.Tokens Compiling: ACE.Combinators Compiling: ACE.Tokenizer Compiling: ACE.Parsers Compiling: ACE.Pretty Compiling: ACE Complete: cabal build (0 compiler messages) @end example Whereas the complete output is normally: @example Building ace-0.5... Preprocessing library ace-0.5... [4 of 9] Compiling ACE.Types.Tokens ( src/ACE/Types/Tokens.hs, dist/build/ACE/Types/Tokens.o ) [5 of 9] Compiling ACE.Combinators ( src/ACE/Combinators.hs, dist/build/ACE/Combinators.o ) [ACE.Types.Tokens changed] [6 of 9] Compiling ACE.Tokenizer ( src/ACE/Tokenizer.hs, dist/build/ACE/Tokenizer.o ) [ACE.Types.Tokens changed] [7 of 9] Compiling ACE.Parsers ( src/ACE/Parsers.hs, dist/build/ACE/Parsers.o ) [8 of 9] Compiling ACE.Pretty ( src/ACE/Pretty.hs, dist/build/ACE/Pretty.o ) [9 of 9] Compiling ACE ( src/ACE.hs, dist/build/ACE.o ) [ACE.Tokenizer changed] In-place registering ace-0.5... @end example Which is considerably more verbose but rarely useful or interesting. @subsection Arbitrary cabal commands To run an arbitrary Cabal command: @example C-u M-x haskell-process-cabal @end example Or run @kbd{C-u C-c c}. It will prompt for an input, so you can write @code{configure -fdev}, for example. @subsection Completing cabal commands To run some common Cabal commands, just run: @example M-x haskell-process-cabal @end example Or @kbd{C-c c}. This is commonly used to do @code{install}, @code{haddock}, @code{configure}, etc. @section Haskell Interactive Mode Debugger There is limited support for debugging in GHCi. Haskell Interactive Mode provides an interface for interacting with this. @subsection Opening the debug buffer To open the debug buffer run the following command from any buffer associated with a session: @example M-x haskell-debug @end example It will open a buffer that looks like this: @example Debugging haskell You have to load a module to start debugging. g - refresh Modules No loaded modules. @end example @subsection Loading modules To debug anything you need to load something into GHCi. Switch to a normal file, for example: @example main = do putStrLn "Hello!" putStrLn "World" @end example and load it into GHCi (@kbd{C-c C-l}). Now when you hit @kbd{g} (to refresh) in the debugging buffer, you'll see something like: @example Debugging haskell b - breakpoint, g - refresh Context Not debugging right now. Breakpoints No active breakpoints. Modules Main - hello.hs @end example @subsection Setting a breakpoint To set a breakpoint hit @kbd{b} in the debugger buffer. It will prompt for a name. Enter @code{main} and hit @kbd{RET}. Now the buffer will look like this: @example Debugging haskell s - step into an expression, b - breakpoint d - delete breakpoint, g - refresh Context Not debugging right now. Breakpoints 0 - Main (1:8) Modules Main - hello.hs @end example @subsection Start stepping Hit @kbd{s} to step through an expression: it will prompt for an expression to evaluate and step through. Enter @code{main} and hit @kbd{RET}. Now the buffer will look like this: @example Debugging haskell s - step into an expression, b - breakpoint d - delete breakpoint, a - abandon context, c - continue p - previous step, n - next step g - refresh Context main - hello.hs (stopped) do putStrLn "Hello!" putStrLn "World" _result :: IO () = _ 1 do putStrLn "Hello!" putStrLn "World" Breakpoints 0 - Main (1:8) Modules Main - hello.hs @end example What we see here is the current expression being evaluated: @example do putStrLn "Hello!" putStrLn "World" @end example And we see the type of it: @example _result :: IO () = _ @end example And we see a backtrace of steps so far: @example 1 do putStrLn "Hello!" putStrLn "World" @end example @subsection Continue stepping To continue stepping, just hit @kbd{s} again. Now the context will change to: @example main - hello.hs (stopped) putStrLn "Hello!" _result :: IO () = _ 1 do putStrLn "Hello!" putStrLn "World" @end example Hitting @kbd{s} once more, we see the context change to: @example putStrLn "World" _result :: IO () = _ 2 putStrLn "Hello!" 1 do putStrLn "Hello!" putStrLn "World" @end example Finally hitting @kbd{s} again will say "Computation finished". Hitting @kbd{s} a final time will change the display back to: @example Debugging haskell s - step into an expression, b - breakpoint d - delete breakpoint, g - refresh Context Finished debugging. 2 putStrLn "Hello!" 1 do putStrLn "Hello!" putStrLn "World" Breakpoints 1 - Main (1:8) Modules Main - hello.hs @end example And you're done debugging. @node Editing Cabal files @chapter Editing Cabal files @findex haskell-cabal-mode @vindex haskell-cabal-mode-hook @code{haskell-cabal-mode} is a major mode for editing @uref{http://www.haskell.org/cabal/users-guide/developing-packages.html,Cabal package description files} and is automatically associated with files having a @file{.cabal} extension. @findex haskell-cabal-visit-file For quickly locating and jumping to the nearest @file{.cabal} file from a Haskell source buffer, you can use @kbd{M-x haskell-cabal-visit-file}; with a prefix argument (i.e. @kbd{C-u}) @code{find-file-other-window} is used to visit the @file{.cabal} file. @code{haskell-cabal-visit-file} is bound to the key sequence @kbd{C-c v c}. TODO/WRITEME @node Browsing Haddocks @chapter Browsing Haddocks using @code{w3m} An experimental feature is use of the w3m browser to browse Haddock docs inside Emacs. @section Get w3m Most Linux distributions will have a package for the binary: @example $ sudo apt-get install w3m @end example Now grab @code{w3m.el} from: @itemize @item @url{http://emacs-w3m.namazu.org/} @item @kbd{M-x} @code{package-install} @kbd{RET} @code{w3m} @kbd{RET} @end itemize Confirm installation by trying @kbd{M-x} @code{w3m-browse-url} @kbd{RET} @code{haskell.org} @kbd{RET}. If this works, you're good to go. @section Configure w3m Now that you have w3m, you probably want to configure it to be more of a passive viewer than a full-fledged browser. For example: @lisp (setq w3m-mode-map (make-sparse-keymap)) (define-key w3m-mode-map (kbd "RET") 'w3m-view-this-url) (define-key w3m-mode-map (kbd "q") 'bury-buffer) (define-key w3m-mode-map (kbd "<mouse-1>") 'w3m-maybe-url) (define-key w3m-mode-map [f5] 'w3m-reload-this-page) (define-key w3m-mode-map (kbd "C-c C-d") 'haskell-w3m-open-haddock) (define-key w3m-mode-map (kbd "M-<left>") 'w3m-view-previous-page) (define-key w3m-mode-map (kbd "M-<right>") 'w3m-view-next-page) (define-key w3m-mode-map (kbd "M-.") 'w3m-haddock-find-tag) (defun w3m-maybe-url () (interactive) (if (or (equal '(w3m-anchor) (get-text-property (point) 'face)) (equal '(w3m-arrived-anchor) (get-text-property (point) 'face))) (w3m-view-this-url))) @end lisp @section Import w3m-haddock It's not enabled by default in haskell-mode at present, so you need to import it manually: @lisp (require 'w3m-haddock) @end lisp @section Add a hook for w3m In order to make haddock pages a little more palatable (and add syntax highlighting to source view), you can add this hook: @lisp (add-hook 'w3m-display-hook 'w3m-haddock-display) @end lisp It's a little rough around the edges, but it's a start. @section Configure your package locations By default, the package locations is set to: @lisp (defcustom haskell-w3m-haddock-dirs '("~/.cabal/share/doc/")) @end lisp If you are using an hsenv or a custom package directory, you should configure this variable with M-x customize-variable or by writing the custom-set-variables code for it. @section Finally You did all that! Now you're ready to bind a useful key: @lisp (define-key haskell-mode-map (kbd "C-c C-d") 'haskell-w3m-open-haddock) @end lisp Now when you press @kbd{C-c} @kbd{C-d} it will prompt for a package to browse to. This feature will be improved gradually as time goes on. @node Spell checking strings and comments @chapter Using with @code{flyspell-prog-mode} Strings and comments can be checked for spelling mistakes. There is a standard Emacs mode for this purpose, @code{flyspell-prog-mode}, that can be enabled in Haskell buffers. Spelling errors are underlined using squiggly red lines. @ifhtml @image{anim/flyspell-prog-mode} @end ifhtml Documentation for @code{flyspell-prog-mode} can be found in @xref{Spelling,,,emacs}. Here we point to a couple of useful keybindings: @itemize @item @kbd{M-$} - Check and correct spelling of the word at point (@code{ispell-word}). @item @kbd{digit} - Replace the word, just this time, with one of the displayed near-misses. Each near-miss is listed with a digit; type that digit to select it. @item @kbd{SPC} - Skip this word—continue to consider it incorrect, but don’t change it here. @end itemize To enable spell checking of strings and comments add this line to your @code{~/.emacs} file: @code{(add-hook 'haskell-mode-hook 'flyspell-prog-mode)} @node Aligning code @chapter Aligning code Select a region you want to align text within, @kbd{M-x} @code{align-regexp}, and type a regexp representing the alignment delimiter. For example, I often line up my Haddock comments: @example f :: a -- ^ does a -> Foo b -- ^ and b -> c -- ^ to c @end example Select the region, and let the regexp be @samp{--}: @example f :: a -- ^ does a -> Foo b -- ^ and b -> c -- ^ to c @end example Of course, this works for just about anything. Personally, I've globally bound it to @kbd{C-x a r}: @lisp (global-set-key (kbd "C-x a r") 'align-regexp) @end lisp Note that you can also just use the rules below for telling the aligner about Haskell. Once you evaluate this, you can just use @kbd{M-x} @code{align}, which I like to bind to @kbd{M-[}. @lisp (add-to-list 'align-rules-list '(haskell-types (regexp . "\\(\\s-+\\)\\(::\\|∷\\)\\s-+") (modes quote (haskell-mode literate-haskell-mode)))) (add-to-list 'align-rules-list '(haskell-assignment (regexp . "\\(\\s-+\\)=\\s-+") (modes quote (haskell-mode literate-haskell-mode)))) (add-to-list 'align-rules-list '(haskell-arrows (regexp . "\\(\\s-+\\)\\(->\\|→\\)\\s-+") (modes quote (haskell-mode literate-haskell-mode)))) (add-to-list 'align-rules-list '(haskell-left-arrows (regexp . "\\(\\s-+\\)\\(<-\\|←\\)\\s-+") (modes quote (haskell-mode literate-haskell-mode)))) @end lisp @node Rectangular commands @chapter Using rectangular region commands Emacs has a set of commands which operate on the region as if it were rectangular. This turns out to be extremely useful when dealing with whitespace sensitive languages. @itemize @item @kbd{C-x r o} is "Open Rectangle". It will shift any text within the rectangle to the right side. Also see: @item @kbd{C-x r t} is "String Rectangle". It will replace any text within the rectangle with the given string on all the lines in the region. If comment-region didn't already exist, you could use this instead, for example. @item @kbd{C-x r d} is "Delete Rectangle". It will delete the contents of the rectangle and move anything on the right over. @item @kbd{C-x r r} is "Copy Rectangle to Register". It will prompt you for a register number so it can save it for later. @item @kbd{C-x r g} is "Insert register". This will insert the contents of the given register, overwriting whatever happens to be within the target rectangle. (So make room) @item @kbd{C-x r k} is "Kill rectangle". Delete rectangle and save contents for: @item @kbd{C-x r y} is "Yank rectangle". This will insert the contents of the last killed rectangle. @end itemize As with all Emacs modifier combos, you can type @kbd{C-x r C-h} to find out what keys are bound beginning with the @kbd{C-x r} prefix. @node REPL @chapter Using GHCi REPL within Emacs To start the REPL you can run one of the following: @itemize @item @kbd{M-x run-haskell} @item @kbd{M-x switch-to-haskell} @end itemize This repl works with @uref{https://www.emacswiki.org/emacs/ComintMode, Comint}. So you will feel at home if you are already using @kbd{M-x Shell} or @kbd{M-x ielm}. @code{Inf-Haskell} is a Major mode for running GHCi, with comint. Important key bindings in @code{Inf-haskell}: @table @kbd @item RET invokes @kbd{comint-send-input}. Sends the input to the GHCi process, evaluates the line and returns the output. @item C-d or <delete> deletes the forward character @item <C-up> or M-p invokes @kbd{comint-previous-input}. Cycle backwards through input history, saving input. @item <C-down> or M-n invokes @kbd{comint-next-input}. Cycle forwards through input history. @item C-c C-c invokes @kbd{comint-interrupt-subjob}. Sends KeyboardInterrupt signal. @item C-c C-\ invokes @kbd{comint-quit-subjob}. Sends KeyboardInterrupt signal. @item C-c C-z invokes @kbd{comint-stop-subjob}. Kills the GHCi process. @item C-c M-r invokes @kbd{comint-previous-matching-input-from-input}. If you are familiar with @kbd{C-r} in bash. This is the same as that. Searches backwards through input history for match for current input. @item C-c M-s invokes @kbd{comint-next-matching-input-from-input}. Searches forwards through input history for match for current input. @item C-c C-l invokes @kbd{comint-dynamic-list-input-ring}. Displays a list of recent inputs entered into the current buffer. @item C-c M-o invokes @kbd{comint-clear-buffer}. Clears the buffer (Only with Emacs 25.X and above) @item C-c C-n invokes @kbd{comint-next-prompt}. Goes to the start of the previous REPL prompt. @item C-c C-p invokes @kbd{comint-previous-prompt}. Goes to the start of the next REPL prompt. @item C-c C-o invokes @kbd{comint-delete-output}. Clears the output of the most recently evaluated expression. @item C-c C-e invokes @kbd{comint-show-maximum-output}. Moves the point to the end of the buffer. @item C-c C-u invokes @kbd{comint-kill-input}. Kills backward, the line at point. (Use this when you have typed in an expression into the prompt but you dont want to evaluate it.) @item C-c C-w invokes @kbd{backward-kill-word}. Kills backward, the word at point @item C-c C-s invokes @kbd{comint-write-output}. Write output from interpreter since last input to FILENAME. Any prompt at the end of the output is not written. @end table @section Relevant defcustoms: @multitable @columnfractions .40 .20 .40 @headitem Interpreter (defcustom) @tab Default Value @tab Possible Values @item @code{haskell-process-type} @tab @code{'auto} @tab @code{'stack-ghci, 'cabal-repl, 'ghci, 'auto} @item @code{inferior-haskell-hook} @tab @code{nil} @tab - @item @code{haskell-process-path-ghci} @tab @code{ghci} @tab - @item @code{haskell-process-args-ghci} @tab @code{-ferror-spans} @tab - @item @code{haskell-process-path-cabal} @tab @code{cabal} @tab - @item @code{haskell-process-args-cabal-repl} @tab @code{--ghc-option=-ferror-spans} @tab - @item @code{haskell-process-path-stack} @tab @code{stack} @tab - @item @code{haskell-process-args-stack-ghci} @tab @code{--ghci-options=-ferror-spans --no-build --no-load} @tab - @end multitable @section More on @code{haskell-process-type} The Haskell interpreter used by @code{Inf-Haskell} is auto-detected by default, but is customizable with defcustom @code{haskell-process-type}. The values recognized by it are (default is 'auto): @itemize @item @code{'stack-ghci} @item @code{'cabal-repl} @item @code{'ghci} @item @code{'auto} @end itemize if the @code{haskell-process-type} is @code{'auto}, the directories are searched for @code{cabal.sandbox.config} or @code{stack.yaml} or @code{*.cabal} file. If the file is present, then appropriate process is started. When @code{cabal.sandbox.config} is found @code{haskell-process-type} is @code{'cabal-repl}. Similarly, when @code{stack.yaml} is found @code{haskell-process-type} is @code{'stack-ghci}. Similarly, when @code{xyz.cabal} is found @code{haskell-process-type} is @code{'cabal-repl}. When nothing is found @code{haskell-process-type} is @code{'ghci}. When more than one file such as @code{cabal.sandbox.config} and @code{stack.yaml} are found the following preference is followed. @code{cabal.sandbox.config} > @code{stack.yaml} > @code{*.cabal} @node Collapsing Haskell code @chapter Collapsing Haskell code This is @code{hs-minor-mode} for @code{haskell-mode}. This module uses hideshow module. To activate this minor mode (haskell-collapse-mode) @itemize @item @kbd{M-x haskell-collapse-mode} is "To start haskell-collapse-mode". @end itemize This minor mode works with indentation. In a quick glance: @table @kbd @item C-c @ C-c is bound to @code{haskell-hide-toggle} @item C-c @ C-M-c @item C-c @ C-M-h @item C-c @ C-M-s are all bound to @code{haskell-hide-toggle-all} @end table How to use @code{M-x haskell-hide-toggle}? Place your point on the code block that you want to collapse and hit the keybinding. Now the code collapses and you can see the first line of the block and elipsis. Take this example code (example usage of @code{M-x haskell-hide-toggle}): when you place the cursor here, like this (notice the thick block in the first line): @code{ f█x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) | otherwise = 0 where i = sum x j = g x (div i 3) 0 0 [] k = zeroes x 0 } or @code{ f x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) █ | otherwise = 0 where i = sum x j = g x (div i 3) 0 0 [] k = zeroes x 0 } then when you collapse it becomes something like this: @code{ f█x@dots{} } It works in terms of (indentation) blocks. One more example: @code{ f x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) | otherwise = 0 w█ere i = sum x j = g x (div i 3) 0 0 [] k = zeroes x 0 } or @code{ f x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) | otherwise = 0 where i = sum x j = g x (div i 3) 0 0 [] █ k = zeroes x 0 } this, will result in something like: @code{ f x | rem i 3 == 0 = if i == 0 && (k /= 0) then (c k) else (h j) | otherwise = 0 where i = sum █@dots{} } The other functionality @code{M-x haskell-hide-toggle-all} also works only for indentation and it collapses all toplevel functions. So a file that looks like this: @example main = interact $ show.f. map read .words f (x:xs) = dp x xs dp money a | money < 0 || null a = [1..1000] dp 0 a = [] dp money a @atchar{} (coin:coins) | (length i) <= length j = i | otherwise = j where i = (coin:(dp (money-coin) a)) j = (dp money coins) @end example will turn into this: @example main = interact $ show.f. map read .words f (x:xs) = dp x xs dp money a | money < 0 || null a = [1..1000] dp 0 a = [] dp money a @atchar{} (coin:coins)@dots{} @end example @node Getting Help and Reporting Bugs @chapter Getting Help and Reporting Bugs Work on Haskell Mode is organized with Github @code{haskell-mode} project. To understand how the project is run please read the information in the @uref{https://github.com/haskell/haskell-mode/wiki,project wiki pages}. To report any issues please use the Github's issue mechanism available from @uref{https://github.com/haskell/haskell-mode,Haskell Mode's GitHub Home}. For a quick question visit @code{#haskell-emacs} channel on IRC @code{irc.freenode.net}. There is also a (now defunct) @uref{http://projects.haskell.org/cgi-bin/mailman/listinfo/haskellmode-emacs, Haskellmode-emacs mailing list}, also available on @uref{http://gmane.org/, Gmane} via the @uref{http://dir.gmane.org/gmane.comp.lang.haskell.emacs, gmane.comp.lang.haskell.emacs} newsgroup. We welcome code and non-code contributions so that we can all enjoy coding Haskell even more. @node Concept index @unnumbered Concept index @printindex cp @node Function index @unnumbered Function index @printindex fn @node Variable index @unnumbered Variable index @printindex vr @bye @c Local Variables: @c End: ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/ghc-core.el�����������������������������������������������������������������������0000664�0000000�0000000�00000007744�13602233217�0016033�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; ghc-core.el --- Syntax highlighting module for GHC Core -*- lexical-binding: t -*- ;; Copyright (C) 2010 Johan Tibell ;; Author: Johan Tibell <johan.tibell@gmail.com> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; Purpose: ;; ;; To make it easier to read GHC Core output by providing highlighting ;; and removal of commonly ignored annotations. ;;; Code: (require 'haskell-mode) (require 'haskell-font-lock) ;;;###autoload (defgroup ghc-core nil "Major mode for viewing pretty printed GHC Core output." :link '(custom-manual "(haskell-mode)") :group 'haskell :prefix "ghc-core-") (defcustom ghc-core-program "ghc" "Name of the GHC executable (excluding any arguments)." :type 'string :group 'ghc-core) (define-obsolete-variable-alias 'ghc-core-create-options 'ghc-core-program-args "haskell-mode 13.7") (defcustom ghc-core-program-args '("-O2") "Additional options to be passed to GHC when generating core output. GHC (see variable `ghc-core-program') is invoked with the basic command line options \"-ddump-simpl -c <source-file>\" followed by the additional options defined here. The following `-ddump-simpl` options might be of interest: - `-dsuppress-all' - `-dsuppress-uniques' - `-dsuppress-idinfo' - `-dsuppress-module-prefixes' - `-dsuppress-type-signatures' - `-dsuppress-type-applications' - `-dsuppress-coercions' See `M-x manual-entry RET ghc' for more details." :type '(repeat (string :tag "Argument")) :group 'ghc-core) (defun ghc-core-clean-region (start end) "Remove commonly ignored annotations and namespace prefixes in the region between START and END." (interactive "r") (save-restriction (narrow-to-region start end) (goto-char (point-min)) (while (search-forward-regexp "GHC\.[^\.]*\." nil t) (replace-match "" nil t)) (goto-char (point-min)) (while (flush-lines "^ *GblId *$" nil)) (goto-char (point-min)) (while (flush-lines "^ *LclId *$" nil)) (goto-char (point-min)) (while (flush-lines (concat "^ *\\[\\(?:Arity [0-9]+\\|NoCafRefs\\|" "Str: DmdType\\|Worker \\)" "\\([^]]*\\n?\\).*\\] *$") nil)) (goto-char (point-min)) (while (search-forward "Main." nil t) (replace-match "" nil t)))) (defun ghc-core-clean-buffer () "Remove commonly ignored annotations and namespace prefixes in the current buffer." (interactive) (ghc-core-clean-region (point-min) (point-max))) ;;;###autoload (defun ghc-core-create-core () "Compile and load the current buffer as tidy core." (interactive) (save-buffer) (let* ((core-buffer (generate-new-buffer "ghc-core")) (neh (lambda () (kill-buffer core-buffer)))) (add-hook 'next-error-hook neh) (apply #'call-process ghc-core-program nil core-buffer nil "-ddump-simpl" "-c" (buffer-file-name) ghc-core-program-args) (display-buffer core-buffer) (with-current-buffer core-buffer (ghc-core-mode)) (remove-hook 'next-error-hook neh))) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.hcr\\'" . ghc-core-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.dump-simpl\\'" . ghc-core-mode)) ;;;###autoload (define-derived-mode ghc-core-mode haskell-mode "GHC-Core" "Major mode for GHC Core files.") (provide 'ghc-core) ;;; ghc-core.el ends here ����������������������������haskell-mode-17.1/ghci-script-mode.el���������������������������������������������������������������0000664�0000000�0000000�00000004763�13602233217�0017500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; ghci-script-mode.el --- GHCi scripts major mode -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'haskell) (defvar ghci-script-mode-keywords ;; The comment syntax can't be described simply in syntax-table. ;; We could use font-lock-syntactic-keywords, but is it worth it? '(("^[ \t]*--.*" . font-lock-comment-face) ("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face)) ("^:[a-z{]+ *\\+" . font-lock-keyword-face) ("^:[a-z{]+ " . font-lock-keyword-face))) ;;;###autoload (define-derived-mode ghci-script-mode text-mode "GHCi-Script" "Major mode for working with .ghci files." (setq-local adaptive-fill-mode nil) (setq-local comment-start "-- ") (setq-local comment-padding 0) (setq-local comment-start-skip "[-{]-[ \t]*") (setq-local comment-end "") (setq-local comment-end-skip "[ \t]*\\(-}\\|\\s>\\)") (setq-local font-lock-defaults '(ghci-script-mode-keywords t t nil nil)) (setq-local indent-tabs-mode nil) (setq-local tab-width 8) (when (boundp 'electric-indent-inhibit) (setq electric-indent-inhibit t)) (setq-local dabbrev-case-fold-search nil) (setq-local dabbrev-case-distinction nil) (setq-local dabbrev-case-replace nil) (setq-local dabbrev-abbrev-char-regexp "\\sw\\|[.]") (setq haskell-literate nil)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.ghci\\'" . ghci-script-mode)) (define-key ghci-script-mode-map (kbd "C-c C-l") 'ghci-script-mode-load) (defun ghci-script-mode-load () "Load the current script file into the GHCi session." (interactive) (let ((buffer (haskell-session-interactive-buffer (haskell-session))) (filename (buffer-file-name))) (save-buffer) (with-current-buffer buffer (set-marker haskell-interactive-mode-prompt-start (point-max)) (haskell-interactive-mode-run-expr (concat ":script " filename))))) (provide 'ghci-script-mode) �������������haskell-mode-17.1/haskell-align-imports.el����������������������������������������������������������0000664�0000000�0000000�00000020666�13602233217�0020550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-align-imports.el --- Align the import lines in a Haskell file -*- lexical-binding: t -*- ;; Copyright (C) 2010 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; 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 ;; <http://www.gnu.org/licenses/>. ;;; Commentary: ;; Consider the following imports list: ;; ;; import One ;; import Two as A ;; import qualified Three ;; import qualified Four as PRELUDE ;; import Five (A) ;; import Six (A,B) ;; import qualified Seven (A,B) ;; import "abc" Eight ;; import "abc" Nine as TWO ;; import qualified "abc" Ten ;; import qualified "defg" Eleven as PRELUDE ;; import "barmu" Twelve (A) ;; import "zotconpop" Thirteen (A,B) ;; import qualified "z" Fourteen (A,B) ;; import Fifteen hiding (A) ;; import Sixteen as TWO hiding (A) ;; import qualified Seventeen hiding (A) ;; import qualified Eighteen as PRELUDE hiding (A) ;; import "abc" Nineteen hiding (A) ;; import "abc" Twenty as TWO hiding (A) ;; ;; When haskell-align-imports is run within the same buffer, the ;; import list is transformed to: ;; ;; import "abc" Eight ;; import qualified Eighteen as PRELUDE hiding (A) ;; import qualified "defg" Eleven as PRELUDE ;; import Fifteen hiding (A) ;; import Five (A) ;; import qualified Four as PRELUDE ;; import qualified "z" Fourteen (A,B) ;; import "abc" Nine as TWO ;; import "abc" Nineteen hiding (A) ;; import One ;; import qualified Seven (A,B) ;; import qualified Seventeen hiding (A) ;; import Six (A,B) ;; import Sixteen as TWO hiding (A) ;; import qualified "abc" Ten ;; import "zotconpop" Thirteen (A,B) ;; import qualified Three ;; import "barmu" Twelve (A) ;; import "abc" Twenty as TWO hiding (A) ;; import Two as A ;; ;; If you want everything after module names to be padded out, too, ;; customize `haskell-align-imports-pad-after-name', and you'll get: ;; ;; import One ;; import Two as A ;; import qualified Three ;; import qualified Four as PRELUDE ;; import Five (A) ;; import Six (A,B) ;; import qualified Seven (A,B) ;; import "abc" Eight ;; import "abc" Nine as TWO ;; import qualified "abc" Ten ;; import qualified "defg" Eleven as PRELUDE ;; import "barmu" Twelve (A) ;; import "zotconpop" Thirteen (A,B) ;; import qualified "z" Fourteen (A,B) ;; import Fifteen hiding (A) ;; import Sixteen as TWO hiding (A) ;; import qualified Seventeen hiding (A) ;; import qualified Eighteen as PRELUDE hiding (A) ;; import "abc" Nineteen hiding (A) ;; import "abc" Twenty as TWO hiding (A) ;;; Code: (require 'cl-lib) (defvar haskell-align-imports-regexp (concat "^\\(import[ ]+\\)" "\\(qualified \\)?" "[ ]*\\(\"[^\"]*\" \\)?" "[ ]*\\([A-Za-z0-9_.']+\\)" "[ ]*\\([ ]*as [A-Z][^ ]*\\)?" "[ ]*\\((.*)\\)?" "\\([ ]*hiding (.*)\\)?" "\\( -- .*\\)?[ ]*$") "Regex used for matching components of an import.") (defcustom haskell-align-imports-pad-after-name nil "Pad layout after the module name also." :type 'boolean :group 'haskell-interactive) ;;;###autoload (defun haskell-align-imports () "Align all the imports in the buffer." (interactive) (when (haskell-align-imports-line-match) (save-excursion (goto-char (point-min)) (let* ((imports (haskell-align-imports-collect)) (padding (haskell-align-imports-padding imports))) (mapc (lambda (x) (goto-char (cdr x)) (delete-region (point) (line-end-position)) (insert (haskell-align-imports-chomp (haskell-align-imports-fill padding (car x))))) imports)))) nil) (defun haskell-align-imports-line-match () "Try to match the current line as a regexp." (let ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) (if (string-match "^import " line) line nil))) (defun haskell-align-imports-collect () "Collect a list of mark / import statement pairs." (let ((imports '())) (while (not (or (equal (point) (point-max)) (haskell-align-imports-after-imports-p))) (let ((line (haskell-align-imports-line-match-it))) (when line (let ((match (haskell-align-imports-merge-parts (cl-loop for i from 1 to 8 collect (haskell-align-imports-chomp (match-string i line)))))) (setq imports (cons (cons match (line-beginning-position)) imports))))) (forward-line)) imports)) (defun haskell-align-imports-merge-parts (l) "Merge together parts of an import statement that shouldn't be separated." (let ((parts (apply #'vector l)) (join (lambda (ls) (cl-reduce (lambda (a b) (concat a (if (and (> (length a) 0) (> (length b) 0)) " " "") b)) ls)))) (if haskell-align-imports-pad-after-name (list (funcall join (list (aref parts 0) (aref parts 1) (aref parts 2))) (aref parts 3) (funcall join (list (aref parts 4) (aref parts 5) (aref parts 6))) (aref parts 7)) (list (funcall join (list (aref parts 0) (aref parts 1) (aref parts 2))) (funcall join (list (aref parts 3) (aref parts 4) (aref parts 5) (aref parts 6) (aref parts 7))))))) (defun haskell-align-imports-chomp (str) "Chomp leading and tailing whitespace from STR." (if str (replace-regexp-in-string "\\(^[[:space:]\n]*\\|[[:space:]\n]*$\\)" "" str) "")) (defun haskell-align-imports-padding (imports) "Find the padding for each part of the import statements." (if (null imports) imports (cl-reduce (lambda (a b) (cl-mapcar #'max a b)) (mapcar (lambda (x) (mapcar #'length (car x))) imports)))) (defun haskell-align-imports-fill (padding line) "Fill an import line using the padding worked out from all statements." (mapconcat #'identity (cl-mapcar (lambda (pad part) (if (> (length part) 0) (concat part (make-string (- pad (length part)) ? )) (make-string pad ? ))) padding line) " ")) (defun haskell-align-imports-line-match-it () "Try to match the current line as a regexp." (let ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) (if (string-match haskell-align-imports-regexp line) line nil))) (defun haskell-align-imports-after-imports-p () "Are we after the imports list?" (save-excursion (goto-char (line-beginning-position)) (let ((case-fold-search nil)) (not (not (search-forward-regexp "\\( = \\|\\<instance\\>\\| :: \\| ∷ \\)" (line-end-position) t 1)))))) (provide 'haskell-align-imports) ;;; haskell-align-imports.el ends here ��������������������������������������������������������������������������haskell-mode-17.1/haskell-c2hs.el�������������������������������������������������������������������0000664�0000000�0000000�00000017235�13602233217�0016620�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;; haskell-c2hs.el --- -*- lexical-binding: t; -*- ;; Copyright (C) 2016 Sergey Vinokurov ;; ;; Author: Sergey Vinokurov <serg.foo@gmail.com> ;; Created: Monday, 7 March 2016 ;; 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; This mode is mostly intended for highlighting {#...#} hooks. ;; ;; Quick setup: ;; (autoload 'haskell-c2hs-mode "haskell-c2hs-mode" nil t) ;; (add-to-list 'auto-mode-alist '("\\.chs\\'" . haskell-c2hs-mode)) ;; (require 'haskell-mode) (require 'haskell-font-lock) (require 'haskell-utils) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.chs\\'" . haskell-c2hs-mode)) (defface haskell-c2hs-hook-pair-face '((t (:inherit 'font-lock-preprocessor-face))) "Face for highlighting {#...#} pairs." :group 'haskell) (defface haskell-c2hs-hook-name-face '((t (:inherit 'font-lock-keyword-face))) "Face for highlighting c2hs hook names." :group 'haskell) (defvar haskell-c2hs-font-lock-keywords `((,(eval-when-compile (let* ((ws '(any ?\s ?\t ?\n ?\r)) (anychar '(or (not (any ?#)) (seq "#" (not (any ?\}))))) (any-nonquote '(or (not (any ?# ?\")) (seq "#" (not (any ?\} ?\"))))) (cid '(seq (any (?a . ?z) (?A . ?Z) ?_) (* (any (?a . ?z) (?A . ?Z) (?0 . ?9) ?_)))) (hsid-type '(seq (? "'") (any (?A . ?Z)) (* (any (?a . ?z) (?A . ?Z) (?0 . ?9) ?_ ?')))) (equals-str-val `(seq (* ,ws) "=" (* ,ws) "\"" (* ,any-nonquote) "\""))) (eval `(rx (seq (group-n 1 "{#") (* ,ws) (or (seq (group-n 2 "import" (opt (+ ,ws) "qualified")) (+ ,ws)) (seq (group-n 2 "context") (opt (+ ,ws) (group-n 3 "lib") ,equals-str-val) (opt (+ ,ws) (group-n 4 "prefix") ,equals-str-val) (opt (+ ,ws) (group-n 5 "add" (+ ,ws) "prefix") ,equals-str-val)) (seq (group-n 2 "type") (+ ,ws) ,cid) (seq (group-n 2 "sizeof") (+ ,ws) ,cid) (seq (group-n 2 "enum" (+ ,ws) "define") (+ ,ws) ,cid) ;; TODO: vanilla enum fontification is incomplete (seq (group-n 2 "enum") (+ ,ws) ,cid (opt (+ ,ws) (group-n 3 "as"))) ;; TODO: fun hook highlighting is incompelete (seq (group-n 2 (or "call" "fun") (opt (+ ,ws) "pure") (opt (+ ,ws) "unsafe")) (+ ,ws) ,cid (opt (+ ,ws) (group-n 3 "as") (opt (+ ,ws) (group-n 8 "^")))) (group-n 2 "get") (group-n 2 "set") (seq (group-n 2 "pointer") (or (seq (* ,ws) (group-n 3 "*") (* ,ws)) (+ ,ws)) ,cid (opt (+ ,ws) (group-n 4 "as") (+ ,ws) ,hsid-type) (opt (+ ,ws) (group-n 5 (or "foreign" "stable"))) (opt (or (seq (+ ,ws) (group-n 6 "newtype")) (seq (* ,ws) "->" (* ,ws) ,hsid-type))) (opt (+ ,ws) (group-n 7 "nocode"))) (group-n 2 "class") (group-n 2 "alignof") (group-n 2 "offsetof") (seq (group-n 2 "const") (+ ,ws) ,cid) (seq (group-n 2 "typedef") (+ ,ws) ,cid (+ ,ws) ,hsid-type) (group-n 2 "nonGNU") ;; TODO: default hook not implemented ) (* ,anychar) (group-n 9 "#}")))))) ;; Override highlighting for pairs in order to always distinguish them. (1 'haskell-c2hs-hook-pair-face t) (2 'haskell-c2hs-hook-name-face) ;; Make matches lax, i.e. do not signal error if nothing ;; matched. (3 'haskell-c2hs-hook-name-face nil t) (4 'haskell-c2hs-hook-name-face nil t) (5 'haskell-c2hs-hook-name-face nil t) (6 'haskell-c2hs-hook-name-face nil t) (7 'haskell-c2hs-hook-name-face nil t) (8 'font-lock-negation-char-face nil t) ;; Override highlighting for pairs in order to always distinguish them. (9 'haskell-c2hs-hook-pair-face t)) ,@(haskell-font-lock-keywords))) ;;;###autoload (define-derived-mode haskell-c2hs-mode haskell-mode "C2HS" "Mode for editing *.chs files of the c2hs haskell tool." (setq-local font-lock-defaults (cons 'haskell-c2hs-font-lock-keywords (cdr font-lock-defaults)))) (provide 'haskell-c2hs) ;; haskell-c2hs.el ends here �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-cabal.el������������������������������������������������������������������0000664�0000000�0000000�00000131343�13602233217�0017020�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-cabal.el --- Support for Cabal packages -*- lexical-binding: t -*- ;; Copyright © 2007, 2008 Stefan Monnier ;; 2016 Arthur Fayzrakhmanov ;; Author: Stefan Monnier <monnier@iro.umontreal.ca> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; Todo: ;; - distinguish continued lines from indented lines. ;; - indent-line-function. ;; - outline-minor-mode. ;;; Code: ;; (defun haskell-cabal-extract-fields-from-doc () ;; (require 'xml) ;; (let ((section (completing-read ;; "Section: " ;; '("general-fields" "library" "executable" "buildinfo")))) ;; (goto-char (point-min)) ;; (search-forward (concat "<sect3 id=\"" section "\">"))) ;; (let* ((xml (xml-parse-region ;; (progn (search-forward "<variablelist>") (match-beginning 0)) ;; (progn (search-forward "</variablelist>") (point)))) ;; (varlist (cl-remove-if-not 'consp (cl-cddar xml))) ;; (syms (mapcar (lambda (entry) (cl-caddr (assq 'literal (assq 'term entry)))) ;; varlist)) ;; (fields (mapcar (lambda (sym) (substring-no-properties sym 0 -1)) syms))) ;; fields)) (require 'cl-lib) (require 'haskell-utils) (defcustom haskell-hasktags-path "hasktags" "Path to `hasktags' executable." :group 'haskell :type 'string) (defcustom haskell-hasktags-arguments '("-e" "-x") "Additional arguments for `hasktags' executable. By default these are: -e - generate ETAGS file -x - generate additional information in CTAGS file." :group 'haskell :type '(list string)) (defconst haskell-cabal-general-fields ;; Extracted with (haskell-cabal-extract-fields-from-doc "general-fields") '("name" "version" "cabal-version" "license" "license-file" "copyright" "author" "maintainer" "stability" "homepage" "package-url" "synopsis" "description" "category" "tested-with" "build-depends" "data-files" "extra-source-files" "extra-tmp-files" "import")) (defconst haskell-cabal-library-fields ;; Extracted with (haskell-cabal-extract-fields-from-doc "library") '("exposed-modules")) (defconst haskell-cabal-executable-fields ;; Extracted with (haskell-cabal-extract-fields-from-doc "executable") '("executable" "main-is")) (defconst haskell-cabal-buildinfo-fields ;; Extracted with (haskell-cabal-extract-fields-from-doc "buildinfo") '("buildable" "other-modules" "hs-source-dirs" "extensions" "ghc-options" "ghc-prof-options" "hugs-options" "nhc-options" "includes" "install-includes" "include-dirs" "c-sources" "extra-libraries" "extra-lib-dirs" "cc-options" "ld-options" "frameworks")) (defvar haskell-cabal-mode-syntax-table (let ((st (make-syntax-table))) ;; The comment syntax can't be described simply in syntax-table. ;; We could use font-lock-syntactic-keywords, but is it worth it? ;; (modify-syntax-entry ?- ". 12" st) (modify-syntax-entry ?\n ">" st) (modify-syntax-entry ?- "w" st) st)) (defvar haskell-cabal-font-lock-keywords ;; The comment syntax can't be described simply in syntax-table. ;; We could use font-lock-syntactic-keywords, but is it worth it? '(("^[ \t]*--.*" . font-lock-comment-face) ("^ *\\([^ \t:]+\\):" (1 font-lock-keyword-face)) ("^\\(Library\\)[ \t]*\\({\\|$\\)" (1 font-lock-keyword-face)) ("^\\(Executable\\|Test-Suite\\|Benchmark\\|Common\\|package\\)[ \t]+\\([^\n \t]*\\)" (1 font-lock-keyword-face) (2 font-lock-function-name-face)) ("^\\(Flag\\|install-dirs\\|repository\\)[ \t]+\\([^\n \t]*\\)" (1 font-lock-keyword-face) (2 font-lock-constant-face)) ("^\\(Source-Repository\\)[ \t]+\\(head\\|this\\)" (1 font-lock-keyword-face) (2 font-lock-constant-face)) ("^\\(haddock\\|source-repository-package\\|program-locations\\|program-default-options\\)\\([ \t]\\|$\\)" (1 font-lock-keyword-face)) ("^ *\\(if\\)[ \t]+.*\\({\\|$\\)" (1 font-lock-keyword-face)) ("^ *\\(}[ \t]*\\)?\\(else\\)[ \t]*\\({\\|$\\)" (2 font-lock-keyword-face)) ("\\<\\(?:True\\|False\\)\\>" (0 font-lock-constant-face)))) (defvar haskell-cabal-buffers nil "List of Cabal buffers.") (defun haskell-cabal-buffers-clean (&optional buffer) "Refresh list of known cabal buffers. Check each buffer in variable `haskell-cabal-buffers' and remove it from list if one of the following conditions are hold: + buffer is killed; + buffer's mode is not derived from `haskell-cabal-mode'; + buffer is a BUFFER (if given)." (let ((bufs ())) (dolist (buf haskell-cabal-buffers) (if (and (buffer-live-p buf) (not (eq buf buffer)) (with-current-buffer buf (derived-mode-p 'haskell-cabal-mode))) (push buf bufs))) (setq haskell-cabal-buffers bufs))) (defun haskell-cabal-unregister-buffer () "Exclude current buffer from global list of known cabal buffers." (haskell-cabal-buffers-clean (current-buffer))) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.cabal\\'\\|/cabal\\.project\\|/\\.cabal/config\\'" . haskell-cabal-mode)) (defvar haskell-cabal-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-s") 'haskell-cabal-subsection-arrange-lines) (define-key map (kbd "C-M-n") 'haskell-cabal-next-section) (define-key map (kbd "C-M-p") 'haskell-cabal-previous-section) (define-key map (kbd "M-n") 'haskell-cabal-next-subsection) (define-key map (kbd "M-p") 'haskell-cabal-previous-subsection) (define-key map (kbd "C-<down>") 'haskell-cabal-next-subsection) (define-key map (kbd "C-<up>") 'haskell-cabal-previous-subsection) (define-key map (kbd "C-c C-f") 'haskell-cabal-find-or-create-source-file) (define-key map (kbd "M-g l") 'haskell-cabal-goto-library-section) (define-key map (kbd "M-g e") 'haskell-cabal-goto-executable-section) (define-key map (kbd "M-g b") 'haskell-cabal-goto-benchmark-section) (define-key map (kbd "M-g o") 'haskell-cabal-goto-common-section) (define-key map (kbd "M-g t") 'haskell-cabal-goto-test-suite-section) map)) ;;;###autoload (define-derived-mode haskell-cabal-mode fundamental-mode "Haskell-Cabal" "Major mode for Cabal package description files." (setq-local font-lock-defaults '(haskell-cabal-font-lock-keywords t t nil nil)) (add-to-list 'haskell-cabal-buffers (current-buffer)) (add-hook 'change-major-mode-hook 'haskell-cabal-unregister-buffer nil 'local) (add-hook 'kill-buffer-hook 'haskell-cabal-unregister-buffer nil 'local) (setq-local comment-start "-- ") (setq-local comment-start-skip "\\(^[ \t]*\\)--[ \t]*") (setq-local comment-end "") (setq-local comment-end-skip "[ \t]*\\(\\s>\\|\n\\)") (setq-local indent-line-function 'haskell-cabal-indent-line) (setq indent-tabs-mode nil) ) (make-obsolete 'haskell-cabal-get-setting 'haskell-cabal--get-field "March 14, 2016") (defalias 'haskell-cabal-get-setting 'haskell-cabal--get-field "Try to read value of field with NAME from current buffer. Obsolete function. Defined for backward compatibility. Use `haskell-cabal--get-field' instead.") (defun haskell-cabal--get-field (name) "Try to read value of field with NAME from current buffer." (save-excursion (let ((case-fold-search t)) (goto-char (point-min)) (when (re-search-forward (concat "^[ \t]*" (regexp-quote name) ":[ \t]*\\(.*\\(\n[ \t]+[ \t\n].*\\)*\\)") nil t) (let ((val (match-string 1)) (start 1)) (when (match-end 2) ;Multiple lines. ;; The documentation is not very precise about what to do about ;; the \n and the indentation: are they part of the value or ;; the encoding? I take the point of view that \n is part of ;; the value (so that values can span multiple lines as well), ;; and that only the first char in the indentation is part of ;; the encoding, the rest is part of the value (otherwise, lines ;; in the value cannot start with spaces or tabs). (while (string-match "^[ \t]\\(?:\\.$\\)?" val start) (setq start (1+ (match-beginning 0))) (setq val (replace-match "" t t val)))) val))))) (make-obsolete 'haskell-cabal-guess-setting 'haskell-cabal-get-field "March 14, 2016") (defalias 'haskell-cabal-guess-setting 'haskell-cabal-get-field "Read the value of field with NAME from project's cabal file. Obsolete function. Defined for backward compatibility. Use `haskell-cabal-get-field' instead.") ;;;###autoload (defun haskell-cabal-get-field (name) "Read the value of field with NAME from project's cabal file. If there is no valid .cabal file to get the setting from (or there is no corresponding setting with that name in the .cabal file), then this function returns nil." (interactive) (when (and name buffer-file-name) (let ((cabal-file (haskell-cabal-find-file))) (when (and cabal-file (file-readable-p cabal-file)) (with-temp-buffer (insert-file-contents cabal-file) (haskell-cabal--get-field name)))))) ;;;###autoload (defun haskell-cabal-get-dir (&optional use-defaults) "Get the Cabal dir for a new project. Various ways of figuring this out, and indeed just prompting the user. Do them all." (let* ((file (haskell-cabal-find-file)) (dir (if file (file-name-directory file) default-directory))) (if use-defaults dir (haskell-utils-read-directory-name (format "Cabal dir%s: " (if file (format " (guessed from %s)" (file-relative-name file)) "")) dir)))) (defun haskell-cabal-compute-checksum (dir) "Compute MD5 checksum of package description file in DIR. Return nil if no Cabal description file could be located via `haskell-cabal-find-pkg-desc'." (let ((cabal-file (haskell-cabal-find-pkg-desc dir))) (when cabal-file (with-temp-buffer (insert-file-contents cabal-file) (md5 (buffer-string)))))) (defun haskell-cabal-find-file (&optional dir) "Search for package description file upwards starting from DIR. If DIR is nil, `default-directory' is used as starting point for directory traversal. Upward traversal is aborted if file owner changes. Uses `haskell-cabal-find-pkg-desc' internally." (let ((use-dir (or dir default-directory))) (while (and use-dir (not (file-directory-p use-dir))) (setq use-dir (file-name-directory (directory-file-name use-dir)))) (when use-dir (catch 'found (let ((user (nth 2 (file-attributes use-dir))) ;; Abbreviate, so as to stop when we cross ~/. (root (abbreviate-file-name use-dir))) ;; traverse current dir up to root as long as file owner doesn't change (while (and root (equal user (nth 2 (file-attributes root)))) (let ((cabal-file (haskell-cabal-find-pkg-desc root))) (when cabal-file (throw 'found cabal-file))) (let ((proot (file-name-directory (directory-file-name root)))) (if (equal proot root) ;; fix-point reached? (throw 'found nil) (setq root proot)))) nil))))) (defun haskell-cabal-find-pkg-desc (dir &optional allow-multiple) "Find a package description file in the directory DIR. Returns nil if none or multiple \".cabal\" files were found. If ALLOW-MULTIPLE is non nil, in case of multiple \".cabal\" files, a list is returned instead of failing with a nil result." ;; This is basically a port of Cabal's ;; Distribution.Simple.Utils.findPackageDesc function ;; http://hackage.haskell.org/packages/archive/Cabal/1.16.0.3/doc/html/Distribution-Simple-Utils.html ;; but without the exception throwing. (let* ((cabal-files (cl-remove-if 'file-directory-p (cl-remove-if-not 'file-exists-p (directory-files dir t ".\\.cabal\\'"))))) (cond ((= (length cabal-files) 1) (car cabal-files)) ;; exactly one candidate found (allow-multiple cabal-files) ;; pass-thru multiple candidates (t nil)))) (defun haskell-cabal-find-dir (&optional dir) "Like `haskell-cabal-find-file' but returns directory instead. See `haskell-cabal-find-file' for meaning of DIR argument." (let ((cabal-file (haskell-cabal-find-file dir))) (when cabal-file (file-name-directory cabal-file)))) ;;;###autoload (defun haskell-cabal-visit-file (other-window) "Locate and visit package description file for file visited by current buffer. This uses `haskell-cabal-find-file' to locate the closest \".cabal\" file and open it. This command assumes a common Cabal project structure where the \".cabal\" file is in the top-folder of the project, and all files related to the project are in or below the top-folder. If called with non-nil prefix argument OTHER-WINDOW use `find-file-other-window'." (interactive "P") ;; Note: We aren't allowed to rely on haskell-session here (which, ;; in pathological cases, can have a different .cabal file ;; associated with the current buffer) (if buffer-file-name (let ((cabal-file (haskell-cabal-find-file (file-name-directory buffer-file-name)))) (if cabal-file (if other-window (find-file-other-window cabal-file) (find-file cabal-file)) (error "Could not locate \".cabal\" file for %S" buffer-file-name))) (error "Cannot locate \".cabal\" file for buffers not visiting any file"))) (defvar haskell-cabal-commands '("install" "update" "list" "info" "upgrade" "fetch" "unpack" "check" "sdist" "upload" "report" "init" "configure" "build" "copy" "haddock" "clean" "hscolour" "register" "test" "help" "run")) ;;;###autoload (defgroup haskell-cabal nil "Haskell cabal files" :group 'haskell ) (defconst haskell-cabal-section-header-regexp "^[[:alnum:]]" ) (defconst haskell-cabal-subsection-header-regexp "^[ \t]*[[:alnum:]]\\w*:") (defconst haskell-cabal-comment-regexp "^[ \t]*--") (defconst haskell-cabal-empty-regexp "^[ \t]*$") (defconst haskell-cabal-conditional-regexp "^[ \t]*\\(\\if\\|else\\|}\\)") (defun haskell-cabal-classify-line () "Classify the current line into 'section-header 'subsection-header 'section-data 'comment and 'empty '" (save-excursion (beginning-of-line) (cond ((looking-at haskell-cabal-subsection-header-regexp ) 'subsection-header) ((looking-at haskell-cabal-section-header-regexp) 'section-header) ((looking-at haskell-cabal-comment-regexp) 'comment) ((looking-at haskell-cabal-empty-regexp ) 'empty) ((looking-at haskell-cabal-conditional-regexp ) 'conditional) (t 'section-data)))) (defun haskell-cabal-header-p () "Is the current line a section or subsection header?" (cl-case (haskell-cabal-classify-line) ((section-header subsection-header) t))) (defun haskell-cabal-section-header-p () "Is the current line a section or subsection header?" (cl-case (haskell-cabal-classify-line) ((section-header) t))) (defun haskell-cabal-section-beginning () "Find the beginning of the current section" (save-excursion (while (not (or (bobp) (haskell-cabal-section-header-p))) (forward-line -1)) (point))) (defun haskell-cabal-beginning-of-section () "go to the beginning of the section" (interactive) (goto-char (haskell-cabal-section-beginning)) ) (defun haskell-cabal-section-end () "Find the end of the current section" (interactive) (save-excursion (if (re-search-forward "\n\\([ \t]*\n\\)*[[:alnum:]]" nil t) (match-beginning 0) (point-max)))) (defun haskell-cabal-end-of-section () "go to the end of the section" (interactive) (goto-char (haskell-cabal-section-end))) (defun haskell-cabal-next-section () "Go to the next section" (interactive) (when (haskell-cabal-section-header-p) (forward-line)) (while (not (or (eobp) (haskell-cabal-section-header-p))) (forward-line))) (defun haskell-cabal-previous-section () "Go to the next section" (interactive) (when (haskell-cabal-section-header-p) (forward-line -1)) (while (not (or (bobp) (haskell-cabal-section-header-p))) (forward-line -1))) (defun haskell-cabal-subsection-end () "find the end of the current subsection" (save-excursion (haskell-cabal-beginning-of-subsection) (forward-line) (while (and (not (eobp)) (member (haskell-cabal-classify-line) '(empty section-data))) (forward-line)) (unless (eobp) (forward-line -1)) (while (and (equal (haskell-cabal-classify-line) 'empty) (not (bobp))) (forward-line -1)) (end-of-line) (point))) (defun haskell-cabal-end-of-subsection () "go to the end of the current subsection" (interactive) (goto-char (haskell-cabal-subsection-end))) (defun haskell-cabal-section () "Get the name and data of the associated section" (save-excursion (haskell-cabal-beginning-of-section) (when (and (haskell-cabal-section-header-p) (looking-at "^\\(\\w+\\)[ \t]*\\(.*\\)$")) (list :name (match-string-no-properties 1) :value (match-string-no-properties 2) :beginning (match-beginning 0) :end (haskell-cabal-section-end))))) (defun haskell-cabal-subsection () "Get the name and bounds of of the current subsection" (save-excursion (haskell-cabal-beginning-of-subsection) (when (looking-at "\\([ \t]*\\(\\w*\\):\\)[ \t]*") (list :name (match-string-no-properties 2) :beginning (match-end 0) :end (save-match-data (haskell-cabal-subsection-end)) :data-start-column (save-excursion (goto-char (match-end 0)) (current-column)) :data-indent-column (save-excursion (goto-char (match-end 0)) (when (looking-at "\n +\\(\\w*\\)") (goto-char (match-beginning 1))) (current-column) ))))) (defun haskell-cabal-section-name (section) (plist-get section :name)) (defun haskell-cabal-section-value (section) (plist-get section :value)) (defun haskell-cabal-section-start (section) (plist-get section :beginning)) (defun haskell-cabal-section-data-start-column (section) (plist-get section :data-start-column)) (defun haskell-cabal-section-data-indent-column (section) (plist-get section :data-indent-column)) (defun haskell-cabal-map-component-type (component-type) "Map from cabal file COMPONENT-TYPE to build command component-type." (let ((component-type (downcase component-type))) (cond ((equal component-type "executable") "exe") ((equal component-type "test-suite") "test") ((equal component-type "benchmark") "bench")))) (defun haskell-cabal-enum-targets (&optional process-type) "Enumerate .cabal targets. PROCESS-TYPE determines the format of the returned target." (let ((cabal-file (haskell-cabal-find-file)) (process-type (if process-type process-type 'ghci))) (when (and cabal-file (file-readable-p cabal-file)) (with-temp-buffer (insert-file-contents cabal-file) (haskell-cabal-mode) (goto-char (point-min)) (let ((matches) (package-name (haskell-cabal--get-field "name"))) (haskell-cabal-next-section) (while (not (eobp)) (if (haskell-cabal-source-section-p (haskell-cabal-section)) (let* ((section (haskell-cabal-section)) (component-type (haskell-cabal-section-name section)) (val (car (split-string (haskell-cabal-section-value section))))) (if (equal (downcase component-type) "library") (let ((lib-target (if (eq 'stack-ghci process-type) (concat package-name ":lib") (concat "lib:" package-name)))) (push lib-target matches)) (push (concat (when (eq 'stack-ghci process-type) (concat package-name ":")) (haskell-cabal-map-component-type component-type) ":" val) matches)))) (haskell-cabal-next-section)) (reverse matches)))))) (defmacro haskell-cabal-with-subsection (subsection replace &rest funs) "Copy subsection data into a temporary buffer, save indentation and execute FORMS If REPLACE is non-nil the subsection data is replaced with the resulting buffer-content" (let ((section (make-symbol "section")) (beg (make-symbol "beg")) (end (make-symbol "end")) (start-col (make-symbol "start-col")) (section-data (make-symbol "section-data"))) `(let* ((,section ,subsection) (,beg (plist-get ,section :beginning)) (,end (plist-get ,section :end)) (,start-col (plist-get ,section :data-start-column)) (,section-data (buffer-substring ,beg ,end))) (save-excursion (prog1 (with-temp-buffer (setq indent-tabs-mode nil) (indent-to ,start-col) (insert ,section-data) (goto-char (point-min)) (prog1 (progn (haskell-cabal-save-indentation ,@funs)) (goto-char (point-min)) (when (looking-at (format "[ ]\\{0,%d\\}" (1+ ,start-col))) (replace-match "")) (setq ,section-data (buffer-substring (point-min) (point-max))))) ,@(when replace `((delete-region ,beg ,end) (goto-char ,beg) (insert ,section-data)))))))) (defmacro haskell-cabal-each-line (&rest fun) "Execute FORMS on each line" `(save-excursion (while (< (point) (point-max)) ,@fun (forward-line)))) (defun haskell-cabal-chomp-line () "Remove leading and trailing whitespaces from current line" (beginning-of-line) (when (looking-at "^[ \t]*\\([^ \t]\\|\\(?:[^ \t].*[^ \t]\\)\\)[ \t]*$") (replace-match (match-string 1) nil t) t)) (defun haskell-cabal-min-indentation (&optional beg end) "Compute largest common whitespace prefix of each line in between BEG and END" (save-excursion (goto-char (or beg (point-min))) (let ((min-indent nil)) (while (< (point) (or end (point-max))) (let ((indent (current-indentation))) (if (and (not (haskell-cabal-ignore-line-p)) (or (not min-indent) (< indent min-indent))) (setq min-indent indent))) (forward-line)) min-indent))) (defun haskell-cabal-ignore-line-p () "Does line only contain whitespaces and comments?" (save-excursion (beginning-of-line) (looking-at "^[ \t]*\\(?:--.*\\)?$"))) (defun haskell-cabal-kill-indentation () "Remove longest common whitespace prefix from each line" (goto-char (point-min)) (let ((indent (haskell-cabal-min-indentation))) (haskell-cabal-each-line (unless (haskell-cabal-ignore-line-p) (delete-char indent)) ) indent)) (defun haskell-cabal-add-indentation (indent) (goto-char (point-min)) (haskell-cabal-each-line (unless (haskell-cabal-ignore-line-p) (indent-to indent)))) (defmacro haskell-cabal-save-indentation (&rest funs) "Strip indentation from each line, execute FORMS and reinstate indentation so that the indentation of the FIRST LINE matches" (let ((old-l1-indent (make-symbol "new-l1-indent")) (new-l1-indent (make-symbol "old-l1-indent"))) `(let ( (,old-l1-indent (save-excursion (goto-char (point-min)) (current-indentation)))) (unwind-protect (progn (haskell-cabal-kill-indentation) ,@funs) (progn (goto-char (point-min)) (let ((,new-l1-indent (current-indentation))) (haskell-cabal-add-indentation (- ,old-l1-indent ,new-l1-indent)))))))) (defun haskell-cabal-comma-separatorp (pos) "Return non-nil when the char at POS is a comma separator. Characters that are not a comma, or commas inside a commment or string, are not comma separators." (when (eq (char-after pos) ?,) (let ((ss (syntax-ppss pos))) (not (or ;; inside a string (nth 3 ss) ;; inside a comment (nth 4 ss)))))) (defun haskell-cabal-strip-list-and-detect-style () "Strip commas from a comma-separated list. Detect and return the comma style. The possible options are: before: a comma at the start of each line (except the first), e.g. Foo , Bar after: a comma at the end of each line (except the last), e.g. Foo, Bar single: everything on a single line, but comma-separated, e.g. Foo, Bar nil: no commas, e.g. Foo Bar If the styles are mixed, the position of the first comma determines the style. If there is only one element then `after' style is assumed." (let (comma-style) ;; split list items on single line (goto-char (point-min)) (while (re-search-forward "\\([^ \t,\n]\\)[ \t]*\\(,\\)[ \t]*\\([^ \t,\n]\\)" nil t) (when (haskell-cabal-comma-separatorp (match-beginning 2)) (setq comma-style 'single) (replace-match "\\1\n\\3" nil nil))) ;; remove commas before (goto-char (point-min)) (while (re-search-forward "^\\([ \t]*\\),\\([ \t]*\\)" nil t) (setq comma-style 'before) (replace-match "" nil nil)) ;; remove trailing commas (goto-char (point-min)) (while (re-search-forward ",[ \t]*$" nil t) (unless (eq comma-style 'before) (setq comma-style 'after)) (replace-match "" nil nil)) ;; if there is just one line then set default as 'after (unless comma-style (goto-char (point-min)) (forward-line) (when (eobp) (setq comma-style 'after))) (goto-char (point-min)) (haskell-cabal-each-line (haskell-cabal-chomp-line)) comma-style)) (defun haskell-cabal-listify (comma-style) "Add commas so that the buffer contains a comma-separated list. Respect the COMMA-STYLE, see `haskell-cabal-strip-list-and-detect-style' for the possible styles." (cl-case comma-style ('before (goto-char (point-min)) (while (haskell-cabal-ignore-line-p) (forward-line)) (indent-to 2) (forward-line) (haskell-cabal-each-line (unless (haskell-cabal-ignore-line-p) (insert ", ")))) ('after (goto-char (point-max)) (while (equal 0 (forward-line -1)) (unless (haskell-cabal-ignore-line-p) (end-of-line) (insert ",") (beginning-of-line)))) ('single (goto-char (point-min)) (while (not (eobp)) (end-of-line) (unless (eobp) (insert ", ") (delete-char 1) (just-one-space)))))) (defmacro haskell-cabal-with-cs-list (&rest funs) "Format the buffer so that each line contains a list element. Respect the comma style." (let ((comma-style (make-symbol "comma-style"))) `(let ((,comma-style (save-excursion (haskell-cabal-strip-list-and-detect-style)))) (unwind-protect (progn ,@funs) (haskell-cabal-listify ,comma-style))))) (defun haskell-cabal-sort-lines-key-fun () (when (looking-at "[ \t]*--[ \t,]*") (goto-char (match-end 0))) nil) (defmacro haskell-cabal-save-position (&rest forms) "Save position as mark, execute FORMs and go back to mark" `(prog2 (haskell-cabal-mark) (progn ,@forms) (haskell-cabal-goto-mark) (haskell-cabal-remove-mark))) (defun haskell-cabal-sort-lines-depends-compare (key1 key2) (let* ((key1str (buffer-substring (car key1) (cdr key1))) (key2str (buffer-substring (car key2) (cdr key2))) (base-regex "^[ \t]*base\\($\\|[^[:alnum:]-]\\)")) (cond ((string-match base-regex key1str) t) ((string-match base-regex key2str) nil) (t (string< key1str key2str))))) (defun haskell-cabal-subsection-arrange-lines () "Sort lines of current subsection" (interactive) (haskell-cabal-save-position (let* ((subsection (haskell-cabal-section-name (haskell-cabal-subsection))) (compare-lines (if (string= (downcase subsection) "build-depends") 'haskell-cabal-sort-lines-depends-compare nil))) (haskell-cabal-with-subsection (haskell-cabal-subsection) t (haskell-cabal-with-cs-list (sort-subr nil 'forward-line 'end-of-line 'haskell-cabal-sort-lines-key-fun 'end-of-line compare-lines )))))) (defun haskell-cabal-subsection-beginning () "find the beginning of the current subsection" (save-excursion (while (and (not (bobp)) (not (haskell-cabal-header-p))) (forward-line -1)) (back-to-indentation) (point))) (defun haskell-cabal-beginning-of-subsection () "go to the beginning of the current subsection" (interactive) (goto-char (haskell-cabal-subsection-beginning))) (defun haskell-cabal-next-subsection () "go to the next subsection" (interactive) (if (haskell-cabal-header-p) (forward-line)) (while (and (not (eobp)) (not (haskell-cabal-header-p))) (forward-line)) (haskell-cabal-forward-to-line-entry)) (defun haskell-cabal-previous-subsection () "go to the previous subsection" (interactive) (if (haskell-cabal-header-p) (forward-line -1)) (while (and (not (bobp)) (not (haskell-cabal-header-p))) (forward-line -1)) (haskell-cabal-forward-to-line-entry) ) (defun haskell-cabal-find-subsection-by (section pred) "Find subsection with name NAME" (save-excursion (when section (goto-char (haskell-cabal-section-start section))) (let* ((end (if section (haskell-cabal-section-end) (point-max))) (found nil)) (while (and (< (point) end) (not found)) (let ((subsection (haskell-cabal-subsection))) (when (and subsection (funcall pred subsection)) (setq found subsection))) (haskell-cabal-next-subsection)) found))) (defun haskell-cabal-find-subsection (section name) "Find subsection with name NAME" (let ((downcase-name (downcase name))) (haskell-cabal-find-subsection-by section `(lambda (subsection) (string= (downcase (haskell-cabal-section-name subsection)) ,downcase-name))))) (defun haskell-cabal-goto-subsection (name) (let ((subsection (haskell-cabal-find-subsection (haskell-cabal-section) name))) (when subsection (goto-char (haskell-cabal-section-start subsection))))) (defun haskell-cabal-goto-exposed-modules () (interactive) (haskell-cabal-goto-subsection "exposed-modules")) (defun haskell-cabal-subsection-entry-list (section name) "Get the data of a subsection as a list" (let ((subsection (haskell-cabal-find-subsection section name))) (when subsection (haskell-cabal-with-subsection subsection nil (haskell-cabal-with-cs-list (delete-matching-lines (format "\\(?:%s\\)\\|\\(?:%s\\)" haskell-cabal-comment-regexp haskell-cabal-empty-regexp) (point-min) (point-max)) (split-string (buffer-substring-no-properties (point-min) (point-max)) "\n" t)))))) (defun haskell-cabal-remove-mark () (remove-list-of-text-properties (point-min) (point-max) '(haskell-cabal-marker))) (defun haskell-cabal-mark () "Mark the current position with the text property haskell-cabal-marker" (haskell-cabal-remove-mark) (put-text-property (line-beginning-position) (line-end-position) 'haskell-cabal-marker 'marked-line) (put-text-property (point) (1+ (point)) 'haskell-cabal-marker 'marked)) (defun haskell-cabal-goto-mark () "Go to marked line" (let ((marked-pos (text-property-any (point-min) (point-max) 'haskell-cabal-marker 'marked)) (marked-line (text-property-any (point-min) (point-max) 'haskell-cabal-marker 'marked-line) ) ) (cond (marked-pos (goto-char marked-pos)) (marked-line (goto-char marked-line))))) (defmacro haskell-cabal-with-subsection-line (replace &rest forms) "Mark line, copy subsection data into a temporary buffer, save indentation and execute FORMS at the marked line. If REPLACE is non-nil the subsection data is replaced with the resulting buffer-content. Unmark line at the end." `(progn (haskell-cabal-mark) (unwind-protect (haskell-cabal-with-subsection (haskell-cabal-subsection) ,replace (haskell-cabal-goto-mark) ,@forms) (haskell-cabal-remove-mark)))) (defun haskell-cabal-get-line-content () (haskell-cabal-with-subsection-line nil (haskell-cabal-with-cs-list (haskell-cabal-goto-mark) (buffer-substring-no-properties (line-beginning-position) (line-end-position))))) (defun haskell-cabal-module-to-filename (module) (concat (replace-regexp-in-string "[.]" "/" module ) ".hs")) (defconst haskell-cabal-module-sections '("exposed-modules" "other-modules") "List of sections that contain module names" ) (defconst haskell-cabal-file-sections '("main-is" "c-sources" "data-files" "extra-source-files" "extra-doc-files" "extra-tmp-files" ) "List of subsections that contain filenames" ) (defconst haskell-cabal-source-bearing-sections '("library" "executable" "test-suite" "benchmark")) (defun haskell-cabal-source-section-p (section) (not (not (member (downcase (haskell-cabal-section-name section)) haskell-cabal-source-bearing-sections)))) (defun haskell-cabal-line-filename () "Expand filename in current line according to the subsection type Module names in exposed-modules and other-modules are expanded by replacing each dot (.) in the module name with a forward slash (/) and appending \".hs\" Example: Foo.Bar.Quux ==> Foo/Bar/Quux.hs Source names from main-is and c-sources sections are left untouched " (let ((entry (haskell-cabal-get-line-content)) (subsection (downcase (haskell-cabal-section-name (haskell-cabal-subsection))))) (cond ((member subsection haskell-cabal-module-sections) (haskell-cabal-module-to-filename entry)) ((member subsection haskell-cabal-file-sections) entry)))) (defun haskell-cabal-join-paths (&rest args) "Crude hack to replace f-join" (mapconcat 'identity args "/") ) (defun haskell-cabal-find-or-create-source-file () "Open the source file this line refers to." (interactive) (let* ((src-dirs (append (haskell-cabal-subsection-entry-list (haskell-cabal-section) "hs-source-dirs") '(""))) (base-dir (file-name-directory (buffer-file-name))) (filename (haskell-cabal-line-filename))) (when filename (let ((candidates (delq nil (mapcar (lambda (dir) (let ((file (haskell-cabal-join-paths base-dir dir filename))) (when (and (file-readable-p file) (not (file-directory-p file))) file))) src-dirs)))) (if (null candidates) (unwind-protect (progn (haskell-mode-toggle-interactive-prompt-state) (let* ((src-dir (haskell-cabal-join-paths base-dir (or (car src-dirs) ""))) (newfile (haskell-cabal-join-paths src-dir filename)) (do-create-p (y-or-n-p (format "Create file %s ?" newfile)))) (when do-create-p (find-file-other-window newfile )))) (haskell-mode-toggle-interactive-prompt-state t)) (find-file-other-window (car candidates))))))) (defun haskell-cabal-find-section-type (type &optional wrap) (save-excursion (haskell-cabal-next-section) (while (not (or (eobp) (string= (downcase type) (downcase (haskell-cabal-section-name (haskell-cabal-section)))))) (haskell-cabal-next-section)) (if (eobp) (if wrap (progn (goto-char (point-min)) (haskell-cabal-find-section-type type nil) ) nil) (point)))) (defun haskell-cabal-goto-section-type (type) (let ((section (haskell-cabal-find-section-type type t))) (if section (goto-char section) (message "No %s section found" type)))) (defun haskell-cabal-goto-library-section () (interactive) (haskell-cabal-goto-section-type "library")) (defun haskell-cabal-goto-test-suite-section () (interactive) (haskell-cabal-goto-section-type "test-suite")) (defun haskell-cabal-goto-executable-section () (interactive) (haskell-cabal-goto-section-type "executable")) (defun haskell-cabal-goto-benchmark-section () (interactive) (haskell-cabal-goto-section-type "benchmark")) (defun haskell-cabal-goto-common-section () (interactive) (haskell-cabal-goto-section-type "common")) (defun haskell-cabal-line-entry-column () "Column at which the line entry starts" (save-excursion (cl-case (haskell-cabal-classify-line) (section-data (beginning-of-line) (when (looking-at "[ ]*\\(?:,[ ]*\\)?") (goto-char (match-end 0)) (current-column))) (subsection-header (haskell-cabal-section-data-start-column (haskell-cabal-subsection)))))) (defun haskell-cabal-forward-to-line-entry () "go forward to the beginning of the line entry (but never move backwards)" (let ((col (haskell-cabal-line-entry-column))) (when (and col (< (current-column) col)) (beginning-of-line) (forward-char col)))) (defun haskell-cabal-indent-line () "Indent current line according to subsection" (interactive) (cl-case (haskell-cabal-classify-line) (section-data (save-excursion (let ((indent (haskell-cabal-section-data-indent-column (haskell-cabal-subsection)))) (indent-line-to indent) (beginning-of-line) (when (looking-at "[ ]*\\([ ]\\{2\\},[ ]*\\)") (replace-match ", " t t nil 1))))) (empty (indent-relative))) (haskell-cabal-forward-to-line-entry)) (defun haskell-cabal-map-sections (fun) "Execute fun over each section, collecting the result" (save-excursion (goto-char (point-min)) (let ((results nil)) (while (not (eobp)) (let* ((section (haskell-cabal-section)) (result (and section (funcall fun (haskell-cabal-section))))) (when section (setq results (cons result results)))) (haskell-cabal-next-section)) (nreverse results)))) (defun haskell-cabal-section-add-build-dependency (dependency &optional sort sec) "Add a build dependency to the build-depends section" (let* ((section (or sec (haskell-cabal-section))) (subsection (and section (haskell-cabal-find-subsection section "build-depends")))) (when subsection (haskell-cabal-with-subsection subsection t (haskell-cabal-with-cs-list (insert dependency) (insert "\n") (when sort (goto-char (point-min)) (sort-subr nil 'forward-line 'end-of-line 'haskell-cabal-sort-lines-key-fun))))))) (defun haskell-cabal-add-build-dependency (dependency &optional sort silent) "Add the given DEPENDENCY to every section in cabal file. If SORT argument is given sort dependencies in section after update. Pass SILENT argument to update all sections without asking user." (haskell-cabal-map-sections (lambda (section) (when (haskell-cabal-source-section-p section) (unwind-protect (progn (when (or silent (y-or-n-p (format "Add dependency %s to %s section %s?" dependency (haskell-cabal-section-name section) (haskell-cabal-section-value section)))) (haskell-cabal-section-add-build-dependency dependency sort section)) nil) (haskell-mode-toggle-interactive-prompt-state t)))))) (defun haskell-cabal-add-dependency (package &optional version no-prompt sort silent) "Add PACKAGE to the cabal file. If VERSION is non-nil it will be appended as a minimum version. If NO-PROMPT is nil the minimum package version is read from the minibuffer. When SORT is non-nil the package entries are sorted afterwards. If SILENT is non-nil the user is prompted for each source-section." (interactive (list (read-from-minibuffer "Package entry: ") nil t t nil)) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (save-window-excursion (find-file-other-window (haskell-cabal-find-file)) (let ((entry (if no-prompt package (read-from-minibuffer "Package entry: " (concat package (if version (concat " >= " version) "")))))) (haskell-cabal-add-build-dependency entry sort silent) (when (or silent (y-or-n-p "Save cabal file? ")) (save-buffer)))) ;; unwind (haskell-mode-toggle-interactive-prompt-state t))) (defun haskell-cabal--find-tags-dir () "Return a directory where TAGS file will be generated. Tries to find cabal file first and if succeeds uses its location. If cabal file not found uses current file directory. If current buffer not visiting a file returns nil." (or (haskell-cabal-find-dir) (when buffer-file-name (file-name-directory buffer-file-name)))) (defun haskell-cabal--compose-hasktags-command (dir) "Prepare command to execute `hasktags` command in DIR folder. To customise the command executed, see `haskell-hasktags-path' and `haskell-hasktags-arguments'. This function takes into account the user's operating system: in case of Windows it generates a simple command, relying on Hasktags itself to find source files: hasktags --output=DIR\TAGS -x -e DIR In other cases it uses `find` command to find all source files recursively avoiding visiting unnecessary heavy directories like .git, .svn, _darcs and build directories created by cabal-install, stack, etc and passes list of found files to Hasktags." (if (eq system-type 'windows-nt) (format "%s --output=%s %s %s" haskell-hasktags-path (shell-quote-argument (expand-file-name "TAGS" dir)) (mapconcat #'identity haskell-hasktags-arguments " ") (shell-quote-argument dir)) (format "cd %s && %s | %s" (shell-quote-argument dir) (concat "find . " "-type d \\( " "-name .git " "-o -name .svn " "-o -name _darcs " "-o -name .stack-work " "-o -name dist " "-o -name dist-newstyle " "-o -name .cabal-sandbox " "\\) -prune " "-o -type f \\( " "-name '*.hs' " "-or -name '*.lhs' " "-or -name '*.hsc' " "\\) -not \\( " "-name '#*' " "-or -name '.*' " "\\) -print0") (format "xargs -0 %s %s" (shell-quote-argument haskell-hasktags-path) (mapconcat #'identity haskell-hasktags-arguments " "))))) (provide 'haskell-cabal) ;;; haskell-cabal.el ends here ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-collapse.el���������������������������������������������������������������0000664�0000000�0000000�00000010057�13602233217�0017556�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-collapse.el --- Collapse expressions -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; Copyright (c) 2017 Vasantha Ganesh Kanniappan <vasanthaganesh.k@tuta.io>. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'hideshow) ;;; TODO: ;;; -> Make it work for braces (defun haskell-hide-toggle () "Toggle visibility of existing forms at point. " (interactive) (hs-minor-mode 1) (save-excursion (let* ((modified (buffer-modified-p)) (inhibit-read-only t) (position (haskell-indented-block)) (beg (car position)) (end (cdr position))) (if (and beg end) (if (overlays-in beg end) (hs-discard-overlays beg end) (hs-make-overlay beg end 'code))) (set-buffer-modified-p modified)))) (defun haskell-blank-line-p () "Returns `t' if line is empty or composed only of whitespace." (save-excursion (beginning-of-line) (= (point-at-eol) (progn (skip-chars-forward "[:blank:]") (point))))) (defun haskell-indented-block () "return (start-of-indentation . end-of-indentation)" (let ((cur-indent (current-indentation)) (nxt-line-indent (haskell-next-line-indentation 1)) (prev-line-indent (haskell-next-line-indentation -1)) (beg-of-line (save-excursion (end-of-line) (point)))) (cond ((and (= cur-indent 0) (= nxt-line-indent 0)) nil) ((haskell-blank-line-p) nil) ((> nxt-line-indent cur-indent) (cons beg-of-line (haskell-find-line-with-indentation '> 1))) ((or (= nxt-line-indent cur-indent) (<= prev-line-indent cur-indent)) (cons (haskell-find-line-with-indentation '>= -1) (haskell-find-line-with-indentation '>= 1))) (t nil)))) (defun haskell-next-line-indentation (dir) "returns (integer) indentation of the next if dir=1, previous line indentation if dir=-1" (save-excursion (progn (while (and (zerop (forward-line dir)) (haskell-blank-line-p))) (current-indentation)))) (defun haskell-find-line-with-indentation (comparison direction) "comparison is >= or >, direction if 1 finds forward, if -1 finds backward" (save-excursion (let ((start-indent (current-indentation))) (progn (while (and (zerop (forward-line direction)) (or (haskell-blank-line-p) (funcall comparison (current-indentation) start-indent)))) (when (= direction 1) (forward-line -1)) (end-of-line) (point))))) (defun haskell-hide-toggle-all () "hides all top level functions" (interactive) (save-excursion (goto-char (point-max)) (while (zerop (forward-line -1)) (goto-char (point-at-bol)) (when (= (current-indentation) 0) (haskell-hide-toggle))))) (defvar haskell-collapse-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c @ C-c") 'haskell-hide-toggle) (define-key map (kbd "C-c @ C-M-c") 'haskell-hide-toggle-all) (define-key map (kbd "C-c @ C-M-s") 'haskell-hide-toggle-all) (define-key map (kbd "C-c @ C-M-h") 'haskell-hide-toggle-all) map) "Keymap for using `haskell-collapse-mode'.") ;;;###autoload (define-minor-mode haskell-collapse-mode "Minor mode to collapse and expand haskell expressions" :init-value nil :lighter " Haskell-Collapse" :keymap haskell-collapse-mode-map) (provide 'haskell-collapse) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-commands.el���������������������������������������������������������������0000664�0000000�0000000�00000121675�13602233217�0017566�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-commands.el --- Commands that can be run on the process -*- lexical-binding: t -*- ;;; Commentary: ;;; This module provides varoius `haskell-mode' and `haskell-interactive-mode' ;;; specific commands such as show type signature, show info, haskell process ;;; commands and etc. ;; Copyright © 2014 Chris Done. All rights reserved. ;; 2016 Arthur Fayzrakhmanov ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'cl-lib) (require 'etags) (require 'haskell-mode) (require 'haskell-process) (require 'haskell-font-lock) (require 'haskell-interactive-mode) (require 'haskell-session) (require 'haskell-string) (require 'haskell-presentation-mode) (require 'haskell-utils) (require 'highlight-uses-mode) (require 'haskell-cabal) (defcustom haskell-mode-stylish-haskell-path "stylish-haskell" "Path to `stylish-haskell' executable." :group 'haskell :type 'string) (defcustom haskell-mode-stylish-haskell-args nil "Arguments to pass to program specified by haskell-mode-stylish-haskell-path." :group 'haskell :type 'list) (defcustom haskell-interactive-set-+c t "Issue ':set +c' in interactive session to support type introspection." :group 'haskell-interactive :type 'boolean) ;;;###autoload (defun haskell-process-restart () "Restart the inferior Haskell process." (interactive) (haskell-process-reset (haskell-interactive-process)) (haskell-process-set (haskell-interactive-process) 'command-queue nil) (haskell-process-start (haskell-interactive-session))) (defun haskell-process-start (session) "Start the inferior Haskell process with a given SESSION. You can create new session using function `haskell-session-make'." (let ((existing-process (get-process (haskell-session-name (haskell-interactive-session))))) (when (processp existing-process) (haskell-interactive-mode-echo session "Restarting process ...") (haskell-process-set (haskell-session-process session) 'is-restarting t) (delete-process existing-process))) (let ((process (or (haskell-session-process session) (haskell-process-make (haskell-session-name session)))) (old-queue (haskell-process-get (haskell-session-process session) 'command-queue))) (haskell-session-set-process session process) (haskell-process-set-session process session) (haskell-process-set-cmd process nil) (haskell-process-set (haskell-session-process session) 'is-restarting nil) (let ((default-directory (haskell-session-cabal-dir session)) (log-and-command (haskell-process-compute-process-log-and-command session (haskell-process-type)))) (haskell-session-prompt-set-current-dir session (not haskell-process-load-or-reload-prompt)) (haskell-process-set-process process (progn (haskell-process-log (propertize (format "%S" log-and-command))) (apply #'start-process (cdr log-and-command))))) (progn (set-process-sentinel (haskell-process-process process) 'haskell-process-sentinel) (set-process-filter (haskell-process-process process) 'haskell-process-filter)) (haskell-process-send-startup process) (unless (memq (haskell-process-type) ;; These all set the proper CWD. (list 'cabal-repl 'cabal-new-repl 'stack-ghci)) (haskell-process-change-dir session process (haskell-session-current-dir session))) (haskell-process-set process 'command-queue (append (haskell-process-get (haskell-session-process session) 'command-queue) old-queue)) process)) (defun haskell-process-send-startup (process) "Send the necessary start messages to haskell PROCESS." (haskell-process-queue-command process (make-haskell-command :state process :go (lambda (process) ;; We must set the prompt last, so that this command as a ;; whole produces only one prompt marker as a response. (haskell-process-send-string process (mapconcat #'identity (append '("Prelude.putStrLn \"\"" ":set -v1") (when haskell-interactive-set-+c '(":set +c"))) ; :type-at in GHC 8+ "\n")) (haskell-process-send-string process ":set prompt \"\\4\"") (haskell-process-send-string process (format ":set prompt-cont \"%s\"" haskell-interactive-prompt-cont))) :live (lambda (process buffer) (when (haskell-process-consume process "^\*\*\* WARNING: \\(.+\\) is writable by someone else, IGNORING!$") (let ((path (match-string 1 buffer))) (haskell-session-modify (haskell-process-session process) 'ignored-files (lambda (files) (cl-remove-duplicates (cons path files) :test 'string=))) (haskell-interactive-mode-compile-warning (haskell-process-session process) (format "GHCi is ignoring: %s (run M-x haskell-process-unignore)" path))))) :complete (lambda (process _) (haskell-interactive-mode-echo (haskell-process-session process) (concat (nth (random (length haskell-process-greetings)) haskell-process-greetings) (when haskell-process-show-debug-tips " If I break, you can: 1. Restart: M-x haskell-process-restart 2. Configure logging: C-h v haskell-process-log (useful for debugging) 3. General config: M-x customize-mode 4. Hide these tips: C-h v haskell-process-show-debug-tips"))) (with-current-buffer (haskell-interactive-buffer) (goto-char haskell-interactive-mode-prompt-start)))))) (defun haskell-commands-process () "Get the Haskell session, throws an error if not available." (or (haskell-session-process (haskell-session-maybe)) (error "No Haskell session/process associated with this buffer. Maybe run M-x haskell-session-change?"))) ;;;###autoload (defun haskell-process-clear () "Clear the current process." (interactive) (haskell-process-reset (haskell-commands-process)) (haskell-process-set (haskell-commands-process) 'command-queue nil)) ;;;###autoload (defun haskell-process-interrupt () "Interrupt the process (SIGINT)." (interactive) (interrupt-process (haskell-process-process (haskell-commands-process)))) (defun haskell-process-reload-with-fbytecode (process module-buffer) "Query a PROCESS to reload MODULE-BUFFER with -fbyte-code set. Restores -fobject-code after reload finished. MODULE-BUFFER is the actual Emacs buffer of the module being loaded." (haskell-process-queue-without-filters process ":set -fbyte-code") ;; We prefix the module's filename with a "*", which asks ghci to ;; ignore any existing object file and interpret the module. ;; Dependencies will still use their object files as usual. (haskell-process-queue-without-filters process (format ":load \"*%s\"" (replace-regexp-in-string "\"" "\\\\\"" (buffer-file-name module-buffer)))) (haskell-process-queue-without-filters process ":set -fobject-code")) (defvar url-http-response-status) (defvar url-http-end-of-headers) (defvar haskell-cabal-targets-history nil "History list for session targets.") (defun haskell-process-hayoo-ident (ident) "Hayoo for IDENT, return a list of modules" ;; We need a real/simulated closure, because otherwise these ;; variables will be unbound when the url-retrieve callback is ;; called. ;; TODO: Remove when this code is converted to lexical bindings by ;; default (Emacs 24.1+) (let ((url (format haskell-process-hayoo-query-url (url-hexify-string ident)))) (with-current-buffer (url-retrieve-synchronously url) (if (= 200 url-http-response-status) (progn (goto-char url-http-end-of-headers) (let* ((res (json-read)) (results (assoc-default 'result res))) ;; TODO: gather packages as well, and when we choose a ;; given import, check that we have the package in the ;; cabal file as well. (cl-mapcan (lambda (r) ;; append converts from vector -> list (append (assoc-default 'resultModules r) nil)) results))) (warn "HTTP error %s fetching %s" url-http-response-status url))))) (defun haskell-process-hoogle-ident (ident) "Hoogle for IDENT, return a list of modules." (with-temp-buffer (let ((hoogle-error (call-process "hoogle" nil t nil "search" "--exact" ident))) (goto-char (point-min)) (unless (or (/= 0 hoogle-error) (looking-at "^No results found") (looking-at "^package ")) (while (re-search-forward "^\\([^ ]+\\).*$" nil t) (replace-match "\\1" nil nil)) (cl-remove-if (lambda (a) (string= "" a)) (split-string (buffer-string) "\n")))))) (defun haskell-process-haskell-docs-ident (ident) "Search with haskell-docs for IDENT, return a list of modules." (cl-remove-if-not (lambda (a) (string-match "^[[:upper:]][[:alnum:]_'.]+$" a)) (split-string (with-output-to-string (with-current-buffer standard-output (call-process "haskell-docs" nil ; no infile t ; output to current buffer (that is string) nil ; do not redisplay "--modules" ident))) "\n"))) (defun haskell-process-import-modules (process modules) "Query PROCESS `:m +' command to import MODULES." (when haskell-process-auto-import-loaded-modules (haskell-process-queue-command process (make-haskell-command :state (cons process modules) :go (lambda (state) (haskell-process-send-string (car state) (format ":m + %s" (mapconcat 'identity (cdr state) " ")))))))) ;;;###autoload (defun haskell-describe (ident) "Describe the given identifier IDENT." (interactive (list (read-from-minibuffer "Describe identifier: " (haskell-ident-at-point)))) (let ((results (read (shell-command-to-string (concat "haskell-docs --sexp " ident))))) (help-setup-xref (list #'haskell-describe ident) (called-interactively-p 'interactive)) (save-excursion (with-help-window (help-buffer) (with-current-buffer (help-buffer) (if results (cl-loop for result in results do (insert (propertize ident 'font-lock-face '((:inherit font-lock-type-face :underline t))) " is defined in " (let ((module (cadr (assoc 'module result)))) (if module (concat module " ") "")) (cadr (assoc 'package result)) "\n\n") do (let ((type (cadr (assoc 'type result)))) (when type (insert (haskell-fontify-as-mode type 'haskell-mode) "\n"))) do (let ((args (cadr (assoc 'type results)))) (cl-loop for arg in args do (insert arg "\n")) (insert "\n")) do (insert (cadr (assoc 'documentation result))) do (insert "\n\n")) (insert "No results for " ident))))))) ;;;###autoload (defun haskell-rgrep (&optional prompt) "Grep the effective project for the symbol at point. Very useful for codebase navigation. Prompts for an arbitrary regexp given a prefix arg PROMPT." (interactive "P") (let ((sym (if prompt (read-from-minibuffer "Look for: ") (haskell-ident-at-point)))) (rgrep sym "*.hs *.lhs *.hsc *.chs *.hs-boot *.lhs-boot" (haskell-session-current-dir (haskell-interactive-session))))) ;;;###autoload (defun haskell-process-do-info (&optional prompt-value) "Print info on the identifier at point. If PROMPT-VALUE is non-nil, request identifier via mini-buffer." (interactive "P") (let ((at-point (haskell-ident-at-point))) (when (or prompt-value at-point) (let* ((ident (replace-regexp-in-string "^!\\([A-Z_a-z]\\)" "\\1" (if prompt-value (read-from-minibuffer "Info: " at-point) at-point))) (modname (unless prompt-value (haskell-utils-parse-import-statement-at-point))) (command (cond (modname (format ":browse! %s" modname)) ((string= ident "") ; For the minibuffer input case nil) (t (format (if (string-match "^[a-zA-Z_]" ident) ":info %s" ":info (%s)") (or ident at-point)))))) (when command (haskell-process-show-repl-response command)))))) ;;;###autoload (defun haskell-process-do-type (&optional insert-value) "Print the type of the given expression. Given INSERT-VALUE prefix indicates that result type signature should be inserted." (interactive "P") (if insert-value (haskell-process-insert-type) (let* ((expr (if (use-region-p) (buffer-substring-no-properties (region-beginning) (region-end)) (haskell-ident-at-point))) (expr-okay (and expr (not (string-match-p "\\`[[:space:]]*\\'" expr)) (not (string-match-p "\n" expr))))) ;; No newlines in expressions, and surround with parens if it ;; might be a slice expression (when expr-okay (haskell-process-show-repl-response (format (if (or (string-match-p "\\`(" expr) (string-match-p "\\`[_[:alpha:]]" expr)) ":type %s" ":type (%s)") expr)))))) ;;;###autoload (defun haskell-mode-jump-to-def-or-tag (&optional _next-p) ;; FIXME NEXT-P arg is not used "Jump to the definition. Jump to definition of identifier at point by consulting GHCi, or tag table as fallback. Remember: If GHCi is busy doing something, this will delay, but it will always be accurate, in contrast to tags, which always work but are not always accurate. If the definition or tag is found, the location from which you jumped will be pushed onto `xref--marker-ring', so you can return to that position with `xref-pop-marker-stack'." (interactive "P") (if (haskell-session-maybe) (let ((initial-loc (point-marker)) (loc (haskell-mode-find-def (haskell-ident-at-point)))) (haskell-mode-handle-generic-loc loc) (unless (equal initial-loc (point-marker)) (xref-push-marker-stack initial-loc))) (call-interactively 'haskell-mode-tag-find))) ;;;###autoload (defun haskell-mode-goto-loc () "Go to the location of the thing at point. Requires the :loc-at command from GHCi." (interactive) (let ((loc (haskell-mode-loc-at))) (when loc (haskell-mode-goto-span loc)))) (defun haskell-mode-goto-span (span) "Jump to the SPAN, whatever file and line and column it needs to get there." (xref-push-marker-stack) (find-file (expand-file-name (plist-get span :path) (haskell-session-cabal-dir (haskell-interactive-session)))) (goto-char (point-min)) (forward-line (1- (plist-get span :start-line))) (forward-char (plist-get span :start-col))) (defun haskell-process-insert-type () "Get the identifier at the point and insert its type. Use GHCi's :type if it's possible." (let ((ident (haskell-ident-at-point))) (when ident (let ((process (haskell-interactive-process)) (query (format (if (string-match "^[_[:lower:][:upper:]]" ident) ":type %s" ":type (%s)") ident))) (haskell-process-queue-command process (make-haskell-command :state (list process query (current-buffer)) :go (lambda (state) (haskell-process-send-string (nth 0 state) (nth 1 state))) :complete (lambda (state response) (cond ;; TODO: Generalize this into a function. ((or (string-match "^Top level" response) (string-match "^<interactive>" response)) (message "%s" response)) (t (with-current-buffer (nth 2 state) (goto-char (line-beginning-position)) (insert (format "%s\n" (replace-regexp-in-string "\n$" "" response))))))))))))) (defun haskell-mode-find-def (ident) ;; TODO Check if it possible to exploit `haskell-process-do-info' "Find definition location of identifier IDENT. Uses the GHCi process to find the location. Returns nil if it can't find the identifier or the identifier isn't a string. Returns: (library <package> <module>) (file <path> <line> <col>) (module <name>) nil" (when (stringp ident) (let ((reply (haskell-process-queue-sync-request (haskell-interactive-process) (format (if (string-match "^[a-zA-Z_]" ident) ":info %s" ":info (%s)") ident)))) (let ((match (string-match "-- Defined \\(at\\|in\\) \\(.+\\)$" reply))) (when match (let ((defined (match-string 2 reply))) (let ((match (string-match "\\(.+?\\):\\([0-9]+\\):\\([0-9]+\\)$" defined))) (cond (match (list 'file (expand-file-name (match-string 1 defined) (haskell-session-current-dir (haskell-interactive-session))) (string-to-number (match-string 2 defined)) (string-to-number (match-string 3 defined)))) (t (let ((match (string-match "`\\(.+?\\):\\(.+?\\)'$" defined))) (if match (list 'library (match-string 1 defined) (match-string 2 defined)) (let ((match (string-match "`\\(.+?\\)'$" defined))) (if match (list 'module (match-string 1 defined))))))))))))))) ;;;###autoload (defun haskell-mode-jump-to-def (ident) "Jump to definition of identifier IDENT at point." (interactive (list (haskell-string-drop-qualifier (haskell-ident-at-point)))) (let ((loc (haskell-mode-find-def ident))) (when loc (haskell-mode-handle-generic-loc loc)))) (defun haskell-mode-handle-generic-loc (loc) "Either jump to or echo a generic location LOC. Either a file or a library." (cl-case (car loc) (file (progn (find-file (elt loc 1)) (goto-char (point-min)) (forward-line (1- (elt loc 2))) (goto-char (+ (line-beginning-position) (1- (elt loc 3)))))) (library (message "Defined in `%s' (%s)." (elt loc 2) (elt loc 1))) (module (message "Defined in `%s'." (elt loc 1))))) (defun haskell-mode-loc-at () "Get the location at point. Requires the :loc-at command from GHCi." (let ((pos (or (when (region-active-p) (cons (region-beginning) (region-end))) (haskell-spanable-pos-at-point) (cons (point) (point))))) (when pos (let ((reply (haskell-process-queue-sync-request (haskell-interactive-process) (save-excursion (format ":loc-at %s %d %d %d %d %s" (buffer-file-name) (progn (goto-char (car pos)) (line-number-at-pos)) (1+ (current-column)) ;; GHC uses 1-based columns. (progn (goto-char (cdr pos)) (line-number-at-pos)) (1+ (current-column)) ;; GHC uses 1-based columns. (buffer-substring-no-properties (car pos) (cdr pos))))))) (if reply (if (string-match "\\(.*?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))" reply) (list :path (match-string 1 reply) :start-line (string-to-number (match-string 2 reply)) ;; ;; GHC uses 1-based columns. :start-col (1- (string-to-number (match-string 3 reply))) :end-line (string-to-number (match-string 4 reply)) ;; GHC uses 1-based columns. :end-col (1- (string-to-number (match-string 5 reply)))) (error (propertize reply 'face 'compilation-error))) (error (propertize "No reply. Is :loc-at supported?" 'face 'compilation-error))))))) ;;;###autoload (defun haskell-process-cd (&optional _not-interactive) ;; FIXME optional arg is not used "Change directory." (interactive) (let* ((session (haskell-interactive-session)) (dir (haskell-session-prompt-set-current-dir session))) (haskell-process-log (propertize (format "Changing directory to %s ...\n" dir) 'face font-lock-comment-face)) (haskell-process-change-dir session (haskell-interactive-process) dir))) (defun haskell-session-buffer-default-dir (session &optional buffer) "Try to deduce a sensible default directory for SESSION and BUFFER, of which the latter defaults to the current buffer." (or (haskell-session-get session 'current-dir) (haskell-session-get session 'cabal-dir) (if (buffer-file-name buffer) (file-name-directory (buffer-file-name buffer)) "~/"))) (defun haskell-session-prompt-set-current-dir (session &optional use-default) "Prompt for the current directory. Return current working directory for SESSION." (let ((default (haskell-session-buffer-default-dir session))) (haskell-session-set-current-dir session (if use-default default (haskell-utils-read-directory-name "Set current directory: " default)))) (haskell-session-get session 'current-dir)) (defun haskell-process-change-dir (session process dir) "Change SESSION's current directory. Query PROCESS to `:cd` to directory DIR." (haskell-process-queue-command process (make-haskell-command :state (list session process dir) :go (lambda (state) (haskell-process-send-string (cadr state) (format ":cd %s" (cl-caddr state)))) :complete (lambda (state _) (haskell-session-set-current-dir (car state) (cl-caddr state)) (haskell-interactive-mode-echo (car state) (format "Changed directory: %s" (cl-caddr state))))))) ;;;###autoload (defun haskell-process-cabal-macros () "Send the cabal macros string." (interactive) (haskell-process-queue-without-filters (haskell-interactive-process) ":set -optP-include -optPdist/build/autogen/cabal_macros.h")) (defun haskell-process-do-try-info (sym) "Get info of SYM and echo in the minibuffer." (let ((process (haskell-interactive-process))) (haskell-process-queue-command process (make-haskell-command :state (cons process sym) :go (lambda (state) (haskell-process-send-string (car state) (if (string-match "^[A-Za-z_]" (cdr state)) (format ":info %s" (cdr state)) (format ":info (%s)" (cdr state))))) :complete (lambda (_state response) (unless (or (string-match "^Top level" response) (string-match "^<interactive>" response)) (haskell-mode-message-line response))))))) (defun haskell-process-do-try-type (sym) "Get type of SYM and echo in the minibuffer." (let ((process (haskell-interactive-process))) (haskell-process-queue-command process (make-haskell-command :state (cons process sym) :go (lambda (state) (haskell-process-send-string (car state) (if (string-match "^[A-Za-z_]" (cdr state)) (format ":type %s" (cdr state)) (format ":type (%s)" (cdr state))))) :complete (lambda (_state response) (unless (or (string-match "^Top level" response) (string-match "^<interactive>" response)) (haskell-mode-message-line response))))))) ;;;###autoload (defun haskell-mode-show-type-at (&optional insert-value) "Show type of the thing at point or within active region asynchronously. This function requires GHCi 8+ or GHCi-ng. \\<haskell-interactive-mode-map> To make this function works sometimes you need to load the file in REPL first using command `haskell-process-load-file' bound to \\[haskell-process-load-file]. Optional argument INSERT-VALUE indicates that recieved type signature should be inserted (but only if nothing happened since function invocation)." (interactive "P") (let* ((pos (haskell-command-capture-expr-bounds)) (req (haskell-utils-compose-type-at-command pos)) (process (haskell-interactive-process)) (buf (current-buffer)) (pos-reg (cons pos (region-active-p)))) (haskell-process-queue-command process (make-haskell-command :state (list process req buf insert-value pos-reg) :go (lambda (state) (let* ((prc (car state)) (req (nth 1 state))) (haskell-utils-async-watch-changes) (haskell-process-send-string prc req))) :complete (lambda (state response) (let* ((init-buffer (nth 2 state)) (insert-value (nth 3 state)) (pos-reg (nth 4 state)) (wrap (cdr pos-reg)) (min-pos (caar pos-reg)) (max-pos (cdar pos-reg)) (sig (haskell-utils-reduce-string response)) (res-type (haskell-utils-repl-response-error-status sig))) (cl-case res-type ;; neither popup presentation buffer ;; nor insert response in error case ('unknown-command (message "This command requires GHCi 8+ or GHCi-ng. Please read command description for details.")) ('option-missing (message "Could not infer type signature. You need to load file first. Also :set +c is required, see customization `haskell-interactive-set-+c'. Please read command description for details.")) ('interactive-error (message "Wrong REPL response: %s" sig)) (otherwise (if insert-value ;; Only insert type signature and do not present it (if (= (length haskell-utils-async-post-command-flag) 1) (if wrap ;; Handle region case (progn (deactivate-mark) (save-excursion (delete-region min-pos max-pos) (goto-char min-pos) (insert (concat "(" sig ")")))) ;; Non-region cases (haskell-command-insert-type-signature sig)) ;; Some commands registered, prevent insertion (message "Type signature insertion was prevented. These commands were registered: %s" (cdr (reverse haskell-utils-async-post-command-flag)))) ;; Present the result only when response is valid and not asked ;; to insert result (haskell-command-echo-or-present response))) (haskell-utils-async-stop-watching-changes init-buffer)))))))) (make-obsolete 'haskell-process-generate-tags 'haskell-mode-generate-tags "2016-03-14") (defun haskell-process-generate-tags (&optional and-then-find-this-tag) "Regenerate the TAGS table. If optional AND-THEN-FIND-THIS-TAG argument is present it is used with function `xref-find-definitions' after new table was generated." (interactive) (let ((process (haskell-interactive-process))) (haskell-process-queue-command process (make-haskell-command :state (cons process and-then-find-this-tag) :go (lambda (state) (let* ((process (car state)) (cabal-dir (haskell-session-cabal-dir (haskell-process-session process))) (command (haskell-cabal--compose-hasktags-command cabal-dir))) (haskell-process-send-string process command))) :complete (lambda (state _response) (when (cdr state) (let ((tags-file-name (haskell-session-tags-filename (haskell-process-session (car state))))) (xref-find-definitions (cdr state)))) (haskell-mode-message-line "Tags generated.")))))) (defun haskell-process-add-cabal-autogen () "Add cabal's autogen dir to the GHCi search path. Add <cabal-project-dir>/dist/build/autogen/ to GHCi seatch path. This allows modules such as 'Path_...', generated by cabal, to be loaded by GHCi." (unless (or (eq 'cabal-repl (haskell-process-type)) (eq 'cabal-new-repl (haskell-process-type))) ;; redundant with "cabal repl" (let* ((session (haskell-interactive-session)) (cabal-dir (haskell-session-cabal-dir session)) (ghci-gen-dir (format "%sdist/build/autogen/" cabal-dir))) (haskell-process-queue-without-filters (haskell-interactive-process) (format ":set -i%s" ghci-gen-dir))))) ;;;###autoload (defun haskell-process-unignore () "Unignore any ignored files. Do not ignore files that were specified as being ignored by the inferior GHCi process." (interactive) (let ((session (haskell-interactive-session)) (changed nil)) (if (null (haskell-session-get session 'ignored-files)) (message "Nothing to unignore!") (cl-loop for file in (haskell-session-get session 'ignored-files) do (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (progn (cl-case (read-event (propertize (format "Set permissions? %s (y, n, v: stop and view file)" file) 'face 'minibuffer-prompt)) (?y (haskell-process-unignore-file session file) (setq changed t)) (?v (find-file file) (cl-return))) (when (and changed (y-or-n-p "Restart GHCi process now? ")) (haskell-process-restart))) ;; unwind (haskell-mode-toggle-interactive-prompt-state t)))))) ;;;###autoload (defun haskell-session-change-target (target) "Set the build TARGET for cabal REPL." (interactive (list (haskell-session-choose-target "New build target: " nil 'haskell-cabal-targets-history))) (let* ((session haskell-session) (old-target (haskell-session-get session 'target))) (when session (haskell-session-set-target session target) (when (not (string= old-target target)) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (when (y-or-n-p "Target changed, restart haskell process? ") (haskell-process-start session))) (haskell-mode-toggle-interactive-prompt-state t))))) ;;;###autoload (defun haskell-mode-stylish-buffer () "Apply stylish-haskell to the current buffer. Use `haskell-mode-stylish-haskell-path' to know where to find stylish-haskell executable. This function tries to preserve cursor position and markers by using `haskell-mode-buffer-apply-command'." (interactive) (haskell-mode-buffer-apply-command haskell-mode-stylish-haskell-path haskell-mode-stylish-haskell-args)) (defun haskell-mode-buffer-apply-command (cmd &optional args) "Execute shell command CMD with ARGS and current buffer as input and output. Use buffer as input and replace the whole buffer with the output. If CMD fails the buffer remains unchanged." (set-buffer-modified-p t) (let* ((out-file (make-temp-file "stylish-output")) (err-file (make-temp-file "stylish-error")) (coding-system-for-read 'utf-8) (coding-system-for-write 'utf-8)) (unwind-protect (let* ((_errcode (apply 'call-process-region (point-min) (point-max) cmd nil `((:file ,out-file) ,err-file) nil args)) (err-file-empty-p (equal 0 (nth 7 (file-attributes err-file)))) (out-file-empty-p (equal 0 (nth 7 (file-attributes out-file))))) (if err-file-empty-p (if out-file-empty-p (message "Error: %s produced no output and no error information, leaving buffer alone" cmd) ;; Command successful, insert file with replacement to preserve ;; markers. (insert-file-contents out-file nil nil nil t)) (progn ;; non-null stderr, command must have failed (with-current-buffer (get-buffer-create "*haskell-mode*") (insert-file-contents err-file) (buffer-string)) (message "Error: %s ended with errors, leaving buffer alone, see *haskell-mode* buffer for stderr" cmd) (with-temp-buffer (insert-file-contents err-file) ;; use (warning-minimum-level :debug) to see this (display-warning cmd (buffer-substring-no-properties (point-min) (point-max)) :debug))))) (ignore-errors (delete-file err-file)) (ignore-errors (delete-file out-file))))) ;;;###autoload (defun haskell-mode-find-uses () "Find use cases of the identifier at point and highlight them all." (interactive) (let ((spans (haskell-mode-uses-at))) (unless (null spans) (highlight-uses-mode 1) (cl-loop for span in spans do (haskell-mode-make-use-highlight span))))) (defun haskell-mode-make-use-highlight (span) "Make a highlight overlay at the given SPAN." (save-window-excursion (save-excursion (haskell-mode-goto-span span) (save-excursion (highlight-uses-mode-highlight (progn (goto-char (point-min)) (forward-line (1- (plist-get span :start-line))) (forward-char (plist-get span :start-col)) (point)) (progn (goto-char (point-min)) (forward-line (1- (plist-get span :end-line))) (forward-char (plist-get span :end-col)) (point))))))) (defun haskell-mode-uses-at () "Get the locations of use cases for the ident at point. Requires the :uses command from GHCi." (let ((pos (or (when (region-active-p) (cons (region-beginning) (region-end))) (haskell-ident-pos-at-point) (cons (point) (point))))) (when pos (let ((reply (haskell-process-queue-sync-request (haskell-interactive-process) (save-excursion (format ":uses %s %d %d %d %d %s" (buffer-file-name) (progn (goto-char (car pos)) (line-number-at-pos)) (1+ (current-column)) ;; GHC uses 1-based columns. (progn (goto-char (cdr pos)) (line-number-at-pos)) (1+ (current-column)) ;; GHC uses 1-based columns. (buffer-substring-no-properties (car pos) (cdr pos))))))) (if reply (let ((lines (split-string reply "\n" t))) (cl-remove-if #'null (mapcar (lambda (line) (if (string-match "\\(.*?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))" line) (list :path (match-string 1 line) :start-line (string-to-number (match-string 2 line)) ;; ;; GHC uses 1-based columns. :start-col (1- (string-to-number (match-string 3 line))) :end-line (string-to-number (match-string 4 line)) ;; GHC uses 1-based columns. :end-col (1- (string-to-number (match-string 5 line)))) (error (propertize line 'face 'compilation-error)))) lines))) (error (propertize "No reply. Is :uses supported?" 'face 'compilation-error))))))) (defun haskell-command-echo-or-present (msg) "Present message in some manner depending on configuration. If variable `haskell-process-use-presentation-mode' is NIL it will output modified message MSG to echo area." (if haskell-process-use-presentation-mode (let ((session (haskell-process-session (haskell-interactive-process)))) (haskell-presentation-present session msg)) (let ((m (haskell-utils-reduce-string msg))) (message "%s" m)))) (defun haskell-command-capture-expr-bounds () "Capture position bounds of expression at point. If there is an active region then it returns region bounds. Otherwise it uses `haskell-spanable-pos-at-point` to capture identifier bounds. If latter function returns NIL this function will return cons cell where min and max positions both are equal to point." (or (when (region-active-p) (cons (region-beginning) (region-end))) (haskell-spanable-pos-at-point) (cons (point) (point)))) (defun haskell-command-insert-type-signature (signature) "Insert type signature. In case of active region is present, wrap it by parentheses and append SIGNATURE to original expression. Otherwise tries to carefully insert SIGNATURE above identifier at point. Removes newlines and extra whitespace in signature before insertion." (let* ((ident-pos (or (haskell-ident-pos-at-point) (cons (point) (point)))) (min-pos (car ident-pos)) (sig (haskell-utils-reduce-string signature))) (save-excursion (goto-char min-pos) (let ((col (current-column))) (insert sig "\n") (indent-to col))))) (provide 'haskell-commands) ;;; haskell-commands.el ends here �������������������������������������������������������������������haskell-mode-17.1/haskell-compile.el����������������������������������������������������������������0000664�0000000�0000000�00000021455�13602233217�0017410�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-compile.el --- Haskell/GHC compilation sub-mode -*- lexical-binding: t -*- ;; Copyright (C) 2013 Herbert Valerio Riedel ;; Author: Herbert Valerio Riedel <hvr@gnu.org> ;; This file is not part of GNU Emacs. ;; This file 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 file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; Simple GHC-centric compilation sub-mode; see info node ;; `(haskell-mode)compilation' for more information ;;; Code: (require 'compile) (require 'haskell-cabal) (require 'ansi-color) (eval-when-compile (require 'subr-x)) ;;;###autoload (defgroup haskell-compile nil "Settings for Haskell compilation mode" :link '(custom-manual "(haskell-mode)compilation") :group 'haskell) (defcustom haskell-compile-cabal-build-command "cabal build --ghc-option=-ferror-spans" "Default build command to use for `haskell-cabal-build' when a cabal file is detected. For legacy compat, `%s' is replaced by the cabal package top folder." :group 'haskell-compile :type 'string) (defcustom haskell-compile-cabal-build-alt-command "cabal clean -s && cabal build --ghc-option=-ferror-spans" "Alternative build command to use when `haskell-cabal-build' is called with a negative prefix argument. For legacy compat, `%s' is replaced by the cabal package top folder." :group 'haskell-compile :type 'string) (defcustom haskell-compile-stack-build-command "stack build --fast" "Default build command to use for `haskell-stack-build' when a stack file is detected. For legacy compat, `%s' is replaced by the stack package top folder." :group 'haskell-compile :type 'string) (defcustom haskell-compile-stack-build-alt-command "stack clean && stack build --fast" "Alternative build command to use when `haskell-stack-build' is called with a negative prefix argument. For legacy compat, `%s' is replaced by the stack package top folder." :group 'haskell-compile :type 'string) (defcustom haskell-compile-command "ghc -Wall -ferror-spans -fforce-recomp -c %s" "Default build command to use for `haskell-cabal-build' when no cabal file is detected. The `%s' placeholder is replaced by the current buffer's filename." :group 'haskell-compile :type 'string) (defcustom haskell-compile-ghc-filter-linker-messages t "Filter out unremarkable \"Loading package...\" linker messages during compilation." :group 'haskell-compile :type 'boolean) (defcustom haskell-compile-ignore-cabal nil "Ignore cabal build definitions files for this buffer when detecting the build tool." :group 'haskell-compile :type 'boolean) (make-variable-buffer-local 'haskell-compile-ignore-cabal) (put 'haskell-compile-ignore-cabal 'safe-local-variable #'booleanp) (defconst haskell-compilation-error-regexp-alist `((,(concat "^ *\\(?1:[^\t\r\n]+?\\):" "\\(?:" "\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)\\(?:-\\(?5:[0-9]+\\)\\)?" ;; "121:1" & "12:3-5" "\\|" "(\\(?2:[0-9]+\\),\\(?4:[0-9]+\\))-(\\(?3:[0-9]+\\),\\(?5:[0-9]+\\))" ;; "(289,5)-(291,36)" "\\)" ":\\(?6:\n?[ \t]+[Ww]arning:\\)?") 1 (2 . 3) (4 . 5) (6 . nil)) ;; error/warning locus ;; multiple declarations ("^ \\(?:Declared at:\\| \\) \\(?1:[^ \t\r\n]+\\):\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)$" 1 2 4 0) ;; info locus ;; failed tasty tests (".*error, called at \\(.*\\.hs\\):\\([0-9]+\\):\\([0-9]+\\) in .*" 1 2 3 2 1) (" +\\(.*\\.hs\\):\\([0-9]+\\):$" 1 2 nil 2 1) ;; this is the weakest pattern as it's subject to line wrapping et al. (" at \\(?1:[^ \t\r\n]+\\):\\(?2:[0-9]+\\):\\(?4:[0-9]+\\)\\(?:-\\(?5:[0-9]+\\)\\)?[)]?$" 1 2 (4 . 5) 0)) ;; info locus "Regexps used for matching GHC compile messages. See `compilation-error-regexp-alist' for semantics.") (defvar haskell-compilation-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map compilation-mode-map)) "Keymap for `haskell-compilation-mode' buffers. This is a child of `compilation-mode-map'.") (defun haskell-compilation-filter-hook () "Local `compilation-filter-hook' for `haskell-compilation-mode'." (when haskell-compile-ghc-filter-linker-messages (delete-matching-lines "^ *Loading package [^ \t\r\n]+ [.]+ linking [.]+ done\\.$" (save-excursion (goto-char compilation-filter-start) (line-beginning-position)) (point))) (let ((inhibit-read-only t)) (ansi-color-apply-on-region compilation-filter-start (point-max)))) (define-compilation-mode haskell-compilation-mode "HsCompilation" "Haskell/GHC specific `compilation-mode' derivative. This mode provides support for GHC 7.[46]'s compile messages. Specifically, also the `-ferror-spans` source location format is supported, as well as info-locations within compile messages pointing to additional source locations." (setq-local compilation-error-regexp-alist haskell-compilation-error-regexp-alist) (add-hook 'compilation-filter-hook 'haskell-compilation-filter-hook nil t) ) ;;;###autoload (defun haskell-compile (&optional edit-command) "Run a compile command for the current Haskell buffer. Locates stack or cabal definitions and, if found, invokes the default build command for that build tool. Cabal is preferred but may be ignored with `haskell-compile-ignore-cabal'. If prefix argument EDIT-COMMAND is non-nil (and not a negative prefix `-'), prompt for a custom compile command. If EDIT-COMMAND contains the negative prefix argument `-', call the alternative command defined in `haskell-compile-stack-build-alt-command' / `haskell-compile-cabal-build-alt-command'. If there is no prefix argument, the most recent custom compile command is used, falling back to `haskell-compile-stack-build-command' for stack builds `haskell-compile-cabal-build-command' for cabal builds, and `haskell-compile-command' otherwise. '% characters in the `-command' templates are replaced by the base directory for build tools, or the current buffer for `haskell-compile-command'." (interactive "P") (save-some-buffers (not compilation-ask-about-save) compilation-save-buffers-predicate) (let ((cabaldir (and (not haskell-compile-ignore-cabal) (or (haskell-cabal-find-dir) (locate-dominating-file default-directory "cabal.project") (locate-dominating-file default-directory "cabal.project.local"))))) (if cabaldir (haskell--compile cabaldir edit-command 'haskell--compile-cabal-last haskell-compile-cabal-build-command haskell-compile-cabal-build-alt-command) (let ((stackdir (and haskell-compile-ignore-cabal (locate-dominating-file default-directory "stack.yaml")))) (if stackdir (haskell--compile stackdir edit-command 'haskell--compile-stack-last haskell-compile-stack-build-command haskell-compile-stack-build-alt-command) (let ((srcfile (buffer-file-name))) (haskell--compile srcfile edit-command 'haskell--compile-ghc-last haskell-compile-command haskell-compile-command))))))) (defvar haskell--compile-stack-last nil) (defvar haskell--compile-cabal-last nil) (defvar haskell--compile-ghc-last nil) (defun haskell--compile (dir-or-file edit last-sym fallback alt) (let* ((default (or (symbol-value last-sym) fallback)) (template (cond ((null edit) default) ((< edit 0) alt) (t (compilation-read-command default)))) (command (format template dir-or-file)) (dir (if (directory-name-p dir-or-file) dir-or-file default-directory)) (name (if (directory-name-p dir-or-file) (file-name-base (directory-file-name dir-or-file)) (file-name-nondirectory dir-or-file)))) (unless (eq edit'-) (set last-sym template)) (let ((default-directory dir)) (compilation-start command 'haskell-compilation-mode (lambda (mode) (format "*%s* <%s>" mode name)))))) (provide 'haskell-compile) ;;; haskell-compile.el ends here �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-complete-module.el��������������������������������������������������������0000664�0000000�0000000�00000011472�13602233217�0021051�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-complete-module.el --- A fast way to complete Haskell module names -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'cl-lib) (defcustom haskell-complete-module-preferred '() "Override ordering of module results by specifying preferred modules." :group 'haskell :type '(repeat string)) (defcustom haskell-complete-module-max-display 10 "Maximum items to display in minibuffer." :group 'haskell :type 'number) (defun haskell-complete-module-read (prompt candidates) "Interactively auto-complete from a list of candidates." (let ((stack (list)) (pattern "") (result nil)) (delete-dups candidates) (setq candidates (sort candidates (lambda (a b) (let ((a-mem (member a haskell-complete-module-preferred)) (b-mem (member b haskell-complete-module-preferred))) (cond ((and a-mem (not b-mem)) t) ((and b-mem (not a-mem)) nil) (t (string< a b))))))) (while (not result) (let ((key (key-description (vector (read-key (concat (propertize prompt 'face 'minibuffer-prompt) (propertize pattern 'face 'font-lock-type-face) "{" (mapconcat #'identity (let* ((i 0)) (cl-loop for candidate in candidates while (<= i haskell-complete-module-max-display) do (cl-incf i) collect (cond ((> i haskell-complete-module-max-display) "...") ((= i 1) (propertize candidate 'face 'ido-first-match-face)) (t candidate)))) " | ") "}")))))) (cond ((string= key "C-g") (keyboard-quit)) ((string= key "DEL") (unless (null stack) (setq candidates (pop stack))) (unless (string= "" pattern) (setq pattern (substring pattern 0 -1)))) ((string= key "RET") (setq result (or (car candidates) pattern))) ((string= key "<left>") (setq candidates (append (last candidates) (butlast candidates)))) ((string= key "<right>") (setq candidates (append (cdr candidates) (list (car candidates))))) (t (when (string-match "[A-Za-z0-9_'.]+" key) (push candidates stack) (setq pattern (concat pattern key)) (setq candidates (haskell-complete-module pattern candidates))))))) result)) (defun haskell-complete-module (pattern candidates) "Filter the CANDIDATES using PATTERN." (let ((case-fold-search t)) (cl-loop for candidate in candidates when (haskell-complete-module-match pattern candidate) collect candidate))) (defun haskell-complete-module-match (pattern text) "Match PATTERN against TEXT." (string-match (haskell-complete-module-regexp pattern) text)) (defun haskell-complete-module-regexp (pattern) "Make a regular expression for the given module pattern. Example: \"c.m.s\" -> \"^c[^.]*\\.m[^.]*\\.s[^.]*\" " (let ((components (mapcar #'haskell-complete-module-component (split-string pattern "\\." t)))) (concat "^" (mapconcat #'identity components "\\.")))) (defun haskell-complete-module-component (component) "Make a regular expression for the given component. Example: \"co\" -> \"c[^.]*o[^.]*\" " (replace-regexp-in-string "\\(.\\)" "\\1[^.]*" component)) (provide 'haskell-complete-module) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-completions.el������������������������������������������������������������0000664�0000000�0000000�00000036556�13602233217�0020324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-completions.el --- Haskell Completion package -*- lexical-binding: t -*- ;; Copyright © 2015-2016 Athur Fayzrakhmanov. All rights reserved. ;; This file is part of haskell-mode package. ;; You can contact with authors using GitHub issue tracker: ;; https://github.com/haskell/haskell-mode/issues ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This package provides completions related functionality for ;; Haskell Mode such grab completion prefix at point, and etc.. ;; Some description ;; ================ ;; ;; For major use function `haskell-completions-grab-prefix' is supposed, and ;; other prefix grabbing functions are used internally by it. So, only this ;; funciton have prefix minimal length functionality and invokes predicate ;; function `haskell-completions-can-grab-prefix'. ;;; Code: (require 'haskell-mode) (require 'haskell-process) (require 'haskell-interactive-mode) ;;;###autoload (defgroup haskell-completions nil "Settings for completions provided by `haskell-mode'" :link '(custom-manual "(haskell-mode)Completion support") :group 'haskell) (defcustom haskell-completions-complete-operators t "Should `haskell-completions-sync-repl-completion-at-point' complete operators. Note: GHCi prior to version 8.0.1 have bug in `:complete` command: when completing operators it returns a list of all imported identifiers (see Track ticket URL `https://ghc.haskell.org/trac/ghc/ticket/10576'). This leads to significant Emacs slowdown. To aviod slowdown you should set this variable to `nil'." :group 'haskell-completions :type 'boolean) (defvar haskell-completions--pragma-names (list "DEPRECATED" "INCLUDE" "INCOHERENT" "INLINABLE" "INLINE" "LANGUAGE" "LINE" "MINIMAL" "NOINLINE" "NOUNPACK" "OPTIONS" "OPTIONS_GHC" "OVERLAPPABLE" "OVERLAPPING" "OVERLAPS" "RULES" "SOURCE" "SPECIALIZE" "UNPACK" "WARNING") "A list of supported pragmas. This list comes from GHC documentation (URL `https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/pragmas.html'.") (defvar haskell-completions--keywords (list "as" "case" "class" "data family" "data instance" "data" "default" "deriving instance" "deriving" "do" "else" "family" "forall" "foreign import" "foreign" "hiding" "if" "import qualified" "import" "in" "infix" "infixl" "infixr" "instance" "let" "mdo" "module" "newtype" "of" "proc" "qualified" "rec" "signature" "then" "type family" "type instance" "type" "where") "A list of Haskell's keywords (URL `https://wiki.haskell.org/Keywords'). Single char keywords and operator like keywords are not included in this list.") (defun haskell-completions-can-grab-prefix () "Check if the case is appropriate for grabbing completion prefix. Returns t if point is either at whitespace character, or at punctuation, or at line end and preceding character is not a whitespace or new line, otherwise returns nil. Returns nil in presence of active region." (when (not (region-active-p)) (when (looking-at-p (rx (| space line-end punct))) (when (not (bobp)) (save-excursion (backward-char) (not (looking-at-p (rx (| space line-end))))))))) (defun haskell-completions-grab-pragma-prefix () "Grab completion prefix for pragma completions. Returns a list of form '(prefix-start-position prefix-end-position prefix-value prefix-type) for pramga names such as WARNING, DEPRECATED, LANGUAGE etc. Also returns completion prefixes for options in case OPTIONS_GHC pragma, or language extensions in case of LANGUAGE pragma. Obsolete OPTIONS pragma is supported also." (when (nth 4 (syntax-ppss)) ;; We're inside comment (let ((p (point)) (comment-start (nth 8 (syntax-ppss))) (case-fold-search nil) prefix-start prefix-end prefix-type prefix-value) (save-excursion (goto-char comment-start) (when (looking-at (rx "{-#" (1+ (| space "\n")))) (let ((pragma-start (match-end 0))) (when (> p pragma-start) ;; point stands after `{-#` (goto-char pragma-start) (when (looking-at (rx (1+ (| upper "_")))) ;; found suitable sequence for pragma name (let ((pragma-end (match-end 0)) (pragma-value (match-string-no-properties 0))) (if (eq p pragma-end) ;; point is at the end of (in)complete pragma name ;; prepare resulting values (progn (setq prefix-start pragma-start) (setq prefix-end pragma-end) (setq prefix-value pragma-value) (setq prefix-type 'haskell-completions-pragma-name-prefix)) (when (and (> p pragma-end) (or (equal "OPTIONS_GHC" pragma-value) (equal "OPTIONS" pragma-value) (equal "LANGUAGE" pragma-value))) ;; point is after pragma name, so we need to check ;; special cases of `OPTIONS_GHC` and `LANGUAGE` pragmas ;; and provide a completion prefix for possible ghc ;; option or language extension. (goto-char pragma-end) (when (re-search-forward (rx (* anything) (1+ (regexp "\\S-"))) p t) (let* ((str (match-string-no-properties 0)) (split (split-string str (rx (| space "\n")) t)) (val (car (last split))) (end (point))) (when (and (equal p end) (not (string-match-p "#" val))) (setq prefix-value val) (backward-char (length val)) (setq prefix-start (point)) (setq prefix-end end) (setq prefix-type (if (not (equal "LANGUAGE" pragma-value)) 'haskell-completions-ghc-option-prefix 'haskell-completions-language-extension-prefix ))))))))))))) (when prefix-value (list prefix-start prefix-end prefix-value prefix-type))))) (defun haskell-completions-grab-identifier-prefix () "Grab completion prefix for identifier at point. Returns a list of form '(prefix-start-position prefix-end-position prefix-value prefix-type) for haskell identifier at point depending on result of function `haskell-ident-pos-at-point'." (let ((pos-at-point (haskell-ident-pos-at-point)) (p (point))) (when pos-at-point (let* ((start (car pos-at-point)) (end (cdr pos-at-point)) (type 'haskell-completions-identifier-prefix) (case-fold-search nil) value) ;; we need end position of result, becase of ;; `haskell-ident-pos-at-point' ignores trailing whitespace, e.g. the ;; result will be same for `map|` and `map |` invocations. (when (<= p end) (setq end p) (setq value (buffer-substring-no-properties start end)) (when (string-match-p (rx bos upper) value) ;; we need to check if found identifier is a module name (save-excursion (goto-char (line-beginning-position)) (when (re-search-forward (rx "import" (? (1+ space) "qualified") (1+ space) upper (1+ (| alnum "."))) p ;; bound t) ;; no-error (if (equal p (point)) (setq type 'haskell-completions-module-name-prefix) (when (re-search-forward (rx (| " as " "(")) start t) ;; but uppercase ident could occur after `as` keyword, or in ;; module imports after opening parenthesis, in this case ;; restore identifier type again, it's necessary to ;; distinguish the means of completions retrieval (setq type 'haskell-completions-identifier-prefix)))))) (when (nth 8 (syntax-ppss)) ;; eighth element of syntax-ppss result is string or comment start, ;; so when it's not nil word at point is inside string or comment, ;; return special literal prefix type (setq type 'haskell-completions-general-prefix)) ;; finally take in account minlen if given and return the result (when value (list start end value type))))))) (defun haskell-completions-grab-prefix (&optional minlen) "Grab prefix at point for possible completion. Returns a list of form '(prefix-start-position prefix-end-position prefix-value prefix-type) depending on situation, e.g. is it needed to complete pragma, module name, arbitrary identifier, etc. Returns nil in case it is impossible to grab prefix. Possible prefix types are: * haskell-completions-pragma-name-prefix * haskell-completions-ghc-option-prefix * haskell-completions-language-extension-prefix * haskell-completions-module-name-prefix * haskell-completions-identifier-prefix * haskell-completions-general-prefix the last type is used in cases when completing things inside comments. If provided optional MINLEN parameter this function will return result only if prefix length is not less than MINLEN." (when (haskell-completions-can-grab-prefix) (let ((prefix (cond ((haskell-completions-grab-pragma-prefix)) ((haskell-completions-grab-identifier-prefix))))) (cond ((and minlen prefix) (when (>= (length (nth 2 prefix)) minlen) prefix)) (prefix prefix))))) (defun haskell-completions--simple-completions (prefix) "Provide a list of completion candidates for given PREFIX. This function is used internally in `haskell-completions-completion-at-point' and `haskell-completions-sync-repl-completion-at-point'. It provides completions for haskell keywords, language pragmas, GHC's options, and language extensions. PREFIX should be a list such one returned by `haskell-completions-grab-identifier-prefix'." (cl-destructuring-bind (beg end _pfx typ) prefix (when (not (eql typ 'haskell-completions-general-prefix)) (let ((candidates (cl-case typ ('haskell-completions-pragma-name-prefix haskell-completions--pragma-names) ('haskell-completions-ghc-option-prefix haskell-ghc-supported-options) ('haskell-completions-language-extension-prefix haskell-ghc-supported-extensions) (otherwise (append (when (bound-and-true-p haskell-tags-on-save) tags-completion-table) haskell-completions--keywords))))) (list beg end candidates))))) ;;;###autoload (defun haskell-completions-completion-at-point () "Provide completion list for thing at point. This function is used in non-interactive `haskell-mode'. It provides completions for haskell keywords, language pragmas, GHC's options, and language extensions, but not identifiers." (let ((prefix (haskell-completions-grab-prefix))) (when prefix (haskell-completions--simple-completions prefix)))) (defun haskell-completions-sync-repl-completion-at-point () "A completion function used in `interactive-haskell-mode'. Completion candidates are provided quering current haskell process, that is sending `:complete repl' command. Completes all possible things: everything that can be completed with non-interactive function `haskell-completions-completion-at-point' plus identifier completions. Returns nil if no completions available." (let ((prefix-data (haskell-completions-grab-prefix))) (when prefix-data (cl-destructuring-bind (beg end pfx typ) prefix-data (when (and (not (eql typ 'haskell-completions-general-prefix)) (or haskell-completions-complete-operators (not (save-excursion (goto-char (1- end)) (haskell-mode--looking-at-varsym))))) ;; do not complete things in comments (if (cl-member typ '(haskell-completions-pragma-name-prefix haskell-completions-ghc-option-prefix haskell-completions-language-extension-prefix)) ;; provide simple completions (haskell-completions--simple-completions prefix-data) ;; only two cases left: haskell-completions-module-name-prefix ;; and haskell-completions-identifier-prefix (let* ((is-import (eql typ 'haskell-completions-module-name-prefix)) (candidates (when (and (haskell-session-maybe) (not (haskell-process-cmd (haskell-interactive-process))) ;; few possible extra checks would be: ;; (haskell-process-get 'is-restarting) ;; (haskell-process-get 'evaluating) ) ;; if REPL is available and not busy try to query it for ;; completions list in case of module name or identifier ;; prefixes (haskell-completions-sync-complete-repl pfx is-import)))) ;; append candidates with keywords (list beg end (append candidates haskell-completions--keywords))))))))) (defun haskell-completions-sync-complete-repl (prefix &optional import) "Return completion list for given PREFIX querying REPL synchronously. When optional IMPORT argument is non-nil complete PREFIX prepending \"import \" keyword (useful for module names). This function is supposed for internal use." (haskell-process-get-repl-completions (haskell-interactive-process) (if import (concat "import " prefix) prefix))) (provide 'haskell-completions) ;;; haskell-completions.el ends here ��������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-customize.el��������������������������������������������������������������0000664�0000000�0000000�00000036723�13602233217�0020006�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-customize.el --- Customization settings -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'cl-lib) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Customization variables (defcustom haskell-process-load-or-reload-prompt nil "Nil means there will be no prompts on starting REPL. Defaults will be accepted." :type 'boolean :group 'haskell-interactive) ;;;###autoload (defgroup haskell nil "Major mode for editing Haskell programs." :link '(custom-manual "(haskell-mode)") :group 'languages :prefix "haskell-") (defvar haskell-mode-pkg-base-dir (file-name-directory load-file-name) "Package base directory of installed `haskell-mode'. Used for locating additional package data files.") (defcustom haskell-completing-read-function 'ido-completing-read "Default function to use for completion." :group 'haskell :type '(choice (function-item :tag "ido" :value ido-completing-read) (function-item :tag "helm" :value helm--completing-read-default) (function-item :tag "completing-read" :value completing-read) (function :tag "Custom function"))) (defcustom haskell-process-type 'auto "The inferior Haskell process type to use. When set to 'auto (the default), the directory contents and available programs will be used to make a best guess at the process type: If the project directory or one of its parents contains a \"cabal.sandbox.config\" file, then cabal-repl will be used. If there's a \"stack.yaml\" file and the \"stack\" executable can be located, then stack-ghci will be used. Otherwise if there's a *.cabal file, cabal-repl will be used. If none of the above apply, ghci will be used." :type '(choice (const auto) (const ghci) (const cabal-repl) (const stack-ghci) (const cabal-new-repl)) :group 'haskell-interactive) (defcustom haskell-process-wrapper-function #'identity "Wrap or transform haskell process commands using this function. Can be set to a custom function which takes a list of arguments and returns a possibly-modified list. The following example function arranges for all haskell process commands to be started in the current nix-shell environment: (lambda (argv) (append (list \"nix-shell\" \"-I\" \".\" \"--command\" ) (list (mapconcat 'identity argv \" \")))) See Info Node `(emacs)Directory Variables' for a way to set this option on a per-project basis." :group 'haskell-interactive :type '(choice (function-item :tag "None" :value identity) (function :tag "Custom function"))) (defcustom haskell-ask-also-kill-buffers t "Ask whether to kill all associated buffers when a session process is killed." :type 'boolean :group 'haskell-interactive) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Configuration (defcustom haskell-doc-prettify-types t "Replace some parts of types with Unicode characters like \"∷\" when showing type information about symbols." :group 'haskell-doc :type 'boolean :safe 'booleanp) (defvar haskell-process-ended-functions (list 'haskell-process-prompt-restart) "Hook for when the haskell process ends.") ;;;###autoload (defgroup haskell-interactive nil "Settings for REPL interaction via `haskell-interactive-mode'" :link '(custom-manual "(haskell-mode)haskell-interactive-mode") :group 'haskell) (defcustom haskell-process-path-ghci "ghci" "The path for starting ghci. This can either be a single string or a list of strings, where the first elements is a string and the remaining elements are arguments, which will be prepended to `haskell-process-args-ghci'." :group 'haskell-interactive :type '(choice string (repeat string))) (defcustom haskell-process-path-cabal "cabal" "Path to the `cabal' executable. This can either be a single string or a list of strings, where the first elements is a string and the remaining elements are arguments, which will be prepended to `haskell-process-args-cabal-repl'." :group 'haskell-interactive :type '(choice string (repeat string))) (defcustom haskell-process-path-stack "stack" "The path for starting stack. This can either be a single string or a list of strings, where the first elements is a string and the remaining elements are arguments, which will be prepended to `haskell-process-args-stack-ghci'." :group 'haskell-interactive :type '(choice string (repeat string))) (defcustom haskell-process-args-ghci '("-ferror-spans") "Any arguments for starting ghci." :group 'haskell-interactive :type '(repeat (string :tag "Argument"))) (defcustom haskell-process-args-cabal-repl '("--ghc-option=-ferror-spans") "Additional arguments for `cabal repl' invocation. Note: The settings in `haskell-process-path-ghci' and `haskell-process-args-ghci' are not automatically reused as `cabal repl' currently invokes `ghc --interactive'. Use `--with-ghc=<path-to-executable>' if you want to use a different interactive GHC frontend; use `--ghc-option=<ghc-argument>' to pass additional flags to `ghc'." :group 'haskell-interactive :type '(repeat (string :tag "Argument"))) (defcustom haskell-process-args-cabal-new-repl '("--ghc-option=-ferror-spans") "Additional arguments for `cabal new-repl' invocation. Note: The settings in `haskell-process-path-ghci' and `haskell-process-args-ghci' are not automatically reused as `cabal new-repl' currently invokes `ghc --interactive'. Use `--with-ghc=<path-to-executable>' if you want to use a different interactive GHC frontend; use `--ghc-option=<ghc-argument>' to pass additional flags to `ghc'." :group 'haskell-interactive :type '(repeat (string :tag "Argument"))) (defcustom haskell-process-args-stack-ghci '("--ghci-options=-ferror-spans" "--no-build" "--no-load") "Additional arguments for `stack ghci' invocation." :group 'haskell-interactive :type '(repeat (string :tag "Argument"))) (defcustom haskell-process-do-cabal-format-string ":!cd %s && %s" "The way to run cabal comands. It takes two arguments -- the directory and the command. See `haskell-process-do-cabal' for more details." :group 'haskell-interactive :type 'string) (defcustom haskell-process-log nil "Enable debug logging to \"*haskell-process-log*\" buffer." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-show-debug-tips t "Show debugging tips when starting the process." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-show-overlays t "Show in-buffer overlays for errors/warnings. Flycheck users might like to disable this." :type 'boolean :group 'haskell-interactive) (defcustom haskell-notify-p nil "Notify using notifications.el (if loaded)?" :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-no-warn-orphans t "Suggest adding -fno-warn-orphans pragma to file when getting orphan warnings." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-hoogle-imports nil "Suggest to add import statements using Hoogle as a backend." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-hayoo-imports nil "Suggest to add import statements using Hayoo as a backend." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-hayoo-query-url "http://hayoo.fh-wedel.de/json/?query=%s" "Query url for json hayoo results." :type 'string :group 'haskell-interactive) (defcustom haskell-process-suggest-haskell-docs-imports nil "Suggest to add import statements using haskell-docs as a backend." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-add-package t "Suggest to add packages to your .cabal file when Cabal says it is a member of the hidden package, blah blah." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-language-pragmas t "Suggest adding LANGUAGE pragmas recommended by GHC." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-remove-import-lines nil "Suggest removing import lines as warned by GHC." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-overloaded-strings t "Suggest adding OverloadedStrings pragma to file when getting type mismatches with [Char]." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-check-cabal-config-on-load t "Check changes cabal config on loading Haskell files and restart the GHCi process if changed.." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-prompt-restart-on-cabal-change t "Ask whether to restart the GHCi process when the Cabal file has changed?" :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-auto-import-loaded-modules nil "Auto import the modules reported by GHC to have been loaded?" :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-reload-with-fbytecode nil "When using -fobject-code, auto reload with -fbyte-code (and then restore the -fobject-code) so that all module info and imports become available?" :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-use-presentation-mode nil "Use presentation mode to show things like type info instead of printing to the message area." :type 'boolean :group 'haskell-interactive) (defcustom haskell-process-suggest-restart t "Suggest restarting the process when it has died" :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-popup-errors t "Popup errors in a separate buffer." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-mode-collapse nil "Collapse printed results." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-types-for-show-ambiguous t "Show types when there's no Show instance or there's an ambiguous class constraint." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-prompt "λ> " "The prompt to use." :type 'string :group 'haskell-interactive) (define-obsolete-variable-alias 'haskell-interactive-prompt2 'haskell-interactive-prompt-cont "17.1") (defcustom haskell-interactive-prompt-cont (replace-regexp-in-string "> $" "| " haskell-interactive-prompt) "The multi-line prompt to use. The default is `haskell-interactive-prompt' with the last > replaced with |." :type 'string :group 'haskell-interactive) (defcustom haskell-interactive-mode-eval-mode nil "Use the given mode's font-locking to render some text." :type '(choice function (const :tag "None" nil)) :group 'haskell-interactive) (defcustom haskell-interactive-mode-hide-multi-line-errors nil "Hide collapsible multi-line compile messages by default." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-mode-delete-superseded-errors t "Whether to delete compile messages superseded by recompile/reloads." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-mode-include-file-name t "Include the file name of the module being compiled when printing compilation messages." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-mode-read-only t "Non-nil means most GHCi/haskell-interactive-mode output is read-only. This does not include the prompt. Configure `haskell-interactive-prompt-read-only' to change the prompt's read-only property." :type 'boolean :group 'haskell-interactive) (defcustom haskell-interactive-prompt-read-only haskell-interactive-mode-read-only "Non-nil means the prompt (and prompt2) is read-only." :type 'boolean :group 'haskell-interactive) (defcustom haskell-import-mapping '() "Support a mapping from module to import lines. E.g. '((\"Data.Map\" . \"import qualified Data.Map as M import Data.Map (Map) \")) This will import import qualified Data.Map as M import Data.Map (Map) when Data.Map is the candidate. " :type '(repeat (cons (string :tag "Module name") (string :tag "Import lines"))) :group 'haskell-interactive) (defcustom haskell-language-extensions '() "Language extensions in use. Should be in format: -XFoo, -XNoFoo etc. The idea is that various tools written with HSE (or any haskell-mode code that needs to be aware of syntactical properties; such as an indentation mode) that don't know what extensions to use can use this variable. Examples: hlint, hindent, structured-haskell-mode, tool-de-jour, etc. You can set this per-project with a .dir-locals.el file" :group 'haskell :type '(repeat 'string)) (defcustom haskell-stylish-on-save nil "Whether to run stylish-haskell on the buffer before saving. If this is true, `haskell-add-import' will not sort or align the imports." :group 'haskell :type 'boolean) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Accessor functions (defvar inferior-haskell-root-dir nil "The path which is considered as project root, this is determined by the presence of a *.cabal file or stack.yaml file or something similar.") (defun haskell-process-type () "Return `haskell-process-type', or a guess if that variable is 'auto. This function also sets the `inferior-haskell-root-dir'" (let ((cabal-sandbox (locate-dominating-file default-directory "cabal.sandbox.config")) (stack (locate-dominating-file default-directory "stack.yaml")) (cabal (locate-dominating-file default-directory (lambda (d) (cl-find-if (lambda (f) (string-match-p ".\\.cabal\\'" f)) (directory-files d)))))) (if (eq 'auto haskell-process-type) (cond ;; User has explicitly initialized this project with cabal ((and cabal-sandbox (executable-find "cabal")) (setq inferior-haskell-root-dir cabal-sandbox) 'cabal-repl) ((and stack (executable-find "stack")) (setq inferior-haskell-root-dir stack) 'stack-ghci) ((and cabal (executable-find "cabal")) (setq inferior-haskell-root-dir cabal) 'cabal-repl) ((executable-find "ghc") (setq inferior-haskell-root-dir default-directory) 'ghci) ((executable-find "stack") (setq inferior-haskell-root-dir default-directory) 'stack-ghci) (t (error "Could not find any installation of GHC."))) haskell-process-type))) (provide 'haskell-customize) ���������������������������������������������haskell-mode-17.1/haskell-debug.el������������������������������������������������������������������0000664�0000000�0000000�00000066342�13602233217�0017052�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-debug.el --- Debugging mode via GHCi -*- lexical-binding: t -*- ;; Copyright © 2014 Chris Done. All rights reserved. ;; 2016 Arthur Fayzrakhmanov ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'cl-lib) (require 'haskell-session) (require 'haskell-process) (require 'haskell-interactive-mode) (require 'haskell-font-lock) (require 'haskell-utils) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Configuration ;;;###autoload (defgroup haskell-debug nil "Settings for debugging support." :link '(custom-manual "(haskell-mode)haskell-debug") :group 'haskell) ;;;###autoload (defface haskell-debug-warning-face '((t :inherit 'compilation-warning)) "Face for warnings." :group 'haskell-debug) ;;;###autoload (defface haskell-debug-trace-number-face '((t :weight bold :background "#f5f5f5")) "Face for numbers in backtrace." :group 'haskell-debug) ;;;###autoload (defface haskell-debug-newline-face '((t :weight bold :background "#f0f0f0")) "Face for newlines in trace steps." :group 'haskell-debug) ;;;###autoload (defface haskell-debug-keybinding-face '((t :inherit 'font-lock-type-face :weight bold)) "Face for keybindings." :group 'haskell-debug) ;;;###autoload (defface haskell-debug-heading-face '((t :inherit 'font-lock-keyword-face)) "Face for headings." :group 'haskell-debug) ;;;###autoload (defface haskell-debug-muted-face '((t :foreground "#999")) "Face for muteds." :group 'haskell-debug) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Mode (defvar haskell-debug-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "g") 'haskell-debug/refresh) (define-key map (kbd "s") 'haskell-debug/step) (define-key map (kbd "t") 'haskell-debug/trace) (define-key map (kbd "d") 'haskell-debug/delete) (define-key map (kbd "b") 'haskell-debug/break-on-function) (define-key map (kbd "a") 'haskell-debug/abandon) (define-key map (kbd "c") 'haskell-debug/continue) (define-key map (kbd "p") 'haskell-debug/previous) (define-key map (kbd "n") 'haskell-debug/next) (define-key map (kbd "RET") 'haskell-debug/select) map) "Keymap for `haskell-debug-mode'.") (define-derived-mode haskell-debug-mode text-mode "Debug" "Major mode for debugging Haskell via GHCi.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Globals (defvar haskell-debug-history-cache nil "Cache of the tracing history.") (defvar haskell-debug-bindings-cache nil "Cache of the current step's bindings.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Macros (defmacro haskell-debug-with-breakpoints (&rest body) "Breakpoints need to exist to start stepping." `(if (haskell-debug-get-breakpoints) ,@body (error "No breakpoints to step into!"))) (defmacro haskell-debug-with-modules (&rest body) "Modules need to exist to do debugging stuff." `(if (haskell-debug-get-modules) ,@body (error "No modules loaded!"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Interactive functions (defun haskell-debug/select () "Select whatever is at point." (interactive) (cond ((get-text-property (point) 'break) (let ((break (get-text-property (point) 'break))) (haskell-debug-highlight (plist-get break :path) (plist-get break :span)))) ((get-text-property (point) 'module) (let ((break (get-text-property (point) 'module))) (haskell-debug-highlight (plist-get break :path)))))) (defun haskell-debug/abandon () "Abandon the current computation." (interactive) (haskell-debug-with-breakpoints (haskell-process-queue-sync-request (haskell-debug-process) ":abandon") (message "Computation abandoned.") (setq haskell-debug-history-cache nil) (setq haskell-debug-bindings-cache nil) (haskell-debug/refresh))) (defun haskell-debug/continue () "Continue the current computation." (interactive) (haskell-debug-with-breakpoints (haskell-process-queue-sync-request (haskell-debug-process) ":continue") (message "Computation continued.") (setq haskell-debug-history-cache nil) (setq haskell-debug-bindings-cache nil) (haskell-debug/refresh))) (defun haskell-debug/break-on-function () "Break on function IDENT." (interactive) (haskell-debug-with-modules (let ((ident (read-from-minibuffer "Function: " (haskell-ident-at-point)))) (haskell-process-queue-sync-request (haskell-debug-process) (concat ":break " ident)) (message "Breaking on function: %s" ident) (haskell-debug/refresh)))) (defun haskell-debug/start-step (expr) "Start stepping EXPR." (interactive (list (read-from-minibuffer "Expression to step through: "))) (haskell-debug/step expr)) (defun haskell-debug/breakpoint-numbers () "List breakpoint numbers." (interactive) (let ((breakpoints (mapcar (lambda (breakpoint) (number-to-string (plist-get breakpoint :number))) (haskell-debug-get-breakpoints)))) (if (null breakpoints) (message "No breakpoints.") (message "Breakpoint(s): %s" (mapconcat #'identity breakpoints ", "))))) (defun haskell-debug/next () "Go to next step to inspect bindings." (interactive) (haskell-debug-with-breakpoints (haskell-debug-navigate "forward"))) (defun haskell-debug/previous () "Go to previous step to inspect the bindings." (interactive) (haskell-debug-with-breakpoints (haskell-debug-navigate "back"))) (defun haskell-debug/refresh () "Refresh the debugger buffer." (interactive) (with-current-buffer (haskell-debug-buffer-name (haskell-debug-session)) (cd (haskell-session-current-dir (haskell-debug-session))) (let ((inhibit-read-only t) (p (point))) (erase-buffer) (insert (propertize (concat "Debugging " (haskell-session-name (haskell-debug-session)) "\n\n") 'face `((:weight bold)))) (let ((modules (haskell-debug-get-modules)) (breakpoints (haskell-debug-get-breakpoints)) (context (haskell-debug-get-context)) (history (haskell-debug-get-history))) (unless modules (insert (propertize "You have to load a module to start debugging." 'face 'haskell-debug-warning-face) "\n\n")) (haskell-debug-insert-bindings modules breakpoints context) (when modules (haskell-debug-insert-current-context context history) (haskell-debug-insert-breakpoints breakpoints)) (haskell-debug-insert-modules modules)) (insert "\n") (goto-char (min (point-max) p))))) (defun haskell-debug/delete () "Delete whatever's at the point." (interactive) (cond ((get-text-property (point) 'break) (let ((break (get-text-property (point) 'break))) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (when (y-or-n-p (format "Delete breakpoint #%d?" (plist-get break :number))) (haskell-process-queue-sync-request (haskell-debug-process) (format ":delete %d" (plist-get break :number))) (haskell-debug/refresh)) (haskell-mode-toggle-interactive-prompt-state t)))))) (defun haskell-debug/trace () "Trace the expression." (interactive) (haskell-debug-with-modules (haskell-debug-with-breakpoints (let ((expr (read-from-minibuffer "Expression to trace: " (haskell-ident-at-point)))) (haskell-process-queue-sync-request (haskell-debug-process) (concat ":trace " expr)) (message "Tracing expression: %s" expr) (haskell-debug/refresh))))) (defun haskell-debug/step (&optional expr) "Step into the next function." (interactive) (haskell-debug-with-breakpoints (let* ((breakpoints (haskell-debug-get-breakpoints)) (context (haskell-debug-get-context)) (string (haskell-process-queue-sync-request (haskell-debug-process) (if expr (concat ":step " expr) ":step")))) (cond ((string= string "not stopped at a breakpoint\n") (if haskell-debug-bindings-cache (progn (setq haskell-debug-bindings-cache nil) (haskell-debug/refresh)) (call-interactively 'haskell-debug/start-step))) (t (let ((maybe-stopped-at (haskell-debug-parse-stopped-at string))) (cond (maybe-stopped-at (setq haskell-debug-bindings-cache maybe-stopped-at) (message "Computation paused.") (haskell-debug/refresh)) (t (if context (message "Computation finished.") (progn (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (when (y-or-n-p "Computation completed without breaking. Reload the module and retry?") (message "Reloading and resetting breakpoints...") (haskell-interactive-mode-reset-error (haskell-debug-session)) (cl-loop for break in breakpoints do (haskell-process-queue-sync-request (haskell-debug-process) (concat ":load " (plist-get break :path)))) (cl-loop for break in breakpoints do (haskell-debug-break break)) (haskell-debug/step expr)) (haskell-mode-toggle-interactive-prompt-state t)))))))))) (haskell-debug/refresh))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Internal functions (defun haskell-debug-session () "Get the Haskell session." (or (haskell-session-maybe) (error "No Haskell session associated with this debug buffer. Please just close the buffer and start again."))) (defun haskell-debug-process () "Get the Haskell session." (or (haskell-session-process (haskell-session-maybe)) (error "No Haskell session associated with this debug buffer. Please just close the buffer and start again."))) (defun haskell-debug-buffer-name (session) "The debug buffer name for the current session." (format "*debug:%s*" (haskell-session-name session))) (defun haskell-debug-get-breakpoints () "Get the list of breakpoints currently set." (let ((string (haskell-process-queue-sync-request (haskell-debug-process) ":show breaks"))) (if (string= string "No active breakpoints.\n") (list) (mapcar #'haskell-debug-parse-break-point (haskell-debug-split-string string))))) (defun haskell-debug-get-modules () "Get the list of modules currently set." (let ((string (haskell-process-queue-sync-request (haskell-debug-process) ":show modules"))) (if (string= string "") (list) (mapcar #'haskell-debug-parse-module (haskell-debug-split-string string))))) (defun haskell-debug-get-context () "Get the current context." (let ((string (haskell-process-queue-sync-request (haskell-debug-process) ":show context"))) (if (string= string "") nil (haskell-debug-parse-context string)))) (defun haskell-debug-get-history () "Get the step history." (let ((string (haskell-process-queue-sync-request (haskell-debug-process) ":history"))) (if (or (string= string "") (string= string "Not stopped at a breakpoint\n")) nil (if (string= string "Empty history. Perhaps you forgot to use :trace?\n") nil (let ((entries (mapcar #'haskell-debug-parse-history-entry (cl-remove-if (lambda (line) (or (string= "<end of history>" line) (string= "..." line))) (haskell-debug-split-string string))))) (setq haskell-debug-history-cache entries) entries))))) (defun haskell-debug-insert-bindings (modules breakpoints context) "Insert a list of bindings." (if breakpoints (progn (haskell-debug-insert-binding "t" "trace an expression") (haskell-debug-insert-binding "s" "step into an expression") (haskell-debug-insert-binding "b" "breakpoint" t)) (progn (when modules (haskell-debug-insert-binding "b" "breakpoint")) (when breakpoints (haskell-debug-insert-binding "s" "step into an expression" t)))) (when breakpoints (haskell-debug-insert-binding "d" "delete breakpoint")) (when context (haskell-debug-insert-binding "a" "abandon context") (haskell-debug-insert-binding "c" "continue" t)) (when context (haskell-debug-insert-binding "p" "previous step") (haskell-debug-insert-binding "n" "next step" t)) (haskell-debug-insert-binding "g" "refresh" t) (insert "\n")) (defun haskell-debug-insert-current-context (context history) "Insert the current context." (haskell-debug-insert-header "Context") (if context (haskell-debug-insert-context context history) (haskell-debug-insert-debug-finished)) (insert "\n")) (defun haskell-debug-insert-breakpoints (breakpoints) "insert the list of breakpoints." (haskell-debug-insert-header "Breakpoints") (if (null breakpoints) (haskell-debug-insert-muted "No active breakpoints.") (cl-loop for break in breakpoints do (insert (propertize (format "%d" (plist-get break :number)) 'face `((:weight bold)) 'break break) (haskell-debug-muted " - ") (propertize (plist-get break :module) 'break break 'break break) (haskell-debug-muted (format " (%d:%d)" (plist-get (plist-get break :span) :start-line) (plist-get (plist-get break :span) :start-col))) "\n"))) (insert "\n")) (defun haskell-debug-insert-modules (modules) "Insert the list of modules." (haskell-debug-insert-header "Modules") (if (null modules) (haskell-debug-insert-muted "No loaded modules.") (progn (cl-loop for module in modules do (insert (propertize (plist-get module :module) 'module module 'face `((:weight bold))) (haskell-debug-muted " - ") (propertize (file-name-nondirectory (plist-get module :path)) 'module module)) do (insert "\n"))))) (defun haskell-debug-split-string (string) "Split GHCi's line-based output, stripping the trailing newline." (split-string string "\n" t)) (defun haskell-debug-parse-context (string) "Parse the context." (cond ((string-match "^--> \\(.+\\)\n \\(.+\\)" string) (let ((name (match-string 1 string)) (stopped (haskell-debug-parse-stopped-at (match-string 2 string)))) (list :name name :path (plist-get stopped :path) :span (plist-get stopped :span)))))) (defun haskell-debug-insert-binding (binding desc &optional end) "Insert a helpful keybinding." (insert (propertize binding 'face 'haskell-debug-keybinding-face) (haskell-debug-muted " - ") desc (if end "\n" (haskell-debug-muted ", ")))) (defun haskell-debug-insert-header (title) "Insert a header title." (insert (propertize title 'face 'haskell-debug-heading-face) "\n\n")) (defun haskell-debug-insert-context (context history) "Insert the context and history." (when context (insert (propertize (plist-get context :name) 'face `((:weight bold))) (haskell-debug-muted " - ") (file-name-nondirectory (plist-get context :path)) (haskell-debug-muted " (stopped)") "\n")) (when haskell-debug-bindings-cache (insert "\n") (let ((bindings haskell-debug-bindings-cache)) (insert (haskell-debug-get-span-string (plist-get bindings :path) (plist-get bindings :span))) (insert "\n\n") (cl-loop for binding in (plist-get bindings :types) do (insert (haskell-fontify-as-mode binding 'haskell-mode) "\n")))) (let ((history (or history (list (haskell-debug-make-fake-history context))))) (when history (insert "\n") (haskell-debug-insert-history history)))) (defun haskell-debug-insert-debug-finished () "Insert message that no debugging is happening, but if there is some old history, then display that." (if haskell-debug-history-cache (progn (haskell-debug-insert-muted "Finished debugging.") (insert "\n") (haskell-debug-insert-history haskell-debug-history-cache)) (haskell-debug-insert-muted "Not debugging right now."))) (defun haskell-debug-insert-muted (text) "Insert some muted text." (insert (haskell-debug-muted text) "\n")) (defun haskell-debug-muted (text) "Make some muted text." (propertize text 'face 'haskell-debug-muted-face)) (defun haskell-debug-parse-logged (string) "Parse the logged breakpoint." (cond ((string= "no more logged breakpoints\n" string) nil) ((string= "already at the beginning of the history\n" string) nil) (t (with-temp-buffer (insert string) (goto-char (point-min)) (list :path (progn (search-forward " at ") (buffer-substring-no-properties (point) (1- (search-forward ":")))) :span (haskell-debug-parse-span (buffer-substring-no-properties (point) (line-end-position))) :types (progn (forward-line) (haskell-debug-split-string (buffer-substring-no-properties (point) (point-max))))))))) (defun haskell-debug-parse-stopped-at (string) "Parse the location stopped at from the given string. For example: Stopped at /home/foo/project/src/x.hs:6:25-36 " (let ((index (string-match "Stopped at \\([^:]+\\):\\(.+\\)\n?" string))) (when index (list :path (match-string 1 string) :span (haskell-debug-parse-span (match-string 2 string)) :types (cdr (haskell-debug-split-string (substring string index))))))) (defun haskell-debug-get-span-string (path span) "Get the string from the PATH and the SPAN." (save-window-excursion (find-file path) (buffer-substring (save-excursion (goto-char (point-min)) (forward-line (1- (plist-get span :start-line))) (forward-char (1- (plist-get span :start-col))) (point)) (save-excursion (goto-char (point-min)) (forward-line (1- (plist-get span :end-line))) (forward-char (plist-get span :end-col)) (point))))) (defun haskell-debug-make-fake-history (context) "Make a fake history item." (list :index -1 :path (plist-get context :path) :span (plist-get context :span))) (defun haskell-debug-insert-history (history) "Insert tracing HISTORY." (let ((i (length history))) (cl-loop for span in history do (let ((string (haskell-debug-get-span-string (plist-get span :path) (plist-get span :span)))) (insert (propertize (format "%4d" i) 'face 'haskell-debug-trace-number-face) " " (haskell-debug-preview-span (plist-get span :span) string t) "\n") (setq i (1- i)))))) (defun haskell-debug-parse-span (string) "Parse a source span from a string. Examples: (5,1)-(6,37) 6:25-36 5:20 People like to make other people's lives interesting by making variances in source span notation." (cond ((string-match "\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)" string) (list :start-line (string-to-number (match-string 1 string)) :start-col (string-to-number (match-string 2 string)) :end-line (string-to-number (match-string 1 string)) :end-col (string-to-number (match-string 3 string)))) ((string-match "\\([0-9]+\\):\\([0-9]+\\)" string) (list :start-line (string-to-number (match-string 1 string)) :start-col (string-to-number (match-string 2 string)) :end-line (string-to-number (match-string 1 string)) :end-col (string-to-number (match-string 2 string)))) ((string-match "(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\))" string) (list :start-line (string-to-number (match-string 1 string)) :start-col (string-to-number (match-string 2 string)) :end-line (string-to-number (match-string 3 string)) :end-col (string-to-number (match-string 4 string)))) (t (error "Unable to parse source span from string: %s" string)))) (defun haskell-debug-preview-span (span string &optional collapsed) "Make a one-line preview of the given expression." (with-temp-buffer (haskell-mode) (insert string) (when (/= 0 (plist-get span :start-col)) (indent-rigidly (point-min) (point-max) 1)) (if (fboundp 'font-lock-ensure) (font-lock-ensure) (with-no-warnings (font-lock-fontify-buffer))) (when (/= 0 (plist-get span :start-col)) (indent-rigidly (point-min) (point-max) -1)) (goto-char (point-min)) (if collapsed (replace-regexp-in-string "\n[ ]*" (propertize " " 'face 'haskell-debug-newline-face) (buffer-substring (point-min) (point-max))) (buffer-string)))) (defun haskell-debug-start (session) "Start the debug mode." (setq buffer-read-only t) (haskell-session-assign session) (haskell-debug/refresh)) (defun haskell-debug () "Start the debugger for the current Haskell (GHCi) session." (interactive) (let ((session (haskell-debug-session))) (switch-to-buffer-other-window (haskell-debug-buffer-name session)) (unless (eq major-mode 'haskell-debug-mode) (haskell-debug-mode) (haskell-debug-start session)))) (defun haskell-debug-break (break) "Set BREAK breakpoint in module at line/col." (haskell-process-queue-without-filters (haskell-debug-process) (format ":break %s %s %d" (plist-get break :module) (plist-get (plist-get break :span) :start-line) (plist-get (plist-get break :span) :start-col)))) (defun haskell-debug-navigate (direction) "Navigate in DIRECTION \"back\" or \"forward\"." (let ((string (haskell-process-queue-sync-request (haskell-debug-process) (concat ":" direction)))) (let ((bindings (haskell-debug-parse-logged string))) (setq haskell-debug-bindings-cache bindings) (when (not bindings) (message "No more %s results!" direction))) (haskell-debug/refresh))) (defun haskell-debug-session-debugging-p (session) "Does the session have a debugging buffer open?" (not (not (get-buffer (haskell-debug-buffer-name session))))) (defun haskell-debug-highlight (path &optional span) "Highlight the file at span." (let ((p (make-overlay (line-beginning-position) (line-end-position)))) (overlay-put p 'face `((:background "#eee"))) (with-current-buffer (if span (save-window-excursion (find-file path) (current-buffer)) (find-file path) (current-buffer)) (let ((o (when span (make-overlay (save-excursion (goto-char (point-min)) (forward-line (1- (plist-get span :start-line))) (forward-char (1- (plist-get span :start-col))) (point)) (save-excursion (goto-char (point-min)) (forward-line (1- (plist-get span :end-line))) (forward-char (plist-get span :end-col)) (point)))))) (when o (overlay-put o 'face `((:background "#eee")))) (sit-for 0.5) (when o (delete-overlay o)) (delete-overlay p))))) (defun haskell-debug-parse-history-entry (string) "Parse a history entry." (if (string-match "^\\([-0-9]+\\)[ ]+:[ ]+\\([A-Za-z0-9_':]+\\)[ ]+(\\([^:]+\\):\\(.+?\\))$" string) (list :index (string-to-number (match-string 1 string)) :name (match-string 2 string) :path (match-string 3 string) :span (haskell-debug-parse-span (match-string 4 string))) (error "Unable to parse history entry: %s" string))) (defun haskell-debug-parse-module (string) "Parse a module and path. For example: X ( /home/foo/X.hs, interpreted ) Main ( /home/foo/X.hs, /home/foo/X.o ) " (if (string-match "\\([^ ]+\\)[ ]+( \\([^ ]+?\\), [/a-zA-Z0-9\.]+ )$" string) (list :module (match-string 1 string) :path (match-string 2 string)) (error "Unable to parse module from string: %s" string))) (defun haskell-debug-parse-break-point (string) "Parse a breakpoint number, module and location from a string. For example: [13] Main /home/foo/src/x.hs:(5,1)-(6,37) " (if (string-match "^\\[\\([0-9]+\\)\\] \\([^ ]+\\) \\([^:]+\\):\\(.+\\)$" string) (list :number (string-to-number (match-string 1 string)) :module (match-string 2 string) :path (match-string 3 string) :span (haskell-debug-parse-span (match-string 4 string))) (error "Unable to parse breakpoint from string: %s" string))) (provide 'haskell-debug) ;;; haskell-debug.el ends here ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-decl-scan.el��������������������������������������������������������������0000664�0000000�0000000�00000070567�13602233217�0017621�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-decl-scan.el --- Declaration scanning module for Haskell Mode -*- lexical-binding: t -*- ;; Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. ;; Copyright (C) 1997-1998 Graeme E Moss ;; Copyright (C) 2016 Chris Gregory ;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> ;; Maintainer: Stefan Monnier <monnier@gnu.org> ;; Keywords: declarations menu files Haskell ;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-decl-scan.el?rev=HEAD ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; Purpose: ;; ;; Top-level declarations are scanned and placed in a menu. Supports ;; full Latin1 Haskell 1.4 as well as literate scripts. ;; ;; ;; Installation: ;; ;; To turn declaration scanning on for all Haskell buffers under the ;; Haskell mode of Moss&Thorn, add this to .emacs: ;; ;; (add-hook 'haskell-mode-hook 'haskell-decl-scan-mode) ;; ;; Otherwise, call `haskell-decl-scan-mode'. ;; ;; ;; Customisation: ;; ;; M-x customize-group haskell-decl-scan ;; ;; ;; History: ;; ;; If you have any problems or suggestions, after consulting the list ;; below, email gem@cs.york.ac.uk quoting the version of the library ;; you are using, the version of Emacs you are using, and a small ;; example of the problem or suggestion. Note that this library ;; requires a reasonably recent version of Emacs. ;; ;; Uses `imenu' under Emacs. ;; ;; Version 1.2: ;; Added support for LaTeX-style literate scripts. ;; ;; Version 1.1: ;; Use own syntax table. Fixed bug for very small buffers. Use ;; markers instead of pointers (markers move with the text). ;; ;; Version 1.0: ;; Brought over from Haskell mode v1.1. ;; ;; ;; Present Limitations/Future Work (contributions are most welcome!): ;; ;; . Declarations requiring information extending beyond starting line ;; don't get scanned properly, eg. ;; > class Eq a => ;; > Test a ;; ;; . Comments placed in the midst of the first few lexemes of a ;; declaration will cause havoc, eg. ;; > infixWithComments :: Int -> Int -> Int ;; > x {-nastyComment-} `infixWithComments` y = x + y ;; but are not worth worrying about. ;; ;; . Would be nice to scan other top-level declarations such as ;; methods of a class, datatype field labels... any more? ;; ;; . Support for GreenCard? ;; ;; . Re-running (literate-)haskell-imenu should not cause the problems ;; that it does. The ability to turn off scanning would also be ;; useful. (Note that re-running (literate-)haskell-mode seems to ;; cause no problems.) ;; All functions/variables start with ;; `(turn-(on/off)-)haskell-decl-scan' or `haskell-ds-'. ;; The imenu support is based on code taken from `hugs-mode', ;; thanks go to Chris Van Humbeeck. ;; Version. ;;; Code: (require 'cl-lib) (require 'haskell-mode) (require 'syntax) (require 'imenu) ;;;###autoload (defgroup haskell-decl-scan nil "Haskell declaration scanning (`imenu' support)." :link '(custom-manual "(haskell-mode)haskell-decl-scan-mode") :group 'haskell :prefix "haskell-decl-scan-") (defcustom haskell-decl-scan-bindings-as-variables nil "Whether to put top-level value bindings into a \"Variables\" category." :group 'haskell-decl-scan :type 'boolean) (defcustom haskell-decl-scan-add-to-menubar t "Whether to add a \"Declarations\" menu entry to menu bar." :group 'haskell-decl-scan :type 'boolean) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; General declaration scanning functions. (defvar haskell-ds-start-keywords-re (concat "\\(\\<" "class\\|data\\|i\\(mport\\|n\\(fix\\(\\|[lr]\\)\\|stance\\)\\)\\|" "module\\|primitive\\|type\\|newtype" "\\)\\>") "Keywords that may start a declaration.") (defvar haskell-ds-syntax-table (let ((table (copy-syntax-table haskell-mode-syntax-table))) (modify-syntax-entry ?\' "w" table) (modify-syntax-entry ?_ "w" table) (modify-syntax-entry ?\\ "_" table) table) "Syntax table used for Haskell declaration scanning.") (defun haskell-ds-get-variable (prefix) "Return variable involved in value binding or type signature. Assumes point is looking at the regexp PREFIX followed by the start of a declaration (perhaps in the middle of a series of declarations concerning a single variable). Otherwise return nil. Point is not changed." ;; I think I can now handle all declarations bar those with comments ;; nested before the second lexeme. (save-excursion (with-syntax-table haskell-ds-syntax-table (if (looking-at prefix) (goto-char (match-end 0))) ;; Keyword. (if (looking-at haskell-ds-start-keywords-re) nil (or ;; Parenthesized symbolic variable. (and (looking-at "(\\(\\s_+\\))") (match-string-no-properties 1)) ;; General case. (if (looking-at (if (eq ?\( (char-after)) ;; Skip paranthesised expression. (progn (forward-sexp) ;; Repeating this code and avoiding moving point if ;; possible speeds things up. "\\(\\'\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)") "\\(\\sw+\\)?\\s-*\\(\\s_+\\|`\\(\\sw+\\)`\\)")) (let ((match2 (match-string-no-properties 2))) ;; Weed out `::', `∷',`=' and `|' from potential infix ;; symbolic variable. (if (member match2 '("::" "∷" "=" "|")) ;; Variable identifier. (match-string-no-properties 1) (if (eq (aref match2 0) ?\`) ;; Infix variable identifier. (match-string-no-properties 3) ;; Infix symbolic variable. match2)))) ;; Variable identifier. (and (looking-at "\\sw+") (match-string-no-properties 0))))))) (defun haskell-ds-move-to-start-regexp (inc regexp) "Move to beginning of line that succeeds/precedes (INC = 1/-1) current line that starts with REGEXP and is not in `font-lock-comment-face'." ;; Making this defsubst instead of defun appears to have little or ;; no effect on efficiency. It is probably not called enough to do ;; so. (while (and (= (forward-line inc) 0) (or (not (looking-at regexp)) (eq (get-text-property (point) 'face) 'font-lock-comment-face))))) (defun haskell-ds-move-to-start-regexp-skipping-comments (inc regexp) "Like haskell-ds-move-to-start-regexp, but uses syntax-ppss to skip comments" (let (p) (cl-loop do (setq p (point)) (haskell-ds-move-to-start-regexp inc regexp) while (and (nth 4 (syntax-ppss)) (/= p (point)))))) (defvar literate-haskell-ds-line-prefix "> ?" "Regexp matching start of a line of Bird-style literate code. Current value is \"> \" as we assume top-level declarations start at column 3. Must not contain the special \"^\" regexp as we may not use the regexp at the start of a regexp string. Note this is only for `imenu' support.") (defvar haskell-ds-start-decl-re "\\(\\sw\\|(\\)" "The regexp that starts a Haskell declaration.") (defvar literate-haskell-ds-start-decl-re (concat literate-haskell-ds-line-prefix haskell-ds-start-decl-re) "The regexp that starts a Bird-style literate Haskell declaration.") (defun haskell-ds-whitespace-p (char) "Test if CHAR is a whitespace character." ;; the nil is a bob/eob test (member char '(nil ?\t ?\n ?\ ))) (defun haskell-ds-move-to-decl (direction bird-literate fix) "General function for moving to the start of a declaration, either forwards or backwards from point, with normal or with Bird-style literate scripts. If DIRECTION is t, then forward, else backward. If BIRD-LITERATE is t, then treat as Bird-style literate scripts, else normal scripts. Returns point if point is left at the start of a declaration, and nil otherwise, ie. because point is at the beginning or end of the buffer and no declaration starts there. If FIX is t, then point does not move if already at the start of a declaration." ;; As `haskell-ds-get-variable' cannot separate an infix variable ;; identifier out of a value binding with non-alphanumeric first ;; argument, this function will treat such value bindings as ;; separate from the declarations surrounding it. (let ( ;; The variable typed or bound in the current series of ;; declarations. name ;; The variable typed or bound in the new declaration. newname ;; Hack to solve hard problem for Bird-style literate scripts ;; that start with a declaration. We are in the abyss if ;; point is before start of this declaration. abyss (line-prefix (if bird-literate literate-haskell-ds-line-prefix "")) ;; The regexp to match for the start of a declaration. (start-decl-re (if bird-literate literate-haskell-ds-start-decl-re haskell-ds-start-decl-re)) (increment (if direction 1 -1)) (bound (if direction (point-max) (point-min)))) ;; Change syntax table. (with-syntax-table haskell-ds-syntax-table ;; move to beginning of line that starts the "current ;; declaration" (dependent on DIRECTION and FIX), and then get ;; the variable typed or bound by this declaration, if any. (let ( ;; Where point was at call of function. (here (point)) ;; Where the declaration on this line (if any) starts. (start (progn (beginning-of-line) ;; Checking the face to ensure a declaration starts ;; here seems to be the only addition to make this ;; module support LaTeX-style literate scripts. (if (and (looking-at start-decl-re) (not (elt (syntax-ppss) 4))) (match-beginning 1))))) (if (and start ;; This complicated boolean determines whether we ;; should include the declaration that starts on the ;; current line as the "current declaration" or not. (or (and (or (and direction (not fix)) (and (not direction) fix)) (>= here start)) (and (or (and direction fix) (and (not direction) (not fix))) (> here start)))) ;; If so, we are already at start of the current line, so ;; do nothing. () ;; If point was before start of a declaration on the first ;; line of the buffer (possible for Bird-style literate ;; scripts) then we are in the abyss. (if (and start (bobp)) (setq abyss t) ;; Otherwise we move to the start of the first declaration ;; on a line preceding the current one, skipping comments (haskell-ds-move-to-start-regexp-skipping-comments -1 start-decl-re)))) ;; If we are in the abyss, position and return as appropriate. (if abyss (if (not direction) nil (re-search-forward (concat "\\=" line-prefix) nil t) (point)) ;; Get the variable typed or bound by this declaration, if any. (setq name (haskell-ds-get-variable line-prefix)) (if (not name) ;; If no such variable, stop at the start of this ;; declaration if moving backward, or move to the next ;; declaration if moving forward. (if direction (haskell-ds-move-to-start-regexp-skipping-comments 1 start-decl-re)) ;; If there is a variable, find the first ;; succeeding/preceding declaration that does not type or ;; bind it. Check for reaching start/end of buffer and ;; comments. (haskell-ds-move-to-start-regexp-skipping-comments increment start-decl-re) (while (and (/= (point) bound) (and (setq newname (haskell-ds-get-variable line-prefix)) (string= name newname))) (setq name newname) (haskell-ds-move-to-start-regexp-skipping-comments increment start-decl-re)) ;; If we are going backward, and have either reached a new ;; declaration or the beginning of a buffer that does not ;; start with a declaration, move forward to start of next ;; declaration (which must exist). Otherwise, we are done. (if (and (not direction) (or (and (looking-at start-decl-re) (not (string= name ;; Note we must not use ;; newname here as this may ;; not have been set if we ;; have reached the beginning ;; of the buffer. (haskell-ds-get-variable line-prefix)))) (and (not (looking-at start-decl-re)) (bobp)))) (haskell-ds-move-to-start-regexp-skipping-comments 1 start-decl-re))) ;; Store whether we are at the start of a declaration or not. ;; Used to calculate final result. (let ((at-start-decl (looking-at start-decl-re))) ;; If we are at the beginning of a line, move over ;; line-prefix, if present at point. (if (bolp) (re-search-forward (concat "\\=" line-prefix) (point-max) t)) ;; Return point if at the start of a declaration and nil ;; otherwise. (if at-start-decl (point) nil)))))) (defun haskell-ds-bird-p () (and (boundp 'haskell-literate) (eq haskell-literate 'bird))) (defun haskell-ds-backward-decl () "Move backward to the first character that starts a top-level declaration. A series of declarations concerning one variable is treated as one declaration by this function. So, if point is within a top-level declaration then move it to the start of that declaration. If point is already at the start of a top-level declaration, then move it to the start of the preceding declaration. Returns point if point is left at the start of a declaration, and nil otherwise, because point is at the beginning of the buffer and no declaration starts there." (interactive) (haskell-ds-move-to-decl nil (haskell-ds-bird-p) nil)) (defun haskell-ds-comment-p (&optional pt) "Test if the cursor is on whitespace or a comment. `PT' defaults to `(point)'" ;; ensure result is `t' or `nil' instead of just truthy (if (or ;; is cursor on whitespace (haskell-ds-whitespace-p (following-char)) ;; http://emacs.stackexchange.com/questions/14269/how-to-detect-if-the-point-is-within-a-comment-area ;; is cursor at begging, inside, or end of comment (let ((fontfaces (get-text-property (or pt (point)) 'face))) (when (not (listp fontfaces)) (setf fontfaces (list fontfaces))) (delq nil (mapcar #'(lambda (f) (member f '(font-lock-comment-face font-lock-doc-face font-lock-comment-delimiter-face))) fontfaces)))) t nil)) (defun haskell-ds-line-commented-p () "Tests if all characters from `point' to `end-of-line' pass `haskell-ds-comment-p'" (let ((r t)) (while (and r (not (eolp))) (if (not (haskell-ds-comment-p)) (setq r nil)) (forward-char)) r)) (defun haskell-ds-forward-decl () "Move forward to the first character that starts a top-level declaration. As `haskell-ds-backward-decl' but forward." (interactive) (let ((p (point)) b e empty was-at-bob) ;; Go back to beginning of defun, then go to beginning of next (haskell-ds-move-to-decl nil (haskell-ds-bird-p) nil) (setq b (point)) (haskell-ds-move-to-decl t (haskell-ds-bird-p) nil) (setq e (point)) ;; tests if line is empty (setq empty (and (<= (point) p) (not (eolp)))) (setq was-at-bob (and (= (point-min) b) (= b p) (< p e))) ;; this conditional allows for when empty lines at end, first ;; `C-M-e' will go to end of defun, next will go to end of file. (when (or was-at-bob empty) (if (or (and was-at-bob (= ?\n (save-excursion (goto-char (point-min)) (following-char)))) empty) (haskell-ds-move-to-decl t (haskell-ds-bird-p) nil)) ;; Then go back to end of current (forward-line -1) (while (and (haskell-ds-line-commented-p) ;; prevent infinite loop (not (bobp))) (forward-line -1)) (forward-line 1))) (point)) (defun haskell-ds-generic-find-next-decl (bird-literate) "Find the name, position and type of the declaration at or after point. Return ((NAME . (START-POSITION . NAME-POSITION)) . TYPE) if one exists and nil otherwise. The start-position is at the start of the declaration, and the name-position is at the start of the name of the declaration. The name is a string, the positions are buffer positions and the type is one of the symbols \"variable\", \"datatype\", \"class\", \"import\" and \"instance\"." (let ( ;; The name, type and name-position of the declaration to ;; return. name type name-pos ;; Buffer positions marking the start and end of the space ;; containing a declaration. start end) ;; Change to declaration scanning syntax. (with-syntax-table haskell-ds-syntax-table ;; Stop when we are at the end of the buffer or when a valid ;; declaration is grabbed. (while (not (or (eobp) name)) ;; Move forward to next declaration at or after point. (haskell-ds-move-to-decl t bird-literate t) ;; Start and end of search space is currently just the starting ;; line of the declaration. (setq start (point) end (line-end-position)) (cond ;; If the start of the top-level declaration does not begin ;; with a starting keyword, then (if legal) must be a type ;; signature or value binding, and the variable concerned is ;; grabbed. ((not (looking-at haskell-ds-start-keywords-re)) (setq name (haskell-ds-get-variable "")) (if name (progn (setq type 'variable) (re-search-forward (regexp-quote name) end t) (setq name-pos (match-beginning 0))))) ;; User-defined datatype declaration. ((re-search-forward "\\=\\(data\\|newtype\\|type\\)\\>" end t) (re-search-forward "=>" end t) (if (looking-at "[ \t]*\\(\\sw+\\)") (progn (setq name (match-string-no-properties 1)) (setq name-pos (match-beginning 1)) (setq type 'datatype)))) ;; Class declaration. ((re-search-forward "\\=class\\>" end t) (re-search-forward "=>" end t) (if (looking-at "[ \t]*\\(\\sw+\\)") (progn (setq name (match-string-no-properties 1)) (setq name-pos (match-beginning 1)) (setq type 'class)))) ;; Import declaration. ((looking-at "import[ \t]+\\(?:safe[\t ]+\\)?\\(?:qualified[ \t]+\\)?\\(?:\"[^\"]*\"[\t ]+\\)?\\(\\(?:\\sw\\|.\\)+\\)") (setq name (match-string-no-properties 1)) (setq name-pos (match-beginning 1)) (setq type 'import)) ;; Instance declaration. ((re-search-forward "\\=instance[ \t]+" end t) (re-search-forward "=>[ \t]+" end t) ;; The instance "title" starts just after the `instance' (and ;; any context) and finishes just before the _first_ `where' ;; if one exists. This solution is ugly, but I can't find a ;; nicer one---a simple regexp will pick up the last `where', ;; which may be rare but nevertheless... (setq name-pos (point)) (setq name (buffer-substring-no-properties (point) (progn ;; Look for a `where'. (if (re-search-forward "\\<where\\>" end t) ;; Move back to just before the `where'. (progn (re-search-backward "\\s-where") (point)) ;; No `where' so move to last non-whitespace ;; before `end'. (progn (goto-char end) (skip-chars-backward " \t") (point)))))) ;; If we did not manage to extract a name, cancel this ;; declaration (eg. when line ends in "=> "). (if (string-match "^[ \t]*$" name) (setq name nil)) (setq type 'instance))) ;; Move past start of current declaration. (goto-char end)) ;; If we have a valid declaration then return it, otherwise return ;; nil. (if name (cons (cons name (cons (copy-marker start t) (copy-marker name-pos t))) type) nil)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Declaration scanning via `imenu'. ;;;###autoload (defun haskell-ds-create-imenu-index () "Function for finding `imenu' declarations in Haskell mode. Finds all declarations (classes, variables, imports, instances and datatypes) in a Haskell file for the `imenu' package." ;; Each list has elements of the form `(INDEX-NAME . INDEX-POSITION)'. ;; These lists are nested using `(INDEX-TITLE . INDEX-ALIST)'. (let* ((bird-literate (haskell-ds-bird-p)) (index-alist '()) (index-class-alist '()) ;; Classes (index-var-alist '()) ;; Variables (index-imp-alist '()) ;; Imports (index-inst-alist '()) ;; Instances (index-type-alist '()) ;; Datatypes ;; Variables for showing progress. (bufname (buffer-name)) (divisor-of-progress (max 1 (/ (buffer-size) 100))) ;; The result we wish to return. result) (goto-char (point-min)) ;; Loop forwards from the beginning of the buffer through the ;; starts of the top-level declarations. (while (< (point) (point-max)) (message "Scanning declarations in %s... (%3d%%)" bufname (/ (- (point) (point-min)) divisor-of-progress)) ;; Grab the next declaration. (setq result (haskell-ds-generic-find-next-decl bird-literate)) (if result ;; If valid, extract the components of the result. (let* ((name-posns (car result)) (name (car name-posns)) (posns (cdr name-posns)) (start-pos (car posns)) (type (cdr result))) ;; Place `(name . start-pos)' in the correct alist. (cl-case type (variable (setq index-var-alist (cl-acons name start-pos index-var-alist))) (datatype (setq index-type-alist (cl-acons name start-pos index-type-alist))) (class (setq index-class-alist (cl-acons name start-pos index-class-alist))) (import (setq index-imp-alist (cl-acons name start-pos index-imp-alist))) (instance (setq index-inst-alist (cl-acons name start-pos index-inst-alist))))))) ;; Now sort all the lists, label them, and place them in one list. (message "Sorting declarations in %s..." bufname) (when index-type-alist (push (cons "Datatypes" (sort index-type-alist 'haskell-ds-imenu-label-cmp)) index-alist)) (when index-inst-alist (push (cons "Instances" (sort index-inst-alist 'haskell-ds-imenu-label-cmp)) index-alist)) (when index-imp-alist (push (cons "Imports" (sort index-imp-alist 'haskell-ds-imenu-label-cmp)) index-alist)) (when index-class-alist (push (cons "Classes" (sort index-class-alist 'haskell-ds-imenu-label-cmp)) index-alist)) (when index-var-alist (if haskell-decl-scan-bindings-as-variables (push (cons "Variables" (sort index-var-alist 'haskell-ds-imenu-label-cmp)) index-alist) (setq index-alist (append index-alist (sort index-var-alist 'haskell-ds-imenu-label-cmp))))) (message "Sorting declarations in %s...done" bufname) ;; Return the alist. index-alist)) (defun haskell-ds-imenu-label-cmp (el1 el2) "Predicate to compare labels in lists from `haskell-ds-create-imenu-index'." (string< (car el1) (car el2))) (defun haskell-ds-imenu () "Install `imenu' for Haskell scripts." (setq imenu-create-index-function 'haskell-ds-create-imenu-index) (when haskell-decl-scan-add-to-menubar (imenu-add-to-menubar "Declarations"))) ;; The main functions to turn on declaration scanning. ;;;###autoload (defun turn-on-haskell-decl-scan () "Unconditionally activate `haskell-decl-scan-mode'." (interactive) (haskell-decl-scan-mode)) (make-obsolete 'turn-on-haskell-decl-scan 'haskell-decl-scan-mode "2015-07-23") ;;;###autoload (define-minor-mode haskell-decl-scan-mode "Toggle Haskell declaration scanning minor mode on or off. With a prefix argument ARG, enable minor mode if ARG is positive, and disable it otherwise. If called from Lisp, enable the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'. See also info node `(haskell-mode)haskell-decl-scan-mode' for more details about this minor mode. Top-level declarations are scanned and listed in the menu item \"Declarations\" (if enabled via option `haskell-decl-scan-add-to-menubar'). Selecting an item from this menu will take point to the start of the declaration. \\[beginning-of-defun] and \\[end-of-defun] move forward and backward to the start of a declaration. This may link with `haskell-doc-mode'. For non-literate and LaTeX-style literate scripts, we assume the common convention that top-level declarations start at the first column. For Bird-style literate scripts, we assume the common convention that top-level declarations start at the third column, ie. after \"> \". Anything in `font-lock-comment-face' is not considered for a declaration. Therefore, using Haskell font locking with comments coloured in `font-lock-comment-face' improves declaration scanning. Literate Haskell scripts are supported: If the value of `haskell-literate' (set automatically by `literate-haskell-mode') is `bird', a Bird-style literate script is assumed. If it is nil or `tex', a non-literate or LaTeX-style literate script is assumed, respectively. Invokes `haskell-decl-scan-mode-hook' on activation." :group 'haskell-decl-scan (kill-local-variable 'beginning-of-defun-function) (kill-local-variable 'end-of-defun-function) (kill-local-variable 'imenu-create-index-function) (unless haskell-decl-scan-mode ;; How can we cleanly remove the "Declarations" menu? (when haskell-decl-scan-add-to-menubar (local-set-key [menu-bar index] nil))) (when haskell-decl-scan-mode (setq-local beginning-of-defun-function 'haskell-ds-backward-decl) (setq-local end-of-defun-function 'haskell-ds-forward-decl) (haskell-ds-imenu))) ;; Provide ourselves: (provide 'haskell-decl-scan) ;;; haskell-decl-scan.el ends here �����������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-doc.el��������������������������������������������������������������������0000664�0000000�0000000�00000232421�13602233217�0016522�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-doc.el --- show function types in echo area -*- coding: utf-8; lexical-binding: t -*- ;; Copyright © 2004, 2005, 2006, 2007, 2009, 2016 Free Software Foundation, Inc. ;; Copyright © 1997 Hans-Wolfgang Loidl ;; 2016 Arthur Fayzrakhmanov ;; Author: Hans-Wolfgang Loidl <hwloidl@dcs.glasgow.ac.uk> ;; Temporary Maintainer and Hacker: Graeme E Moss <gem@cs.york.ac.uk> ;; Keywords: extensions, minor mode, language mode, Haskell ;; Created: 1997-06-17 ;; URL: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/CONTRIB/haskell-modes/emacs/haskell-doc.el?rev=HEAD ;; This file is not part of GNU Emacs. ;; 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, 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; This program shows the type of the Haskell function under the cursor in the ;; minibuffer. It acts as a kind of "Emacs background process", by regularly ;; checking the word under the cursor and matching it against a list of ;; prelude, library, local and global functions. ;; This program was inspired by the `eldoc.el' package by Noah Friedman. ;; Installation: ;; Depending on the major mode you use for your Haskell programs add ;; one of the following to your .emacs: ;; ;; (add-hook 'haskell-mode-hook 'haskell-doc-mode) ;; Customisation: ;; You can control what exactly is shown by setting the following variables to ;; either t or nil: ;; `haskell-doc-show-global-types' (default: nil) ;; `haskell-doc-show-reserved' (default: t) ;; `haskell-doc-show-prelude' (default: t) ;; `haskell-doc-show-strategy' (default: t) ;; `haskell-doc-show-user-defined' (default: t) ;; If you want to define your own strings for some identifiers define an ;; alist of (ID . STRING) and set `haskell-doc-show-user-defined' to t. ;; E.g: ;; ;; (setq haskell-doc-show-user-defined t) ;; (setq haskell-doc-user-defined-ids ;; (list ;; '("main" . "just another pathetic main function") ;; '("foo" . "a very dummy name") ;; '("bar" . "another dummy name"))) ;; The following two variables are useful to make the type fit on one line: ;; If `haskell-doc-chop-off-context' is non-nil the context part of the type ;; of a local fct will be eliminated (default: t). ;; If `haskell-doc-chop-off-fctname' is non-nil the function name is not ;; shown together with the type (default: nil). ;; Internals: ;; `haskell-doc-mode' is implemented as a minor-mode. So, you can combine it ;; with any other mode. To enable it just type ;; M-x haskell-doc-mode ;; These are the names of the functions that can be called directly by the ;; user (with keybindings in `haskell-mode'): ;; `haskell-doc-mode' ... toggle haskell-doc-mode; with prefix turn it on ;; unconditionally if the prefix is greater 0 otherwise ;; turn it off ;; Key: CTRL-c CTRL-o (CTRL-u CTRL-c CTRL-o) ;; `haskell-doc-ask-mouse-for-type' ... show the type of the id under the mouse ;; Key: C-S-M-mouse-3 ;; `haskell-doc-show-reserved' ... toggle echoing of reserved id's types ;; `haskell-doc-show-prelude' ... toggle echoing of prelude id's types ;; `haskell-doc-show-strategy' ... toggle echoing of strategy id's types ;; `haskell-doc-show-user-defined' ... toggle echoing of user def id's types ;; `haskell-doc-check-active' ... check whether haskell-doc is active; ;; Key: CTRL-c ESC-/ ;; ToDo: ;; - Fix byte-compile problems in `haskell-doc-prelude-types' for getArgs etc ;; - Write a parser for .hi files. Read library interfaces via this parser. ;; - Indicate kind of object with colours ;; - Handle multi-line types ;; - Encode i-am-fct info in the alist of ids and types. ;; Bugs: ;; - Some prelude fcts aren't displayed properly. This might be due to a ;; name clash of Haskell and Elisp functions (e.g. length) which ;; confuses Emacs when reading `haskell-doc-prelude-types' ;;; Changelog: ;; $Log: haskell-doc.el,v $ ;; Revision 1.31 2015/07/23 10:34:20 ankhers ;; (turn-on-haskell-doc-mode): marked obsolete ;; (turn-on-haskell-doc): marked obsolete ;; other packages have been moving away from (turn-on-haskell-*) ;; ;; Revision 1.30 2009/02/02 21:00:33 monnier ;; (haskell-doc-imported-list): Don't add current buffer ;; to the imported file list if it is not (yet?) visiting a file. ;; ;; Revision 1.29 2007-12-12 04:04:19 monnier ;; (haskell-doc-in-code-p): New function. ;; (haskell-doc-show-type): Use it. ;; ;; Revision 1.28 2007/08/30 03:10:08 monnier ;; Comment/docs fixes. ;; ;; Revision 1.27 2007/07/30 17:36:50 monnier ;; (displayed-month): Remove declaration since it's not used here. ;; ;; Revision 1.26 2007/02/10 06:28:55 monnier ;; (haskell-doc-get-current-word): Remove. ;; Change all refs to it, to use haskell-ident-at-point instead. ;; ;; Revision 1.25 2007/02/09 21:53:42 monnier ;; (haskell-doc-get-current-word): Correctly distinguish ;; variable identifiers and infix identifiers. ;; (haskell-doc-rescan-files): Avoid switch-to-buffer. ;; (haskell-doc-imported-list): Operate on current buffer. ;; (haskell-doc-make-global-fct-index): Adjust call. ;; ;; Revision 1.24 2006/11/20 20:18:24 monnier ;; (haskell-doc-mode-print-current-symbol-info): Fix thinko. ;; ;; Revision 1.23 2006/10/20 03:12:31 monnier ;; Drop post-command-idle-hook in favor of run-with-idle-timer. ;; (haskell-doc-timer, haskell-doc-buffers): New vars. ;; (haskell-doc-mode): Use them. ;; (haskell-doc-check-active): Update the check. ;; (haskell-doc-mode-print-current-symbol-info): Remove the interactive spec. ;; Don't sit-for unless it's really needed. ;; ;; Revision 1.22 2006/09/20 18:42:35 monnier ;; Doc fix. ;; ;; Revision 1.21 2005/11/21 21:48:52 monnier ;; * haskell-doc.el (haskell-doc-extract-types): Get labelled data working. ;; (haskell-doc-prelude-types): Update via auto-generation. ;; ;; * haskell-doc.el (haskell-doc-extract-types): Get it partly working. ;; (haskell-doc-fetch-lib-urls): Don't use a literal if we apply ;; `nreverse' on it later on. ;; (haskell-doc-prelude-types): Update some parts by auto-generation. ;; (haskell-doc-grab, haskell-doc-string-nub-ws): Simplify. ;; ;; * haskell-doc.el (haskell-doc-maintainer, haskell-doc-varlist) ;; (haskell-doc-submit-bug-report, haskell-doc-ftp-site) ;; (haskell-doc-visit-home): Remove. ;; (haskell-doc-reserved-ids, haskell-doc-fetch-lib-urls) ;; (haskell-doc-extract-and-insert-types): New funs. ;; (haskell-doc-reserved-ids): Fix type of `map'. ;; ;; Revision 1.20 2005/11/21 21:27:57 monnier ;; (haskell-doc-extract-types): Get labelled data working. ;; (haskell-doc-prelude-types): Update via auto-generation. ;; ;; Revision 1.19 2005/11/21 20:44:13 monnier ;; (haskell-doc-extract-types): Get it partly working. ;; (haskell-doc-fetch-lib-urls): Don't use a literal if we apply ;; `nreverse' on it later on. ;; (haskell-doc-prelude-types): Update some parts by auto-generation. ;; (haskell-doc-grab, haskell-doc-string-nub-ws): Simplify. ;; ;; Revision 1.18 2005/11/21 18:02:15 monnier ;; (haskell-doc-maintainer, haskell-doc-varlist) ;; (haskell-doc-submit-bug-report, haskell-doc-ftp-site) ;; (haskell-doc-visit-home): Remove. ;; (haskell-doc-reserved-ids, haskell-doc-fetch-lib-urls) ;; (haskell-doc-extract-and-insert-types): New funs. ;; (haskell-doc-reserved-ids): Fix type of `map'. ;; ;; Revision 1.17 2005/11/20 23:55:09 monnier ;; Add coding cookie. ;; ;; Revision 1.16 2005/11/07 01:28:16 monnier ;; (haskell-doc-xemacs-p, haskell-doc-emacs-p) ;; (haskell-doc-message): Remove. ;; (haskell-doc-is-id-char-at): Remove. ;; (haskell-doc-get-current-word): Rewrite. ;; ;; Revision 1.15 2005/11/04 17:11:12 monnier ;; Add arch-tag. ;; ;; Revision 1.14 2005/08/24 11:36:32 monnier ;; (haskell-doc-message): Paren typo. ;; ;; Revision 1.13 2005/08/23 19:23:27 monnier ;; (haskell-doc-show-type): Assume that the availability ;; of display-message won't change at runtime. ;; ;; Revision 1.12 2005/07/18 21:04:14 monnier ;; (haskell-doc-message): Remove. ;; (haskell-doc-show-type): inline it. Do nothing for if there's no doc to show. ;; ;; Revision 1.11 2004/12/10 17:33:18 monnier ;; (haskell-doc-minor-mode-string): Make it dynamic. ;; (haskell-doc-install-keymap): Remove conflicting C-c C-o binding. ;; (haskell-doc-mode): Make a nil arg turn the mode ON. ;; (turn-on-haskell-doc-mode): Make it an alias for haskell-doc-mode. ;; (haskell-doc-mode): Don't touch haskell-doc-minor-mode-string. ;; (haskell-doc-show-global-types): Don't touch ;; haskell-doc-minor-mode-string. Call haskell-doc-make-global-fct-index. ;; (haskell-doc-check-active): Fix message. ;; (define-key-after): Don't define. ;; (haskell-doc-install-keymap): Check existence of define-key-after. ;; ;; Revision 1.10 2004/11/25 23:03:23 monnier ;; (haskell-doc-sym-doc): Make even the last char bold. ;; ;; Revision 1.9 2004/11/24 22:14:36 monnier ;; (haskell-doc-install-keymap): Don't blindly assume there's a Hugs menu. ;; ;; Revision 1.8 2004/11/22 10:45:35 simonmar ;; Fix type of getLine ;; ;; Revision 1.7 2004/10/14 22:27:47 monnier ;; (turn-off-haskell-doc-mode, haskell-doc-current-info): Don't autoload. ;; ;; Revision 1.6 2004/10/13 22:45:22 monnier ;; (haskell-doc): New group. ;; (haskell-doc-show-reserved, haskell-doc-show-prelude) ;; (haskell-doc-show-strategy, haskell-doc-show-user-defined) ;; (haskell-doc-chop-off-context, haskell-doc-chop-off-fctname): ;; Make them custom vars. ;; (haskell-doc-keymap): Declare and fill it right there. ;; (haskell-doc-mode): Simplify. ;; (haskell-doc-toggle-var): Make it into what it was supposed to be. ;; (haskell-doc-mode-print-current-symbol-info): Simplify. ;; (haskell-doc-current-info): New autoloaded function. ;; (haskell-doc-sym-doc): New fun extracted from haskell-doc-show-type. ;; (haskell-doc-show-type): Use it. ;; (haskell-doc-wrapped-type-p): Remove unused var `lim'. ;; (haskell-doc-forward-sexp-safe, haskell-doc-current-symbol): Remove. Unused. ;; (haskell-doc-visit-home): Don't require ange-ftp, it's autoloaded. ;; (haskell-doc-install-keymap): Simplify. ;; ;; Revision 1.5 2003/01/09 11:56:26 simonmar ;; Patches from Ville Skyttä <scop@xemacs.org>, the XEmacs maintainer of ;; the haskell-mode: ;; ;; - Make the auto-mode-alist modifications autoload-only. ;; ;; Revision 1.4 2002/10/14 09:55:03 simonmar ;; Patch to update the Prelude/libraries function names and to remove ;; support for older versions of Haskell. ;; ;; Submitted by: Anders Lau Olsen <alauo@mip.sdu.dk> ;; ;; Revision 1.3 2002/04/30 09:34:37 rrt ;; Remove supporting Haskell 1.4 and 1.2 from the ToDo list. It's Far Too Late. ;; ;; Add (require 'imenu). Thanks to N. Y. Kwok. ;; ;; Revision 1.2 2002/04/23 14:45:10 simonmar ;; Tweaks to the doc strings and support for customization, from ;; Ville Skyttä <scop@xemacs.org>. ;; ;; Revision 1.1 2001/07/19 16:17:36 rrt ;; Add the current version of the Moss/Thorn/Marlow Emacs mode, along with its ;; web pages and sample files. This is now the preferred mode, and the ;; haskell.org pages are being changed to reflect that. Also includes the new ;; GHCi mode from Chris Webb. ;; ;; Revision 1.6 1998/12/10 16:27:25 hwloidl ;; Minor changes ("Doc" as modeline string, mouse-3 moved to C-S-M-mouse-3) ;; ;; Revision 1.5 1998/09/24 14:25:46 gem ;; Fixed minor compatibility bugs with Haskell mode of Moss&Thorn. ;; Disabled M-/ binding. ;; ;; Revision 1.4 1997/11/12 23:51:19 hwloidl ;; Fixed start-up problem under emacs-19.34. ;; Added support for wrapped (multi-line) types and 2 vars to control the ;; behaviour with long fct types ;; ;; Revision 1.3 1997/11/03 00:48:03 hwloidl ;; Major revision for first release. ;; Added alists for showing prelude fcts, haskell syntax, and strategies ;; Added mouse interface to show type under mouse ;; Fixed bug which causes demon to fall over ;; Works now with hugs-mode and haskell-mode under emacs 19.34,20 and xemacs 19.15 ;; ;;; Code: (require 'haskell-mode) (require 'haskell-process) (require 'haskell) (require 'haskell-utils) (require 'inf-haskell) (require 'imenu) (require 'eldoc) ;;;###autoload (defgroup haskell-doc nil "Show Haskell function types in echo area." :group 'haskell :prefix "haskell-doc-") (defvar-local haskell-doc-mode nil "*If non-nil, show the type of the function near point or a related comment. If the identifier near point is a Haskell keyword and the variable `haskell-doc-show-reserved' is non-nil show a one line summary of the syntax. If the identifier near point is a Prelude or one of the standard library functions and `haskell-doc-show-prelude' is non-nil show its type. If the identifier near point is local \(i.e. defined in this module\) check the `imenu' list of functions for the type. This obviously requires that your language mode uses `imenu'. If the identifier near point is global \(i.e. defined in an imported module\) and the variable `haskell-doc-show-global-types' is non-nil show the type of its function. If the identifier near point is a standard strategy or a function, type related related to strategies and `haskell-doc-show-strategy' is non-nil show the type of the function. Strategies are special to the parallel execution of Haskell. If you're not interested in that just turn it off. If the identifier near point is a user defined function that occurs as key in the alist `haskell-doc-user-defined-ids' and the variable `haskell-doc-show-user-defined' is non-nil show the type of the function. This variable is buffer-local.") (defvar haskell-doc-mode-hook nil "Hook invoked when entering `haskell-doc-mode'.") (defvar-local haskell-doc-index nil "Variable holding an alist matching file names to fct-type alists. The function `haskell-doc-make-global-fct-index' rebuilds this variables \(similar to an `imenu' rescan\). This variable is buffer-local.") (defcustom haskell-doc-show-global-types nil "If non-nil, search for the types of global functions by loading the files. This variable is buffer-local." :group 'haskell-doc :type 'boolean) (make-variable-buffer-local 'haskell-doc-show-global-types) (defcustom haskell-doc-show-reserved t "If non-nil, show a documentation string for reserved ids. This variable is buffer-local." :group 'haskell-doc :type 'boolean) (make-variable-buffer-local 'haskell-doc-show-reserved) (defcustom haskell-doc-show-prelude t "If non-nil, show a documentation string for prelude functions. This variable is buffer-local." :group 'haskell-doc :type 'boolean) (make-variable-buffer-local 'haskell-doc-show-prelude) (defcustom haskell-doc-show-strategy t "If non-nil, show a documentation string for strategies. This variable is buffer-local." :group 'haskell-doc :type 'boolean) (make-variable-buffer-local 'haskell-doc-show-strategy) (defcustom haskell-doc-show-user-defined t "If non-nil, show a documentation string for user defined ids. This variable is buffer-local." :group 'haskell-doc :type 'boolean) (make-variable-buffer-local 'haskell-doc-show-user-defined) (defcustom haskell-doc-chop-off-context t "If non-nil eliminate the context part in a Haskell type." :group 'haskell-doc :type 'boolean) (defcustom haskell-doc-chop-off-fctname nil "If non-nil omit the function name and show only the type." :group 'haskell-doc :type 'boolean) (defcustom haskell-doc-use-inf-haskell nil "If non-nil use inf-haskell.el to get type and kind information." :group 'haskell-doc :type 'boolean) (defvar haskell-doc-search-distance 40 ; distance in characters "*How far to search when looking for the type declaration of fct under cursor.") (defvar haskell-doc-idle-delay 0.50 "*Number of seconds of idle time to wait before printing. If user input arrives before this interval of time has elapsed after the last input, no documentation will be printed. If this variable is set to 0, no idle time is required.") (defvar haskell-doc-argument-case 'identity ; 'upcase "Case in which to display argument names of functions, as a symbol. This has two preferred values: `upcase' or `downcase'. Actually, any name of a function which takes a string as an argument and returns another string is acceptable.") (defvar haskell-doc-mode-message-commands nil "*Obarray of command names where it is appropriate to print in the echo area. This is not done for all commands since some print their own messages in the echo area, and these functions would instantly overwrite them. But `self-insert-command' as well as most motion commands are good candidates. It is probably best to manipulate this data structure with the commands `haskell-doc-add-command' and `haskell-doc-remove-command'.") ;;(cond ((null haskell-doc-mode-message-commands) ;; ;; If you increase the number of buckets, keep it a prime number. ;; (setq haskell-doc-mode-message-commands (make-vector 31 0)) ;; (let ((list '("self-insert-command" ;; "next-" "previous-" ;; "forward-" "backward-" ;; "beginning-of-" "end-of-" ;; "goto-" ;; "recenter" ;; "scroll-")) ;; (syms nil)) ;; (while list ;; (setq syms (all-completions (car list) obarray 'fboundp)) ;; (setq list (cdr list)) ;; (while syms ;; (set (intern (car syms) haskell-doc-mode-message-commands) t) ;; (setq syms (cdr syms))))))) ;; Bookkeeping; the car contains the last symbol read from the buffer. ;; The cdr contains the string last displayed in the echo area, so it can ;; be printed again if necessary without reconsing. (defvar haskell-doc-last-data '(nil . nil)) (defvar haskell-doc-minor-mode-string '(haskell-doc-show-global-types " DOC" " Doc") "*String to display in mode line when Haskell-Doc Mode is enabled.") (defvar haskell-doc-reserved-ids '(("case" . "case exp of { alts [;] }") ("class" . "class [context =>] simpleclass [where { cbody [;] }]") ("data" . "data [context =>] simpletype = constrs [deriving]") ("default" . "default (type1 , ... , typen)") ("deriving" . "deriving (dclass | (dclass1, ... , dclassn))") ; used with data or newtype ("do" . "do { stmts [;] } stmts -> exp [; stmts] | pat <- exp ; stmts | let decllist ; stmts") ("else" . "if exp then exp else exp") ("if" . "if exp then exp else exp") ("import" . "import [qualified] modid [as modid] [impspec]") ("in" . "let decllist in exp") ("infix" . "infix [digit] ops") ("infixl" . "infixl [digit] ops") ("infixr" . "infixr [digit] ops") ("instance" . "instance [context =>] qtycls inst [where { valdefs [;] }]") ("let" . "let { decl; ...; decl [;] } in exp") ("module" . "module modid [exports] where body") ("newtype" . "newtype [context =>] simpletype = con atype [deriving]") ("of" . "case exp of { alts [;] }") ("then" . "if exp then exp else exp") ("type" . "type simpletype = type") ("where" . "exp where { decl; ...; decl [;] }") ; check that ; see also class, instance, module ("as" . "import [qualified] modid [as modid] [impspec]") ("qualified" . "import [qualified] modid [as modid] [impspec]") ("hiding" . "hiding ( import1 , ... , importn [ , ] )") ("family" . "(type family type [kind] [= type_fam_equations]) | (data family type [kind])")) "An alist of reserved identifiers. Each element is of the form (ID . DOC) where both ID and DOC are strings. DOC should be a concise single-line string describing the construct in which the keyword is used.") (defun haskell-doc-extract-types (url) (with-temp-buffer (insert-file-contents url) (goto-char (point-min)) (while (search-forward " " nil t) (replace-match " " t t)) ;; First, focus on the actual code, removing the surrounding HTML text. (goto-char (point-min)) (let ((last (point-min)) (modules nil)) (while (re-search-forward "^module +\\([[:alnum:]]+\\)" nil t) (let ((module (match-string 1))) (if (member module modules) ;; The library nodes of the HTML doc contain modules twice: ;; once at the top, with only type declarations, and once at ;; the bottom with an actual sample implementation which may ;; include declaration of non-exported values. ;; We're now at this second occurrence is the implementation ;; which should thus be ignored. nil (push module modules) (delete-region last (point)) (search-forward "</tt>") ;; Some of the blocks of code are split. (while (looking-at "\\(<[^<>]+>[ \t\n]*\\)*<tt>") (goto-char (match-end 0)) (search-forward "</tt>")) (setq last (point))))) (delete-region last (point-max)) ;; Then process the HTML encoding to get back to pure ASCII. (goto-char (point-min)) (while (search-forward "<br>" nil t) (replace-match "\n" t t)) ;; (goto-char (point-min)) ;; (while (re-search-forward "<[^<>]+>" nil t) (replace-match "" t t)) (goto-char (point-min)) (while (search-forward ">" nil t) (replace-match ">" t t)) (goto-char (point-min)) (while (search-forward "<" nil t) (replace-match "<" t t)) (goto-char (point-min)) (while (search-forward "&" nil t) (replace-match "&" t t)) (goto-char (point-min)) (if (re-search-forward "&[a-z]+;" nil t) (error "Unexpected charref %s" (match-string 0))) ;; Remove TABS. (goto-char (point-min)) (while (search-forward "\t" nil t) (replace-match " " t t)) ;; Finally, extract the actual data. (goto-char (point-min)) (let* ((elems nil) (space-re "[ \t\n]*\\(?:--.*\n[ \t\n]*\\)*") (comma-re (concat " *," space-re)) ;; A list of identifiers. We have to be careful to weed out ;; entries like "ratPrec = 7 :: Int". Also ignore entries ;; which start with a < since they're actually in the HTML text ;; part. And the list may be spread over several lines, cut ;; after a comma. (idlist-re (concat "\\([^< \t\n][^ \t\n]*" "\\(?:" comma-re "[^ \t\n]+\\)*\\)")) ;; A type. A few types are spread over 2 lines, ;; cut after the "=>", so we have to handle these as well. (type-re "\\(.*[^\n>]\\(?:>[ \t\n]+.*[^\n>]\\)*\\) *$") ;; A decl of a list of values, possibly indented. (val-decl-re (concat "^\\( +\\)?" idlist-re "[ \t\n]*::[ \t\n]*" type-re)) (re (concat ;; 3 possibilities: a class decl, a data decl, or val decl. ;; First, let's match a class decl. "^class \\(?:.*=>\\)? *\\(.*[^ \t\n]\\)[ \t\n]*where" ;; Or a value decl: "\\|" val-decl-re "\\|" ;; Or a data decl. We only handle single-arm ;; datatypes with labels. "^data +\\([[:alnum:]][[:alnum:] ]*[[:alnum:]]\\)" " *=.*{\\([^}]+\\)}" )) (re-class (concat "^[^ \t\n]\\|" re)) curclass) (while (re-search-forward (if curclass re-class re) nil t) (cond ;; A class decl. ((match-end 1) (setq curclass (match-string 1))) ;; A value decl. ((match-end 4) (let ((type (match-string 4)) (vars (match-string 3)) (indented (match-end 2))) (if (string-match "[ \t\n][ \t\n]+" type) (setq type (replace-match " " t t type))) (if (string-match " *\\(--.*\\)?\\'" type) (setq type (substring type 0 (match-beginning 0)))) (if indented (if curclass (if (string-match "\\`\\(.*[^ \t\n]\\) *=> *" type) (let ((classes (match-string 1 type))) (setq type (substring type (match-end 0))) (if (string-match "\\`(.*)\\'" classes) (setq classes (substring classes 1 -1))) (setq type (concat "(" curclass ", " classes ") => " type))) (setq type (concat curclass " => " type))) ;; It's actually not an error: just a type annotation on ;; some local variable. ;; (error "Indentation outside a class in %s: %s" ;; module vars) nil) (setq curclass nil)) (dolist (var (split-string vars comma-re t)) (if (string-match "(.*)" var) (setq var (substring var 1 -1))) (push (cons var type) elems)))) ;; A datatype decl. ((match-end 5) (setq curclass nil) (let ((name (match-string 5))) (save-excursion (save-restriction (narrow-to-region (match-beginning 6) (match-end 6)) (goto-char (point-min)) (while (re-search-forward val-decl-re nil t) (let ((vars (match-string 2)) (type (match-string 3))) (if (string-match "[ \t\n][ \t\n]+" type) (setq type (replace-match " " t t type))) (if (string-match " *\\(--.*\\)?\\'" type) (setq type (substring type 0 (match-beginning 0)))) (if (string-match ",\\'" type) (setq type (substring type 0 -1))) (setq type (concat name " -> " type)) (dolist (var (split-string vars comma-re t)) (if (string-match "(.*)" var) (setq var (substring var 1 -1))) (push (cons var type) elems)))))))) ;; The end of a class declaration. (t (setq curclass nil) (beginning-of-line)))) (cons (car (last modules)) elems))))) (defun haskell-doc-fetch-lib-urls (base-url) (with-temp-buffer (insert-file-contents base-url) (goto-char (point-min)) (search-forward "Part II: Libraries") (delete-region (point-min) (point)) (search-forward "</table>") (delete-region (point) (point-max)) (goto-char (point-min)) (let ((libs (list "standard-prelude.html"))) (while (re-search-forward "<a href=\"\\([^\"]+\\)\">" nil t) (push (match-string 1) libs)) (mapcar (lambda (s) (expand-file-name s (file-name-directory base-url))) (nreverse libs))))) (defun haskell-doc-extract-and-insert-types (url) "Fetch the types from the online doc and insert them at point. URL is the URL of the online doc." (interactive (if current-prefix-arg (read-file-name "URL: ") (list "http://www.haskell.org/onlinereport/"))) (let ((urls (haskell-doc-fetch-lib-urls url))) (dolist (url urls) (let ((data (haskell-doc-extract-types url))) (insert ";; " (pop data)) (indent-according-to-mode) (newline) (dolist (elem (sort data (lambda (x y) (string-lessp (car x) (car y))))) (prin1 elem (current-buffer)) (indent-according-to-mode) (newline)))))) (defvar haskell-doc-prelude-types ;; This list was auto generated by `haskell-doc-extract-and-insert-types'. '( ;; Prelude ("!!" . "[a] -> Int -> a") ("$" . "(a -> b) -> a -> b") ("$!" . "(a -> b) -> a -> b") ("&&" . "Bool -> Bool -> Bool") ("*" . "Num a => a -> a -> a") ("**" . "Floating a => a -> a -> a") ("+" . "Num a => a -> a -> a") ("++" . "[a] -> [a] -> [a]") ("-" . "Num a => a -> a -> a") ("." . "(b -> c) -> (a -> b) -> a -> c") ("/" . "Fractional a => a -> a -> a") ("/=" . "Eq a => a -> a -> Bool") ("<" . "Ord a => a -> a -> Bool") ("<=" . "Ord a => a -> a -> Bool") ("=<<" . "Monad m => (a -> m b) -> m a -> m b") ("==" . "Eq a => a -> a -> Bool") (">" . "Ord a => a -> a -> Bool") (">=" . "Ord a => a -> a -> Bool") (">>" . "Monad m => m a -> m b -> m b") (">>=" . "Monad m => m a -> (a -> m b) -> m b") ("^" . "(Num a, Integral b) => a -> b -> a") ("^^" . "(Fractional a, Integral b) => a -> b -> a") ("abs" . "Num a => a -> a") ("acos" . "Floating a => a -> a") ("acosh" . "Floating a => a -> a") ("all" . "(a -> Bool) -> [a] -> Bool") ("and" . "[Bool] -> Bool") ("any" . "(a -> Bool) -> [a] -> Bool") ("appendFile" . "FilePath -> String -> IO ()") ("asTypeOf" . "a -> a -> a") ("asin" . "Floating a => a -> a") ("asinh" . "Floating a => a -> a") ("atan" . "Floating a => a -> a") ("atan2" . "RealFloat a => a -> a -> a") ("atanh" . "Floating a => a -> a") ("break" . "(a -> Bool) -> [a] -> ([a],[a])") ("catch" . "IO a -> (IOError -> IO a) -> IO a") ("ceiling" . "(RealFrac a, Integral b) => a -> b") ("compare" . "Ord a => a -> a -> Ordering") ("concat" . "[[a]] -> [a]") ("concatMap" . "(a -> [b]) -> [a] -> [b]") ("const" . "a -> b -> a") ("cos" . "Floating a => a -> a") ("cosh" . "Floating a => a -> a") ("curry" . "((a, b) -> c) -> a -> b -> c") ("cycle" . "[a] -> [a]") ("decodeFloat" . "RealFloat a => a -> (Integer,Int)") ("div" . "Integral a => a -> a -> a") ("divMod" . "Integral a => a -> a -> (a,a)") ("drop" . "Int -> [a] -> [a]") ("dropWhile" . "(a -> Bool) -> [a] -> [a]") ("either" . "(a -> c) -> (b -> c) -> Either a b -> c") ("elem" . "(Eq a) => a -> [a] -> Bool") ("encodeFloat" . "RealFloat a => Integer -> Int -> a") ("enumFrom" . "Enum a => a -> [a]") ("enumFromThen" . "Enum a => a -> a -> [a]") ("enumFromThenTo" . "Enum a => a -> a -> a -> [a]") ("enumFromTo" . "Enum a => a -> a -> [a]") ("error" . "String -> a") ("even" . "(Integral a) => a -> Bool") ("exp" . "Floating a => a -> a") ("exponent" . "RealFloat a => a -> Int") ("fail" . "Monad m => String -> m a") ("filter" . "(a -> Bool) -> [a] -> [a]") ("flip" . "(a -> b -> c) -> b -> a -> c") ("floatDigits" . "RealFloat a => a -> Int") ("floatRadix" . "RealFloat a => a -> Integer") ("floatRange" . "RealFloat a => a -> (Int,Int)") ("floor" . "(RealFrac a, Integral b) => a -> b") ("fmap" . "Functor f => (a -> b) -> f a -> f b") ("foldl" . "(a -> b -> a) -> a -> [b] -> a") ("foldl1" . "(a -> a -> a) -> [a] -> a") ("foldr" . "(a -> b -> b) -> b -> [a] -> b") ("foldr1" . "(a -> a -> a) -> [a] -> a") ("fromEnum" . "Enum a => a -> Int") ("fromInteger" . "Num a => Integer -> a") ("fromIntegral" . "(Integral a, Num b) => a -> b") ("fromRational" . "Fractional a => Rational -> a") ("fst" . "(a,b) -> a") ("gcd" . "(Integral a) => a -> a -> a") ("getChar" . "IO Char") ("getContents" . "IO String") ("getLine" . "IO String") ("head" . "[a] -> a") ("id" . "a -> a") ("init" . "[a] -> [a]") ("interact" . "(String -> String) -> IO ()") ("ioError" . "IOError -> IO a") ("isDenormalized" . "RealFloat a => a -> Bool") ("isIEEE" . "RealFloat a => a -> Bool") ("isInfinite" . "RealFloat a => a -> Bool") ("isNaN" . "RealFloat a => a -> Bool") ("isNegativeZero" . "RealFloat a => a -> Bool") ("iterate" . "(a -> a) -> a -> [a]") ("last" . "[a] -> a") ("lcm" . "(Integral a) => a -> a -> a") ("length" . "[a] -> Int") ("lex" . "ReadS String") ("lines" . "String -> [String]") ("log" . "Floating a => a -> a") ("logBase" . "Floating a => a -> a -> a") ("lookup" . "(Eq a) => a -> [(a,b)] -> Maybe b") ("map" . "(a -> b) -> [a] -> [b]") ("mapM" . "Monad m => (a -> m b) -> [a] -> m [b]") ("mapM_" . "Monad m => (a -> m b) -> [a] -> m ()") ("max" . "Ord a => a -> a -> a") ("maxBound" . "Bounded a => a") ("maximum" . "(Ord a) => [a] -> a") ("maybe" . "b -> (a -> b) -> Maybe a -> b") ("min" . "Ord a => a -> a -> a") ("minBound" . "Bounded a => a") ("minimum" . "(Ord a) => [a] -> a") ("mod" . "Integral a => a -> a -> a") ("negate" . "Num a => a -> a") ("not" . "Bool -> Bool") ("notElem" . "(Eq a) => a -> [a] -> Bool") ("null" . "[a] -> Bool") ("numericEnumFrom" . "(Fractional a) => a -> [a]") ("numericEnumFromThen" . "(Fractional a) => a -> a -> [a]") ("numericEnumFromThenTo" . "(Fractional a, Ord a) => a -> a -> a -> [a]") ("numericEnumFromTo" . "(Fractional a, Ord a) => a -> a -> [a]") ("odd" . "(Integral a) => a -> Bool") ("or" . "[Bool] -> Bool") ("otherwise" . "Bool") ("pi" . "Floating a => a") ("pred" . "Enum a => a -> a") ("print" . "Show a => a -> IO ()") ("product" . "(Num a) => [a] -> a") ("properFraction" . "(RealFrac a, Integral b) => a -> (b,a)") ("putChar" . "Char -> IO ()") ("putStr" . "String -> IO ()") ("putStrLn" . "String -> IO ()") ("quot" . "Integral a => a -> a -> a") ("quotRem" . "Integral a => a -> a -> (a,a)") ("read" . "(Read a) => String -> a") ("readFile" . "FilePath -> IO String") ("readIO" . "Read a => String -> IO a") ("readList" . "Read a => ReadS [a]") ("readLn" . "Read a => IO a") ("readParen" . "Bool -> ReadS a -> ReadS a") ("reads" . "(Read a) => ReadS a") ("readsPrec" . "Read a => Int -> ReadS a") ("realToFrac" . "(Real a, Fractional b) => a -> b") ("recip" . "Fractional a => a -> a") ("rem" . "Integral a => a -> a -> a") ("repeat" . "a -> [a]") ("replicate" . "Int -> a -> [a]") ("return" . "Monad m => a -> m a") ("reverse" . "[a] -> [a]") ("round" . "(RealFrac a, Integral b) => a -> b") ("scaleFloat" . "RealFloat a => Int -> a -> a") ("scanl" . "(a -> b -> a) -> a -> [b] -> [a]") ("scanl1" . "(a -> a -> a) -> [a] -> [a]") ("scanr" . "(a -> b -> b) -> b -> [a] -> [b]") ("scanr1" . "(a -> a -> a) -> [a] -> [a]") ("seq" . "a -> b -> b") ("sequence" . "Monad m => [m a] -> m [a]") ("sequence_" . "Monad m => [m a] -> m ()") ("show" . "Show a => a -> String") ("showChar" . "Char -> ShowS") ("showList" . "Show a => [a] -> ShowS") ("showParen" . "Bool -> ShowS -> ShowS") ("showString" . "String -> ShowS") ("shows" . "(Show a) => a -> ShowS") ("showsPrec" . "Show a => Int -> a -> ShowS") ("significand" . "RealFloat a => a -> a") ("signum" . "Num a => a -> a") ("sin" . "Floating a => a -> a") ("sinh" . "Floating a => a -> a") ("snd" . "(a,b) -> b") ("span" . "(a -> Bool) -> [a] -> ([a],[a])") ("splitAt" . "Int -> [a] -> ([a],[a])") ("sqrt" . "Floating a => a -> a") ("subtract" . "(Num a) => a -> a -> a") ("succ" . "Enum a => a -> a") ("sum" . "(Num a) => [a] -> a") ("tail" . "[a] -> [a]") ("take" . "Int -> [a] -> [a]") ("takeWhile" . "(a -> Bool) -> [a] -> [a]") ("tan" . "Floating a => a -> a") ("tanh" . "Floating a => a -> a") ("toEnum" . "Enum a => Int -> a") ("toInteger" . "Integral a => a -> Integer") ("toRational" . "Real a => a -> Rational") ("truncate" . "(RealFrac a, Integral b) => a -> b") ("uncurry" . "(a -> b -> c) -> ((a, b) -> c)") ("undefined" . "a") ("unlines" . "[String] -> String") ("until" . "(a -> Bool) -> (a -> a) -> a -> a") ("unwords" . "[String] -> String") ("unzip" . "[(a,b)] -> ([a],[b])") ("unzip3" . "[(a,b,c)] -> ([a],[b],[c])") ("userError" . "String -> IOError") ("words" . "String -> [String]") ("writeFile" . "FilePath -> String -> IO ()") ("zip" . "[a] -> [b] -> [(a,b)]") ("zip3" . "[a] -> [b] -> [c] -> [(a,b,c)]") ("zipWith" . "(a->b->c) -> [a]->[b]->[c]") ("zipWith3" . "(a->b->c->d) -> [a]->[b]->[c]->[d]") ("||" . "Bool -> Bool -> Bool") ;; Ratio ("%" . "(Integral a) => a -> a -> Ratio a") ("approxRational" . "(RealFrac a) => a -> a -> Rational") ("denominator" . "(Integral a) => Ratio a -> a") ("numerator" . "(Integral a) => Ratio a -> a") ;; Complex ("cis" . "(RealFloat a) => a -> Complex a") ("conjugate" . "(RealFloat a) => Complex a -> Complex a") ("imagPart" . "(RealFloat a) => Complex a -> a") ("magnitude" . "(RealFloat a) => Complex a -> a") ("mkPolar" . "(RealFloat a) => a -> a -> Complex a") ("phase" . "(RealFloat a) => Complex a -> a") ("polar" . "(RealFloat a) => Complex a -> (a,a)") ("realPart" . "(RealFloat a) => Complex a -> a") ;; Numeric ("floatToDigits" . "(RealFloat a) => Integer -> a -> ([Int], Int)") ("fromRat" . "(RealFloat a) => Rational -> a") ("lexDigits" . "ReadS String") ("readDec" . "(Integral a) => ReadS a") ("readFloat" . "(RealFrac a) => ReadS a") ("readHex" . "(Integral a) => ReadS a") ("readInt" . "(Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a") ("readOct" . "(Integral a) => ReadS a") ("readSigned" . "(Real a) => ReadS a -> ReadS a") ("showEFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") ("showFFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") ("showFloat" . "(RealFloat a) => a -> ShowS") ("showGFloat" . "(RealFloat a) => Maybe Int -> a -> ShowS") ("showHex" . "Integral a => a -> ShowS") ("showInt" . "Integral a => a -> ShowS") ("showIntAtBase" . "Integral a => a -> (Int -> Char) -> a -> ShowS") ("showOct" . "Integral a => a -> ShowS") ("showSigned" . "(Real a) => (a -> ShowS) -> Int -> a -> ShowS") ;; Ix ("inRange" . "Ix a => (a,a) -> a -> Bool") ("index" . "Ix a => (a,a) -> a -> Int") ("range" . "Ix a => (a,a) -> [a]") ("rangeSize" . "Ix a => (a,a) -> Int") ;; Array ("!" . "(Ix a) => Array a b -> a -> b") ("//" . "(Ix a) => Array a b -> [(a,b)] -> Array a b") ("accum" . "(Ix a) => (b -> c -> b) -> Array a b -> [(a,c)]") ("accumArray" . "(Ix a) => (b -> c -> b) -> b -> (a,a) -> [(a,c)]") ("array" . "(Ix a) => (a,a) -> [(a,b)] -> Array a b") ("assocs" . "(Ix a) => Array a b -> [(a,b)]") ("bounds" . "(Ix a) => Array a b -> (a,a)") ("elems" . "(Ix a) => Array a b -> [b]") ("indices" . "(Ix a) => Array a b -> [a]") ("ixmap" . "(Ix a, Ix b) => (a,a) -> (a -> b) -> Array b c") ("listArray" . "(Ix a) => (a,a) -> [b] -> Array a b") ;; List ("\\\\" . "Eq a => [a] -> [a] -> [a]") ("delete" . "Eq a => a -> [a] -> [a]") ("deleteBy" . "(a -> a -> Bool) -> a -> [a] -> [a]") ("deleteFirstsBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") ("elemIndex" . "Eq a => a -> [a] -> Maybe Int") ("elemIndices" . "Eq a => a -> [a] -> [Int]") ("find" . "(a -> Bool) -> [a] -> Maybe a") ("findIndex" . "(a -> Bool) -> [a] -> Maybe Int") ("findIndices" . "(a -> Bool) -> [a] -> [Int]") ("genericDrop" . "Integral a => a -> [b] -> [b]") ("genericIndex" . "Integral a => [b] -> a -> b") ("genericLength" . "Integral a => [b] -> a") ("genericReplicate" . "Integral a => a -> b -> [b]") ("genericSplitAt" . "Integral a => a -> [b] -> ([b],[b])") ("genericTake" . "Integral a => a -> [b] -> [b]") ("group" . "Eq a => [a] -> [[a]]") ("groupBy" . "(a -> a -> Bool) -> [a] -> [[a]]") ("inits" . "[a] -> [[a]]") ("insert" . "Ord a => a -> [a] -> [a]") ("insertBy" . "(a -> a -> Ordering) -> a -> [a] -> [a]") ("intersect" . "Eq a => [a] -> [a] -> [a]") ("intersectBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") ("intersperse" . "a -> [a] -> [a]") ("isPrefixOf" . "Eq a => [a] -> [a] -> Bool") ("isSuffixOf" . "Eq a => [a] -> [a] -> Bool") ("mapAccumL" . "(a -> b -> (a, c)) -> a -> [b] -> (a, [c])") ("mapAccumR" . "(a -> b -> (a, c)) -> a -> [b] -> (a, [c])") ("maximumBy" . "(a -> a -> Ordering) -> [a] -> a") ("minimumBy" . "(a -> a -> Ordering) -> [a] -> a") ("nub" . "Eq a => [a] -> [a]") ("nubBy" . "(a -> a -> Bool) -> [a] -> [a]") ("partition" . "(a -> Bool) -> [a] -> ([a],[a])") ("sort" . "Ord a => [a] -> [a]") ("sortBy" . "(a -> a -> Ordering) -> [a] -> [a]") ("tails" . "[a] -> [[a]]") ("transpose" . "[[a]] -> [[a]]") ("unfoldr" . "(b -> Maybe (a,b)) -> b -> [a]") ("union" . "Eq a => [a] -> [a] -> [a]") ("unionBy" . "(a -> a -> Bool) -> [a] -> [a] -> [a]") ("unzip4" . "[(a,b,c,d)] -> ([a],[b],[c],[d])") ("unzip5" . "[(a,b,c,d,e)] -> ([a],[b],[c],[d],[e])") ("unzip6" . "[(a,b,c,d,e,f)] -> ([a],[b],[c],[d],[e],[f])") ("unzip7" . "[(a,b,c,d,e,f,g)] -> ([a],[b],[c],[d],[e],[f],[g])") ("zip4" . "[a] -> [b] -> [c] -> [d] -> [(a,b,c,d)]") ("zip5" . "[a] -> [b] -> [c] -> [d] -> [e] -> [(a,b,c,d,e)]") ("zip6" . "[a] -> [b] -> [c] -> [d] -> [e] -> [f]") ("zip7" . "[a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g]") ("zipWith4" . "(a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]") ("zipWith5" . "(a->b->c->d->e->f) ->") ("zipWith6" . "(a->b->c->d->e->f->g) -> [a]->[b]->[c]->[d]->[e]->[f]->[g]") ("zipWith7" . "(a->b->c->d->e->f->g->h) -> [a]->[b]->[c]->[d]->[e]->[f]->[g]->[h]") ;; Maybe ("catMaybes" . "[Maybe a] -> [a]") ("fromJust" . "Maybe a -> a") ("fromMaybe" . "a -> Maybe a -> a") ("isJust" . "Maybe a -> Bool") ("isNothing" . "Maybe a -> Bool") ("listToMaybe" . "[a] -> Maybe a") ("mapMaybe" . "(a -> Maybe b) -> [a] -> [b]") ("maybeToList" . "Maybe a -> [a]") ;; Char ("chr" . "Int -> Char") ("digitToInt" . "Char -> Int") ("intToDigit" . "Int -> Char") ("isAlpha" . "Char -> Bool") ("isAlphaNum" . "Char -> Bool") ("isAscii" . "Char -> Bool") ("isControl" . "Char -> Bool") ("isDigit" . "Char -> Bool") ("isHexDigit" . "Char -> Bool") ("isLatin1" . "Char -> Bool") ("isLower" . "Char -> Bool") ("isOctDigit" . "Char -> Bool") ("isPrint" . "Char -> Bool") ("isSpace" . "Char -> Bool") ("isUpper" . "Char -> Bool") ("lexLitChar" . "ReadS String") ("ord" . "Char -> Int") ("readLitChar" . "ReadS Char") ("showLitChar" . "Char -> ShowS") ("toLower" . "Char -> Char") ("toUpper" . "Char -> Char") ;; Monad ("ap" . "Monad m => m (a -> b) -> m a -> m b") ("filterM" . "Monad m => (a -> m Bool) -> [a] -> m [a]") ("foldM" . "Monad m => (a -> b -> m a) -> a -> [b] -> m a") ("guard" . "MonadPlus m => Bool -> m ()") ("join" . "Monad m => m (m a) -> m a") ("liftM" . "Monad m => (a -> b) -> (m a -> m b)") ("liftM2" . "Monad m => (a -> b -> c) -> (m a -> m b -> m c)") ("liftM3" . "Monad m => (a -> b -> c -> d) -> (m a -> m b -> m c -> m d)") ("liftM4" . "Monad m => (a -> b -> c -> d -> e) -> (m a -> m b -> m c -> m d -> m e)") ("liftM5" . "Monad m => (a -> b -> c -> d -> e -> f) -> (m a -> m b -> m c -> m d -> m e -> m f)") ("mapAndUnzipM" . "Monad m => (a -> m (b,c)) -> [a] -> m ([b], [c])") ("mplus" . "MonadPlus m => m a -> m a -> m a") ("msum" . "MonadPlus m => [m a] -> m a") ("mzero" . "MonadPlus m => m a") ("unless" . "Monad m => Bool -> m () -> m ()") ("when" . "Monad m => Bool -> m () -> m ()") ("zipWithM" . "Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]") ("zipWithM_" . "Monad m => (a -> b -> m c) -> [a] -> [b] -> m ()") ;; IO ("bracket" . "IO a -> (a -> IO b) -> (a -> IO c) -> IO c") ("bracket_" . "IO a -> (a -> IO b) -> IO c -> IO c") ("hClose" . "Handle -> IO ()") ("hFileSize" . "Handle -> IO Integer") ("hFlush" . "Handle -> IO ()") ("hGetBuffering" . "Handle -> IO BufferMode") ("hGetChar" . "Handle -> IO Char") ("hGetContents" . "Handle -> IO String") ("hGetLine" . "Handle -> IO String") ("hGetPosn" . "Handle -> IO HandlePosn") ("hIsClosed" . "Handle -> IO Bool") ("hIsEOF" . "Handle -> IO Bool") ("hIsOpen" . "Handle -> IO Bool") ("hIsReadable" . "Handle -> IO Bool") ("hIsSeekable" . "Handle -> IO Bool") ("hIsWritable" . "Handle -> IO Bool") ("hLookAhead" . "Handle -> IO Char") ("hPrint" . "Show a => Handle -> a -> IO ()") ("hPutChar" . "Handle -> Char -> IO ()") ("hPutStr" . "Handle -> String -> IO ()") ("hPutStrLn" . "Handle -> String -> IO ()") ("hReady" . "Handle -> IO Bool") ("hSeek" . "Handle -> SeekMode -> Integer -> IO ()") ("hSetBuffering" . "Handle -> BufferMode -> IO ()") ("hSetPosn" . "HandlePosn -> IO ()") ("hWaitForInput" . "Handle -> Int -> IO Bool") ("ioeGetErrorString" . "IOError -> String") ("ioeGetFileName" . "IOError -> Maybe FilePath") ("ioeGetHandle" . "IOError -> Maybe Handle") ("isAlreadyExistsError" . "IOError -> Bool") ("isAlreadyInUseError" . "IOError -> Bool") ("isDoesNotExistError" . "IOError -> Bool") ("isEOF" . "IO Bool") ("isEOFError" . "IOError -> Bool") ("isFullError" . "IOError -> Bool") ("isIllegalOperation" . "IOError -> Bool") ("isPermissionError" . "IOError -> Bool") ("isUserError" . "IOError -> Bool") ("openFile" . "FilePath -> IOMode -> IO Handle") ("stderr" . "Handle") ("stdin" . "Handle") ("stdout" . "Handle") ("try" . "IO a -> IO (Either IOError a)") ;; Directory ("createDirectory" . "FilePath -> IO ()") ("doesDirectoryExist" . "FilePath -> IO Bool") ("doesFileExist" . "FilePath -> IO Bool") ("executable" . "Permissions -> Bool") ("getCurrentDirectory" . "IO FilePath") ("getDirectoryContents" . "FilePath -> IO [FilePath]") ("getModificationTime" . "FilePath -> IO ClockTime") ("getPermissions" . "FilePath -> IO Permissions") ("readable" . "Permissions -> Bool") ("removeDirectory" . "FilePath -> IO ()") ("removeFile" . "FilePath -> IO ()") ("renameDirectory" . "FilePath -> FilePath -> IO ()") ("renameFile" . "FilePath -> FilePath -> IO ()") ("searchable" . "Permissions -> Bool") ("setCurrentDirectory" . "FilePath -> IO ()") ("setPermissions" . "FilePath -> Permissions -> IO ()") ("writable" . "Permissions -> Bool") ;; System ("exitFailure" . "IO a") ("exitWith" . "ExitCode -> IO a") ("getArgs" . "IO [String]") ("getEnv" . "String -> IO String") ("getProgName" . "IO String") ("system" . "String -> IO ExitCode") ;; Time ("addToClockTime" . "TimeDiff -> ClockTime -> ClockTime") ("calendarTimeToString" . "CalendarTime -> String") ("ctDay" . "CalendarTime -> Int") ("ctHour" . "CalendarTime -> Int") ("ctIsDST" . "CalendarTime -> Bool") ("ctMin" . "CalendarTime -> Int") ("ctMonth" . "CalendarTime -> Month") ("ctPicosec" . "CalendarTime -> Integer") ("ctSec" . "CalendarTime -> Int") ("ctTZ" . "CalendarTime -> Int") ("ctTZName" . "CalendarTime -> String") ("ctWDay" . "CalendarTime -> Day") ("ctYDay" . "CalendarTime -> Int") ("ctYear" . "CalendarTime -> Int") ("diffClockTimes" . "ClockTime -> ClockTime -> TimeDiff") ("formatCalendarTime" . "TimeLocale -> String -> CalendarTime -> String") ("getClockTime" . "IO ClockTime") ("tdDay" . "TimeDiff -> Int") ("tdHour" . "TimeDiff -> Int") ("tdMin" . "TimeDiff -> Int") ("tdMonth" . "TimeDiff -> Int") ("tdPicosec" . "TimeDiff -> Integer") ("tdSec" . "TimeDiff -> Int") ("tdYear" . "TimeDiff -> Int") ("toCalendarTime" . "ClockTime -> IO CalendarTime") ("toClockTime" . "CalendarTime -> ClockTime") ("toUTCTime" . "ClockTime -> CalendarTime") ;; Locale ("amPm" . "TimeLocale -> (String, String)") ("dateFmt" . "TimeLocale -> String") ("dateTimeFmt" . "TimeLocale -> String") ("defaultTimeLocale" . "TimeLocale") ("months" . "TimeLocale -> [(String, String)]") ("time12Fmt" . "TimeLocale -> String") ("timeFmt" . "TimeLocale -> String") ("wDays" . "TimeLocale -> [(String, String)]") ;; CPUTime ("cpuTimePrecision" . "Integer") ("getCPUTime" . "IO Integer") ;; Random ("genRange" . "RandomGen g => g -> (Int, Int)") ("getStdGen" . "IO StdGen") ("getStdRandom" . "(StdGen -> (a, StdGen)) -> IO a") ("mkStdGen" . "Int -> StdGen") ("newStdGen" . "IO StdGen") ("next" . "RandomGen g => g -> (Int, g)") ("random" . "(Random a, RandomGen g) => g -> (a, g)") ("randomIO" . "Random a => IO a") ("randomR" . "(Random a, RandomGen g) => (a, a) -> g -> (a, g)") ("randomRIO" . "Random a => (a,a) -> IO a") ("randomRs" . "(Random a, RandomGen g) => (a, a) -> g -> [a]") ("randoms" . "(Random a, RandomGen g) => g -> [a]") ("setStdGen" . "StdGen -> IO ()") ("split" . "RandomGen g => g -> (g, g)") ) "Alist of prelude functions and their types.") (defvar haskell-doc-strategy-ids (list '("par" . "Done -> Done -> Done ; [infixr 0]") '("seq" . "Done -> Done -> Done ; [infixr 1]") '("using" . "a -> Strategy a -> a ; [infixl 0]") '("demanding" . "a -> Done -> a ; [infixl 0]") '("sparking" . "a -> Done -> a ; [infixl 0]") '(">||" . "Done -> Done -> Done ; [infixr 2]") '(">|" . "Done -> Done -> Done ; [infixr 3]") '("$||" . "(a -> b) -> Strategy a -> a -> b ; [infixl 6]") '("$|" . "(a -> b) -> Strategy a -> a -> b ; [infixl 6]") '(".|" . "(b -> c) -> Strategy b -> (a -> b) -> (a -> c) ; [infixl 9]") '(".||" . "(b -> c) -> Strategy b -> (a -> b) -> (a -> c) ; [infixl 9]") '("-|" . "(a -> b) -> Strategy b -> (b -> c) -> (a -> c) ; [infixl 9]") '("-||" . "(a -> b) -> Strategy b -> (b -> c) -> (a -> c) ; [infixl 9]") '("Done" . "type Done = ()") '("Strategy" . "type Strategy a = a -> Done") '("r0" . "Strategy a") '("rwhnf" . "Eval a => Strategy a") '("rnf" . "Strategy a") '("NFData" . "class Eval a => NFData a where rnf :: Strategy a") '("NFDataIntegral" ."class (NFData a, Integral a) => NFDataIntegral a") '("NFDataOrd" . "class (NFData a, Ord a) => NFDataOrd a") '("markStrat" . "Int -> Strategy a -> Strategy a") '("seqPair" . "Strategy a -> Strategy b -> Strategy (a,b)") '("parPair" . "Strategy a -> Strategy b -> Strategy (a,b)") '("seqTriple" . "Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)") '("parTriple" . "Strategy a -> Strategy b -> Strategy c -> Strategy (a,b,c)") '("parList" . "Strategy a -> Strategy [a]") '("parListN" . "(Integral b) => b -> Strategy a -> Strategy [a]") '("parListNth" . "Int -> Strategy a -> Strategy [a]") '("parListChunk" . "Int -> Strategy a -> Strategy [a]") '("parMap" . "Strategy b -> (a -> b) -> [a] -> [b]") '("parFlatMap" . "Strategy [b] -> (a -> [b]) -> [a] -> [b]") '("parZipWith" . "Strategy c -> (a -> b -> c) -> [a] -> [b] -> [c]") '("seqList" . "Strategy a -> Strategy [a]") '("seqListN" . "(Integral a) => a -> Strategy b -> Strategy [b]") '("seqListNth" . "Int -> Strategy b -> Strategy [b]") '("parBuffer" . "Int -> Strategy a -> [a] -> [a]") '("seqArr" . "(Ix b) => Strategy a -> Strategy (Array b a)") '("parArr" . "(Ix b) => Strategy a -> Strategy (Array b a)") '("fstPairFstList" . "(NFData a) => Strategy [(a,b)]") '("force" . "(NFData a) => a -> a ") '("sforce" . "(NFData a) => a -> b -> b") ) "Alist of strategy functions and their types as defined in Strategies.lhs.") (defvar haskell-doc-user-defined-ids nil "Alist of functions and strings defined by the user.") (defsubst haskell-doc-is-of (fn types) "Check whether FN is one of the functions in the alist TYPES and return the type." (assoc fn types) ) ;; Put this minor mode on the global minor-mode-alist. (or (assq 'haskell-doc-mode (default-value 'minor-mode-alist)) (setq-default minor-mode-alist (append (default-value 'minor-mode-alist) '((haskell-doc-mode haskell-doc-minor-mode-string))))) (defvar haskell-doc-keymap (let ((map (make-sparse-keymap))) (define-key map [visit] '("Visit FTP home site" . haskell-doc-visit-home)) (define-key map [submit] '("Submit bug report" . haskell-doc-submit-bug-report)) (define-key map [dummy] '("---" . nil)) (define-key map [make-index] '("Make global fct index" . haskell-doc-make-global-fct-index)) (define-key map [global-types-on] '("Toggle display of global types" . haskell-doc-show-global-types)) (define-key map [strategy-on] '("Toggle display of strategy ids" . haskell-doc-show-strategy)) (define-key map [user-defined-on] '("Toggle display of user defined ids" . haskell-doc-show-user-defined)) (define-key map [prelude-on] '("Toggle display of prelude functions" . haskell-doc-show-prelude)) (define-key map [reserved-ids-on] '("Toggle display of reserved ids" . haskell-doc-show-reserved)) (define-key map [haskell-doc-on] '("Toggle haskell-doc mode" . haskell-doc-mode)) map)) (defun haskell-doc-install-keymap () "Install a menu for `haskell-doc-mode' as a submenu of \"Hugs\"." (interactive) ;; Add the menu to the hugs menu as last entry. (let ((hugsmap (lookup-key (current-local-map) [menu-bar Hugs]))) (if (not (or (featurep 'xemacs) ; XEmacs has problems here (not (keymapp hugsmap)) (lookup-key hugsmap [haskell-doc]))) (if (functionp 'define-key-after) (define-key-after hugsmap [haskell-doc] (cons "Haskell-doc" haskell-doc-keymap) [Haskell-doc mode])))) ;; Add shortcuts for these commands. (local-set-key "\C-c\e/" 'haskell-doc-check-active) ;; Conflicts with the binding of haskell-insert-otherwise. ;; (local-set-key "\C-c\C-o" 'haskell-doc-mode) (local-set-key [(control shift meta mouse-3)] 'haskell-doc-ask-mouse-for-type)) (defvar haskell-doc-timer nil) (defvar haskell-doc-buffers nil) ;;;###autoload (defun haskell-doc-mode (&optional arg) "Enter `haskell-doc-mode' for showing fct types in the echo area. See variable docstring." (interactive (list (or current-prefix-arg 'toggle))) (setq haskell-doc-mode (cond ((eq arg 'toggle) (not haskell-doc-mode)) (arg (> (prefix-numeric-value arg) 0)) (t))) ;; First, unconditionally turn the mode OFF. (setq haskell-doc-buffers (delq (current-buffer) haskell-doc-buffers)) ;; Refresh the buffers list. (dolist (buf haskell-doc-buffers) (unless (and (buffer-live-p buf) (with-current-buffer buf haskell-doc-mode)) (setq haskell-doc-buffers (delq buf haskell-doc-buffers)))) ;; Turn off the idle timer (or idle post-command-hook). (when (and haskell-doc-timer (null haskell-doc-buffers)) (cancel-timer haskell-doc-timer) (setq haskell-doc-timer nil)) (remove-hook 'post-command-hook 'haskell-doc-mode-print-current-symbol-info 'local) (when haskell-doc-mode ;; Turning the mode ON. (push (current-buffer) haskell-doc-buffers) (if (fboundp 'run-with-idle-timer) (unless haskell-doc-timer (setq haskell-doc-timer (run-with-idle-timer haskell-doc-idle-delay t 'haskell-doc-mode-print-current-symbol-info))) (add-hook 'post-command-hook 'haskell-doc-mode-print-current-symbol-info nil 'local)) (and haskell-doc-show-global-types (haskell-doc-make-global-fct-index)) ; build type index for global fcts (haskell-doc-install-keymap) (run-hooks 'haskell-doc-mode-hook)) (and (called-interactively-p 'any) (message "haskell-doc-mode is %s" (if haskell-doc-mode "enabled" "disabled"))) haskell-doc-mode) (defmacro haskell-doc-toggle-var (id prefix) ;; toggle variable or set it based on prefix value `(setq ,id (if ,prefix (>= (prefix-numeric-value ,prefix) 0) (not ,id))) ) (defun haskell-doc-show-global-types (&optional prefix) "Turn on global types information in `haskell-doc-mode'." (interactive "P") (haskell-doc-toggle-var haskell-doc-show-global-types prefix) (if haskell-doc-show-global-types (haskell-doc-make-global-fct-index))) (defun haskell-doc-show-reserved (&optional prefix) "Toggle the automatic display of a doc string for reserved ids." (interactive "P") (haskell-doc-toggle-var haskell-doc-show-reserved prefix)) (defun haskell-doc-show-prelude (&optional prefix) "Toggle the automatic display of a doc string for reserved ids." (interactive "P") (haskell-doc-toggle-var haskell-doc-show-prelude prefix)) (defun haskell-doc-show-strategy (&optional prefix) "Toggle the automatic display of a doc string for strategy ids." (interactive "P") (haskell-doc-toggle-var haskell-doc-show-strategy prefix)) (defun haskell-doc-show-user-defined (&optional prefix) "Toggle the automatic display of a doc string for user defined ids." (interactive "P") (haskell-doc-toggle-var haskell-doc-show-user-defined prefix)) ;;;###autoload (defalias 'turn-on-haskell-doc-mode 'haskell-doc-mode) (make-obsolete 'turn-on-haskell-doc-mode 'haskell-doc-mode "2015-07-23") ;;;###autoload (defalias 'turn-on-haskell-doc 'haskell-doc-mode) (make-obsolete 'turn-on-haskell-doc 'haskell-doc-mode "2015-07-23") (defalias 'turn-off-haskell-doc-mode 'turn-off-haskell-doc) (defun turn-off-haskell-doc () "Unequivocally turn off `haskell-doc-mode' (which see)." (haskell-doc-mode 0)) (defun haskell-doc-check-active () "Check whether the print function is hooked in. Should be the same as the value of `haskell-doc-mode' but alas currently it is not." (interactive) (message "%s" (if (or (and haskell-doc-mode haskell-doc-timer) (memq 'haskell-doc-mode-print-current-symbol-info post-command-hook)) "haskell-doc is ACTIVE" (substitute-command-keys "haskell-doc is not ACTIVE \(Use \\[haskell-doc-mode] to turn it on\)")))) ;; This is the function hooked into the elisp command engine (defun haskell-doc-mode-print-current-symbol-info () "Print the type of the symbol under the cursor. This function is run by an idle timer to print the type automatically if `haskell-doc-mode' is turned on." (and haskell-doc-mode (haskell-doc-in-code-p) (not haskell-mode-interactive-prompt-state) (not (eobp)) (not executing-kbd-macro) ;; Having this mode operate in the minibuffer makes it impossible to ;; see what you're doing. (not (eq (selected-window) (minibuffer-window))) ;; not in string or comment ;; take a nap, if run straight from post-command-hook. (if (fboundp 'run-with-idle-timer) t (sit-for haskell-doc-idle-delay)) ;; good morning! read the word under the cursor for breakfast (haskell-doc-show-type))) ;; ;; ToDo: find surrounding fct ;; (cond ((eq current-symbol current-fnsym) ;; (haskell-doc-show-type current-fnsym)) ;; (t ;; (or nil ; (haskell-doc-print-var-docstring current-symbol) ;; (haskell-doc-show-type current-fnsym))))))) ;;;###autoload (defun haskell-doc-current-info () "Return the info about symbol at point. Meant for `eldoc-documentation-function'." ;; There are a number of possible documentation functions. ;; Some of them are asynchronous. (when (haskell-doc-in-code-p) (let ((msg (or (haskell-doc-current-info--interaction) (haskell-doc-sym-doc (haskell-ident-at-point))))) (unless (symbolp msg) msg)))) (defun haskell-doc-ask-mouse-for-type (event) "Read the identifier under the mouse and echo its type. This uses the same underlying function `haskell-doc-show-type' as the hooked function. Only the user interface is different." (interactive "e") (save-excursion (select-window (posn-window (event-end event))) (goto-char (posn-point (event-end event))) (haskell-doc-show-type))) (defun haskell-doc-in-code-p () "A predicate indicating suitable case to show docs." (not (or (and (eq haskell-literate 'bird) ;; Copied from haskell-indent-bolp. (<= (current-column) 2) (eq (char-after (line-beginning-position)) ?\>)) (nth 8 (syntax-ppss))))) ;;;###autoload (defun haskell-doc-show-type (&optional sym) "Show the type of the function near point or given symbol SYM. For the function under point, show the type in the echo area. This information is extracted from the `haskell-doc-prelude-types' alist of prelude functions and their types, or from the local functions in the current buffer." (interactive) (unless sym (setq sym (haskell-ident-at-point))) ;; if printed before do not print it again (unless (string= sym (car haskell-doc-last-data)) (let ((doc (or (haskell-doc-current-info--interaction t) (haskell-doc-sym-doc sym)))) (when (and doc (haskell-doc-in-code-p)) ;; In Emacs 19.29 and later, and XEmacs 19.13 and later, all ;; messages are recorded in a log. Do not put haskell-doc messages ;; in that log since they are legion. (let ((message-log-max nil)) (message "%s" doc)))))) (defvar haskell-doc-current-info--interaction-last nil "Async message stack. If non-nil, a previous eldoc message from an async call, that hasn't been displayed yet.") (defun haskell-doc-current-info--interaction (&optional sync) "Asynchronous call to `haskell-process-get-type'. Suitable for use in the eldoc function `haskell-doc-current-info'. If SYNC is non-nil, the call will be synchronous instead, and instead of calling `eldoc-print-current-symbol-info', the result will be returned directly." ;; Return nil if nothing is available, or 'async if something might ;; be available, but asynchronously later. This will call ;; `eldoc-print-current-symbol-info' later. (when (haskell-doc-in-code-p) ;; do nothing when inside string or comment (let (sym prev-message) (cond ((setq prev-message haskell-doc-current-info--interaction-last) (setq haskell-doc-current-info--interaction-last nil) (cdr prev-message)) ((setq sym (if (use-region-p) (buffer-substring-no-properties (region-beginning) (region-end)) (haskell-ident-at-point))) (if sync (haskell-process-get-type sym #'identity t) (haskell-process-get-type sym (lambda (response) (setq haskell-doc-current-info--interaction-last (cons 'async response)) (eldoc-print-current-symbol-info))))))))) (defun haskell-process-get-type (expr-string &optional callback sync) "Asynchronously get the type of a given string. EXPR-STRING should be an expression passed to :type in ghci. CALLBACK will be called with a formatted type string. If SYNC is non-nil, make the call synchronously instead." (unless callback (setq callback (lambda (response) (message "%s" response)))) (let ((process (and (haskell-session-maybe) (haskell-session-process (haskell-session-maybe)))) ;; Avoid passing bad strings to ghci (expr-okay (and (not (string-match-p "\\`[[:space:]]*\\'" expr-string)) (not (string-match-p "\n" expr-string)))) (ghci-command (concat ":type " expr-string)) (process-response (lambda (response) ;; Responses with empty first line are likely errors (if (string-match-p (rx string-start line-end) response) (setq response nil) ;; Remove a newline at the end (setq response (replace-regexp-in-string "\n\\'" "" response)) ;; Propertize for eldoc (save-match-data (when (string-match " :: " response) ;; Highlight type (let ((name (substring response 0 (match-end 0))) (type (propertize (substring response (match-end 0)) 'face 'eldoc-highlight-function-argument))) (setq response (concat name type))))) (when haskell-doc-prettify-types (dolist (re '(("::" . "∷") ("=>" . "⇒") ("->" . "→"))) (setq response (replace-regexp-in-string (car re) (cdr re) response)))) response)))) (when (and process expr-okay) (if sync (let ((response (haskell-process-queue-sync-request process ghci-command))) (funcall callback (funcall process-response response))) (haskell-process-queue-command process (make-haskell-command :go (lambda (_) (haskell-process-send-string process ghci-command)) :complete (lambda (_ response) (funcall callback (funcall process-response response))))) 'async)))) (defun haskell-doc-sym-doc (sym) "Show the type of given symbol SYM. For the function under point, show the type in the echo area. This information is extracted from the `haskell-doc-prelude-types' alist of prelude functions and their types, or from the local functions in the current buffer. If `haskell-doc-use-inf-haskell' is non-nil, this function will consult the inferior Haskell process for type/kind information, rather than using the haskell-doc database." (if haskell-doc-use-inf-haskell (unless (or (null sym) (string= "" sym)) (let* ((message-log-max nil) (result (ignore-errors (unwind-protect (inferior-haskell-type sym) (message ""))))) (if (and result (string-match " :: " result)) result (setq result (unwind-protect (inferior-haskell-kind sym) (message ""))) (and result (string-match " :: " result) result)))) (let ((i-am-prelude nil) (i-am-fct nil) (type nil) (is-reserved (haskell-doc-is-of sym haskell-doc-reserved-ids)) (is-prelude (haskell-doc-is-of sym haskell-doc-prelude-types)) (is-strategy (haskell-doc-is-of sym haskell-doc-strategy-ids)) (is-user-defined (haskell-doc-is-of sym haskell-doc-user-defined-ids))) (cond ;; if reserved id (i.e. Haskell keyword ((and haskell-doc-show-reserved is-reserved) (setq type (cdr is-reserved)) (setcdr haskell-doc-last-data type)) ;; if built-in function get type from docstring ((and (not (null haskell-doc-show-prelude)) is-prelude) (setq type (cdr is-prelude)) ; (cdr (assoc sym haskell-doc-prelude-types))) (if (= 2 (length type)) ; horrible hack to remove bad formatting (setq type (car (cdr type)))) (setq i-am-prelude t) (setq i-am-fct t) (setcdr haskell-doc-last-data type)) ((and haskell-doc-show-strategy is-strategy) (setq i-am-fct t) (setq type (cdr is-strategy)) (setcdr haskell-doc-last-data type)) ((and haskell-doc-show-user-defined is-user-defined) ;; (setq i-am-fct t) (setq type (cdr is-user-defined)) (setcdr haskell-doc-last-data type)) (t (let ( (x (haskell-doc-get-and-format-fct-type sym)) ) (if (null x) (setcdr haskell-doc-last-data nil) ; if not found reset last data (setq type (car x)) (setq i-am-fct (string= "Variables" (cdr x))) (if (and haskell-doc-show-global-types (null type)) (setq type (haskell-doc-get-global-fct-type sym))) (setcdr haskell-doc-last-data type)))) ) ;; ToDo: encode i-am-fct info into alist of types (and type ;; drop `::' if it's not a fct (let ( (str (cond ((and i-am-fct (not haskell-doc-chop-off-fctname)) (format "%s :: %s" sym type)) (t (format "%s" type)))) ) (if i-am-prelude (add-text-properties 0 (length str) '(face bold) str)) str))))) ;; ToDo: define your own notion of `near' to find surrounding fct ;;(defun haskell-doc-fnsym-in-current-sexp () ;; (let* ((p (point)) ;; (sym (progn ;; (forward-word -1) ;; (while (and (forward-word -1) ; (haskell-doc-forward-sexp-safe -1) ;; (> (point) (point-min)))) ;; (cond ((or (= (point) (point-min)) ;; (memq (or (char-after (point)) 0) ;; '(?\( ?\")) ;; ;; If we hit a quotation mark before a paren, we ;; ;; are inside a specific string, not a list of ;; ;; symbols. ;; (eq (or (char-after (1- (point))) 0) ?\")) ;; nil) ;; (t (condition-case nil ;; (read (current-buffer)) ;; (error nil))))))) ;; (goto-char p) ;; (if sym ;; (format "%s" sym) ;; sym))) ;; (and (symbolp sym) ;; sym))) ;; ToDo: handle open brackets to decide if it's a wrapped type (defun haskell-doc-grab-line (fct-and-pos) "Get the type of an \(FCT POSITION\) pair from the current buffer." ;; (if (null fct-and-pos) ;; "" ; fn is not a local fct (let ( (str "")) (goto-char (cdr fct-and-pos)) (beginning-of-line) ;; search for start of type (phsp give better bound?) (if (null (search-forward "::" (+ (point) haskell-doc-search-distance) t)) "" (setq str (haskell-doc-grab)) ; leaves point at end of line (while (haskell-doc-wrapped-type-p) ; while in a multi-line type expr (forward-line 1) (beginning-of-line) (skip-chars-forward " \t") (setq str (concat str (haskell-doc-grab)))) (haskell-doc-string-nub-ws ; squeeze string (if haskell-doc-chop-off-context ; no context (haskell-doc-chop-off-context str) str))))) ;; (concat (car fct-and-pos) "::" (haskell-doc-string-nub-ws str)))) (defun haskell-doc-wrapped-type-p () "Check whether the type under the cursor is wrapped over several lines. The cursor must be at the end of a line, which contains the type. Currently, only the following is checked: If this line ends with a `->' or the next starts with an `->' it is a multi-line type \(same for `=>'\). `--' comments are ignored. ToDo: Check for matching parenthesis!." (save-excursion (let ( (here (point)) (lim (progn (beginning-of-line) (point))) ;; (foo "") (res nil) ) (goto-char here) (search-backward "--" lim t) ; skip over `--' comment (skip-chars-backward " \t") (if (bolp) ; skip empty lines (progn (forward-line 1) (end-of-line) (setq res (haskell-doc-wrapped-type-p))) (forward-char -1) ;; (setq foo (concat foo (char-to-string (preceding-char)) (char-to-string (following-char)))) (if (or (and (or (char-equal (preceding-char) ?-) (char-equal (preceding-char) ?=)) (char-equal (following-char) ?>)) ; (or -!> =!> (char-equal (following-char) ?,)) ; !,) (setq res t) (forward-line) (let ((here (point))) (goto-char here) (skip-chars-forward " \t") (if (looking-at "--") ; it is a comment line (progn (forward-line 1) (end-of-line) (setq res (haskell-doc-wrapped-type-p))) (forward-char 1) ;; (setq foo (concat foo (char-to-string (preceding-char)) (char-to-string (following-char)))) ;; (message "|%s|" foo) (if (and (or (char-equal (preceding-char) ?-) (char-equal (preceding-char) ?=)) (char-equal (following-char) ?>)) ; -!> or =!> (setq res t)))))) res))) (defun haskell-doc-grab () "Return the text from point to the end of the line, chopping off comments. Leaves point at end of line." (let ((str (buffer-substring-no-properties (point) (progn (end-of-line) (point))))) (if (string-match "--" str) (substring str 0 (match-beginning 0)) str))) (defun haskell-doc-string-nub-ws (str) "Replace all sequences of whitespace in STR by just one space. ToDo: Also eliminate leading and trailing whitespace." (let ((i -1)) (while (setq i (string-match " [ \t\n]+\\|[\t\n]+" str (1+ i))) (setq str (replace-match " " t t str))) str)) (defun haskell-doc-chop-off-context (str) "Eliminate the context in a type represented by the string STR." (let ((i (string-match "=>" str)) ) (if (null i) str (substring str (+ i 2))))) (defun haskell-doc-get-imenu-info (obj kind) "Return a string describing OBJ of KIND \(Variables, Types, Data\)." (cond ((eq major-mode 'haskell-mode) (let* ((imenu-info-alist (cdr (assoc kind imenu--index-alist))) ;; (names (mapcar 'car imenu-info-alist)) (x (assoc obj imenu-info-alist))) (when x (haskell-doc-grab-line x)))) (t ;; (error "Cannot get local functions in %s mode, sorry" major-mode))) nil))) ;; ToDo: ;; - modular way of defining a mapping of module name to file ;; - use a path to search for file (not just current directory) (defun haskell-doc-imported-list () "Return a list of the imported modules in current buffer." (interactive "fName of outer `include' file: ") ; (buffer-file-name)) ;; Don't add current buffer to the imported file list if it is not (yet?) ;; visiting a file since it leads to errors further down. (let ((imported-file-list (and buffer-file-name (list buffer-file-name)))) (widen) (goto-char (point-min)) (while (re-search-forward "^\\s-*import\\s-+\\([^ \t\n]+\\)" nil t) (let ((basename (match-string 1))) (dolist (ext '(".hs" ".lhs")) (let ((file (concat basename ext))) (if (file-exists-p file) (push file imported-file-list)))))) (nreverse imported-file-list) ;;(message imported-file-list) )) ;; ToDo: generalise this to "Types" etc (not just "Variables") (defun haskell-doc-rescan-files (filelist) "Do an `imenu' rescan on every file in FILELIST and return the fct-list. This function switches to and potentially loads many buffers." (save-current-buffer (mapcar (lambda (f) (set-buffer (find-file-noselect f)) (imenu--make-index-alist t) (cons f (mapcar (lambda (x) `(,(car x) . ,(haskell-doc-grab-line x))) (cdr (assoc "Variables" imenu--index-alist))))) filelist))) (defun haskell-doc-make-global-fct-index () "Scan imported files for types of global fcts and update `haskell-doc-index'." (interactive) (setq haskell-doc-index (haskell-doc-rescan-files (haskell-doc-imported-list)))) ;; ToDo: use a separate munge-type function to format type concisely (defun haskell-doc-get-global-fct-type (&optional sym) "Get type for function symbol SYM by examining `haskell-doc-index'." (interactive) ; "fName of outer `include' file: \nsFct:") (save-excursion ;; (switch-to-buffer "*scratch*") ;; (goto-char (point-max)) ;; ;; Produces a list of fct-type alists ;; (if (null sym) ;; (setq sym (progn (forward-word -1) (read (current-buffer))))) (or sym (current-word)) (let* ( (fn sym) ; (format "%s" sym)) (fal haskell-doc-index) (res "") ) (while (not (null fal)) (let* ( (l (car fal)) (f (car l)) (x (assoc fn (cdr l))) ) (if (not (null x)) (let* ( (ty (cdr x)) ; the type as string (idx (string-match "::" ty)) (str (if (null idx) ty (substring ty (+ idx 2)))) ) (setq res (format "[%s] %s" f str)))) (setq fal (cdr fal)))) res))) ; (message res)) ) (defun haskell-doc-get-and-format-fct-type (fn) "Get the type and kind of FN by checking local and global functions." (save-excursion (save-match-data (let ((docstring "") (doc nil) ) ;; is it a local function? (setq docstring (haskell-doc-get-imenu-info fn "Variables")) (if (not (null docstring)) ;; (string-match (format "^%s\\s-+::\\s-+\\(.*\\)$" fn) docstring)) (setq doc `(,docstring . "Variables"))) ; `(,(match-string 1 docstring) . "Variables") )) ;; is it a type declaration? (setq docstring (haskell-doc-get-imenu-info fn "Types")) (if (not (null docstring)) ;; (string-match (format "^\\s-*type\\s-+%s.*$" fn) docstring)) (setq doc `(,docstring . "Types"))) ; `(,(match-string 0 docstring) . "Types")) ) (if (not (null docstring)) ;; (string-match (format "^\\s-*data.*%s.*$" fn) docstring)) (setq doc `(,docstring . "Data"))) ; (setq doc `(,(match-string 0 docstring) . "Data")) ) ;; return the result doc )))) (defun inferior-haskell-kind (sym) "Find the kind of SYM with `:kind' ghci feature." (inferior-haskell-get-result (format ":kind %s" sym))) (defun inferior-haskell-type (sym) "Find the type of SYM with `:type' ghci feature." (inferior-haskell-get-result (format ":type (%s)" sym))) (provide 'haskell-doc) ;;; haskell-doc.el ends here �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-font-lock.el��������������������������������������������������������������0000664�0000000�0000000�00000072714�13602233217�0017660�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-font-lock.el --- Font locking module for Haskell Mode -*- lexical-binding: t -*- ;; Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. ;; Copyright 1997-1998 Graeme E Moss, and Tommy Thorn ;; Author: 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> ;; 1997-1998 Tommy Thorn <thorn@irisa.fr> ;; 2003 Dave Love <fx@gnu.org> ;; Keywords: faces files Haskell ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'cl-lib) (require 'haskell-lexeme) (require 'font-lock) ;;;###autoload (defgroup haskell-appearance nil "Haskell Appearance." :group 'haskell) (defcustom haskell-font-lock-symbols nil "Display \\ and -> and such using symbols in fonts. This may sound like a neat trick, but be extra careful: it changes the alignment and can thus lead to nasty surprises with regards to layout." :group 'haskell-appearance :type 'boolean) (defcustom haskell-font-lock-symbols-alist '(("\\" . "λ") ("not" . "¬") ("->" . "→") ("<-" . "←") ("=>" . "⇒") ("()" . "∅") ("==" . "≡") ("/=" . "≢") (">=" . "≥") ("<=" . "≤") ("!!" . "‼") ("&&" . "∧") ("||" . "∨") ("sqrt" . "√") ("undefined" . "⊥") ("pi" . "π") ("~>" . "⇝") ;; Omega language ;; ("~>" "↝") ;; less desirable ("-<" . "↢") ;; Paterson's arrow syntax ;; ("-<" "⤙") ;; nicer but uncommon ("::" . "∷") ("." "∘" ; "○" ;; Need a predicate here to distinguish the . used by ;; forall <foo> . <bar>. haskell-font-lock-dot-is-not-composition) ("forall" . "∀")) "Alist mapping Haskell symbols to chars. Each element has the form (STRING . COMPONENTS) or (STRING COMPONENTS PREDICATE). STRING is the Haskell symbol. COMPONENTS is a representation specification suitable as an argument to `compose-region'. PREDICATE if present is a function of one argument (the start position of the symbol) which should return non-nil if this mapping should be disabled at that position." :type '(alist string string) :group 'haskell-appearance) (defcustom haskell-font-lock-keywords ;; `as', `hiding', and `qualified' are part of the import ;; spec syntax, but they are not reserved. ;; `_' can go in here since it has temporary word syntax. '("case" "class" "data" "default" "deriving" "do" "else" "if" "import" "in" "infix" "infixl" "infixr" "instance" "let" "module" "mdo" "newtype" "of" "rec" "pattern" "proc" "signature" "then" "type" "where" "_" "anyclass" "stock" "via") "Identifiers treated as reserved keywords in Haskell." :group 'haskell-appearance :type '(repeat string)) (defun haskell-font-lock-dot-is-not-composition (start) "Return non-nil if the \".\" at START is not a composition operator. This is the case if the \".\" is part of a \"forall <tvar> . <type>\"." (save-excursion (goto-char start) (or (re-search-backward "\\<forall\\>[^.\"]*\\=" (line-beginning-position) t) (not (or (string= " " (string (char-after start))) (null (char-before start)) (string= " " (string (char-before start)))))))) (defvar haskell-yesod-parse-routes-mode-keywords '(("^\\([^ \t\n]+\\)\\(?:[ \t]+\\([^ \t\n]+\\)\\)?" (1 'font-lock-string-face) (2 'haskell-constructor-face nil lax)))) (define-derived-mode haskell-yesod-parse-routes-mode text-mode "Yesod parseRoutes mode" "Mode for parseRoutes from Yesod." (setq-local font-lock-defaults '(haskell-yesod-parse-routes-mode-keywords t t nil nil))) (defcustom haskell-font-lock-quasi-quote-modes `(("hsx" . xml-mode) ("hamlet" . shakespeare-hamlet-mode) ("shamlet" . shakespeare-hamlet-mode) ("whamlet" . shakespeare-hamlet-mode) ("xmlQQ" . xml-mode) ("xml" . xml-mode) ("cmd" . shell-mode) ("sh_" . shell-mode) ("jmacro" . javascript-mode) ("jmacroE" . javascript-mode) ("r" . ess-mode) ("rChan" . ess-mode) ("sql" . sql-mode) ("json" . json-mode) ("aesonQQ" . json-mode) ("parseRoutes" . haskell-yesod-parse-routes-mode)) "Mapping from quasi quoter token to fontification mode. If a quasi quote is seen in Haskell code its contents will have font faces assigned as if respective mode was enabled." :group 'haskell-appearance :type '(repeat (cons string symbol))) ;;;###autoload (defface haskell-keyword-face '((t :inherit font-lock-keyword-face)) "Face used to highlight Haskell keywords." :group 'haskell-appearance) ;;;###autoload (defface haskell-type-face '((t :inherit font-lock-type-face)) "Face used to highlight Haskell types" :group 'haskell-appearance) ;;;###autoload (defface haskell-constructor-face '((t :inherit font-lock-type-face)) "Face used to highlight Haskell constructors." :group 'haskell-appearance) ;; This used to be `font-lock-variable-name-face' but it doesn't result in ;; a highlighting that's consistent with other modes (it's mostly used ;; for function defintions). (defface haskell-definition-face '((t :inherit font-lock-function-name-face)) "Face used to highlight Haskell definitions." :group 'haskell-appearance) ;; This is probably just wrong, but it used to use ;; `font-lock-function-name-face' with a result that was not consistent with ;; other major modes, so I just exchanged with `haskell-definition-face'. ;;;###autoload (defface haskell-operator-face '((t :inherit font-lock-variable-name-face)) "Face used to highlight Haskell operators." :group 'haskell-appearance) ;;;###autoload (defface haskell-pragma-face '((t :inherit font-lock-preprocessor-face)) "Face used to highlight Haskell pragmas ({-# ... #-})." :group 'haskell-appearance) ;;;###autoload (defface haskell-liquid-haskell-annotation-face '((t :inherit haskell-pragma-face)) "Face used to highlight LiquidHaskell annotations ({-@ ... @-})." :group 'haskell-appearance) ;;;###autoload (defface haskell-literate-comment-face '((t :inherit font-lock-doc-face)) "Face with which to fontify literate comments. Inherit from `default' to avoid fontification of them." :group 'haskell-appearance) (defface haskell-quasi-quote-face '((t :inherit font-lock-string-face)) "Generic face for quasiquotes. Some quote types are fontified according to other mode defined in `haskell-font-lock-quasi-quote-modes'." :group 'haskell-appearance) (defun haskell-font-lock-compose-symbol (alist) "Compose a sequence of ascii chars into a symbol. Regexp match data 0 points to the chars." ;; Check that the chars should really be composed into a symbol. (let* ((start (match-beginning 0)) (end (match-end 0)) (syntaxes (cond ((eq (char-syntax (char-after start)) ?w) '(?w)) ((eq (char-syntax (char-after start)) ?.) '(?.)) ;; Special case for the . used for qualified names. ((and (eq (char-after start) ?\.) (= end (1+ start))) '(?_ ?\\ ?w)) (t '(?_ ?\\)))) sym-data) (if (or (memq (char-syntax (or (char-before start) ?\ )) syntaxes) (memq (char-syntax (or (char-after end) ?\ )) syntaxes) (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4)) (and (consp (setq sym-data (cdr (assoc (match-string 0) alist)))) (let ((pred (cadr sym-data))) (setq sym-data (car sym-data)) (funcall pred start)))) ;; No composition for you. Let's actually remove any composition ;; we may have added earlier and which is now incorrect. (remove-text-properties start end '(composition)) ;; That's a symbol alright, so add the composition. (compose-region start end sym-data))) ;; Return nil because we're not adding any face property. nil) (defun haskell-font-lock-symbols-keywords () (when (and haskell-font-lock-symbols haskell-font-lock-symbols-alist) `((,(regexp-opt (mapcar 'car haskell-font-lock-symbols-alist) t) (0 (haskell-font-lock-compose-symbol ',haskell-font-lock-symbols-alist) ;; In Emacs-21, if the `override' field is nil, the face ;; expressions is only evaluated if the text has currently ;; no face. So force evaluation by using `keep'. keep))))) (defun haskell-font-lock--forward-type (&optional ignore) "Find where does this type declaration end. Moves the point to the end of type declaration. It should be invoked with point just after one of type introducing keywords like ::, class, instance, data, newtype, type." (interactive) (let ((cont t) (end (point)) (token nil) ;; we are starting right after :: (last-token-was-operator t) (last-token-was-newline nil) (open-parens 0)) (while cont (setq token (haskell-lexeme-looking-at-token 'newline)) (cond ((null token) (setq cont nil)) ((member token '(newline)) (setq last-token-was-newline (not last-token-was-operator)) (setq end (match-end 0)) (goto-char (match-end 0))) ((member (match-string-no-properties 0) '(")" "]" "}")) (setq open-parens (1- open-parens)) (if (< open-parens 0) ;; unmatched closing parenthesis closes type declaration (setq cont nil) (setq end (match-end 0)) (goto-char end)) (setq last-token-was-newline nil)) ((and (member (match-string-no-properties 0) '("," ";" "|")) (not (member (match-string-no-properties 0) ignore))) (if (equal 0 open-parens) (setq cont nil) (setq last-token-was-operator t) (setq end (match-end 0)) (goto-char end)) (setq last-token-was-newline nil)) ((and (or (member (match-string-no-properties 0) '("<-" "=" "←")) (member (match-string-no-properties 0) haskell-font-lock-keywords)) (not (member (match-string-no-properties 0) ignore))) (setq cont nil) (setq last-token-was-newline nil)) ((member (match-string-no-properties 0) '("(" "[" "{")) (if last-token-was-newline (setq cont nil) (setq open-parens (1+ open-parens)) (setq end (match-end 0)) (goto-char end) (setq last-token-was-newline nil))) ((member token '(qsymid char string number template-haskell-quote template-haskell-quasi-quote)) (setq last-token-was-operator (member (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) '(varsym consym))) (if (and (not last-token-was-operator) last-token-was-newline) (setq cont nil) (goto-char (match-end 0)) (setq end (point))) (setq last-token-was-newline nil)) ((member token '(comment nested-comment literate-comment)) (goto-char (match-end 0)) (setq end (point))) (t (goto-char (match-end 0)) (setq end (point)) (setq last-token-was-newline nil)))) (goto-char end))) (defun haskell-font-lock--select-face-on-type-or-constructor () "Private function used to select either type or constructor face on an uppercase identifier." (cl-case (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) (varid (let ((word (match-string-no-properties 0))) (cond ((member word haskell-font-lock-keywords) ;; Note: keywords parse as keywords only when not qualified. ;; GHC parses Control.let as a single but illegal lexeme. (when (member word '("class" "instance" "type" "data" "newtype")) (save-excursion (goto-char (match-end 0)) (save-match-data (haskell-font-lock--forward-type (cond ((member word '("class" "instance")) '("|")) ((member word '("type")) ;; Need to support 'type instance' '("=" "instance"))))) (add-text-properties (match-end 0) (point) '(font-lock-multiline t haskell-type t)))) 'haskell-keyword-face) ((member word '("forall")) (when (get-text-property (match-beginning 0) 'haskell-type) 'haskell-keyword-face))))) (conid (if (get-text-property (match-beginning 0) 'haskell-type) 'haskell-type-face 'haskell-constructor-face)) (varsym (unless (and (member (match-string 0) '("-" "+" ".")) (equal (string-to-syntax "w") (syntax-after (match-beginning 0)))) ;; We need to protect against the case of ;; plus, minus or dot inside a floating ;; point number. 'haskell-operator-face)) (consym (if (not (member (match-string 1) '("::" "∷"))) (if (get-text-property (match-beginning 0) 'haskell-type) 'haskell-type-face 'haskell-constructor-face) (save-excursion (goto-char (match-end 0)) (save-match-data (haskell-font-lock--forward-type)) (add-text-properties (match-end 0) (point) '(font-lock-multiline t haskell-type t))) 'haskell-operator-face)))) (defun haskell-font-lock--put-face-on-type-or-constructor () "Private function used to put either type or constructor face on an uppercase identifier." (let ((face (haskell-font-lock--select-face-on-type-or-constructor))) (when (and face (not (text-property-not-all (match-beginning 0) (match-end 0) 'face nil))) (put-text-property (match-beginning 0) (match-end 0) 'face face)))) (defun haskell-font-lock-keywords () ;; this has to be a function because it depends on global value of ;; `haskell-font-lock-symbols' "Generate font lock eywords." (let* (;; Bird-style literate scripts start a line of code with ;; "^>", otherwise a line of code starts with "^". (line-prefix "^\\(?:> ?\\)?") (varid "[[:lower:]_][[:alnum:]'_]*") ;; We allow ' preceding conids because of DataKinds/PolyKinds (conid "'?[[:upper:]][[:alnum:]'_]*") (sym "\\s.+") ;; Top-level declarations (topdecl-var (concat line-prefix "\\(" varid "\\(?:\\s-*,\\s-*" varid "\\)*" "\\)" ;; optionally allow for a single newline after identifier "\\(\\s-+\\|\\s-*[\n]\\s-+\\)" ;; A toplevel declaration can be followed by a definition ;; (=), a type (::) or (∷), a guard, or a pattern which can ;; either be a variable, a constructor, a parenthesized ;; thingy, or an integer or a string. "\\(" varid "\\|" conid "\\|::\\|∷\\|=\\||\\|\\s(\\|[0-9\"']\\)")) (topdecl-var2 (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*`\\(" varid "\\)`")) (topdecl-bangpat (concat line-prefix "\\(" varid "\\)\\s-*!")) (topdecl-sym (concat line-prefix "\\(" varid "\\|" conid "\\)\\s-*\\(" sym "\\)")) (topdecl-sym2 (concat line-prefix "(\\(" sym "\\))")) keywords) (setq keywords `(;; NOTICE the ordering below is significant ;; ("^#\\(?:[^\\\n]\\|\\\\\\(?:.\\|\n\\|\\'\\)\\)*\\(?:\n\\|\\'\\)" 0 'font-lock-preprocessor-face t) ,@(haskell-font-lock-symbols-keywords) ;; Special case for `as', `hiding', `safe' and `qualified', which are ;; keywords in import statements but are not otherwise reserved. ("\\<import[ \t]+\\(?:\\(safe\\>\\)[ \t]*\\)?\\(?:\\(qualified\\>\\)[ \t]*\\)?\\(?:\"[^\"]*\"[\t ]*\\)?[^ \t\n()]+[ \t]*\\(?:\\(\\<as\\>\\)[ \t]*[^ \t\n()]+[ \t]*\\)?\\(\\<hiding\\>\\)?" (1 'haskell-keyword-face nil lax) (2 'haskell-keyword-face nil lax) (3 'haskell-keyword-face nil lax) (4 'haskell-keyword-face nil lax)) ;; Special case for `foreign import' ;; keywords in foreign import statements but are not otherwise reserved. ("\\<\\(foreign\\)[ \t]+\\(import\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?\\(?:\\(safe\\|unsafe\\|interruptible\\)[ \t]+\\)?" (1 'haskell-keyword-face nil lax) (2 'haskell-keyword-face nil lax) (3 'haskell-keyword-face nil lax) (4 'haskell-keyword-face nil lax)) ;; Special case for `foreign export' ;; keywords in foreign export statements but are not otherwise reserved. ("\\<\\(foreign\\)[ \t]+\\(export\\)[ \t]+\\(?:\\(ccall\\|stdcall\\|cplusplus\\|jvm\\|dotnet\\)[ \t]+\\)?" (1 'haskell-keyword-face nil lax) (2 'haskell-keyword-face nil lax) (3 'haskell-keyword-face nil lax)) ;; Special case for `type family' and `data family'. ;; `family' is only reserved in these contexts. ("\\<\\(type\\|data\\)[ \t]+\\(family\\>\\)" (1 'haskell-keyword-face nil lax) (2 'haskell-keyword-face nil lax)) ;; Special case for `type role' ;; `role' is only reserved in this context. ("\\<\\(type\\)[ \t]+\\(role\\>\\)" (1 'haskell-keyword-face nil lax) (2 'haskell-keyword-face nil lax)) ;; Toplevel Declarations. ;; Place them *before* generic id-and-op highlighting. (,topdecl-var (1 (unless (member (match-string 1) haskell-font-lock-keywords) 'haskell-definition-face))) (,topdecl-var2 (2 (unless (member (match-string 2) haskell-font-lock-keywords) 'haskell-definition-face))) (,topdecl-bangpat (1 (unless (member (match-string 1) haskell-font-lock-keywords) 'haskell-definition-face))) (,topdecl-sym (2 (unless (member (match-string 2) '("\\" "=" "->" "→" "<-" "←" "::" "∷" "," ";" "`")) 'haskell-definition-face))) (,topdecl-sym2 (1 (unless (member (match-string 1) '("\\" "=" "->" "→" "<-" "←" "::" "∷" "," ";" "`")) 'haskell-definition-face))) ;; These four are debatable... ("(\\(,*\\|->\\))" 0 'haskell-constructor-face) ("\\[\\]" 0 'haskell-constructor-face) ("`" (0 (if (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4)) (parse-partial-sexp (point) (point-max) nil nil (syntax-ppss) 'syntax-table) (when (save-excursion (goto-char (match-beginning 0)) (haskell-lexeme-looking-at-backtick)) (goto-char (match-end 0)) (unless (text-property-not-all (match-beginning 1) (match-end 1) 'face nil) (put-text-property (match-beginning 1) (match-end 1) 'face 'haskell-operator-face)) (unless (text-property-not-all (match-beginning 2) (match-end 2) 'face nil) (put-text-property (match-beginning 2) (match-end 2) 'face 'haskell-operator-face)) (unless (text-property-not-all (match-beginning 4) (match-end 4) 'face nil) (put-text-property (match-beginning 4) (match-end 4) 'face 'haskell-operator-face)) (add-text-properties (match-beginning 0) (match-end 0) '(font-lock-fontified t fontified t font-lock-multiline t)))))) (,haskell-lexeme-idsym-first-char (0 (if (or (elt (syntax-ppss) 3) (elt (syntax-ppss) 4)) (parse-partial-sexp (point) (point-max) nil nil (syntax-ppss) 'syntax-table) (when (save-excursion (goto-char (match-beginning 0)) (haskell-lexeme-looking-at-qidsym)) (goto-char (match-end 0)) ;; note that we have to put face ourselves here because font-lock ;; will use match data from the original matcher (haskell-font-lock--put-face-on-type-or-constructor))))))) keywords)) (defun haskell-font-lock-fontify-block (lang-mode start end) "Fontify a block as LANG-MODE." (let ((string (buffer-substring-no-properties start end)) (modified (buffer-modified-p)) (org-buffer (current-buffer)) pos next) (remove-text-properties start end '(face nil)) (with-current-buffer (get-buffer-create (concat " haskell-font-lock-fontify-block:" (symbol-name lang-mode))) (delete-region (point-min) (point-max)) (insert string " ") ;; so there's a final property change (cl-letf (((symbol-function 'message) (lambda (_fmt &rest _args)))) ;; silence messages (unless (eq major-mode lang-mode) (funcall lang-mode)) (font-lock-ensure)) (setq pos (point-min)) (while (setq next (next-single-property-change pos 'face)) (put-text-property (+ start (1- pos)) (1- (+ start next)) 'face (or (get-text-property pos 'face) 'default) org-buffer) (setq pos next)) (unless (equal pos (point-max)) (put-text-property (+ start (1- pos)) (1- (+ start (point-max))) 'face 'default org-buffer))) (add-text-properties start end '(font-lock-fontified t fontified t font-lock-multiline t)) (set-buffer-modified-p modified))) (defun haskell-syntactic-face-function (state) "`font-lock-syntactic-face-function' for Haskell." (cond ((nth 3 state) (if (equal ?| (nth 3 state)) ;; find out what kind of QuasiQuote is this (let* ((qqname (save-excursion (goto-char (nth 8 state)) (skip-syntax-backward "w._") (buffer-substring-no-properties (point) (nth 8 state)))) (lang-mode (cdr (assoc qqname haskell-font-lock-quasi-quote-modes)))) (if (and lang-mode (fboundp lang-mode)) (save-excursion ;; find the end of the QuasiQuote (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (haskell-font-lock-fontify-block lang-mode (1+ (nth 8 state)) (1- (point))) ;; must return nil here so that it is not fontified again as string nil) ;; fontify normally as string because lang-mode is not present 'haskell-quasi-quote-face)) (save-excursion (let ((state2 (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table)) (end-of-string (point))) (put-text-property (nth 8 state) (point) 'face 'font-lock-string-face) (if (or (equal t (nth 3 state)) (nth 3 state2)) ;; This is an unterminated string constant, use warning ;; face for the opening quote. (put-text-property (nth 8 state) (1+ (nth 8 state)) 'face 'font-lock-warning-face)) (goto-char (1+ (nth 8 state))) (while (re-search-forward "\\\\" end-of-string t) (goto-char (1- (point))) (if (looking-at haskell-lexeme-string-literal-inside-item) (goto-char (match-end 0)) ;; We are looking at an unacceptable escape ;; sequence. Use warning face to highlight that. (put-text-property (point) (1+ (point)) 'face 'font-lock-warning-face) (goto-char (1+ (point))))))) ;; must return nil here so that it is not fontified again as string nil)) ;; Detect literate comment lines starting with syntax class '<' ((save-excursion (goto-char (nth 8 state)) (equal (string-to-syntax "<") (syntax-after (point)))) 'haskell-literate-comment-face) ;; Detect pragmas. A pragma is enclosed in special comment ;; delimiters {-# .. #-}. ((save-excursion (goto-char (nth 8 state)) (and (looking-at-p "{-#") (forward-comment 1) (goto-char (- (point) 3)) (looking-at-p "#-}"))) 'haskell-pragma-face) ;; Detect Liquid Haskell annotations enclosed in special comment ;; delimiters {-@ .. @-}. ((save-excursion (goto-char (nth 8 state)) (and (looking-at-p "{-@") (forward-comment 1) (goto-char (- (point) 3)) (looking-at-p "@-}"))) 'haskell-liquid-haskell-annotation-face) ;; Haddock comment start with either "-- [|^*$]" or "{- ?[|^*$]" ;; (note space optional for nested comments and mandatory for ;; double dash comments). ;; ;; Haddock comment will also continue on next line, provided: ;; - current line is a double dash haddock comment ;; - next line is also double dash comment ;; - there is only whitespace between ;; ;; We recognize double dash haddock comments by property ;; 'font-lock-doc-face attached to newline. In case of {- -} ;; comments newline is outside of comment. ((save-excursion (goto-char (nth 8 state)) (or (looking-at-p "\\(?:{- ?\\|-- \\)[|^*$]") (and (looking-at-p "--") ; are we at double dash comment (forward-line -1) ; this is nil on first line (eq (get-text-property (line-end-position) 'face) 'font-lock-doc-face) ; is a doc face (forward-line) (skip-syntax-forward "-") ; see if there is only whitespace (eq (point) (nth 8 state))))) ; we are back in position ;; Here we look inside the comment to see if there are substrings ;; worth marking inside we try to emulate as much of haddock as ;; possible. First we add comment face all over the comment, then ;; we add special features. (let ((beg (nth 8 state)) (end (save-excursion (parse-partial-sexp (point) (point-max) nil nil state 'syntax-table) (point))) (emphasis-open-point nil) (strong-open-point nil)) (put-text-property beg end 'face 'font-lock-doc-face) (when (fboundp 'add-face-text-property) ;; `add-face-text-property' is not defined in Emacs 23 ;; iterate over chars, take escaped chars unconditionally ;; mark when a construct is opened, close and face it when ;; it is closed (save-excursion (while (< (point) end) (if (looking-at "__\\|\\\\.\\|\\\n\\|[/]") (progn (cond ((equal (match-string 0) "/") (if emphasis-open-point (progn (add-face-text-property emphasis-open-point (match-end 0) '(:slant italic)) (setq emphasis-open-point nil)) (setq emphasis-open-point (point)))) ((equal (match-string 0) "__") (if strong-open-point (progn (add-face-text-property strong-open-point (match-end 0) '(:weight bold)) (setq strong-open-point nil)) (setq strong-open-point (point)))) (t ;; this is a backslash escape sequence, skip over it )) (goto-char (match-end 0))) ;; skip chars that are not interesting (goto-char (1+ (point))) (skip-chars-forward "^_\\\\/" end)))))) nil) (t 'font-lock-comment-face))) (defun haskell-font-lock-defaults-create () "Locally set `font-lock-defaults' for Haskell." (setq-local font-lock-defaults '((haskell-font-lock-keywords) nil nil nil nil (font-lock-syntactic-face-function . haskell-syntactic-face-function) ;; Get help from font-lock-syntactic-keywords. (parse-sexp-lookup-properties . t) (font-lock-extra-managed-props . (composition))))) (defun haskell-fontify-as-mode (text mode) "Fontify TEXT as MODE, returning the fontified text." (with-temp-buffer (funcall mode) (insert text) (if (fboundp 'font-lock-ensure) (font-lock-ensure) (with-no-warnings (font-lock-fontify-buffer))) (buffer-substring (point-min) (point-max)))) ;; Provide ourselves: (provide 'haskell-font-lock) ;; Local Variables: ;; coding: utf-8 ;; tab-width: 8 ;; End: ;;; haskell-font-lock.el ends here ����������������������������������������������������haskell-mode-17.1/haskell-ghc-support.el������������������������������������������������������������0000664�0000000�0000000�00000103117�13602233217�0020227�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-ghc-support.el --- GHC specific code -*- coding: utf-8; lexical-binding: t -*- ;; Copyright © 2016 Haskell Mode ;; Author: 2016 Gracjan Polak ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; This file containt GHC specific constants and information. ;;; Code: (defvar haskell-ghc-supported-extensions '( ;;; BEGIN haskell-ghc-supported-extensions "AllowAmbiguousTypes" "AlternativeLayoutRule" "AlternativeLayoutRuleTransitional" "ApplicativeDo" "Arrows" "AutoDeriveTypeable" "BangPatterns" "BinaryLiterals" "CApiFFI" "CPP" "ConstrainedClassMethods" "ConstraintKinds" "DataKinds" "DatatypeContexts" "DefaultSignatures" "DeriveAnyClass" "DeriveDataTypeable" "DeriveFoldable" "DeriveFunctor" "DeriveGeneric" "DeriveLift" "DeriveTraversable" "DisambiguateRecordFields" "DoAndIfThenElse" "DoRec" "DuplicateRecordFields" "EmptyCase" "EmptyDataDecls" "ExistentialQuantification" "ExplicitForAll" "ExplicitNamespaces" "ExtendedDefaultRules" "FlexibleContexts" "FlexibleInstances" "ForeignFunctionInterface" "FunctionalDependencies" "GADTSyntax" "GADTs" "GHCForeignImportPrim" "GeneralizedNewtypeDeriving" "Haskell2010" "Haskell98" "ImplicitParams" "ImplicitPrelude" "ImpredicativeTypes" "IncoherentInstances" "InstanceSigs" "InterruptibleFFI" "JavaScriptFFI" "KindSignatures" "LambdaCase" "LiberalTypeSynonyms" "MagicHash" "MonadComprehensions" "MonadFailDesugaring" "MonoLocalBinds" "MonoPatBinds" "MonomorphismRestriction" "MultiParamTypeClasses" "MultiWayIf" "NPlusKPatterns" "NamedFieldPuns" "NamedWildCards" "NegativeLiterals" "NoAllowAmbiguousTypes" "NoAlternativeLayoutRule" "NoAlternativeLayoutRuleTransitional" "NoApplicativeDo" "NoArrows" "NoAutoDeriveTypeable" "NoBangPatterns" "NoBinaryLiterals" "NoCApiFFI" "NoCPP" "NoConstrainedClassMethods" "NoConstraintKinds" "NoDataKinds" "NoDatatypeContexts" "NoDefaultSignatures" "NoDeriveAnyClass" "NoDeriveDataTypeable" "NoDeriveFoldable" "NoDeriveFunctor" "NoDeriveGeneric" "NoDeriveLift" "NoDeriveTraversable" "NoDisambiguateRecordFields" "NoDoAndIfThenElse" "NoDoRec" "NoDuplicateRecordFields" "NoEmptyCase" "NoEmptyDataDecls" "NoExistentialQuantification" "NoExplicitForAll" "NoExplicitNamespaces" "NoExtendedDefaultRules" "NoFlexibleContexts" "NoFlexibleInstances" "NoForeignFunctionInterface" "NoFunctionalDependencies" "NoGADTSyntax" "NoGADTs" "NoGHCForeignImportPrim" "NoGeneralizedNewtypeDeriving" "NoImplicitParams" "NoImplicitPrelude" "NoImpredicativeTypes" "NoIncoherentInstances" "NoInstanceSigs" "NoInterruptibleFFI" "NoJavaScriptFFI" "NoKindSignatures" "NoLambdaCase" "NoLiberalTypeSynonyms" "NoMagicHash" "NoMonadComprehensions" "NoMonadFailDesugaring" "NoMonoLocalBinds" "NoMonoPatBinds" "NoMonomorphismRestriction" "NoMultiParamTypeClasses" "NoMultiWayIf" "NoNPlusKPatterns" "NoNamedFieldPuns" "NoNamedWildCards" "NoNegativeLiterals" "NoNondecreasingIndentation" "NoNullaryTypeClasses" "NoNumDecimals" "NoOverlappingInstances" "NoOverloadedLabels" "NoOverloadedLists" "NoOverloadedStrings" "NoPackageImports" "NoParallelArrays" "NoParallelListComp" "NoPartialTypeSignatures" "NoPatternGuards" "NoPatternSignatures" "NoPatternSynonyms" "NoPolyKinds" "NoPolymorphicComponents" "NoPostfixOperators" "NoQuasiQuotes" "NoRank2Types" "NoRankNTypes" "NoRebindableSyntax" "NoRecordPuns" "NoRecordWildCards" "NoRecursiveDo" "NoRelaxedLayout" "NoRelaxedPolyRec" "NoRoleAnnotations" "NoScopedTypeVariables" "NoStandaloneDeriving" "NoStaticPointers" "NoStrict" "NoStrictData" "NoTemplateHaskell" "NoTemplateHaskellQuotes" "NoTraditionalRecordSyntax" "NoTransformListComp" "NoTupleSections" "NoTypeApplications" "NoTypeFamilies" "NoTypeFamilyDependencies" "NoTypeInType" "NoTypeOperators" "NoTypeSynonymInstances" "NoUnboxedTuples" "NoUndecidableInstances" "NoUndecidableSuperClasses" "NoUnicodeSyntax" "NoUnliftedFFITypes" "NoViewPatterns" "NondecreasingIndentation" "NullaryTypeClasses" "NumDecimals" "OverlappingInstances" "OverloadedLabels" "OverloadedLists" "OverloadedStrings" "PackageImports" "ParallelArrays" "ParallelListComp" "PartialTypeSignatures" "PatternGuards" "PatternSignatures" "PatternSynonyms" "PolyKinds" "PolymorphicComponents" "PostfixOperators" "QuasiQuotes" "Rank2Types" "RankNTypes" "RebindableSyntax" "RecordPuns" "RecordWildCards" "RecursiveDo" "RelaxedLayout" "RelaxedPolyRec" "RoleAnnotations" "Safe" "ScopedTypeVariables" "StandaloneDeriving" "StaticPointers" "Strict" "StrictData" "TemplateHaskell" "TemplateHaskellQuotes" "TraditionalRecordSyntax" "TransformListComp" "Trustworthy" "TupleSections" "TypeApplications" "TypeFamilies" "TypeFamilyDependencies" "TypeInType" "TypeOperators" "TypeSynonymInstances" "UnboxedTuples" "UndecidableInstances" "UndecidableSuperClasses" "UnicodeSyntax" "UnliftedFFITypes" "Unsafe" "ViewPatterns" ;;; END haskell-ghc-supported-extensions ) "List of language extensions supported by any known version of GHC. This list should be updated by running `haskell-update-ghc-support'.") (defvar haskell-ghc-supported-options '( ;;; BEGIN haskell-ghc-supported-options "-#include" "--abi-hash" "--frontend" "--help" "--info" "--interactive" "--make" "--numeric-version" "--print-booter-version" "--print-build-platform" "--print-c-compiler-flags" "--print-c-compiler-link-flags" "--print-debug-on" "--print-gcc-linker-flags" "--print-global-package-db" "--print-have-interpreter" "--print-have-native-code-generator" "--print-host-platform" "--print-ld-flags" "--print-ld-linker-flags" "--print-leading-underscore" "--print-libdir" "--print-object-splitting-supported" "--print-project-git-commit-id" "--print-project-version" "--print-rts-ways" "--print-stage" "--print-support-smp" "--print-tables-next-to-code" "--print-target-platform" "--print-unregisterised" "--show-iface" "--show-options" "--show-packages" "--supported-extensions" "--supported-languages" "--version" "-?" "-C" "-D" "-E" "-F" "-H" "-I" "-L" "-M" "-O" "-Odph" "-Onot" "-Rghc-timing" "-S" "-U" "-V" "-W" "-Wall" "-Wall-missed-specialisations" "-Walternative-layout-rule-transitional" "-Wamp" "-Wauto-orphans" "-Wcompat" "-Wcontext-quantification" "-Wdefault" "-Wdeferred-type-errors" "-Wdeprecated-flags" "-Wdeprecations" "-Wderiving-typeable" "-Wdodgy-exports" "-Wdodgy-foreign-imports" "-Wdodgy-imports" "-Wduplicate-constraints" "-Wduplicate-exports" "-Wempty-enumerations" "-Werror" "-Weverything" "-Wextra" "-Whi-shadowing" "-Widentities" "-Wimplicit-prelude" "-Wincomplete-patterns" "-Wincomplete-record-updates" "-Wincomplete-uni-patterns" "-Winline-rule-shadowing" "-Wmissed-specialisations" "-Wmissing-exported-signatures" "-Wmissing-exported-sigs" "-Wmissing-fields" "-Wmissing-import-lists" "-Wmissing-local-signatures" "-Wmissing-local-sigs" "-Wmissing-methods" "-Wmissing-monadfail-instances" "-Wmissing-pattern-synonym-signatures" "-Wmissing-signatures" "-Wmonomorphism-restriction" "-Wname-shadowing" "-Wno-all" "-Wno-all-missed-specialisations" "-Wno-alternative-layout-rule-transitional" "-Wno-amp" "-Wno-auto-orphans" "-Wno-compat" "-Wno-context-quantification" "-Wno-default" "-Wno-deferred-type-errors" "-Wno-deprecated-flags" "-Wno-deprecations" "-Wno-deriving-typeable" "-Wno-dodgy-exports" "-Wno-dodgy-foreign-imports" "-Wno-dodgy-imports" "-Wno-duplicate-constraints" "-Wno-duplicate-exports" "-Wno-empty-enumerations" "-Wno-everything" "-Wno-extra" "-Wno-hi-shadowing" "-Wno-identities" "-Wno-implicit-prelude" "-Wno-incomplete-patterns" "-Wno-incomplete-record-updates" "-Wno-incomplete-uni-patterns" "-Wno-inline-rule-shadowing" "-Wno-missed-specialisations" "-Wno-missing-exported-signatures" "-Wno-missing-exported-sigs" "-Wno-missing-fields" "-Wno-missing-import-lists" "-Wno-missing-local-signatures" "-Wno-missing-local-sigs" "-Wno-missing-methods" "-Wno-missing-monadfail-instances" "-Wno-missing-pattern-synonym-signatures" "-Wno-missing-signatures" "-Wno-monomorphism-restriction" "-Wno-name-shadowing" "-Wno-noncanonical-monad-instances" "-Wno-noncanonical-monadfail-instances" "-Wno-noncanonical-monoid-instances" "-Wno-orphans" "-Wno-overflowed-literals" "-Wno-overlapping-patterns" "-Wno-partial-type-signatures" "-Wno-redundant-constraints" "-Wno-safe" "-Wno-semigroup" "-Wno-tabs" "-Wno-trustworthy-safe" "-Wno-type-defaults" "-Wno-typed-holes" "-Wno-unrecognised-pragmas" "-Wno-unrecognised-warning-flags" "-Wno-unsafe" "-Wno-unsupported-calling-conventions" "-Wno-unsupported-llvm-version" "-Wno-unticked-promoted-constructors" "-Wno-unused-binds" "-Wno-unused-do-bind" "-Wno-unused-foralls" "-Wno-unused-imports" "-Wno-unused-local-binds" "-Wno-unused-matches" "-Wno-unused-pattern-binds" "-Wno-unused-top-binds" "-Wno-unused-type-patterns" "-Wno-warnings-deprecations" "-Wno-wrong-do-bind" "-Wnoncanonical-monad-instances" "-Wnoncanonical-monadfail-instances" "-Wnoncanonical-monoid-instances" "-Wnot" "-Worphans" "-Woverflowed-literals" "-Woverlapping-patterns" "-Wpartial-type-signatures" "-Wredundant-constraints" "-Wsafe" "-Wsemigroup" "-Wtabs" "-Wtrustworthy-safe" "-Wtype-defaults" "-Wtyped-holes" "-Wunrecognised-pragmas" "-Wunrecognised-warning-flags" "-Wunsafe" "-Wunsupported-calling-conventions" "-Wunsupported-llvm-version" "-Wunticked-promoted-constructors" "-Wunused-binds" "-Wunused-do-bind" "-Wunused-foralls" "-Wunused-imports" "-Wunused-local-binds" "-Wunused-matches" "-Wunused-pattern-binds" "-Wunused-top-binds" "-Wunused-type-patterns" "-Wwarn" "-Wwarnings-deprecations" "-Wwrong-do-bind" "-XAllowAmbiguousTypes" "-XAlternativeLayoutRule" "-XAlternativeLayoutRuleTransitional" "-XApplicativeDo" "-XArrows" "-XAutoDeriveTypeable" "-XBangPatterns" "-XBinaryLiterals" "-XCApiFFI" "-XCPP" "-XConstrainedClassMethods" "-XConstraintKinds" "-XDataKinds" "-XDatatypeContexts" "-XDefaultSignatures" "-XDeriveAnyClass" "-XDeriveDataTypeable" "-XDeriveFoldable" "-XDeriveFunctor" "-XDeriveGeneric" "-XDeriveLift" "-XDeriveTraversable" "-XDisambiguateRecordFields" "-XDoAndIfThenElse" "-XDoRec" "-XDuplicateRecordFields" "-XEmptyCase" "-XEmptyDataDecls" "-XExistentialQuantification" "-XExplicitForAll" "-XExplicitNamespaces" "-XExtendedDefaultRules" "-XFlexibleContexts" "-XFlexibleInstances" "-XForeignFunctionInterface" "-XFunctionalDependencies" "-XGADTSyntax" "-XGADTs" "-XGHCForeignImportPrim" "-XGeneralizedNewtypeDeriving" "-XGenerics" "-XHaskell2010" "-XHaskell98" "-XImplicitParams" "-XImplicitPrelude" "-XImpredicativeTypes" "-XIncoherentInstances" "-XInstanceSigs" "-XInterruptibleFFI" "-XJavaScriptFFI" "-XKindSignatures" "-XLambdaCase" "-XLiberalTypeSynonyms" "-XMagicHash" "-XMonadComprehensions" "-XMonadFailDesugaring" "-XMonoLocalBinds" "-XMonoPatBinds" "-XMonomorphismRestriction" "-XMultiParamTypeClasses" "-XMultiWayIf" "-XNPlusKPatterns" "-XNamedFieldPuns" "-XNamedWildCards" "-XNegativeLiterals" "-XNoAllowAmbiguousTypes" "-XNoAlternativeLayoutRule" "-XNoAlternativeLayoutRuleTransitional" "-XNoApplicativeDo" "-XNoArrows" "-XNoAutoDeriveTypeable" "-XNoBangPatterns" "-XNoBinaryLiterals" "-XNoCApiFFI" "-XNoCPP" "-XNoConstrainedClassMethods" "-XNoConstraintKinds" "-XNoDataKinds" "-XNoDatatypeContexts" "-XNoDefaultSignatures" "-XNoDeriveAnyClass" "-XNoDeriveDataTypeable" "-XNoDeriveFoldable" "-XNoDeriveFunctor" "-XNoDeriveGeneric" "-XNoDeriveLift" "-XNoDeriveTraversable" "-XNoDisambiguateRecordFields" "-XNoDoAndIfThenElse" "-XNoDoRec" "-XNoDuplicateRecordFields" "-XNoEmptyCase" "-XNoEmptyDataDecls" "-XNoExistentialQuantification" "-XNoExplicitForAll" "-XNoExplicitNamespaces" "-XNoExtendedDefaultRules" "-XNoFlexibleContexts" "-XNoFlexibleInstances" "-XNoForeignFunctionInterface" "-XNoFunctionalDependencies" "-XNoGADTSyntax" "-XNoGADTs" "-XNoGHCForeignImportPrim" "-XNoGeneralizedNewtypeDeriving" "-XNoGenerics" "-XNoImplicitParams" "-XNoImplicitPrelude" "-XNoImpredicativeTypes" "-XNoIncoherentInstances" "-XNoInstanceSigs" "-XNoInterruptibleFFI" "-XNoJavaScriptFFI" "-XNoKindSignatures" "-XNoLambdaCase" "-XNoLiberalTypeSynonyms" "-XNoMagicHash" "-XNoMonadComprehensions" "-XNoMonadFailDesugaring" "-XNoMonoLocalBinds" "-XNoMonoPatBinds" "-XNoMonomorphismRestriction" "-XNoMultiParamTypeClasses" "-XNoMultiWayIf" "-XNoNPlusKPatterns" "-XNoNamedFieldPuns" "-XNoNamedWildCards" "-XNoNegativeLiterals" "-XNoNondecreasingIndentation" "-XNoNullaryTypeClasses" "-XNoNumDecimals" "-XNoOverlappingInstances" "-XNoOverloadedLabels" "-XNoOverloadedLists" "-XNoOverloadedStrings" "-XNoPackageImports" "-XNoParallelArrays" "-XNoParallelListComp" "-XNoPartialTypeSignatures" "-XNoPatternGuards" "-XNoPatternSignatures" "-XNoPatternSynonyms" "-XNoPolyKinds" "-XNoPolymorphicComponents" "-XNoPostfixOperators" "-XNoQuasiQuotes" "-XNoRank2Types" "-XNoRankNTypes" "-XNoRebindableSyntax" "-XNoRecordPuns" "-XNoRecordWildCards" "-XNoRecursiveDo" "-XNoRelaxedLayout" "-XNoRelaxedPolyRec" "-XNoRoleAnnotations" "-XNoScopedTypeVariables" "-XNoStandaloneDeriving" "-XNoStaticPointers" "-XNoStrict" "-XNoStrictData" "-XNoTemplateHaskell" "-XNoTemplateHaskellQuotes" "-XNoTraditionalRecordSyntax" "-XNoTransformListComp" "-XNoTupleSections" "-XNoTypeApplications" "-XNoTypeFamilies" "-XNoTypeFamilyDependencies" "-XNoTypeInType" "-XNoTypeOperators" "-XNoTypeSynonymInstances" "-XNoUnboxedTuples" "-XNoUndecidableInstances" "-XNoUndecidableSuperClasses" "-XNoUnicodeSyntax" "-XNoUnliftedFFITypes" "-XNoViewPatterns" "-XNondecreasingIndentation" "-XNullaryTypeClasses" "-XNumDecimals" "-XOverlappingInstances" "-XOverloadedLabels" "-XOverloadedLists" "-XOverloadedStrings" "-XPackageImports" "-XParallelArrays" "-XParallelListComp" "-XPartialTypeSignatures" "-XPatternGuards" "-XPatternSignatures" "-XPatternSynonyms" "-XPolyKinds" "-XPolymorphicComponents" "-XPostfixOperators" "-XQuasiQuotes" "-XRank2Types" "-XRankNTypes" "-XRebindableSyntax" "-XRecordPuns" "-XRecordWildCards" "-XRecursiveDo" "-XRelaxedLayout" "-XRelaxedPolyRec" "-XRoleAnnotations" "-XSafe" "-XScopedTypeVariables" "-XStandaloneDeriving" "-XStaticPointers" "-XStrict" "-XStrictData" "-XTemplateHaskell" "-XTemplateHaskellQuotes" "-XTraditionalRecordSyntax" "-XTransformListComp" "-XTrustworthy" "-XTupleSections" "-XTypeApplications" "-XTypeFamilies" "-XTypeFamilyDependencies" "-XTypeInType" "-XTypeOperators" "-XTypeSynonymInstances" "-XUnboxedTuples" "-XUndecidableInstances" "-XUndecidableSuperClasses" "-XUnicodeSyntax" "-XUnliftedFFITypes" "-XUnsafe" "-XViewPatterns" "-auto" "-auto-all" "-c" "-caf-all" "-clear-package-db" "-cpp" "-dannot-lint" "-dasm-lint" "-dcmm-lint" "-dcore-lint" "-ddump-asm" "-ddump-asm-conflicts" "-ddump-asm-expanded" "-ddump-asm-liveness" "-ddump-asm-native" "-ddump-asm-regalloc" "-ddump-asm-regalloc-stages" "-ddump-asm-stats" "-ddump-bcos" "-ddump-call-arity" "-ddump-cmm" "-ddump-cmm-cbe" "-ddump-cmm-cfg" "-ddump-cmm-cps" "-ddump-cmm-info" "-ddump-cmm-proc" "-ddump-cmm-procmap" "-ddump-cmm-raw" "-ddump-cmm-sink" "-ddump-cmm-sp" "-ddump-cmm-split" "-ddump-cmm-switch" "-ddump-core-stats" "-ddump-cs-trace" "-ddump-cse" "-ddump-debug" "-ddump-deriv" "-ddump-ds" "-ddump-file-prefix" "-ddump-foreign" "-ddump-hi" "-ddump-hi-diffs" "-ddump-hpc" "-ddump-if-trace" "-ddump-inlinings" "-ddump-llvm" "-ddump-minimal-imports" "-ddump-mod-cycles" "-ddump-mod-map" "-ddump-occur-anal" "-ddump-opt-cmm" "-ddump-parsed" "-ddump-prep" "-ddump-rn" "-ddump-rn-stats" "-ddump-rn-trace" "-ddump-rtti" "-ddump-rule-firings" "-ddump-rule-rewrites" "-ddump-rules" "-ddump-simpl" "-ddump-simpl-iterations" "-ddump-simpl-stats" "-ddump-simpl-trace" "-ddump-spec" "-ddump-splices" "-ddump-stg" "-ddump-str-signatures" "-ddump-stranal" "-ddump-strsigs" "-ddump-tc" "-ddump-tc-trace" "-ddump-ticked" "-ddump-to-file" "-ddump-types" "-ddump-vect" "-ddump-view-pattern-commoning" "-ddump-vt-trace" "-ddump-worker-wrapper" "-debug" "-dep-makefile" "-dep-suffix" "-dfaststring-stats" "-dinitial-unique" "-distrust" "-distrust-all-packages" "-dno-debug-output" "-dno-llvm-mangler" "-dno-ppr-case-as-let" "-dno-ppr-ticks" "-dno-suppress-coercions" "-dno-suppress-idinfo" "-dno-suppress-module-prefixes" "-dno-suppress-type-applications" "-dno-suppress-type-signatures" "-dno-suppress-unfoldings" "-dno-suppress-uniques" "-dno-suppress-var-kinds" "-dppr-case-as-let" "-dppr-cols" "-dppr-debug" "-dppr-ticks" "-dppr-user-length" "-dshow-passes" "-dsource-stats" "-dstg-lint" "-dstg-stats" "-dsuppress-all" "-dsuppress-coercions" "-dsuppress-idinfo" "-dsuppress-module-prefixes" "-dsuppress-type-applications" "-dsuppress-type-signatures" "-dsuppress-unfoldings" "-dsuppress-uniques" "-dsuppress-var-kinds" "-dth-dec-file" "-dtrace-level" "-dumpdir" "-dunique-increment" "-dverbose-core2core" "-dverbose-stg2stg" "-dylib-install-name" "-dynamic" "-dynamic-too" "-dynhisuf" "-dynload" "-dyno" "-dynosuf" "-e" "-eventlog" "-exclude-module" "-fPArr" "-fPIC" "-fallow-incoherent-instances" "-fallow-overlapping-instances" "-fallow-undecidable-instances" "-farrows" "-fasm" "-fbang-patterns" "-fbuilding-cabal-package" "-fbyte-code" "-fcall-arity" "-fcase-merge" "-fcmm-elim-common-blocks" "-fcmm-sink" "-fconstraint-solver-iterations" "-fcontext-stack" "-fcpr-anal" "-fcpr-off" "-fcross-module-specialise" "-fcse" "-fdefer-type-errors" "-fdefer-typed-holes" "-fdicts-cheap" "-fdicts-strict" "-fdmd-tx-dict-sel" "-fdo-eta-reduction" "-fdo-lambda-eta-expansion" "-feager-blackholing" "-fembed-manifest" "-fenable-rewrite-rules" "-ferror-spans" "-fexcess-precision" "-fexpose-all-unfoldings" "-fext-core" "-fextended-default-rules" "-fexternal-interpreter" "-fffi" "-ffi" "-fflat-cache" "-ffloat-all-lams" "-ffloat-in" "-ffloat-lam-args" "-fforce-recomp" "-ffrontend-opt" "-ffull-laziness" "-ffun-to-thunk" "-fgen-manifest" "-fghci-history" "-fghci-sandbox" "-fglasgow-exts" "-fhelpful-errors" "-fhistory-size" "-fhpc" "-fhpc-no-auto" "-fignore-asserts" "-fignore-interface-pragmas" "-fimplicit-params" "-fimplicit-prelude" "-firrefutable-tuples" "-fkill-absence" "-fkill-one-shot" "-flate-dmd-anal" "-fliberate-case" "-fliberate-case-threshold" "-fllvm" "-floopification" "-fmax-inline-alloc-size" "-fmax-inline-memcpy-insns" "-fmax-inline-memset-insns" "-fmax-pmcheck-iterations" "-fmax-relevant-binds" "-fmax-simplifier-iterations" "-fmax-worker-args" "-fmono-pat-binds" "-fmonomorphism-restriction" "-fno-PArr" "-fno-PIC" "-fno-allow-incoherent-instances" "-fno-allow-overlapping-instances" "-fno-allow-undecidable-instances" "-fno-arrows" "-fno-bang-patterns" "-fno-building-cabal-package" "-fno-call-arity" "-fno-case-merge" "-fno-cmm-elim-common-blocks" "-fno-cmm-sink" "-fno-code" "-fno-cpr-anal" "-fno-cross-module-specialise" "-fno-cse" "-fno-defer-type-errors" "-fno-defer-typed-holes" "-fno-dicts-cheap" "-fno-dicts-strict" "-fno-dmd-tx-dict-sel" "-fno-do-eta-reduction" "-fno-do-lambda-eta-expansion" "-fno-eager-blackholing" "-fno-embed-manifest" "-fno-enable-rewrite-rules" "-fno-error-spans" "-fno-excess-precision" "-fno-expose-all-unfoldings" "-fno-ext-core" "-fno-extended-default-rules" "-fno-external-interpreter" "-fno-ffi" "-fno-fi" "-fno-flat-cache" "-fno-float-in" "-fno-force-recomp" "-fno-full-laziness" "-fno-fun-to-thunk" "-fno-gen-manifest" "-fno-ghci-history" "-fno-ghci-sandbox" "-fno-glasgow-exts" "-fno-helpful-errors" "-fno-hpc" "-fno-hpc-no-auto" "-fno-ignore-asserts" "-fno-ignore-interface-pragmas" "-fno-implicit-params" "-fno-implicit-prelude" "-fno-irrefutable-tuples" "-fno-kill-absence" "-fno-kill-one-shot" "-fno-late-dmd-anal" "-fno-liberate-case" "-fno-liberate-case-threshold" "-fno-loopification" "-fno-max-relevant-binds" "-fno-mono-pat-binds" "-fno-monomorphism-restriction" "-fno-omit-interface-pragmas" "-fno-omit-yields" "-fno-opt-coercion" "-fno-parr" "-fno-pedantic-bottoms" "-fno-pre-inlining" "-fno-print-equality-relations" "-fno-print-expanded-synonyms" "-fno-print-explicit-coercions" "-fno-print-explicit-foralls" "-fno-print-explicit-kinds" "-fno-print-explicit-runtime-reps" "-fno-print-potential-instances" "-fno-print-typechecker-elaboration" "-fno-print-unicode-syntax" "-fno-prof-auto" "-fno-prof-cafs" "-fno-prof-count-entries" "-fno-regs-graph" "-fno-regs-iterative" "-fno-reverse-errors" "-fno-rewrite-rules" "-fno-safe-infer" "-fno-scoped-type-variables" "-fno-shared-implib" "-fno-show-warning-groups" "-fno-simple-list-literals" "-fno-spec-constr" "-fno-spec-constr-count" "-fno-spec-constr-threshold" "-fno-specialise" "-fno-specialise-aggressively" "-fno-state-hack" "-fno-static-argument-transformation" "-fno-strictness" "-fno-th" "-fno-unbox-small-strict-fields" "-fno-unbox-strict-fields" "-fno-use-rpaths" "-fno-vectorisation-avoidance" "-fno-vectorise" "-fno-version-macros" "-fno-warn-" "-fno-warn-alternative-layout-rule-transitional" "-fno-warn-amp" "-fno-warn-auto-orphans" "-fno-warn-context-quantification" "-fno-warn-deprecated-flags" "-fno-warn-deprecations" "-fno-warn-deriving-typeable" "-fno-warn-dodgy-exports" "-fno-warn-dodgy-foreign-imports" "-fno-warn-dodgy-imports" "-fno-warn-duplicate-constraints" "-fno-warn-duplicate-exports" "-fno-warn-empty-enumerations" "-fno-warn-hi-shadowing" "-fno-warn-identities" "-fno-warn-implicit-prelude" "-fno-warn-incomplete-patterns" "-fno-warn-incomplete-record-updates" "-fno-warn-incomplete-uni-patterns" "-fno-warn-inline-rule-shadowing" "-fno-warn-missing-exported-sigs" "-fno-warn-missing-fields" "-fno-warn-missing-import-lists" "-fno-warn-missing-local-sigs" "-fno-warn-missing-methods" "-fno-warn-missing-signatures" "-fno-warn-monomorphism-restriction" "-fno-warn-name-shadowing" "-fno-warn-orphans" "-fno-warn-overflowed-literals" "-fno-warn-overlapping-patterns" "-fno-warn-partial-type-signatures" "-fno-warn-pointless-pragmas" "-fno-warn-safe" "-fno-warn-tabs" "-fno-warn-trustworthy-safe" "-fno-warn-type-defaults" "-fno-warn-typed-holes" "-fno-warn-unrecognised-pragmas" "-fno-warn-unsafe" "-fno-warn-unsupported-calling-conventions" "-fno-warn-unsupported-llvm-version" "-fno-warn-unticked-promoted-constructors" "-fno-warn-unused-binds" "-fno-warn-unused-do-bind" "-fno-warn-unused-imports" "-fno-warn-unused-matches" "-fno-warn-warnings-deprecations" "-fno-warn-wrong-do-bind" "-fno-worker-wrapper" "-fno-write-interface" "-fobject-code" "-fomit-interface-pragmas" "-fomit-yields" "-fpackage-trust" "-fparr" "-fpedantic-bottoms" "-fplugin" "-fplugin-opt" "-fpre-inlining" "-fprint-equality-relations" "-fprint-expanded-synonyms" "-fprint-explicit-coercions" "-fprint-explicit-foralls" "-fprint-explicit-kinds" "-fprint-explicit-runtime-reps" "-fprint-potential-instances" "-fprint-typechecker-elaboration" "-fprint-unicode-syntax" "-fprof-auto" "-fprof-auto-calls" "-fprof-auto-exported" "-fprof-auto-top" "-fprof-cafs" "-fprof-count-entries" "-framework" "-framework-path" "-freduction-depth" "-fregs-graph" "-fregs-iterative" "-freverse-errors" "-frewrite-rules" "-frule-check" "-fscoped-type-variables" "-fshared-implib" "-fshow-warning-groups" "-fsimpl-tick-factor" "-fsimple-list-literals" "-fsimplifier-phases" "-fspec-constr" "-fspec-constr-count" "-fspec-constr-recursive" "-fspec-constr-threshold" "-fspecialise" "-fspecialise-aggressively" "-fstatic-argument-transformation" "-fstrictness" "-fstrictness-before" "-fth" "-ftype-function-depth" "-funbox-small-strict-fields" "-funbox-strict-fields" "-funfolding-creation-threshold" "-funfolding-dict-discount" "-funfolding-fun-discount" "-funfolding-keeness-factor" "-funfolding-use-threshold" "-fuse-rpaths" "-fvectorisation-avoidance" "-fvectorise" "-fversion-macros" "-fvia-C" "-fvia-c" "-fwarn-" "-fwarn-alternative-layout-rule-transitional" "-fwarn-amp" "-fwarn-auto-orphans" "-fwarn-context-quantification" "-fwarn-deprecated-flags" "-fwarn-deprecations" "-fwarn-deriving-typeable" "-fwarn-dodgy-exports" "-fwarn-dodgy-foreign-imports" "-fwarn-dodgy-imports" "-fwarn-duplicate-constraints" "-fwarn-duplicate-exports" "-fwarn-empty-enumerations" "-fwarn-hi-shadowing" "-fwarn-identities" "-fwarn-implicit-prelude" "-fwarn-incomplete-patterns" "-fwarn-incomplete-record-updates" "-fwarn-incomplete-uni-patterns" "-fwarn-inline-rule-shadowing" "-fwarn-missing-exported-sigs" "-fwarn-missing-fields" "-fwarn-missing-import-lists" "-fwarn-missing-local-sigs" "-fwarn-missing-methods" "-fwarn-missing-signatures" "-fwarn-monomorphism-restriction" "-fwarn-name-shadowing" "-fwarn-orphans" "-fwarn-overflowed-literals" "-fwarn-overlapping-patterns" "-fwarn-partial-type-signatures" "-fwarn-pointless-pragmas" "-fwarn-safe" "-fwarn-tabs" "-fwarn-trustworthy-safe" "-fwarn-type-defaults" "-fwarn-typed-holes" "-fwarn-unrecognised-pragmas" "-fwarn-unsafe" "-fwarn-unsupported-calling-conventions" "-fwarn-unsupported-llvm-version" "-fwarn-unticked-promoted-constructors" "-fwarn-unused-binds" "-fwarn-unused-do-bind" "-fwarn-unused-imports" "-fwarn-unused-matches" "-fwarn-warnings-deprecations" "-fwarn-wrong-do-bind" "-fworker-wrapper" "-fwrite-interface" "-g" "-global-package-db" "-gransim" "-haddock" "-haddock-opts" "-hcsuf" "-hide-all-packages" "-hide-all-plugin-packages" "-hide-package" "-hidir" "-hisuf" "-hpcdir" "-i" "-ignore-package" "-include-pkg-deps" "-j" "-keep-hc-file" "-keep-hc-files" "-keep-llvm-file" "-keep-llvm-files" "-keep-s-file" "-keep-s-files" "-keep-tmp-files" "-l" "-main-is" "-mavx" "-mavx2" "-mavx512cd" "-mavx512er" "-mavx512f" "-mavx512pf" "-msse" "-msse2" "-msse3" "-msse4" "-msse4.2" "-n" "-ndp" "-no-auto" "-no-auto-all" "-no-auto-link-packages" "-no-caf-all" "-no-global-package-db" "-no-hs-main" "-no-link" "-no-recomp" "-no-rtsopts" "-no-rtsopts-suggestions" "-no-user-package-conf" "-no-user-package-db" "-o" "-odir" "-ohi" "-optF" "-optL" "-optP" "-opta" "-optc" "-opti" "-optl" "-optlc" "-optlo" "-optwindres" "-osuf" "-outputdir" "-package" "-package-conf" "-package-db" "-package-env" "-package-id" "-package-key" "-package-name" "-parallel" "-pgmF" "-pgmL" "-pgmP" "-pgma" "-pgmc" "-pgmdll" "-pgmi" "-pgml" "-pgmlc" "-pgmlibtool" "-pgmlo" "-pgms" "-pgmwindres" "-plugin-package" "-plugin-package-id" "-prof" "-rdynamic" "-recomp" "-relative-dynlib-paths" "-rtsopts" "-rtsopts=all" "-rtsopts=none" "-rtsopts=some" "-shared" "-sig-of" "-smp" "-split-objs" "-split-sections" "-static" "-staticlib" "-stubdir" "-syslib" "-this-package-key" "-this-unit-id" "-threaded" "-ticky" "-ticky-LNE" "-ticky-allocd" "-ticky-dyn-thunk" "-tmpdir" "-trust" "-user-package-db" "-v" "-w" "-with-rtsopts" ;;; END haskell-ghc-supported-options ) "List of options supported by any known version of GHC. This list should be updated by running `haskell-update-ghc-support'.") (defun haskell-update-ghc-support (ghc-path) "Update `haskell-ghc-supported-options' and `haskell-ghc-supported-extensions'. This command should be run once a GHC is released. It will use --show-options and --supported-extensions to source the information from GHC-PATH. Then it will update source code to include newly found options. Old options are never removed and are retained to support old versions of the compiler. Options and extension are kept in ascending order." (interactive (list (read-shell-command "GHC command: " nil nil (let ((filename (cond (buffer-file-name) ((eq major-mode 'dired-mode) (when (fboundp 'dired-get-filename) ;; silence the checker (dired-get-filename nil t)))))) (and filename (file-relative-name filename)))))) (let ((extentions (split-string (shell-command-to-string (concat ghc-path " --supported-extensions")))) (options (split-string (shell-command-to-string (concat ghc-path " --show-options"))))) (with-current-buffer (find-file-noselect (replace-regexp-in-string "\\.elc$" ".el" (symbol-file 'haskell-ghc-supported-options))) (save-excursion (goto-char (point-min)) (re-search-forward "BEGIN haskell-ghc-supported-extensions") (forward-line 1) (let ((point (point))) (re-search-forward "END haskell-ghc-supported-extensions") (goto-char (line-beginning-position)) (delete-region point (point))) (setq haskell-ghc-supported-extensions (delete-dups (sort (append extentions haskell-ghc-supported-extensions) #'string<))) (dolist (item haskell-ghc-supported-extensions) (insert " \"" item "\"\n")) (re-search-forward "BEGIN haskell-ghc-supported-options") (forward-line 1) (let ((point (point))) (re-search-forward "END haskell-ghc-supported-options") (goto-char (line-beginning-position)) (delete-region point (point))) (setq haskell-ghc-supported-options (delete-dups (sort (append options haskell-ghc-supported-options) #'string<))) (dolist (item haskell-ghc-supported-options) (insert " \"" item "\"\n")))))) (provide 'haskell-ghc-support) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-hoogle.el�����������������������������������������������������������������0000664�0000000�0000000�00000013420�13602233217�0017226�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-hoogle.el --- Look up Haskell documentation via hoogle or hayoo -*- lexical-binding: t; -*- ;; Copyright © 2015 Steve Purcell ;; 2016 Arthur Fayzrakhmanov ;; Author: Steve Purcell <steve@sanityinc.com> ;; Keywords: docs ;; 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; Functions for looking up documentation with hayoo or hoogle, via ;; either local or remote servers. ;;; Code: (require 'ansi-color) (require 'haskell-mode) (require 'haskell-utils) (defcustom haskell-hoogle-command (if (executable-find "hoogle") "hoogle") "Name of the command to use to query Hoogle. If nil, use the Hoogle web-site." :group 'haskell :type '(choice (const :tag "Use Web-site" nil) string)) (defcustom haskell-hoogle-url "https://hoogle.haskell.org/?hoogle=%s" "Default value for hoogle web site." :group 'haskell :type '(choice (const :tag "haskell-org" "https://hoogle.haskell.org/?hoogle=%s") (const :tag "fp-complete" "https://www.stackage.org/lts/hoogle?q=%s") (const :tag "hayoo" "http://hayoo.fh-wedel.de/?query=%s") string)) (defcustom haskell-hoogle-server-command (lambda (port) (list "hoogle" "server" "--local" "-p" (number-to-string port))) "Command used to start the local hoogle server." :group 'haskell :type 'function ) ;;;###autoload (defun haskell-hoogle (query &optional info) "Do a Hoogle search for QUERY. When `haskell-hoogle-command' is non-nil, this command runs that. Otherwise, it opens a hoogle search result in the browser. If prefix argument INFO is given, then `haskell-hoogle-command' is asked to show extra info for the items matching QUERY.." (interactive (let ((def (haskell-ident-at-point))) (if (and def (symbolp def)) (setq def (symbol-name def))) (list (read-string (if def (format "Hoogle query (default %s): " def) "Hoogle query: ") nil nil def) current-prefix-arg))) (if (null haskell-hoogle-command) (browse-url (format haskell-hoogle-url (url-hexify-string query))) (let ((command (concat haskell-hoogle-command (if info " -i " "") " --color " (shell-quote-argument query)))) (with-help-window "*hoogle*" (with-current-buffer standard-output (insert (shell-command-to-string command)) (ansi-color-apply-on-region (point-min) (point-max))))))) ;;;###autoload (defalias 'hoogle 'haskell-hoogle) (defvar haskell-hoogle-server-process-name "emacs-local-hoogle") (defvar haskell-hoogle-server-buffer-name (format "*%s*" haskell-hoogle-server-process-name)) (defvar haskell-hoogle-port-number 49513 "Port number.") (defvar haskell-hoogle-server-process nil "The process handle of the local hoogle server.") (defun haskell-hoogle-start-server () "Start hoogle local server." (interactive) (unless (haskell-hoogle-server-live-p) (set 'haskell-hoogle-server-process (apply 'start-process (append (list haskell-hoogle-server-process-name (get-buffer-create haskell-hoogle-server-buffer-name)) (funcall haskell-hoogle-server-command haskell-hoogle-port-number)))) ) ) (defun haskell-hoogle-server-live-p () "Whether the hoogle server process is live." (condition-case _err (process-live-p haskell-hoogle-server-process) (error nil))) (defun haskell-hoogle-kill-server () "Kill the hoogle server if it is live." (interactive) (when (haskell-hoogle-server-live-p) (kill-process (get-buffer-create haskell-hoogle-server-buffer-name)) (set 'haskell-hoogle-server-process nil))) ;;;###autoload (defun haskell-hoogle-lookup-from-local () "Lookup by local hoogle." (interactive) (if (haskell-hoogle-server-live-p) (browse-url (format "http://localhost:%i/?hoogle=%s" haskell-hoogle-port-number (read-string "hoogle: " (haskell-ident-at-point)))) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (when (y-or-n-p "Hoogle server not running, start hoogle server? ") (haskell-hoogle-start-server)) (haskell-mode-toggle-interactive-prompt-state t)))) (defcustom haskell-hayoo-url "http://hayoo.fh-wedel.de/?query=%s" "Default value for hayoo web site." :group 'haskell :type '(choice (const :tag "fh-wedel.de" "http://hayoo.fh-wedel.de/?query=%s") string)) ;;;###autoload (defun haskell-hayoo (query) "Do a Hayoo search for QUERY." (interactive (let ((def (haskell-ident-at-point))) (if (and def (symbolp def)) (setq def (symbol-name def))) (list (read-string (if def (format "Hayoo query (default %s): " def) "Hayoo query: ") nil nil def)))) (browse-url (format haskell-hayoo-url (url-hexify-string query)))) ;;;###autoload (defalias 'hayoo 'haskell-hayoo) (provide 'haskell-hoogle) ;;; haskell-hoogle.el ends here ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-indent.el�����������������������������������������������������������������0000664�0000000�0000000�00000210462�13602233217�0017237�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-indent.el --- "semi-intelligent" indentation module for Haskell Mode -*- lexical-binding: t -*- ;; Copyright 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. ;; Copyright 1997-1998 Guy Lapalme ;; Author: 1997-1998 Guy Lapalme <lapalme@iro.umontreal.ca> ;; Keywords: indentation Haskell layout-rule ;; URL: http://www.iro.umontreal.ca/~lapalme/layout/index.html ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; Purpose: ;; ;; To support automatic indentation of Haskell programs using ;; the layout rule described in section 1.5 and appendix B.3 of the ;; the Haskell report. The rationale and the implementation principles ;; are described in an article to appear in Journal of Functional Programming. ;; "Dynamic tabbing for automatic indentation with the layout rule" ;; ;; It supports literate scripts. ;; Haskell indentation is performed ;; within \begin{code}...\end{code} sections of a literate script ;; and in lines beginning with > with Bird style literate script ;; TAB aligns to the left column outside of these sections. ;; ;; Installation: ;; ;; To turn indentation on for all Haskell buffers under the Haskell ;; mode of Moss&Thorn <http://www.haskell.org/haskell-mode/> ;; add this to .emacs: ;; ;; (add-hook 'haskell-mode-hook 'turn-on-haskell-indent) ;; ;; Otherwise, call `turn-on-haskell-indent'. ;; ;; ;; Customisation: ;; The "standard" offset for statements is 4 spaces. ;; It can be changed by setting the variable "haskell-indent-offset" to ;; another value ;; ;; The default number of blanks after > in a Bird style literate script ;; is 1; it can be changed by setting the variable ;; "haskell-indent-literate-Bird-default-offset" ;; ;; `haskell-indent-hook' is invoked if not nil. ;; ;; All functions/variables start with ;; `(turn-(on/off)-)haskell-indent' or `haskell-indent-'. ;; This file can also be used as a hook for the Hugs Mode developed by ;; Chris Van Humbeeck <chris.vanhumbeeck@cs.kuleuven.ac.be> ;; It can be obtained at: ;; http://www-i2.informatik.rwth-aachen.de/Forschung/FP/Haskell/hugs-mode.el ;; ;; For the Hugs mode put the following in your .emacs ;; ;;(setq auto-mode-alist (append auto-mode-alist '(("\\.hs\\'" . hugs-mode)))) ;;(autoload 'hugs-mode "hugs-mode" "Go into hugs mode" t) ;; ;; If only the indentation mode is used then replace the two ;; preceding lines with ;;(setq auto-mode-alist (append auto-mode-alist ;; '(("\\.hs\\'" . turn-on-haskell-indent)))) ;;(autoload 'turn-on-haskell-indent "hindent" "Indentation mode for Haskell" t) ;; ;; For indentation in both cases then add the following to your .emacs ;;(add-hook 'hugs-mode-hook 'turn-on-haskell-indent) ;;(autoload 'haskell-indent-cycle "hindent" "Indentation cycle for Haskell" t) ;; ;;; Code: (require 'cl-lib) (require 'haskell-string) (defvar haskell-literate) ;;;###autoload (defgroup haskell-indent nil "Haskell indentation." :group 'haskell :link '(custom-manual "(haskell-mode)Indentation") :prefix "haskell-indent-") (defcustom haskell-indent-offset 4 "Indentation of Haskell statements with respect to containing block." :type 'integer :safe #'natnump :group 'haskell-indent) (defcustom haskell-indent-literate-Bird-default-offset 1 "Default number of blanks after > in a Bird style literate script." :type 'integer :safe #'natnump :group 'haskell-indent) (defcustom haskell-indent-rhs-align-column 0 "Column on which to align right-hand sides (use 0 for ad-hoc alignment)." :type 'integer :safe #'natnump :group 'haskell-indent) (defun haskell-indent-point-to-col (apoint) "Return the column number of APOINT." (save-excursion (goto-char apoint) (current-column))) (defconst haskell-indent-start-keywords-re (concat "\\<" (regexp-opt '("class" "data" "import" "infix" "infixl" "infixr" "instance" "module" "newtype" "primitive" "signature" "type") t) "\\>") "Regexp for keywords to complete when standing at the first word of a line.") ;; Customizations for different kinds of environments ;; in which dealing with low-level events are different. (defun haskell-indent-mark-active () (if (featurep 'xemacs) (if zmacs-regions zmacs-region-active-p t) mark-active)) ;; for pushing indentation information (defvar haskell-indent-info) ;Used with dynamic scoping. (defun haskell-indent-push-col (col &optional name) "Push indentation information for the column COL. The info is followed by NAME (if present). Makes sure that the same indentation info is not pushed twice. Uses free var `haskell-indent-info'." (let ((tmp (cons col name))) (if (member tmp haskell-indent-info) haskell-indent-info (push tmp haskell-indent-info)))) (defun haskell-indent-push-pos (pos &optional name) "Push indentation information for POS followed by NAME (if present)." (haskell-indent-push-col (haskell-indent-point-to-col pos) name)) ;; (defvar haskell-indent-tab-align nil ;; "Align all indentations on TAB stops.") (defun haskell-indent-column+offset (column offset) (unless offset (setq offset haskell-indent-offset)) (setq column (+ column offset)) ;; (if (and haskell-indent-tab-align (> offset 0)) ;; (* 8 (/ (+ column 7) 8)) column) ;; ) (defun haskell-indent-push-pos-offset (pos &optional offset) "Pushes indentation information for the column corresponding to POS followed by an OFFSET (if present use its value otherwise use `haskell-indent-offset')." (haskell-indent-push-col (haskell-indent-column+offset (haskell-indent-point-to-col pos) offset))) ;; redefinition of some Emacs function for dealing with ;; Bird Style literate scripts (defun haskell-indent-bolp () "`bolp' but dealing with Bird-style literate scripts." (or (bolp) (and (eq haskell-literate 'bird) (<= (current-column) (1+ haskell-indent-literate-Bird-default-offset)) (eq (char-after (line-beginning-position)) ?\>)))) (defun haskell-indent-empty-line-p () "Checks if the current line is empty; deals with Bird style scripts." (save-excursion (beginning-of-line) (if (and (eq haskell-literate 'bird) (eq (following-char) ?\>)) (forward-char 1)) (looking-at "[ \t]*$"))) (defun haskell-indent-back-to-indentation () "`back-to-indentation' function but dealing with Bird-style literate scripts." (if (and (eq haskell-literate 'bird) (progn (beginning-of-line) (eq (following-char) ?\>))) (progn (forward-char 1) (skip-chars-forward " \t")) (back-to-indentation))) (defun haskell-indent-current-indentation () "`current-indentation' function dealing with Bird-style literate scripts." (if (eq haskell-literate 'bird) (save-excursion (haskell-indent-back-to-indentation) (current-column)) (current-indentation))) (defun haskell-indent-backward-to-indentation (n) "`backward-to-indentation' function dealing with Bird-style literate scripts." (if (eq haskell-literate 'bird) (progn (forward-line (- n)) (haskell-indent-back-to-indentation)) (backward-to-indentation n))) (defun haskell-indent-forward-line (&optional n) "`forward-line' function but dealing with Bird-style literate scripts." (prog1 (forward-line n) (if (and (eq haskell-literate 'bird) (eq (following-char) ?\>)) (progn (forward-char 1) ; skip > and initial blanks... (skip-chars-forward " \t"))))) (defun haskell-indent-line-to (n) "`indent-line-to' function but dealing with Bird-style literate scripts." (if (eq haskell-literate 'bird) (progn (beginning-of-line) (if (eq (following-char) ?\>) (delete-char 1)) (delete-horizontal-space) ; remove any starting TABs so (indent-line-to n) ; that indent-line only adds spaces (save-excursion (beginning-of-line) (if (> n 0) (delete-char 1)) ; delete the first space before (insert ?\>))) ; inserting a > (indent-line-to n))) (defun haskell-indent-skip-blanks-and-newlines-forward (end) "Skip forward blanks, tabs and newlines until END. Take account of Bird-style literate scripts." (skip-chars-forward " \t\n" end) (if (eq haskell-literate 'bird) (while (and (bolp) (eq (following-char) ?\>)) (forward-char 1) ; skip > (skip-chars-forward " \t\n" end)))) (defun haskell-indent-skip-blanks-and-newlines-backward (start) "Skip backward blanks, tabs and newlines up to START. Take account of Bird-style literate scripts." (skip-chars-backward " \t\n" start) (if (eq haskell-literate 'bird) (while (and (eq (current-column) 1) (eq (preceding-char) ?\>)) (forward-char -1) ; skip back > (skip-chars-backward " \t\n" start)))) ;; specific functions for literate code (defun haskell-indent-within-literate-code () "Check if point is within a part of literate Haskell code. If so, return its start; otherwise return nil: If it is Bird-style, then return the position of the >; otherwise return the ending position of \\begin{code}." (save-excursion (cl-case haskell-literate (bird (beginning-of-line) (if (or (eq (following-char) ?\>) (and (bolp) (forward-line -1) (eq (following-char) ?\>))) (progn (while (and (zerop (forward-line -1)) (eq (following-char) ?\>))) (if (not (eq (following-char) ?\>)) (forward-line)) (point)))) ;; Look for a \begin{code} or \end{code} line. ((latex tex) (if (re-search-backward "^\\(\\\\begin{code}$\\)\\|\\(\\\\end{code}$\\)" nil t) ;; within a literate code part if it was a \\begin{code}. (match-end 1))) (t (error "haskell-indent-within-literate-code: should not happen!"))))) (defun haskell-indent-put-region-in-literate (beg end &optional arg) "Put lines of the region as a piece of literate code. With prefix arg, remove indication that the region is literate code. It deals with both Bird style and non Bird-style scripts." (interactive "r\nP") (unless haskell-literate (error "Cannot put a region in literate in a non literate script")) (if (eq haskell-literate 'bird) (let ((comment-start "> ") ; Change dynamic bindings for (comment-start-skip "^> ?") ; comment-region. (comment-end "") (comment-end-skip "\n") (comment-style 'plain)) (comment-region beg end arg)) ;; Not Bird style. (if arg ; Remove the literate indication. (save-excursion (goto-char end) ; Remove end. (if (re-search-backward "^\\\\end{code}[ \t\n]*\\=" (line-beginning-position -2) t) (delete-region (point) (line-beginning-position 2))) (goto-char beg) ; Remove end. (beginning-of-line) (if (looking-at "\\\\begin{code}") (kill-line 1))) (save-excursion ; Add the literate indication. (goto-char end) (unless (bolp) (newline)) (insert "\\end{code}\n") (goto-char beg) (unless (bolp) (newline)) (insert "\\begin{code}\n"))))) ;;; Start of indentation code (defcustom haskell-indent-look-past-empty-line t "If nil, indentation engine will not look past an empty line for layout points." :group 'haskell-indent :safe #'booleanp :type 'boolean) (defun haskell-indent-start-of-def () "Return the position of the start of a definition. The start of a def is expected to be recognizable by starting in column 0, unless `haskell-indent-look-past-empty-line' is nil, in which case we take a coarser approximation and stop at the first empty line." (save-excursion (let ((start-code (and haskell-literate (haskell-indent-within-literate-code))) (top-col (if (eq haskell-literate 'bird) 2 0)) (save-point (point))) ;; determine the starting point of the current piece of code (setq start-code (if start-code (1+ start-code) (point-min))) ;; go backward until the first preceding empty line (haskell-indent-forward-line -1) (while (and (if haskell-indent-look-past-empty-line (or (> (haskell-indent-current-indentation) top-col) (haskell-indent-empty-line-p)) (and (> (haskell-indent-current-indentation) top-col) (not (haskell-indent-empty-line-p)))) (> (point) start-code) (= 0 (haskell-indent-forward-line -1)))) ;; go forward after the empty line (if (haskell-indent-empty-line-p) (haskell-indent-forward-line 1)) (setq start-code (point)) ;; find the first line of code which is not a comment (forward-comment (point-max)) (if (> (point) save-point) start-code (point))))) (defun haskell-indent-open-structure (start end) "If any structure (list or tuple) is not closed, between START and END, returns the location of the opening symbol, nil otherwise." (save-excursion (nth 1 (parse-partial-sexp start end)))) (defun haskell-indent-in-string (start end) "If a string is not closed , between START and END, returns the location of the opening symbol, nil otherwise." (save-excursion (let ((pps (parse-partial-sexp start end))) (if (nth 3 pps) (nth 8 pps))))) (defun haskell-indent-in-comment (start end) "Check, starting from START, if END is at or within a comment. Returns the location of the start of the comment, nil otherwise." (let (pps) (cl-assert (<= start end)) (cond ((= start end) nil) ((nth 4 (save-excursion (setq pps (parse-partial-sexp start end)))) (nth 8 pps)) ;; We also want to say that we are *at* the beginning of a comment. ((and (not (nth 8 pps)) (>= (point-max) (+ end 2)) (nth 4 (save-excursion (setq pps (parse-partial-sexp end (+ end 2)))))) (nth 8 pps))))) (defvar haskell-indent-off-side-keywords-re "\\<\\(do\\|let\\|of\\|where\\|mdo\\|rec\\)\\>[ \t]*") (defun haskell-indent-type-at-point () "Return the type of the line (also puts information in `match-data')." (cond ((haskell-indent-empty-line-p) 'empty) ((haskell-indent-in-comment (point-min) (point)) 'comment) ((looking-at "\\(\\([[:alpha:]]\\(\\sw\\|'\\)*\\)\\|_\\)[ \t\n]*") 'ident) ((looking-at "\\(|[^|]\\)[ \t\n]*") 'guard) ((looking-at "\\(=[^>=]\\|::\\|∷\\|→\\|←\\|->\\|<-\\)[ \t\n]*") 'rhs) (t 'other))) (defvar haskell-indent-current-line-first-ident "" "Global variable that keeps track of the first ident of the line to indent.") (defun haskell-indent-contour-line (start end) "Generate contour information between START and END points." (if (< start end) (save-excursion (goto-char end) (haskell-indent-skip-blanks-and-newlines-backward start) (let ((cur-col (current-column)) ; maximum column number (fl 0) ; number of lines that forward-line could not advance contour) (while (and (> cur-col 0) (= fl 0) (>= (point) start)) (haskell-indent-back-to-indentation) (if (< (point) start) (goto-char start)) (and (not (member (haskell-indent-type-at-point) '(empty comment))) ; skip empty and comment lines (< (current-column) cur-col) ; less indented column found (push (point) contour) ; new contour point found (setq cur-col (current-column))) (setq fl (haskell-indent-forward-line -1))) contour)))) (defun haskell-indent-next-symbol (end) "Move point to the next symbol." (skip-syntax-forward ")" end) (if (< (point) end) (progn (forward-sexp 1) (haskell-indent-skip-blanks-and-newlines-forward end)))) (defun haskell-indent-next-symbol-safe (end) "Puts point to the next following symbol, or to end if there are no more symbols in the sexp." (condition-case _errlist (haskell-indent-next-symbol end) (error (goto-char end)))) (defun haskell-indent-separate-valdef (start end) "Return a list of positions for important parts of a valdef." (save-excursion (let (valname valname-string aft-valname guard aft-guard rhs-sign aft-rhs-sign type) ;; "parse" a valdef separating important parts (goto-char start) (setq type (haskell-indent-type-at-point)) (if (or (memq type '(ident other))) ; possible start of a value def (progn (if (eq type 'ident) (progn (setq valname (match-beginning 0)) (setq valname-string (match-string 0)) (goto-char (match-end 0))) (skip-chars-forward " \t" end) (setq valname (point)) ; type = other (haskell-indent-next-symbol-safe end)) (while (and (< (point) end) (setq type (haskell-indent-type-at-point)) (or (memq type '(ident other)))) (if (null aft-valname) (setq aft-valname (point))) (haskell-indent-next-symbol-safe end)))) (if (and (< (point) end) (eq type 'guard)) ; start of a guard (progn (setq guard (match-beginning 0)) (goto-char (match-end 0)) (while (and (< (point) end) (setq type (haskell-indent-type-at-point)) (not (eq type 'rhs))) (if (null aft-guard) (setq aft-guard (point))) (haskell-indent-next-symbol-safe end)))) (if (and (< (point) end) (eq type 'rhs)) ; start of a rhs (progn (setq rhs-sign (match-beginning 0)) (goto-char (match-end 0)) (if (< (point) end) (setq aft-rhs-sign (point))))) (list valname valname-string aft-valname guard aft-guard rhs-sign aft-rhs-sign)))) (defsubst haskell-indent-no-otherwise (guard) "Check if there is no otherwise at GUARD." (save-excursion (goto-char guard) (not (looking-at "|[ \t]*otherwise\\>")))) (defun haskell-indent-guard (start end end-visible indent-info) "Find indentation information for a line starting with a guard." (save-excursion (let* ((haskell-indent-info indent-info) (sep (haskell-indent-separate-valdef start end)) (valname (nth 0 sep)) (guard (nth 3 sep)) (rhs-sign (nth 5 sep))) ;; push information indentation for the visible part (if (and guard (< guard end-visible) (haskell-indent-no-otherwise guard)) (haskell-indent-push-pos guard) (if rhs-sign (haskell-indent-push-pos rhs-sign) ; probably within a data definition... (if valname (haskell-indent-push-pos-offset valname)))) haskell-indent-info))) (defun haskell-indent-rhs (start end end-visible indent-info) "Find indentation information for a line starting with a rhs." (save-excursion (let* ((haskell-indent-info indent-info) (sep (haskell-indent-separate-valdef start end)) (valname (nth 0 sep)) (guard (nth 3 sep)) (rhs-sign (nth 5 sep))) ;; push information indentation for the visible part (if (and rhs-sign (< rhs-sign end-visible)) (haskell-indent-push-pos rhs-sign) (if (and guard (< guard end-visible)) (haskell-indent-push-pos-offset guard) (if valname ; always visible !! (haskell-indent-push-pos-offset valname)))) haskell-indent-info))) (defconst haskell-indent-decision-table (let ((or "\\)\\|\\(")) (concat "\\(" "1.1.11" or ; 1= vn gd rh arh "1.1.10" or ; 2= vn gd rh "1.1100" or ; 3= vn gd agd "1.1000" or ; 4= vn gd "1.0011" or ; 5= vn rh arh "1.0010" or ; 6= vn rh "110000" or ; 7= vn avn "100000" or ; 8= vn "001.11" or ; 9= gd rh arh "001.10" or ;10= gd rh "001100" or ;11= gd agd "001000" or ;12= gd "000011" or ;13= rh arh "000010" or ;14= rh "000000" ;15= "\\)"))) (defun haskell-indent-find-case (test) "Find the index that matches TEST in the decision table." (if (string-match haskell-indent-decision-table test) ;; use the fact that the resulting match-data is a list of the form ;; (0 6 [2*(n-1) nil] 0 6) where n is the number of the matching regexp ;; so n= ((length match-data)/2)-1 (- (/ (length (match-data 'integers)) 2) 1) (error "haskell-indent-find-case: impossible case: %s" test))) (defun haskell-indent-empty (start end end-visible indent-info) "Find indentation points for an empty line." (save-excursion (let* ((haskell-indent-info indent-info) (sep (haskell-indent-separate-valdef start end)) (valname (pop sep)) (valname-string (pop sep)) (aft-valname (pop sep)) (guard (pop sep)) (aft-guard (pop sep)) (rhs-sign (pop sep)) (aft-rhs-sign (pop sep)) (last-line (= end end-visible)) (test (string (if valname ?1 ?0) (if (and aft-valname (< aft-valname end-visible)) ?1 ?0) (if (and guard (< guard end-visible)) ?1 ?0) (if (and aft-guard (< aft-guard end-visible)) ?1 ?0) (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0) (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0)))) (if (and valname-string ; special case for start keywords (string-match haskell-indent-start-keywords-re valname-string)) (progn (haskell-indent-push-pos valname) ;; very special for data keyword (if (string-match "\\<data\\>" valname-string) (if rhs-sign (haskell-indent-push-pos rhs-sign) (haskell-indent-push-pos-offset valname)) (haskell-indent-push-pos-offset valname))) (cl-case ; general case (haskell-indent-find-case test) ;; "1.1.11" 1= vn gd rh arh (1 (haskell-indent-push-pos valname) (haskell-indent-push-pos valname valname-string) (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) (haskell-indent-push-pos aft-rhs-sign)) ;; "1.1.10" 2= vn gd rh (2 (haskell-indent-push-pos valname) (haskell-indent-push-pos valname valname-string) (if last-line (haskell-indent-push-pos-offset guard) (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")))) ;; "1.1100" 3= vn gd agd (3 (haskell-indent-push-pos valname) (haskell-indent-push-pos aft-guard) (if last-line (haskell-indent-push-pos-offset valname))) ;; "1.1000" 4= vn gd (4 (haskell-indent-push-pos valname) (if last-line (haskell-indent-push-pos-offset guard 2))) ;; "1.0011" 5= vn rh arh (5 (haskell-indent-push-pos valname) (if (or (and aft-valname (= (char-after rhs-sign) ?\=)) (= (char-after rhs-sign) ?\:)) (haskell-indent-push-pos valname valname-string)) (haskell-indent-push-pos aft-rhs-sign)) ;; "1.0010" 6= vn rh (6 (haskell-indent-push-pos valname) (haskell-indent-push-pos valname valname-string) (if last-line (haskell-indent-push-pos-offset valname))) ;; "110000" 7= vn avn (7 (haskell-indent-push-pos valname) (if last-line (haskell-indent-push-pos aft-valname) (haskell-indent-push-pos valname valname-string))) ;; "100000" 8= vn (8 (haskell-indent-push-pos valname)) ;; "001.11" 9= gd rh arh (9 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) (haskell-indent-push-pos aft-rhs-sign)) ;; "001.10" 10= gd rh (10 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) (if last-line (haskell-indent-push-pos-offset guard))) ;; "001100" 11= gd agd (11 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) (haskell-indent-push-pos aft-guard)) ;; "001000" 12= gd (12 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos guard "| ")) (if last-line (haskell-indent-push-pos-offset guard 2))) ;; "000011" 13= rh arh (13 (haskell-indent-push-pos aft-rhs-sign)) ;; "000010" 14= rh (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2 ))) ;; "000000" 15= (t (error "haskell-indent-empty: %s impossible case" test )))) haskell-indent-info))) (defun haskell-indent-ident (start end end-visible indent-info) "Find indentation points for a line starting with an identifier." (save-excursion (let* ((haskell-indent-info indent-info) (sep (haskell-indent-separate-valdef start end)) (valname (pop sep)) (valname-string (pop sep)) (aft-valname (pop sep)) (guard (pop sep)) (aft-guard (pop sep)) (rhs-sign (pop sep)) (aft-rhs-sign (pop sep)) (last-line (= end end-visible)) (is-where (string-match "where[ \t]*" haskell-indent-current-line-first-ident)) (diff-first ; not a function def with the same name (or (null valname-string) (not (string= (haskell-string-trim valname-string) (haskell-string-trim haskell-indent-current-line-first-ident))))) ;; (is-type-def ;; (and rhs-sign (eq (char-after rhs-sign) ?\:))) (test (string (if valname ?1 ?0) (if (and aft-valname (< aft-valname end-visible)) ?1 ?0) (if (and guard (< guard end-visible)) ?1 ?0) (if (and aft-guard (< aft-guard end-visible)) ?1 ?0) (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0) (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0)))) (if (and valname-string ; special case for start keywords (string-match haskell-indent-start-keywords-re valname-string)) (progn (haskell-indent-push-pos valname) (if (string-match "\\<data\\>" valname-string) ;; very special for data keyword (if aft-rhs-sign (haskell-indent-push-pos aft-rhs-sign) (haskell-indent-push-pos-offset valname)) (if (not (string-match haskell-indent-start-keywords-re haskell-indent-current-line-first-ident)) (haskell-indent-push-pos-offset valname)))) (if (string= haskell-indent-current-line-first-ident "::") (if valname (haskell-indent-push-pos valname)) (cl-case ; general case (haskell-indent-find-case test) ;; "1.1.11" 1= vn gd rh arh (1 (if is-where (haskell-indent-push-pos guard) (haskell-indent-push-pos valname) (if diff-first (haskell-indent-push-pos aft-rhs-sign)))) ;; "1.1.10" 2= vn gd rh (2 (if is-where (haskell-indent-push-pos guard) (haskell-indent-push-pos valname) (if last-line (haskell-indent-push-pos-offset guard)))) ;; "1.1100" 3= vn gd agd (3 (if is-where (haskell-indent-push-pos-offset guard) (haskell-indent-push-pos valname) (if diff-first (haskell-indent-push-pos aft-guard)))) ;; "1.1000" 4= vn gd (4 (if is-where (haskell-indent-push-pos guard) (haskell-indent-push-pos valname) (if last-line (haskell-indent-push-pos-offset guard 2)))) ;; "1.0011" 5= vn rh arh (5 (if is-where (haskell-indent-push-pos-offset valname) (haskell-indent-push-pos valname) (if diff-first (haskell-indent-push-pos aft-rhs-sign)))) ;; "1.0010" 6= vn rh (6 (if is-where (haskell-indent-push-pos-offset valname) (haskell-indent-push-pos valname) (if last-line (haskell-indent-push-pos-offset valname)))) ;; "110000" 7= vn avn (7 (if is-where (haskell-indent-push-pos-offset valname) (haskell-indent-push-pos valname) (if last-line (haskell-indent-push-pos aft-valname)))) ;; "100000" 8= vn (8 (if is-where (haskell-indent-push-pos-offset valname) (haskell-indent-push-pos valname))) ;; "001.11" 9= gd rh arh (9 (if is-where (haskell-indent-push-pos guard) (haskell-indent-push-pos aft-rhs-sign))) ;; "001.10" 10= gd rh (10 (if is-where (haskell-indent-push-pos guard) (if last-line (haskell-indent-push-pos-offset guard)))) ;; "001100" 11= gd agd (11 (if is-where (haskell-indent-push-pos guard) (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos aft-guard)))) ;; "001000" 12= gd (12 (if last-line (haskell-indent-push-pos-offset guard 2))) ;; "000011" 13= rh arh (13 (haskell-indent-push-pos aft-rhs-sign)) ;; "000010" 14= rh (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2))) ;; "000000" 15= (t (error "haskell-indent-ident: %s impossible case" test ))))) haskell-indent-info))) (defun haskell-indent-other (start end end-visible indent-info) "Find indentation points for a non-empty line starting with something other than an identifier, a guard or rhs." (save-excursion (let* ((haskell-indent-info indent-info) (sep (haskell-indent-separate-valdef start end)) (valname (pop sep)) (valname-string (pop sep)) (aft-valname (pop sep)) (guard (pop sep)) (aft-guard (pop sep)) (rhs-sign (pop sep)) (aft-rhs-sign (pop sep)) (last-line (= end end-visible)) (test (string (if valname ?1 ?0) (if (and aft-valname (< aft-valname end-visible)) ?1 ?0) (if (and guard (< guard end-visible)) ?1 ?0) (if (and aft-guard (< aft-guard end-visible)) ?1 ?0) (if (and rhs-sign (< rhs-sign end-visible)) ?1 ?0) (if (and aft-rhs-sign (< aft-rhs-sign end-visible)) ?1 ?0)))) (if (and valname-string ; special case for start keywords (string-match haskell-indent-start-keywords-re valname-string)) (haskell-indent-push-pos-offset valname) (cl-case ; general case (haskell-indent-find-case test) ;; "1.1.11" 1= vn gd rh arh (1 (haskell-indent-push-pos aft-rhs-sign)) ;; "1.1.10" 2= vn gd rh (2 (if last-line (haskell-indent-push-pos-offset guard) (haskell-indent-push-pos-offset rhs-sign 2))) ;; "1.1100" 3= vn gd agd (3 (haskell-indent-push-pos aft-guard)) ;; "1.1000" 4= vn gd (4 (haskell-indent-push-pos-offset guard 2)) ;; "1.0011" 5= vn rh arh (5 (haskell-indent-push-pos valname) (haskell-indent-push-pos aft-rhs-sign)) ;; "1.0010" 6= vn rh (6 (if last-line (haskell-indent-push-pos-offset valname) (haskell-indent-push-pos-offset rhs-sign 2))) ;; "110000" 7= vn avn (7 (haskell-indent-push-pos-offset aft-valname)) ;; "100000" 8= vn (8 (haskell-indent-push-pos valname)) ;; "001.11" 9= gd rh arh (9 (haskell-indent-push-pos aft-rhs-sign)) ;; "001.10" 10= gd rh (10 (if last-line (haskell-indent-push-pos-offset guard) (haskell-indent-push-pos-offset rhs-sign 2))) ;; "001100" 11= gd agd (11 (if (haskell-indent-no-otherwise guard) (haskell-indent-push-pos aft-guard))) ;; "001000" 12= gd (12 (if last-line (haskell-indent-push-pos-offset guard 2))) ;; "000011" 13= rh arh (13 (haskell-indent-push-pos aft-rhs-sign)) ;; "000010" 14= rh (14 (if last-line (haskell-indent-push-pos-offset rhs-sign 2))) ;; "000000" 15= (t (error "haskell-indent-other: %s impossible case" test )))) haskell-indent-info))) (defun haskell-indent-valdef-indentation (start end end-visible curr-line-type indent-info) "Find indentation information for a value definition." (let ((haskell-indent-info indent-info)) (if (< start end-visible) (cl-case curr-line-type (empty (haskell-indent-empty start end end-visible indent-info)) (ident (haskell-indent-ident start end end-visible indent-info)) (guard (haskell-indent-guard start end end-visible indent-info)) (rhs (haskell-indent-rhs start end end-visible indent-info)) (comment (error "Comment indent should never happen")) (other (haskell-indent-other start end end-visible indent-info))) haskell-indent-info))) (defun haskell-indent-line-indentation (line-start line-end end-visible curr-line-type indent-info) "Compute indentation info between LINE-START and END-VISIBLE. Separate a line of program into valdefs between offside keywords and find indentation info for each part." (save-excursion ;; point is (already) at line-start (cl-assert (eq (point) line-start)) (let ((haskell-indent-info indent-info) (start (or (haskell-indent-in-comment line-start line-end) (haskell-indent-in-string line-start line-end)))) (if start ; if comment at the end (setq line-end start)) ; end line before it ;; loop on all parts separated by off-side-keywords (while (and (re-search-forward haskell-indent-off-side-keywords-re line-end t) (not (or (haskell-indent-in-comment line-start (point)) (haskell-indent-in-string line-start (point))))) (let ((beg-match (match-beginning 0)) ; save beginning of match (end-match (match-end 0))) ; save end of match ;; Do not try to find indentation points if off-side-keyword at ;; the start... (if (or (< line-start beg-match) ;; Actually, if we're looking at a "let" inside a "do", we ;; should add the corresponding indentation point. (eq (char-after beg-match) ?l)) (setq haskell-indent-info (haskell-indent-valdef-indentation line-start beg-match end-visible curr-line-type haskell-indent-info))) ;; ...but keep the start of the line if keyword alone on the line (if (= line-end end-match) (haskell-indent-push-pos beg-match)) (setq line-start end-match) (goto-char line-start))) (haskell-indent-valdef-indentation line-start line-end end-visible curr-line-type haskell-indent-info)))) (defun haskell-indent-layout-indent-info (start contour-line) (let ((haskell-indent-info nil) (curr-line-type (haskell-indent-type-at-point)) line-start line-end end-visible) (save-excursion (if (eq curr-line-type 'ident) (let ; guess the type of line ((sep (haskell-indent-separate-valdef (point) (line-end-position)))) ;; if the first ident is where or the start of a def ;; keep it in a global variable (setq haskell-indent-current-line-first-ident (if (string-match "where[ \t]*" (nth 1 sep)) (nth 1 sep) (if (nth 5 sep) ; is there a rhs-sign (if (= (char-after (nth 5 sep)) ?\:) ;is it a typdef "::" (nth 1 sep)) ""))))) (while contour-line ; explore the contour points (setq line-start (pop contour-line)) (goto-char line-start) (setq line-end (line-end-position)) (setq end-visible ; visible until the column of the (if contour-line ; next contour point (save-excursion (move-to-column (haskell-indent-point-to-col (car contour-line))) (point)) line-end)) (unless (or (haskell-indent-open-structure start line-start) (haskell-indent-in-comment start line-start)) (setq haskell-indent-info (haskell-indent-line-indentation line-start line-end end-visible curr-line-type haskell-indent-info))))) haskell-indent-info)) (defun haskell-indent-find-matching-start (regexp limit &optional pred start) (let ((open (haskell-indent-open-structure limit (point)))) (if open (setq limit (1+ open)))) (unless start (setq start (point))) (when (re-search-backward regexp limit t) (let ((nestedcase (match-end 1)) (outer (or (haskell-indent-in-string limit (point)) (haskell-indent-in-comment limit (point)) (haskell-indent-open-structure limit (point)) (if (and pred (funcall pred start)) (point))))) (cond (outer (goto-char outer) (haskell-indent-find-matching-start regexp limit pred start)) (nestedcase ;; Nested case. (and (haskell-indent-find-matching-start regexp limit pred) (haskell-indent-find-matching-start regexp limit pred start))) (t (point)))))) (defun haskell-indent-filter-let-no-in (start) "Return non-nil if point is in front of a `let' that has no `in'. START is the position of the presumed `in'." ;; We're looking at either `in' or `let'. (when (looking-at "let") (ignore-errors (save-excursion (forward-word 1) (forward-comment (point-max)) (if (looking-at "{") (progn (forward-sexp 1) (forward-comment (point-max)) (< (point) start)) ;; Use the layout rule to see whether this let is already closed ;; without an `in'. (let ((col (current-column))) (while (progn (forward-line 1) (haskell-indent-back-to-indentation) (< (point) start)) (when (< (current-column) col) (setq col nil) (goto-char start))) (null col))))))) (defun haskell-indent-comment (open start) "Compute indent info for comments and text inside comments. OPEN is the start position of the comment in which point is." ;; Ideally we'd want to guess whether it's commented out code or ;; whether it's text. Instead, we'll assume it's text. (save-excursion (if (= open (point)) ;; We're actually just in front of a comment: align with following ;; code or with comment on previous line. (let ((prev-line-info (cond ((eq (char-after) ?\{) nil) ;Align as if it were code. ((and (forward-comment -1) (> (line-beginning-position 3) open)) ;; We're after another comment and there's no empty line ;; between us. (list (list (haskell-indent-point-to-col (point))))) (t nil)))) ;Else align as if it were code ;; Align with following code. (forward-comment (point-max)) ;; There are several possible indentation points for this code-line, ;; but the only valid indentation point for the comment is the one ;; that the user will select for the code-line. Obviously we can't ;; know that, so we just assume that the code-line is already at its ;; proper place. ;; Strictly speaking "assume it's at its proper place" would mean ;; we'd just use (current-column), but since this is using info from ;; lines further down and it's common to reindent line-by-line, ;; we'll align not with the current indentation, but with the ;; one that auto-indentation "will" select. (append prev-line-info (let ((indent-info (save-excursion (haskell-indent-indentation-info start))) (col (current-column))) ;; Sort the indent-info so that the current indentation comes ;; out first. (setq indent-info (sort indent-info (lambda (x y) (<= (abs (- col (car x))) (abs (- col (car y))))))) indent-info))) ;; We really are inside a comment. (if (looking-at "-}") (progn (forward-char 2) (forward-comment -1) (list (list (1+ (haskell-indent-point-to-col (point)))))) (let ((offset (if (looking-at "--?") (- (match-beginning 0) (match-end 0))))) (forward-line -1) ;Go to previous line. (haskell-indent-back-to-indentation) (if (< (point) start) (goto-char start)) (list (list (if (looking-at comment-start-skip) (if offset (+ 2 offset (haskell-indent-point-to-col (point))) (haskell-indent-point-to-col (match-end 0))) (haskell-indent-point-to-col (point)))))))))) (defcustom haskell-indent-thenelse 0 "If non-nil, \"then\" and \"else\" are indented. This is necessary in the \"do\" layout under Haskell-98. See http://hackage.haskell.org/trac/haskell-prime/wiki/DoAndIfThenElse" :group 'haskell-indent :safe #'booleanp :type 'integer) (defun haskell-indent-closing-keyword (start) (let ((open (save-excursion (haskell-indent-find-matching-start (cl-case (char-after) (?i "\\<\\(?:\\(in\\)\\|let\\)\\>") (?o "\\<\\(?:\\(of\\)\\|case\\)\\>") (?t "\\<\\(?:\\(then\\)\\|if\\)\\>") (?e "\\<\\(?:\\(else\\)\\|if\\)\\>")) start (if (eq (char-after) ?i) ;; Filter out the `let's that have no `in'. 'haskell-indent-filter-let-no-in))))) ;; For a "hanging let/case/if at EOL" we should use a different ;; indentation scheme. (save-excursion (goto-char open) (if (haskell-indent-hanging-p) (setq open (haskell-indent-virtual-indentation start)))) ;; FIXME: we should try and figure out if the `if' is in a `do' layout ;; before using haskell-indent-thenelse. (list (list (+ (if (memq (char-after) '(?t ?e)) haskell-indent-thenelse 0) (haskell-indent-point-to-col open)))))) (defcustom haskell-indent-after-keywords '(("where" 2 0) ("of" 2) ("do" 2) ("mdo" 2) ("rec" 2) ("in" 2 0) ("{" 2) "if" "then" "else" "let") "Keywords after which indentation should be indented by some offset. Each keyword info can have the following forms: KEYWORD | (KEYWORD OFFSET [OFFSET-HANGING]) If absent OFFSET-HANGING defaults to OFFSET. If absent OFFSET defaults to `haskell-indent-offset'. OFFSET-HANGING is the offset to use in the case where the keyword is at the end of an otherwise-non-empty line." :group 'haskell-indent :type '(repeat (choice string (cons :tag "" (string :tag "keyword:") (cons :tag "" (integer :tag "offset") (choice (const nil) (list :tag "" (integer :tag "offset-pending")))))))) (defun haskell-indent-skip-lexeme-forward () (and (zerop (skip-syntax-forward "w")) (skip-syntax-forward "_") (skip-syntax-forward "(") (skip-syntax-forward ")"))) (defvar haskell-indent-inhibit-after-offset nil) (defun haskell-indent-offset-after-info () "Return the info from `haskell-indent-after-keywords' for keyword at point." (let ((id (buffer-substring (point) (save-excursion (haskell-indent-skip-lexeme-forward) (point))))) (or (assoc id haskell-indent-after-keywords) (car (member id haskell-indent-after-keywords))))) (defcustom haskell-indent-dont-hang '("(") "Lexemes that should never be considered as hanging." :group 'haskell-indent :type '(repeat string)) (defun haskell-indent-hanging-p () ;; A Hanging keyword is one that's at the end of a line except it's not at ;; the beginning of a line. (not (or (= (current-column) (haskell-indent-current-indentation)) (save-excursion (let ((lexeme (buffer-substring (point) (progn (haskell-indent-skip-lexeme-forward) (point))))) (or (member lexeme haskell-indent-dont-hang) (> (line-end-position) (progn (forward-comment (point-max)) (point))))))))) (defun haskell-indent-after-keyword-column (offset-info start &optional default) (unless offset-info (setq offset-info (haskell-indent-offset-after-info))) (unless default (setq default haskell-indent-offset)) (setq offset-info (if haskell-indent-inhibit-after-offset '(0) (cdr-safe offset-info))) (if (not (haskell-indent-hanging-p)) (haskell-indent-column+offset (current-column) (or (car offset-info) default)) ;; The keyword is hanging at the end of the line. (haskell-indent-column+offset (haskell-indent-virtual-indentation start) (or (cadr offset-info) (car offset-info) default)))) (defun haskell-indent-inside-paren (open) ;; there is an open structure to complete (if (looking-at "\\s)\\|[;,]") ;; A close-paren or a , or ; can only correspond syntactically to ;; the open-paren at `open'. So there is no ambiguity. (progn (if (or (and (eq (char-after) ?\;) (eq (char-after open) ?\()) (and (eq (char-after) ?\,) (eq (char-after open) ?\{))) (message "Mismatched punctuation: `%c' in %c...%c" (char-after) (char-after open) (if (eq (char-after open) ?\() ?\) ?\}))) (save-excursion (goto-char open) (list (list (if (haskell-indent-hanging-p) (haskell-indent-virtual-indentation nil) (haskell-indent-point-to-col open)))))) ;; There might still be layout within the open structure. (let* ((end (point)) (basic-indent-info ;; Anything else than a ) is subject to layout. (if (looking-at "\\s.\\|\\$ ") (haskell-indent-point-to-col open) ; align a punct with ( (let ((follow (save-excursion (goto-char (1+ open)) (haskell-indent-skip-blanks-and-newlines-forward end) (point)))) (if (= follow end) (save-excursion (goto-char open) (haskell-indent-after-keyword-column nil nil 1)) (haskell-indent-point-to-col follow))))) (open-column (haskell-indent-point-to-col open)) (contour-line (haskell-indent-contour-line (1+ open) end))) (if (null contour-line) (list (list basic-indent-info)) (let ((indent-info (haskell-indent-layout-indent-info (1+ open) contour-line))) ;; Fix up indent info. (let ((base-elem (assoc open-column indent-info))) (if base-elem (progn (setcar base-elem basic-indent-info) (setcdr base-elem nil)) (setq indent-info (append indent-info (list (list basic-indent-info))))) indent-info)))))) (defun haskell-indent-virtual-indentation (start) "Compute the \"virtual indentation\" of text at point. The \"virtual indentation\" is the indentation that text at point would have had, if it had been placed on its own line." (let ((col (current-column)) (haskell-indent-inhibit-after-offset (haskell-indent-hanging-p))) (if (save-excursion (skip-chars-backward " \t") (bolp)) ;; If the text is indeed on its own line, than the virtual indent is ;; the current indentation. col ;; Else, compute the indentation that it would have had. (let ((info (haskell-indent-indentation-info start)) (max -1)) ;; `info' is a list of possible indent points. Each indent point is ;; assumed to correspond to a different parse. So we need to find ;; the parse that corresponds to the case at hand (where there's no ;; line break), which is assumed to always be the ;; deepest indentation. (dolist (x info) (setq x (car x)) ;; Sometimes `info' includes the current indentation (or yet ;; deeper) by mistake, because haskell-indent-indentation-info ;; wasn't designed to be called on a piece of text that is not at ;; BOL. So ignore points past `col'. (if (and (> x max) (not (>= x col))) (setq max x))) ;; In case all the indent points are past `col', just use `col'. (if (>= max 0) max col))))) (defun haskell-indent-indentation-info (&optional start) "Return a list of possible indentations for the current line. These are then used by `haskell-indent-cycle'. START if non-nil is a presumed start pos of the current definition." (unless start (setq start (haskell-indent-start-of-def))) (let (open contour-line) (cond ;; in string? ((setq open (haskell-indent-in-string start (point))) (list (list (+ (haskell-indent-point-to-col open) (if (looking-at "\\\\") 0 1))))) ;; in comment ? ((setq open (haskell-indent-in-comment start (point))) (haskell-indent-comment open start)) ;; Closing the declaration part of a `let' or the test exp part of a case. ((looking-at "\\(?:in\\|of\\|then\\|else\\)\\>") (haskell-indent-closing-keyword start)) ;; Right after a special keyword. ((save-excursion (forward-comment (- (point-max))) (when (and (not (zerop (skip-syntax-backward "w"))) (setq open (haskell-indent-offset-after-info))) (list (list (haskell-indent-after-keyword-column open start)))))) ;; open structure? ie ( { [ ((setq open (haskell-indent-open-structure start (point))) (haskell-indent-inside-paren open)) ;; full indentation ((setq contour-line (haskell-indent-contour-line start (point))) (haskell-indent-layout-indent-info start contour-line)) (t ;; simple contour just one indentation at start (list (list (if (and (eq haskell-literate 'bird) (eq (haskell-indent-point-to-col start) 1)) ;; for a Bird style literate script put default offset ;; in the case of no indentation (1+ haskell-indent-literate-Bird-default-offset) (haskell-indent-point-to-col start)))))))) (defvar haskell-indent-last-info nil) (defun haskell-indent-cycle () "Indentation cycle. We stay in the cycle as long as the TAB key is pressed." (interactive "*") (if (and haskell-literate (not (haskell-indent-within-literate-code))) ;; use the ordinary tab for text... (funcall (default-value 'indent-line-function)) (let ((marker (if (> (current-column) (haskell-indent-current-indentation)) (point-marker))) (bol (progn (beginning-of-line) (point)))) (haskell-indent-back-to-indentation) (unless (and (eq last-command this-command) (eq bol (car haskell-indent-last-info))) (save-excursion (setq haskell-indent-last-info (list bol (haskell-indent-indentation-info) 0 0)))) (let* ((il (nth 1 haskell-indent-last-info)) (index (nth 2 haskell-indent-last-info)) (last-insert-length (nth 3 haskell-indent-last-info)) (indent-info (nth index il))) (haskell-indent-line-to (car indent-info)) ; insert indentation (delete-char last-insert-length) (setq last-insert-length 0) (let ((text (cdr indent-info))) (if text (progn (insert text) (setq last-insert-length (length text))))) (setq haskell-indent-last-info (list bol il (% (1+ index) (length il)) last-insert-length)) (if (= (length il) 1) (message "Sole indentation") (message "Indent cycle (%d)..." (length il))) (if marker (goto-char (marker-position marker))))))) (defun haskell-indent-region (_start _end) (error "Auto-reindentation of a region is not supported")) ;;; alignment functions (defun haskell-indent-shift-columns (dest-column region-stack) "Shift columns in REGION-STACK to go to DEST-COLUMN. Elements of the stack are pairs of points giving the start and end of the regions to move." (let (reg col diffcol reg-end) (while (setq reg (pop region-stack)) (setq reg-end (copy-marker (cdr reg))) (goto-char (car reg)) (setq col (current-column)) (setq diffcol (- dest-column col)) (if (not (zerop diffcol)) (catch 'end-of-buffer (while (<= (point) (marker-position reg-end)) (if (< diffcol 0) (backward-delete-char-untabify (- diffcol) nil) (insert-char ?\ diffcol)) (end-of-line 2) ; should be (forward-line 1) (if (eobp) ; but it adds line at the end... (throw 'end-of-buffer nil)) (move-to-column col))))))) (defun haskell-indent-align-def (p-arg type) "Align guards or rhs within the current definition before point. If P-ARG is t align all defs up to the mark. TYPE is either 'guard or 'rhs." (save-excursion (let (start-block end-block (maxcol (if (eq type 'rhs) haskell-indent-rhs-align-column 0)) contour sep defname defnamepos defcol pos lastpos regstack eqns-start start-found) ;; find the starting and ending boundary points for alignment (if p-arg (if (mark) ; aligning everything in the region (progn (when (> (mark) (point)) (exchange-point-and-mark)) (setq start-block (save-excursion (goto-char (mark)) (line-beginning-position))) (setq end-block (progn (if (haskell-indent-bolp) (haskell-indent-forward-line -1)) (line-end-position)))) (error "The mark is not set for aligning definitions")) ;; aligning the current definition (setq start-block (haskell-indent-start-of-def)) (setq end-block (line-end-position))) ;; find the start of the current valdef using the contour line ;; in reverse order because we need the nearest one from the end (setq contour (reverse (haskell-indent-contour-line start-block end-block))) (setq pos (car contour)) ; keep the start of the first contour ;; find the nearest start of a definition (while (and (not defname) contour) (goto-char (pop contour)) (if (haskell-indent-open-structure start-block (point)) nil (setq sep (haskell-indent-separate-valdef (point) end-block)) (if (nth 5 sep) ; is there a rhs? (progn (setq defnamepos (nth 0 sep)) (setq defname (nth 1 sep)))))) ;; start building the region stack (if defnamepos (progn ; there is a valdef ;; find the start of each equation or guard (if p-arg ; when indenting a region ;; accept any start of id or pattern as def name (setq defname "\\<\\|(")) (setq defcol (haskell-indent-point-to-col defnamepos)) (goto-char pos) (setq end-block (line-end-position)) (catch 'top-of-buffer (while (and (not start-found) (>= (point) start-block)) (if (<= (haskell-indent-current-indentation) defcol) (progn (move-to-column defcol) (if (and (looking-at defname) ; start of equation (not (haskell-indent-open-structure start-block (point)))) (push (cons (point) 'eqn) eqns-start) ;; found a less indented point not starting an equation (setq start-found t))) ;; more indented line (haskell-indent-back-to-indentation) (if (and (eq (haskell-indent-type-at-point) 'guard) ; start of a guard (not (haskell-indent-open-structure start-block (point)))) (push (cons (point) 'gd) eqns-start))) (if (bobp) (throw 'top-of-buffer nil) (haskell-indent-backward-to-indentation 1)))) ;; remove the spurious guards before the first equation (while (and eqns-start (eq (cdar eqns-start) 'gd)) (pop eqns-start)) ;; go through each equation to find the region to indent (while eqns-start (let ((eqn (caar eqns-start))) (setq lastpos (if (cdr eqns-start) (save-excursion (goto-char (cl-caadr eqns-start)) (haskell-indent-forward-line -1) (line-end-position)) end-block)) (setq sep (haskell-indent-separate-valdef eqn lastpos))) (if (eq type 'guard) (setq pos (nth 3 sep)) ;; check if what follows a rhs sign is more indented or not (let ((rhs (nth 5 sep)) (aft-rhs (nth 6 sep))) (if (and rhs aft-rhs (> (haskell-indent-point-to-col rhs) (haskell-indent-point-to-col aft-rhs))) (setq pos aft-rhs) (setq pos rhs)))) (if pos (progn ; update region stack (push (cons pos (or lastpos pos)) regstack) (setq maxcol ; find the highest column number (max maxcol (progn ;find the previous non-empty column (goto-char pos) (skip-chars-backward " \t" (line-beginning-position)) (if (haskell-indent-bolp) ;;if on an empty prefix (haskell-indent-point-to-col pos) ;keep original indent (1+ (haskell-indent-point-to-col (point))))))))) (pop eqns-start)) ;; now shift according to the region stack (if regstack (haskell-indent-shift-columns maxcol regstack))))))) (defun haskell-indent-align-guards-and-rhs (_start _end) "Align the guards and rhs of functions in the region, which must be active." ;; The `start' and `end' args are dummys right now: they're just there so ;; we can use the "r" interactive spec which properly signals an error. (interactive "*r") (haskell-indent-align-def t 'guard) (haskell-indent-align-def t 'rhs)) ;;; insertion functions (defun haskell-indent-insert-equal () "Insert an = sign and align the previous rhs of the current function." (interactive "*") (if (or (haskell-indent-bolp) (/= (preceding-char) ?\ )) (insert ?\ )) (insert "= ") (haskell-indent-align-def (haskell-indent-mark-active) 'rhs)) (defun haskell-indent-insert-guard (&optional text) "Insert and align a guard sign (|) followed by optional TEXT. Alignment works only if all guards are to the south-east of their |." (interactive "*") (let ((pc (if (haskell-indent-bolp) ?\012 (preceding-char))) (pc1 (or (char-after (- (point) 2)) 0))) ;; check what guard to insert depending on the previous context (if (= pc ?\ ) ; x = any char other than blank or | (if (/= pc1 ?\|) (insert "| ") ; after " x" ()) ; after " |" (if (= pc ?\|) (if (= pc1 ?\|) (insert " | ") ; after "||" (insert " ")) ; after "x|" (insert " | "))) ; general case (if text (insert text)) (haskell-indent-align-def (haskell-indent-mark-active) 'guard))) (defun haskell-indent-insert-otherwise () "Insert a guard sign (|) followed by `otherwise'. Also align the previous guards of the current function." (interactive "*") (haskell-indent-insert-guard "otherwise") (haskell-indent-insert-equal)) (defun haskell-indent-insert-where () "Insert a where keyword at point and indent resulting line. One indentation cycle is used." (interactive "*") (insert "where ") (haskell-indent-cycle)) ;;; haskell-indent-mode (defvar-local haskell-indent-mode nil "Non-nil if the semi-intelligent Haskell indentation mode is in effect.") (defvar haskell-indent-map (let ((map (make-sparse-keymap))) ;; Removed: remapping DEL seems a bit naughty --SDM ;; (define-key map "\177" 'backward-delete-char-untabify) ;; The binding to TAB is already handled by indent-line-function. --Stef ;; (define-key map "\t" 'haskell-indent-cycle) (define-key map (kbd "C-c C-=") 'haskell-indent-insert-equal) (define-key map (kbd "C-c C-|") 'haskell-indent-insert-guard) ;; Alternate binding, in case C-c C-| is too inconvenient to type. ;; Duh, C-g is a special key, let's not use it here. ;; (define-key map (kbd "C-c C-g") 'haskell-indent-insert-guard) (define-key map (kbd "C-c C-o") 'haskell-indent-insert-otherwise) (define-key map (kbd "C-c C-w") 'haskell-indent-insert-where) (define-key map (kbd "C-c C-.") 'haskell-indent-align-guards-and-rhs) (define-key map (kbd "C-c C->") 'haskell-indent-put-region-in-literate) map)) ;;;###autoload (defun turn-on-haskell-indent () "Turn on ``intelligent'' Haskell indentation mode." (when (and (bound-and-true-p haskell-indentation-mode) (fboundp 'haskell-indentation-mode)) (haskell-indentation-mode 0)) (setq-local indent-line-function 'haskell-indent-cycle) (setq-local indent-region-function 'haskell-indent-region) (setq haskell-indent-mode t) ;; Activate our keymap. (let ((map (current-local-map))) (while (and map (not (eq map haskell-indent-map))) (setq map (keymap-parent map))) ;; if haskell-indent-map is already active: there's nothing to do. (unless map ;; Put our keymap on top of the others. We could also put it in ;; second place, or in a minor-mode. The minor-mode approach would be ;; easier, but it's harder for the user to override it. This approach ;; is the closest in behavior compared to the previous code that just ;; used a bunch of local-set-key. (set-keymap-parent haskell-indent-map (current-local-map)) ;; Protect our keymap. (setq map (make-sparse-keymap)) (set-keymap-parent map haskell-indent-map) (use-local-map map))) (run-hooks 'haskell-indent-hook)) (defun turn-off-haskell-indent () "Turn off ``intelligent'' Haskell indentation mode." (kill-local-variable 'indent-line-function) (kill-local-variable 'indent-region-function) ;; Remove haskell-indent-map from the local map. (let ((map (current-local-map))) (while map (let ((parent (keymap-parent map))) (if (eq haskell-indent-map parent) (set-keymap-parent map (keymap-parent parent)) (setq map parent))))) (setq haskell-indent-mode nil)) ;; Put this minor mode on the global minor-mode-alist. (or (assq 'haskell-indent-mode (default-value 'minor-mode-alist)) (setq-default minor-mode-alist (append (default-value 'minor-mode-alist) '((haskell-indent-mode " Ind"))))) ;;;###autoload (defun haskell-indent-mode (&optional arg) "``Intelligent'' Haskell indentation mode. This deals with the layout rule of Haskell. \\[haskell-indent-cycle] starts the cycle which proposes new possibilities as long as the TAB key is pressed. Any other key or mouse click terminates the cycle and is interpreted except for RET which merely exits the cycle. Other special keys are: \\[haskell-indent-insert-equal] inserts an = \\[haskell-indent-insert-guard] inserts an | \\[haskell-indent-insert-otherwise] inserts an | otherwise = these functions also align the guards and rhs of the current definition \\[haskell-indent-insert-where] inserts a where keyword \\[haskell-indent-align-guards-and-rhs] aligns the guards and rhs of the region \\[haskell-indent-put-region-in-literate] makes the region a piece of literate code in a literate script If `ARG' is falsey, toggle `haskell-indent-mode'. Else sets `haskell-indent-mode' to whether `ARG' is greater than 0. Invokes `haskell-indent-hook' if not nil." (interactive "P") (setq haskell-indent-mode (if (null arg) (not haskell-indent-mode) (> (prefix-numeric-value arg) 0))) (if haskell-indent-mode (turn-on-haskell-indent) (turn-off-haskell-indent))) (provide 'haskell-indent) ;;; haskell-indent.el ends here ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-indentation.el������������������������������������������������������������0000664�0000000�0000000�00000142661�13602233217�0020277�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-indentation.el --- indentation module for Haskell Mode -*- lexical-binding: t -*- ;; Copyright (C) 2013 Kristof Bastiaensen, Gergely Risko ;; Author: Kristof Bastiaensen <kristof.bastiaensen@vleeuwen.org> ;; Author: Gergely Risko <errge@nilcons.com> ;; Keywords: indentation haskell ;; URL: https://github.com/haskell/haskell-mode ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; Installation: ;; ;; To turn indentation on for all Haskell buffers under Haskell mode add ;; this to your configuration file: ;; ;; (add-hook haskell-mode-hook 'haskell-indentation-mode) ;; ;; Otherwise, call `haskell-indentation-mode'. ;;; Code: ;; TODO eliminate magic number 2 where possible, use a variable ;; TODO `haskell-indentation-find-indentation' — fix it, get rid of "safe" ;; version (require 'cl-lib) (require 'haskell-lexeme) ;;;###autoload (defgroup haskell-indentation nil "Haskell indentation." :link '(custom-manual "(haskell-mode)Indentation") :group 'haskell :prefix "haskell-indentation-") (defcustom haskell-indentation-layout-offset 2 "Extra indentation to add before expressions in a Haskell layout list." :type 'integer :group 'haskell-indentation) (defcustom haskell-indentation-starter-offset 2 "Extra indentation after an opening keyword (e.g. \"let\")." :type 'integer :group 'haskell-indentation) (defcustom haskell-indentation-left-offset 2 "Extra indentation after an indentation to the left (e.g. after \"do\")." :type 'integer :group 'haskell-indentation) (defcustom haskell-indentation-where-pre-offset 2 "Extra indentation before the keyword \"where\"." :type 'integer :group 'haskell-indentation) (defcustom haskell-indentation-where-post-offset 2 "Extra indentation after the keyword \"where\"." :type 'integer :group 'haskell-indentation) (defcustom haskell-indentation-electric-flag nil "Non-nil means insertion of some characters may auto reindent the line. If the variable `electric-indent-mode' is non-nil then this variable is overridden." :type 'symbol :group 'haskell-indentation) (make-variable-buffer-local 'haskell-indentation-electric-flag) (defvar haskell-indentation-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "RET") #'haskell-indentation-newline-and-indent) (define-key map (kbd "<backtab>") #'haskell-indentation-indent-backwards) (define-key map (kbd ",") #'haskell-indentation-common-electric-command) (define-key map (kbd ";") #'haskell-indentation-common-electric-command) (define-key map (kbd ")") #'haskell-indentation-common-electric-command) (define-key map (kbd "}") #'haskell-indentation-common-electric-command) (define-key map (kbd "]") #'haskell-indentation-common-electric-command) map) "Keymap for `haskell-indentation-mode'.") ;;;###autoload (define-minor-mode haskell-indentation-mode "Haskell indentation mode that deals with the layout rule. It rebinds RET, DEL and BACKSPACE, so that indentations can be set and deleted as if they were real tabs." :keymap haskell-indentation-mode-map (kill-local-variable 'indent-line-function) (kill-local-variable 'indent-region-function) (when haskell-indentation-mode (when (and (bound-and-true-p haskell-indent-mode) (fboundp 'turn-off-haskell-indent)) (turn-off-haskell-indent)) (setq-local indent-line-function #'haskell-indentation-indent-line) (setq-local indent-region-function #'haskell-indentation-indent-region))) ;;;###autoload (defun turn-on-haskell-indentation () "Turn on the haskell-indentation minor mode." (interactive) (haskell-indentation-mode t)) (make-obsolete 'turn-on-haskell-indentation 'haskell-indentation-mode "2015-05-25") (defvar haskell-literate) ; defined in haskell-mode.el (defun haskell-indentation-bird-p () "Return t if this is a literate Haskell buffer in bird style, NIL otherwise." (eq haskell-literate 'bird)) ;;---------------------------------------------------------------------------- ;; UI starts here (defun haskell-indentation-reindent-to (col &optional move) "Reindent current line to COL, move the point there if MOVE is non-NIL." (let* ((ci (haskell-indentation-current-indentation))) (save-excursion (move-to-column ci) (if (<= ci col) (insert-before-markers (make-string (- col ci) ? )) (delete-char (- col ci)))) (when move (move-to-column col)))) (defun haskell-indentation-indent-rigidly (start end arg) "Indent all lines starting in the region sideways by ARG columns. Called from a program, takes three arguments, START, END and ARG. You can remove all indentation from a region by giving a large negative ARG. Handles bird style literate Haskell too." (interactive "*r\np") (save-excursion (goto-char end) (let ((end-marker (point-marker))) (goto-char start) (or (bolp) (forward-line 0)) (while (< (point) end-marker) (let ((ci (haskell-indentation-current-indentation))) (when (and t (eq (char-after) ?>)) (forward-char 1)) (skip-syntax-forward "-") (unless (eolp) (haskell-indentation-reindent-to (max 0 (+ ci arg)))) (forward-line 1))) (move-marker end-marker nil)))) (defun haskell-indentation-current-indentation () "Column position of first non-whitespace character in current line." (save-excursion (beginning-of-line) (when (haskell-indentation-bird-p) (forward-char)) (skip-syntax-forward "-") (current-column))) (defun haskell-indentation-bird-outside-code-p () "Non-NIL if we are in bird literate mode, but outside of code." (and (haskell-indentation-bird-p) (or (< (current-column) 2) (save-excursion (beginning-of-line) (not (eq (char-after) ?>)))))) (defun haskell-indentation-newline-and-indent () "Insert newline and indent." (interactive "*") ;; On RET (or C-j), we: ;; - just jump to the next line if literate haskell, but outside code (if (haskell-indentation-bird-outside-code-p) (progn (delete-horizontal-space) (newline)) ;; - save the current column (let ((ci (haskell-indentation-current-indentation))) ;; - jump to the next line and reindent to at the least same level (delete-horizontal-space) (newline) ;; calculate indentation after newline is inserted because if we ;; break an identifier we might create a keyword, for example ;; "dowhere" => "do where" (let ((indentations (or (haskell-indentation-find-indentations) '(0)))) (when (haskell-indentation-bird-p) (insert "> ")) (haskell-indentation-reindent-to (haskell-indentation-next-indentation (- ci 1) indentations 'nofail) 'move))))) (defun haskell-indentation-next-indentation (col indentations &optional nofail) "Find the leftmost indentation which is greater than COL. Indentations are taken from INDENTATIONS, which should be a list. Return the last indentation if there are no bigger ones and NOFAIL is non-NIL." (when (null indentations) (error "haskell-indentation-next-indentation called with empty list")) (or (cl-find-if (lambda (i) (> i col)) indentations) (when nofail (car (last indentations))))) (defun haskell-indentation-previous-indentation (col indentations &optional nofail) "Find the rightmost indentation less than COL from INDENTATIONS. When no indentations are less than COL, return the rightmost indentation if NOFAIL is non-nil, or nil otherwise." (when (null indentations) (error "haskell-indentation-previous-indentation called with empty list")) (let ((rev (reverse indentations))) (or (cl-find-if (lambda (i) (< i col)) rev) (when nofail (car rev))))) (defvar haskell-indentation-dyn-last-direction nil "") ; FIXME (defvar haskell-indentation-dyn-last-indentations nil "") ; FIXME (defun haskell-indentation-indent-line () "Indent current line, cycle though indentation positions. Do nothing inside multiline comments and multiline strings. Start enumerating the indentation points to the right. The user can continue by repeatedly pressing TAB. When there is no more indentation points to the right, we switch going to the left." (interactive "*") ;; try to repeat (when (not (haskell-indentation-indent-line-repeat)) (setq haskell-indentation-dyn-last-direction nil) ;; parse error is intentionally not cought here, it may come from ;; `haskell-indentation-find-indentations', but escapes the scope ;; and aborts the opertaion before any moving happens (let* ((cc (current-column)) (ci (haskell-indentation-current-indentation)) (inds (save-excursion (move-to-column ci) (or (haskell-indentation-find-indentations) '(0)))) (valid (memq ci inds)) (cursor-in-whitespace (< cc ci))) (if (and valid cursor-in-whitespace) (move-to-column ci) (haskell-indentation-reindent-to (haskell-indentation-next-indentation ci inds 'nofail) cursor-in-whitespace)) (setq haskell-indentation-dyn-last-direction 'right haskell-indentation-dyn-last-indentations inds)))) (defun haskell-indentation-indent-line-repeat () "Cycle though indentation positions." (cond ((and (memq last-command '(indent-for-tab-command haskell-indentation-indent-backwards)) (eq haskell-indentation-dyn-last-direction 'region)) (let ((mark-even-if-inactive t)) (haskell-indentation-indent-rigidly (region-beginning) (region-end) 1)) t) ((and (eq last-command 'indent-for-tab-command) (memq haskell-indentation-dyn-last-direction '(left right)) haskell-indentation-dyn-last-indentations) (let ((ci (haskell-indentation-current-indentation))) (if (eq haskell-indentation-dyn-last-direction 'left) (haskell-indentation-reindent-to (haskell-indentation-previous-indentation ci haskell-indentation-dyn-last-indentations 'nofail)) ;; right (if (haskell-indentation-next-indentation ci haskell-indentation-dyn-last-indentations) (haskell-indentation-reindent-to (haskell-indentation-next-indentation ci haskell-indentation-dyn-last-indentations 'nofail)) ;; but failed, switch to left (setq haskell-indentation-dyn-last-direction 'left) (haskell-indentation-indent-line-repeat))) t)) (t nil))) (defun haskell-indentation-indent-region (_start _end) "This function does nothing. It is better to do nothing to indent region in Haskell than to break the semantics of indentation. This function is used for `indent-region-function' because the default is to call `indent-line-function' on every line from START to END and that also produces catastrophic results. Someday we will have indent region that preserves semantics and fixes up only indentation." nil) (defun haskell-indentation-indent-backwards () "Indent the current line to the previous indentation point." (interactive "*") (cond ((and (memq last-command '(indent-for-tab-command haskell-indentation-indent-backwards)) (eq haskell-indentation-dyn-last-direction 'region)) (let ((mark-even-if-inactive t)) (haskell-indentation-indent-rigidly (region-beginning) (region-end) -1))) ((use-region-p) (setq haskell-indentation-dyn-last-direction 'region) (haskell-indentation-indent-rigidly (region-beginning) (region-end) -1) (message "Press TAB or S-TAB again to indent the region more")) (t (setq haskell-indentation-dyn-last-direction nil) (let* ((cc (current-column)) (ci (haskell-indentation-current-indentation)) (inds (save-excursion (move-to-column ci) (or (haskell-indentation-find-indentations) '(0)))) (cursor-in-whitespace (< cc ci)) (pi (haskell-indentation-previous-indentation ci inds))) (if (null pi) ;; if there are no more indentations to the left, just go to column 0 (haskell-indentation-reindent-to (car (haskell-indentation-first-indentation)) cursor-in-whitespace) (haskell-indentation-reindent-to pi cursor-in-whitespace)))))) (defun haskell-indentation-common-electric-command (arg) "Call `self-insert-command' to insert the character typed ARG times and indent when all of the following are true: 1) The character is the first non-whitespace character on the line. 2) There is only one possible indentation position. 3) The variable `electric-indent-mode' or `haskell-indentation-electric-flag' is non-nil. 4) The point is not in a comment, string, or quasiquote." (interactive "*p") (let ((col (current-column)) ind) (self-insert-command arg) (when (and (or haskell-indentation-electric-flag electric-indent-mode) (= (haskell-indentation-current-indentation) col) (> arg 0) (not (nth 8 (syntax-ppss))) (= 1 (save-excursion (move-to-column col) (length (setq ind (haskell-indentation-find-indentations)))))) (haskell-indentation-reindent-to (car ind))))) ;;---------------------------------------------------------------------------- ;; Parser Starts Here ;; The parser is implemented as a recursive descent parser. Each parser ;; advances the point to after the expression it parses, and sets the ;; dynamic scoped variables containing the information about the ;; indentations. The dynamic scoping allows transparent backtracking to ;; previous states of these variables. A new state can be set using `let'. ;; When the scope of this function ends, the variable is automatically ;; reverted to its old value. ;; This is basically a performance hack. It would have been possible to ;; thread this state using a association-list through the parsers, but it ;; would be probably more complicated and slower due to the lack of real ;; closures in Emacs Lisp. ;; ;; When finished parsing, the tokenizer returns 'end-token, and ;; following-token is set to the token after point. The parser adds its ;; indentations to possible-indentations and returns to it's parent, or ;; exits non-locally by throwing parse-end, so that the parent will not add ;; new indentations to it. ;; the parse state: (defvar following-token) ;; the next token after parsing finished ;; the token at the current parser point or a pseudo-token (see ;; `haskell-indentation-read-next-token') (defvar current-token) (defvar previous-token) (defvar left-indent) ;; most left possible indentation (defvar starter-indent) ;; column at a keyword (defvar current-indent) ;; the most right indentation (defvar layout-indent) ;; the column of the layout list (defvar possible-indentations) ;; the return value of the indentations (defvar indentation-point) ;; where to stop parsing (defvar implicit-layout-active) ;; is "off-side" rule active? (defun haskell-indentation-goto-least-indentation () "" ; FIXME (beginning-of-line) (if (haskell-indentation-bird-p) (catch 'return (while t (when (not (eq (char-after) ?>)) (forward-line) (forward-char 2) (throw 'return nil)) (let ((ps (nth 8 (syntax-ppss)))) (when ps ;; inside comment or string (goto-char ps) (beginning-of-line))) (when (and (>= 2 (haskell-indentation-current-indentation)) (not (looking-at ">\\s-*$"))) (forward-char 2) (throw 'return nil)) (when (bobp) (forward-char 2) (throw 'return nil)) (forward-line -1))) ;; not bird style (catch 'return (while (not (bobp)) (let ((point (point))) ;; (forward-comment -1) gets lost if there are unterminated ;; string constants and does not move point anywhere. We fix ;; that case with (forward-line -1) (forward-comment (- (buffer-size))) (if (equal (point) point) (forward-line -1) (beginning-of-line))) (let* ((ps (syntax-ppss)) (start-of-comment-or-string (nth 8 ps)) (start-of-list-expression (nth 1 ps))) (cond (start-of-comment-or-string ;; inside comment or string (goto-char start-of-comment-or-string)) (start-of-list-expression ;; inside a parenthesized expression (goto-char start-of-list-expression)) ((= 0 (haskell-indentation-current-indentation)) (throw 'return nil)))))) (beginning-of-line) (when (bobp) (forward-comment (buffer-size))))) (defun haskell-indentation-parse-to-indentations () "" ; FIXME (save-excursion (skip-syntax-forward "-") (let ((indentation-point (point)) (layout-indent 0) (current-indent haskell-indentation-layout-offset) (starter-indent haskell-indentation-layout-offset) (left-indent haskell-indentation-layout-offset) (case-fold-search nil) current-token previous-token following-token possible-indentations implicit-layout-active) (haskell-indentation-goto-least-indentation) (if (<= indentation-point (point)) (haskell-indentation-first-indentation) (setq current-token (haskell-indentation-peek-token)) (catch 'parse-end (haskell-indentation-toplevel)) possible-indentations)))) (defun haskell-indentation-first-indentation () "Return column of first indentation." (list (if (haskell-indentation-bird-p) 2 0))) (defun haskell-indentation-find-indentations () "Return list of indentation positions corresponding to actual cursor position." (let ((ppss (syntax-ppss))) (cond ((nth 3 ppss) (if (save-excursion (and (forward-line -1) (< (nth 8 ppss) (point)))) ;; if this string goes over more than one line we want to ;; sync with the last line, not the first one (list (save-excursion (forward-line -1) (current-indentation))) (append (haskell-indentation-first-indentation) (list (save-excursion (goto-char (nth 8 ppss)) (current-column)))))) ((nth 4 ppss) (if (save-excursion (and (skip-syntax-forward "-") (eolp) (not (> (forward-line 1) 0)) (not (nth 4 (syntax-ppss))))) (haskell-indentation-parse-to-indentations) (haskell-indentation-first-indentation))) (t (haskell-indentation-parse-to-indentations))))) (defconst haskell-indentation-unicode-tokens '(("→" . "->") ;; #x2192 RIGHTWARDS ARROW ("∷" . "::") ;; #x2237 PROPORTION ("←" . "<-") ;; #x2190 LEFTWARDS ARROW ("⇒" . "=>") ;; #x21D2 RIGHTWARDS DOUBLE ARROW ("∀" . "forall") ;; #x2200 FOR ALL ("⤙" . "-<") ;; #x2919 LEFTWARDS ARROW-TAIL ("⤚" . ">-") ;; #x291A RIGHTWARDS ARROW-TAIL ("⤛" . "-<<") ;; #x291B LEFTWARDS DOUBLE ARROW-TAIL ("⤜" . ">>-") ;; #x291C RIGHTWARDS DOUBLE ARROW-TAIL ("★" . "*")) ;; #x2605 BLACK STAR "Translation from UnicodeSyntax tokens to their ASCII representation.") (defconst haskell-indentation-toplevel-list `(("module" . haskell-indentation-module) ("signature" . haskell-indentation-module) ("data" . haskell-indentation-data) ("type" . haskell-indentation-data) ("newtype" . haskell-indentation-data) ("import" . haskell-indentation-import) ("foreign" . haskell-indentation-foreign) ("where" . haskell-indentation-toplevel-where) ("class" . haskell-indentation-class-declaration) ("instance" . haskell-indentation-class-declaration) ("deriving" . haskell-indentation-deriving)) "Alist of toplevel keywords with associated parsers.") (defconst haskell-indentation-type-list `(("::" . ,(apply-partially 'haskell-indentation-with-starter (apply-partially 'haskell-indentation-separated 'haskell-indentation-type '("->" "=>")))) ("(" . ,(apply-partially 'haskell-indentation-list 'haskell-indentation-type ")" ",")) ("[" . ,(apply-partially 'haskell-indentation-list 'haskell-indentation-type "]" ",")) ("{" . ,(apply-partially 'haskell-indentation-list 'haskell-indentation-type "}" ","))) "Alist of tokens in type declarations with associated parsers.") (defconst haskell-indentation-expression-list `(("data" . haskell-indentation-data) ("type" . haskell-indentation-data) ("newtype" . haskell-indentation-data) ("if" . haskell-indentation-if) ("let" . ,(apply-partially 'haskell-indentation-phrase '(haskell-indentation-declaration-layout "in" haskell-indentation-expression))) ("do" . ,(apply-partially 'haskell-indentation-with-starter 'haskell-indentation-expression-layout)) ("mdo" . ,(apply-partially 'haskell-indentation-with-starter 'haskell-indentation-expression-layout)) ("rec" . ,(apply-partially 'haskell-indentation-with-starter 'haskell-indentation-expression-layout)) ("case" . ,(apply-partially 'haskell-indentation-phrase '(haskell-indentation-expression "of" haskell-indentation-case-layout))) ("\\" . ,(apply-partially 'haskell-indentation-with-starter 'haskell-indentation-lambda-maybe-lambdacase)) ("proc" . ,(apply-partially 'haskell-indentation-phrase '(haskell-indentation-expression "->" haskell-indentation-expression))) ("where" . ,(apply-partially 'haskell-indentation-with-starter 'haskell-indentation-declaration-layout nil t)) ("::" . haskell-indentation-scoped-type) ("=" . ,(apply-partially 'haskell-indentation-statement-right 'haskell-indentation-expression)) ("<-" . ,(apply-partially 'haskell-indentation-statement-right 'haskell-indentation-expression)) ("(" . ,(apply-partially 'haskell-indentation-list 'haskell-indentation-expression ")" '(list "," "->"))) ("[" . ,(apply-partially 'haskell-indentation-list 'haskell-indentation-expression "]" "," "|")) ("{" . ,(apply-partially 'haskell-indentation-list 'haskell-indentation-expression "}" ","))) "Alist of keywords in expressions with associated parsers.") (defun haskell-indentation-expression-layout () "Parse layout list with expressions, such as after \"do\"." (haskell-indentation-layout #'haskell-indentation-expression)) (defun haskell-indentation-declaration-layout () "Parse layout list with declarations, such as after \"where\"." (haskell-indentation-layout #'haskell-indentation-declaration)) (defun haskell-indentation-case-layout () "Parse layout list with case expressions." (haskell-indentation-layout #'haskell-indentation-case)) (defun haskell-indentation-lambda-maybe-lambdacase () "Parse lambda or lambda-case expression. After a lambda (backslash) there are two possible cases: - the new lambdacase expression, that can be recognized by the next token being \"case\"; - or simply an anonymous function definition in the form of \"expression -> expression\"." (if (string= current-token "case") (haskell-indentation-with-starter #'haskell-indentation-case-layout) (haskell-indentation-phrase-rest '(haskell-indentation-expression "->" haskell-indentation-expression)))) (defun haskell-indentation-fundep () "Parse functional dependency." (haskell-indentation-with-starter (apply-partially #'haskell-indentation-separated #'haskell-indentation-fundep1 ","))) (defun haskell-indentation-fundep1 () "Parse an item in functional dependency declaration." (let ((current-indent (current-column))) (while (member current-token '(value "->")) (haskell-indentation-read-next-token)) (when (and (eq current-token 'end-tokens) (member following-token '(value "->"))) (haskell-indentation-add-indentation current-indent)))) (defun haskell-indentation-toplevel () "Parse toplevel statements." (haskell-indentation-layout (lambda () (let ((parser (assoc current-token haskell-indentation-toplevel-list))) (if parser (funcall (cdr parser)) (haskell-indentation-declaration)))))) (defun haskell-indentation-type () "Parse type declaration." (let ((current-indent (current-column))) (catch 'return (while t (cond ((member current-token '(value operator "->" "=>")) (haskell-indentation-read-next-token)) ((eq current-token 'end-tokens) (when (member following-token '(value operator no-following-token "(" "[" "{" "::")) (if (equal following-token "=>") (haskell-indentation-add-indentation starter-indent) (haskell-indentation-add-indentation current-indent)) (haskell-indentation-add-indentation left-indent)) (throw 'return nil)) (t (let ((parser (assoc current-token haskell-indentation-type-list))) (if (not parser) (throw 'return nil) (funcall (cdr parser)))))))))) (defun haskell-indentation-type-1 () "Parse a single type declaration." (let ((current-indent (current-column))) (catch 'return (cond ((member current-token '(value operator "->" "=>")) (haskell-indentation-read-next-token)) ((eq current-token 'end-tokens) (when (member following-token '(value operator no-following-token "->" "=>" "(" "[" "{" "::")) (haskell-indentation-add-indentation current-indent)) (throw 'return nil)) (t (let ((parser (assoc current-token haskell-indentation-type-list))) (if (not parser) (throw 'return nil) (funcall (cdr parser))))))))) (defun haskell-indentation-scoped-type () "Parse scoped type declaration. For example let x :: Int = 12 do x :: Int <- return 12" (haskell-indentation-with-starter (apply-partially #'haskell-indentation-separated #'haskell-indentation-type '("->" "=>"))) (when (member current-token '("<-" "=")) (haskell-indentation-statement-right #'haskell-indentation-expression))) (defun haskell-indentation-data () "Parse data or type declaration." (haskell-indentation-read-next-token) (when (string= current-token "instance") (haskell-indentation-read-next-token)) (haskell-indentation-type) (cond ((eq current-token 'end-tokens) (when (member following-token '("=" "where")) (haskell-indentation-add-indentation current-indent) (throw 'parse-end nil))) ((string= current-token "=") (let ((starter-indent-inside (current-column))) (haskell-indentation-with-starter (lambda () (haskell-indentation-separated #'haskell-indentation-expression "|"))) (cond ((equal current-token 'end-tokens) (when (string= following-token "deriving") (haskell-indentation-push-indentation starter-indent-inside) (haskell-indentation-add-left-indent))) ((equal current-token "deriving") (haskell-indentation-with-starter #'haskell-indentation-type-1))))) ((string= current-token "where") (haskell-indentation-with-starter #'haskell-indentation-expression-layout nil) (cond ((equal current-token 'end-tokens) (when (string= following-token "deriving") (haskell-indentation-add-left-indent))) ((equal current-token "deriving") (haskell-indentation-with-starter #'haskell-indentation-type-1)))))) (defun haskell-indentation-import () "Parse import declaration." (haskell-indentation-with-starter #'haskell-indentation-expression)) (defun haskell-indentation-foreign () "Parse foreign import declaration." (haskell-indentation-with-starter (apply-partially #'haskell-indentation-expression '(value operator "import")))) (defun haskell-indentation-class-declaration () "Parse class declaration." (haskell-indentation-with-starter (lambda () (haskell-indentation-type) (when (string= current-token "|") (haskell-indentation-fundep)) (when (string= current-token "where") (haskell-indentation-with-starter #'haskell-indentation-declaration-layout nil))))) (defun haskell-indentation-deriving () "Parse standalone declaration." (haskell-indentation-with-starter (lambda () (when (string= "instance" current-token) (haskell-indentation-read-next-token)) (when (equal current-token 'end-tokens) (haskell-indentation-add-left-indent) (throw 'parse-end nil)) (haskell-indentation-type) (when (string= current-token "|") (haskell-indentation-fundep))))) (defun haskell-indentation-module () "Parse module declaration." (haskell-indentation-with-starter (lambda () (haskell-indentation-read-next-token) (when (equal current-token 'layout-item) (haskell-indentation-read-next-token)) (when (string= current-token "(") (haskell-indentation-list #'haskell-indentation-module-export ")" ",")) (if (string= current-token "where") (haskell-indentation-read-next-token) (when (eq current-token 'end-tokens) (when (member following-token '(value no-following-token "(")) (haskell-indentation-add-indentation (+ starter-indent haskell-indentation-starter-offset)) (haskell-indentation-add-indentation (+ left-indent haskell-indentation-starter-offset)) (throw 'parse-end nil)) (haskell-indentation-add-layout-indent) (throw 'parse-end nil)))))) (defun haskell-indentation-toplevel-where () "Parse 'where' that we may hit as a standalone in module declaration." (haskell-indentation-read-next-token) (when (eq current-token 'end-tokens) (haskell-indentation-add-layout-indent) (throw 'parse-end nil))) (defun haskell-indentation-module-export () "Parse export list." (cond ((string= current-token "module") (let ((current-indent (current-column))) (haskell-indentation-read-next-token) (cond ((eq current-token 'end-tokens) (haskell-indentation-add-indentation current-indent)) ((eq current-token 'value) (haskell-indentation-read-next-token))))) (t (haskell-indentation-type)))) (defun haskell-indentation-list (parser end sep &optional stmt-sep) "Parse a list, pair or other expression containing multiple items parsed by PARSER, separated by SEP or STMT-SEP, and ending with END." ;; note that we use macro expansion here to preserver Emacs 23 ;; compatibility and its lack of lexical binding (haskell-indentation-with-starter `(lambda () (let ((implicit-layout-active nil)) (haskell-indentation-separated #',parser ,sep ,stmt-sep))) end)) (defun haskell-indentation-with-starter (parser &optional end where-expr?) "Parse an expression starting with a keyword or parenthesis. Skip the keyword or parenthesis." ; FIXME: better description needed (let ((starter-column (current-column)) (current-indent current-indent) (left-indent (if (= (current-column) (haskell-indentation-current-indentation)) (current-column) left-indent))) (haskell-indentation-read-next-token) (when (eq current-token 'end-tokens) (cond ((equal following-token end) ;; indent before keyword or parenthesis (haskell-indentation-add-indentation starter-column)) (where-expr? ;; left indent + where post indent (haskell-indentation-add-where-post-indent left-indent)) (t (haskell-indentation-add-left-indent))) (throw 'parse-end nil)) (let* ((current-indent (current-column)) (starter-indent (min starter-column current-indent)) (left-indent (if end (+ starter-indent haskell-indentation-starter-offset) left-indent))) (funcall parser) (cond ((eq current-token 'end-tokens) (when (equal following-token end) ;; indent before keyword or parenthesis (haskell-indentation-add-indentation starter-indent)) ;; add no more indentations if we expect a closing keyword (when end (throw 'parse-end nil))) ((equal current-token end) (haskell-indentation-read-next-token)))))) (defun haskell-indentation-case-alternative () "" ; FIXME (setq left-indent (current-column)) (haskell-indentation-separated #'haskell-indentation-expression "," nil) (cond ((eq current-token 'end-tokens) (haskell-indentation-add-indentation current-indent)) ((string= current-token "->") (haskell-indentation-statement-right #'haskell-indentation-expression)) ;; otherwise fallthrough )) (defun haskell-indentation-case () "" ; FIXME (haskell-indentation-expression) (cond ((eq current-token 'end-tokens) (haskell-indentation-add-indentation current-indent)) ((string= current-token "|") (haskell-indentation-with-starter (apply-partially #'haskell-indentation-separated #'haskell-indentation-case-alternative "|" nil) nil)) ((string= current-token "->") (haskell-indentation-statement-right #'haskell-indentation-expression)) ;; otherwise fallthrough )) (defun haskell-indentation-statement-right (parser) "Process right side of a statement. Set `current-indent' to the current column and calls the given parser. If parsing ends here, set indentation to left-indent." (haskell-indentation-read-next-token) (when (eq current-token 'end-tokens) (haskell-indentation-add-left-indent) (haskell-indentation-add-indentation current-indent) (throw 'parse-end nil)) (funcall parser) (when (equal current-token "where") (haskell-indentation-with-starter #'haskell-indentation-expression-layout nil))) (defun haskell-indentation-guard () "Parse \"guard\" statement." (setq left-indent (current-column)) (haskell-indentation-separated #'haskell-indentation-expression "," nil)) (defun haskell-indentation-declaration () "Parse function or type declaration." (haskell-indentation-separated #'haskell-indentation-expression "," nil) (when (string= current-token "|") (haskell-indentation-with-starter (apply-partially #'haskell-indentation-separated #'haskell-indentation-guard "|" nil) nil)) (when (eq current-token 'end-tokens) (when (member following-token '("|" "=" "::" ",")) (haskell-indentation-add-indentation current-indent) (throw 'parse-end nil)))) (defun haskell-indentation-layout (parser) "Parse layout list, where each layout item is parsed by parser." (if (string= current-token "{") (haskell-indentation-list parser "}" ";") ; explicit layout (haskell-indentation-implicit-layout-list parser))) (defun haskell-indentation-expression-token-p (token) "Return non-NIL value if TOKEN is an expression token." (member token '("if" "let" "do" "case" "\\" "(" "{" "[" "::" value operator no-following-token))) (defun haskell-indentation-expression (&optional accepted-tokens) "Parse an expression until an unknown token is encountered." (catch 'return (let ((current-indent (current-column))) (unless accepted-tokens (setq accepted-tokens '(value operator))) (while t (cond ((memq current-token accepted-tokens) (haskell-indentation-read-next-token)) ((eq current-token 'end-tokens) (cond ((string= following-token "where") (haskell-indentation-add-where-pre-indent)) ; before a where ((haskell-indentation-expression-token-p following-token) ;; a normal expression can be either continued or have ;; left indent (haskell-indentation-add-indentation current-indent) (haskell-indentation-add-indentation left-indent))) (throw 'return nil)) (t (let ((parser (assoc current-token haskell-indentation-expression-list))) (when (null parser) (throw 'return nil)) ; not expression token, so exit (funcall (cdr parser)) ; run parser ;; after an 'open' expression such as 'if', exit (unless (member (car parser) '("(" "[" "{" "case")) (throw 'return nil))))))))) (defun haskell-indentation-separated (parser separator &optional stmt-separator) "Evaluate PARSER separated by SEPARATOR and STMT-SEPARATOR. If STMT-SEPARATOR is not NIL, it will be used to set a new starter-indent. For example: [ i | i <- [1..10] ," (catch 'return (unless (listp separator) (setq separator (list separator))) (unless (listp stmt-separator) (setq stmt-separator (list stmt-separator))) (while t (funcall parser) (cond ((member current-token separator) (haskell-indentation-at-separator)) ((member current-token stmt-separator) (setq starter-indent (current-column)) (haskell-indentation-at-separator)) ((eq current-token 'end-tokens) (when (or (member following-token separator) (member following-token stmt-separator)) ;; Set an indentation before a separator, for example: ;; [ 1 or [ 1 | a ;; , 2 , 20 (haskell-indentation-add-indentation starter-indent) (when (< left-indent starter-indent) (haskell-indentation-add-indentation left-indent)) (throw 'parse-end nil)) (when (equal following-token 'no-following-token) ;; Set an indentation before a separator, for example: ;; [ 1 or [ 1 | a ;; , 2 , 20 (haskell-indentation-add-indentation starter-indent) (haskell-indentation-add-indentation left-indent)) (throw 'return nil)) (t (throw 'return nil)))))) (defun haskell-indentation-at-separator () "At a separator. If at a new line, set starter-indent at the separator and current-indent after the separator, for example: l = [ 1 , 2 , -- start now here." (let ((separator-column (and (= (current-column) (haskell-indentation-current-indentation)) (current-column)))) (haskell-indentation-read-next-token) (cond ((eq current-token 'end-tokens) (haskell-indentation-add-indentation current-indent) (haskell-indentation-add-indentation left-indent) (throw 'return nil)) (separator-column ; on the beginning of the line (setq current-indent (current-column)) (setq starter-indent separator-column) (setq left-indent (+ starter-indent haskell-indentation-starter-offset)))))) (defun haskell-indentation-implicit-layout-list (parser) "An implicit layout list, elements are parsed with PARSER. This sets the `layout-indent' variable to the column where the layout starts." (let* ((layout-indent (current-column)) (current-indent (current-column)) (left-indent (current-column)) (implicit-layout-active t)) (catch 'return (while t (let ((left-indent left-indent)) (funcall parser)) (cond ((member current-token '(layout-item ";")) (haskell-indentation-read-next-token)) ((eq current-token 'end-tokens) (when (or (and (not (member following-token '("{" operator))) (not (member previous-token '(operator))) (haskell-indentation-expression-token-p following-token)) (string= following-token ";") (and (equal layout-indent 0) (member following-token (mapcar #'car haskell-indentation-toplevel-list)) (not (string= following-token "where")))) (haskell-indentation-add-layout-indent)) (throw 'return nil)) (t (throw 'return nil)))))) ;; put `haskell-indentation-read-next-token' outside the current-indent ;; definition so it will not return 'layout-end again (when (eq current-token 'layout-end) (let ((implicit-layout-active t)) ;; leave layout at 'layout-end or illegal token (haskell-indentation-read-next-token)))) (defun haskell-indentation-if () "" ; FIXME (haskell-indentation-with-starter (lambda () (if (string= current-token "|") (haskell-indentation-with-starter (lambda () (haskell-indentation-separated #'haskell-indentation-case-alternative "|" nil)) nil) (haskell-indentation-phrase-rest '(haskell-indentation-expression "then" haskell-indentation-expression "else" haskell-indentation-expression)))) nil)) (defun haskell-indentation-phrase (phrase) "" ; FIXME (haskell-indentation-with-starter (apply-partially #'haskell-indentation-phrase-rest phrase) nil)) (defun haskell-indentation-phrase-rest (phrase1) "" ; FIXME (while phrase1 (let ((phrase phrase1)) (setq phrase1 nil) (let ((current-indent (current-column)) (left-indent left-indent) (layout-indent layout-indent)) (funcall (car phrase))) (cond ((eq current-token 'end-tokens) (cond ((null (cdr phrase))) ;; fallthrough ((equal following-token (cadr phrase)) (haskell-indentation-add-indentation starter-indent) (unless (member following-token '("," ";")) ;; we want to keep comma and semicolon aligned always (haskell-indentation-add-indentation left-indent)) (throw 'parse-end nil)) ((string= (cadr phrase) "in") (when (= left-indent layout-indent) (haskell-indentation-add-layout-indent) (throw 'parse-end nil))) (t (throw 'parse-end nil)))) ((null (cdr phrase))) ((equal (cadr phrase) current-token) (haskell-indentation-read-next-token) (when (eq current-token 'end-tokens) (haskell-indentation-add-indentation (+ starter-indent haskell-indentation-starter-offset)) (haskell-indentation-add-indentation (+ left-indent haskell-indentation-starter-offset)) (throw 'parse-end nil)) (setq phrase1 (cddr phrase))) ((string= (cadr phrase) "in")))))) (defun haskell-indentation-add-indentation (indent) "" ; FIXME (haskell-indentation-push-indentation (if (<= indent layout-indent) (+ layout-indent haskell-indentation-layout-offset) indent))) (defun haskell-indentation-add-layout-indent () "" ; FIXME (haskell-indentation-push-indentation layout-indent)) (defun haskell-indentation-add-where-pre-indent () "" ; FIXME (haskell-indentation-push-indentation (+ layout-indent haskell-indentation-where-pre-offset)) (if (= layout-indent haskell-indentation-layout-offset) (haskell-indentation-push-indentation haskell-indentation-where-pre-offset))) (defun haskell-indentation-add-where-post-indent (indent) "" ; FIXME (haskell-indentation-push-indentation (+ indent haskell-indentation-where-post-offset))) (defun haskell-indentation-add-left-indent () "" ; FIXME (haskell-indentation-add-indentation (+ left-indent haskell-indentation-left-offset))) (defun haskell-indentation-push-indentation (indent) "Add INDENT to list of possible indentations. Add INDENT to `possible-indentations' if it is not there yet. Keep the list in ascending order." (unless (member indent possible-indentations) (setq possible-indentations (sort (cons indent possible-indentations) #'<)))) (defun haskell-indentation-read-next-token () "Go to the next token and set current-token to the next token. The following symbols are used as pseudo tokens: 'layout-item: A new item in a layout list. The next token will be the first token from the item. 'layout-end: the end of a layout list. Next token will be the first token after the layout list. 'end-tokens: back at point where we started, following-token will be set to the next token. Pseudo tokens are used only when implicit-layout-active is t. That is the case only after keywords \"do\", \"where\", \"let\" and \"of\". If we are at a new line, parse-line is increased, and current-indent and left-indent are set to the indentation of the line." (cond ((and implicit-layout-active (eq current-token 'end-tokens)) 'end-tokens) ((and implicit-layout-active (eq current-token 'layout-end)) (cond ((> layout-indent (current-column)) 'layout-end) ((= layout-indent (current-column)) (setq current-token 'layout-item)) ((< layout-indent (current-column)) (setq current-token (haskell-indentation-peek-token))))) ((and implicit-layout-active (eq current-token 'layout-item)) (setq current-token (haskell-indentation-peek-token))) ((and implicit-layout-active (> layout-indent (current-column))) (setq current-token 'layout-end)) (t (setq previous-token (haskell-indentation-peek-token)) (haskell-indentation-skip-token) (if (>= (point) indentation-point) (progn (setq following-token (if (and (not (eobp)) (= (point) indentation-point)) (haskell-indentation-peek-token) 'no-following-token)) (setq current-token 'end-tokens)) (when (= (current-column) (haskell-indentation-current-indentation)) ;; on a new line (setq current-indent (current-column))) (cond ((and implicit-layout-active (> layout-indent (current-column))) (setq current-token 'layout-end)) ((and implicit-layout-active (= layout-indent (current-column))) (setq current-token 'layout-item)) (t (setq current-token (haskell-indentation-peek-token)))))))) (defun haskell-indentation-peek-token () "Return token starting at point." (cond ((looking-at "\\(if\\|then\\|else\\|let\\|in\\|mdo\\|rec\\|do\\|proc\\|case\\|of\\|where\\|module\\|signature\\|deriving\\|import\\|data\\|type\\|newtype\\|class\\|instance\\)\\([^[:alnum:]'_]\\|$\\)") (match-string-no-properties 1)) ((looking-at "[][(){}[,;]") (match-string-no-properties 0)) ((looking-at "\\(\\\\\\|->\\|<-\\|::\\|=\\||\\|=>\\)\\([^-:!#$%&*+./<=>?@\\\\^|~]\\|$\\)") (match-string-no-properties 1)) ((looking-at "\\(→\\|←\\|∷\\|⇒\\)\\([^-:!#$%&*+./<=>?@\\\\^|~]\\|$\\)") (let ((tok (match-string-no-properties 1))) (or (cdr (assoc tok haskell-indentation-unicode-tokens)) tok))) ((looking-at"[-:!#$%&*+./<=>?@\\\\^|~`]" ) 'operator) (t 'value))) (defun haskell-indentation-skip-token () "Skip to the next token." (if (haskell-lexeme-looking-at-token) (goto-char (match-end 0)) ;; otherwise skip until space found (skip-syntax-forward "^-")) ;; we have to skip unterminated string fence at the end of line (skip-chars-forward "\n") (forward-comment (buffer-size)) (while (and (haskell-indentation-bird-p) (bolp) (eq (char-after) ?>)) (forward-char) (forward-comment (buffer-size)))) (provide 'haskell-indentation) ;; Local Variables: ;; tab-width: 8 ;; End: ;;; haskell-indentation.el ends here �������������������������������������������������������������������������������haskell-mode-17.1/haskell-interactive-mode.el�������������������������������������������������������0000664�0000000�0000000�00000135560�13602233217�0021222�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-interactive-mode.el --- The interactive Haskell mode -*- lexical-binding: t -*- ;; Copyright © 2011-2012 Chris Done ;; 2016 Arthur Fayzrakhmanov ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;;; Todo: ;;; Code: (require 'haskell-mode) (require 'haskell-compile) (require 'haskell-process) (require 'haskell-session) (require 'haskell-font-lock) (require 'haskell-presentation-mode) (require 'haskell-utils) (require 'haskell-string) (require 'ansi-color) (require 'cl-lib) (require 'etags) (defvar-local haskell-interactive-mode-history-index 0) (defvar-local haskell-interactive-mode-history (list)) (defvar-local haskell-interactive-mode-old-prompt-start nil "Mark used for the old beginning of the prompt.") (defun haskell-interactive-prompt-regex () "Generate a regex for searching for any occurrence of the prompt\ at the beginning of the line. This should prevent any interference with prompts that look like haskell expressions." (concat "^" (regexp-quote haskell-interactive-prompt))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Globals used internally (declare-function haskell-interactive-kill "haskell") (defvar haskell-interactive-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "RET") 'haskell-interactive-mode-return) (define-key map (kbd "SPC") 'haskell-interactive-mode-space) (define-key map (kbd "C-j") 'haskell-interactive-mode-newline-indent) (define-key map [remap move-beginning-of-line] 'haskell-interactive-mode-bol) (define-key map (kbd "<home>") 'haskell-interactive-mode-beginning) (define-key map (kbd "C-c C-k") 'haskell-interactive-mode-clear) (define-key map (kbd "C-c C-c") 'haskell-process-interrupt) (define-key map (kbd "C-c C-f") 'next-error-follow-minor-mode) (define-key map (kbd "C-c C-z") 'haskell-interactive-switch-back) (define-key map (kbd "M-p") 'haskell-interactive-mode-history-previous) (define-key map (kbd "M-n") 'haskell-interactive-mode-history-next) (define-key map (kbd "C-c C-p") 'haskell-interactive-mode-prompt-previous) (define-key map (kbd "C-c C-n") 'haskell-interactive-mode-prompt-next) (define-key map (kbd "C-<up>") 'haskell-interactive-mode-history-previous) (define-key map (kbd "C-<down>") 'haskell-interactive-mode-history-next) (define-key map (kbd "TAB") 'haskell-interactive-mode-tab) (define-key map (kbd "<C-S-backspace>") 'haskell-interactive-mode-kill-whole-line) map) "Keymap used in `haskell-interactive-mode'.") (define-derived-mode haskell-interactive-mode fundamental-mode "Interactive-Haskell" "Interactive mode for Haskell. Key bindings: \\{haskell-interactive-mode-map}" :group 'haskell-interactive :syntax-table haskell-mode-syntax-table (setq haskell-interactive-mode-history (list)) (setq haskell-interactive-mode-history-index 0) (setq next-error-function #'haskell-interactive-next-error-function) (add-hook 'completion-at-point-functions #'haskell-interactive-mode-completion-at-point-function nil t) (add-hook 'kill-buffer-hook #'haskell-interactive-kill nil t) (haskell-interactive-mode-prompt)) (defvar haskell-interactive-mode-prompt-start nil "Mark used for the beginning of the prompt.") (defvar haskell-interactive-mode-result-end nil "Mark used to figure out where the end of the current result output is. Used to distinguish between user input.") (defvar-local haskell-interactive-previous-buffer nil "Records the buffer to which `haskell-interactive-switch-back' should jump. This is set by `haskell-interactive-switch', and should otherwise be nil.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Hooks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Faces ;;;###autoload (defface haskell-interactive-face-prompt '((t :inherit font-lock-function-name-face)) "Face for the prompt." :group 'haskell-interactive) ;;;###autoload (defface haskell-interactive-face-prompt-cont '((t :inherit font-lock-keyword-face)) "Face for GHCi's prompt-cont in multi-line mode." :group 'haskell-interactive) ;;;###autoload (define-obsolete-face-alias 'haskell-interactive-face-prompt2 'haskell-interactive-face-prompt-cont "16.2") ;;;###autoload (defface haskell-interactive-face-compile-error '((t :inherit compilation-error)) "Face for compile errors." :group 'haskell-interactive) ;;;###autoload (defface haskell-interactive-face-compile-warning '((t :inherit compilation-warning)) "Face for compiler warnings." :group 'haskell-interactive) ;;;###autoload (defface haskell-interactive-face-result '((t :inherit font-lock-string-face)) "Face for the result." :group 'haskell-interactive) ;;;###autoload (defface haskell-interactive-face-garbage '((t :inherit font-lock-string-face)) "Face for trailing garbage after a command has completed." :group 'haskell-interactive) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Actions (defun haskell-interactive-mode-newline-indent () "Make newline and indent." (interactive) (newline) (indent-to (length haskell-interactive-prompt)) (indent-relative)) (defun haskell-interactive-mode-kill-whole-line () "Kill the whole REPL line." (interactive) (kill-region haskell-interactive-mode-prompt-start (line-end-position))) (defun haskell-interactive-switch-back () "Switch back to the buffer from which this interactive buffer was reached." (interactive) (if haskell-interactive-previous-buffer (switch-to-buffer-other-window haskell-interactive-previous-buffer) (message "No previous buffer."))) (defun haskell-interactive-copy-to-prompt () "Copy the current line to the prompt, overwriting the current prompt." (interactive) (let ((l (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) ;; If it looks like the prompt is at the start of the line, chop ;; it off. (when (and (>= (length l) (length haskell-interactive-prompt)) (string= (substring l 0 (length haskell-interactive-prompt)) haskell-interactive-prompt)) (setq l (substring l (length haskell-interactive-prompt)))) (haskell-interactive-mode-set-prompt l))) (defun haskell-interactive-mode-space (n) "Handle the space key." (interactive "p") (if (and (bound-and-true-p god-local-mode) (fboundp 'god-mode-self-insert)) (call-interactively 'god-mode-self-insert) (if (haskell-interactive-at-compile-message) (next-error-no-select 0) (self-insert-command n)))) (defun haskell-interactive-at-prompt (&optional end-line) "If at prompt, return start position of user-input, otherwise return nil. If END-LINE is non-nil, then return non-nil when the end of line is at the prompt." (if (>= (if end-line (line-end-position) (point)) haskell-interactive-mode-prompt-start) haskell-interactive-mode-prompt-start nil)) (defun haskell-interactive-mode-bol () "Go to beginning of current line, but after current prompt if any." (interactive) (let ((beg (line-beginning-position)) (end (line-end-position))) (goto-char (if (>= end haskell-interactive-mode-prompt-start beg) haskell-interactive-mode-prompt-start beg)))) (define-derived-mode haskell-error-mode special-mode "Error" "Major mode for viewing Haskell compile errors.") ;; (define-key haskell-error-mode-map (kbd "q") 'quit-window) (defun haskell-interactive-mode-handle-h () "Handle ^H in output." (let ((bound (point-min)) (inhibit-read-only t)) (save-excursion (while (search-backward "\b" bound t 1) (save-excursion (forward-char) (let ((end (point))) (if (search-backward-regexp "[^\b]" bound t 1) (forward-char) (goto-char (point-min))) (let ((start (point))) (delete-region (max (- (point) (- end start)) (point-min)) end)))))))) (defun haskell-interactive-mode-multi-line (expr) "If a multi-line expression EXPR has been entered, then reformat it to be: :{ do the multi-liner expr :}" (if (not (string-match-p "\n" expr)) expr (let ((pre (format "^%s" (regexp-quote haskell-interactive-prompt))) (lines (split-string expr "\n"))) (cl-loop for elt on (cdr lines) do (setcar elt (replace-regexp-in-string pre "" (car elt)))) ;; Temporarily set prompt2 to be empty to avoid unwanted output (concat ":set prompt2 \"\"\n" ":{\n" (mapconcat #'identity lines "\n") "\n:}\n" (format ":set prompt-cont \"%s\"" haskell-interactive-prompt-cont))))) (defun haskell-interactive-mode-line-is-query (line) "Is LINE actually a :t/:k/:i?" (and (string-match "^:[itk] " line) t)) (defun haskell-interactive-mode-beginning () "Go to the start of the line." (interactive) (if (haskell-interactive-at-prompt) (goto-char haskell-interactive-mode-prompt-start) (move-beginning-of-line nil))) (defun haskell-interactive-mode-input-partial () "Get the interactive mode input up to point." (let ((input-start (haskell-interactive-at-prompt))) (unless input-start (error "not at prompt")) (buffer-substring-no-properties input-start (point)))) (defun haskell-interactive-mode-input () "Get the interactive mode input." (buffer-substring-no-properties haskell-interactive-mode-prompt-start (point-max))) (defun haskell-interactive-mode-prompt (&optional session) "Show a prompt at the end of the REPL buffer. If SESSION is non-nil, use the REPL buffer associated with SESSION, otherwise operate on the current buffer." (with-current-buffer (if session (haskell-session-interactive-buffer session) (current-buffer)) (save-excursion (goto-char (point-max)) (let ((prompt (propertize haskell-interactive-prompt 'font-lock-face 'haskell-interactive-face-prompt 'prompt t 'read-only haskell-interactive-prompt-read-only 'rear-nonsticky t))) ;; At the time of writing, front-stickying the first char gives an error ;; Has unfortunate side-effect of being able to insert before the prompt (insert (substring prompt 0 1) (propertize (substring prompt 1) 'front-sticky t))) (let ((marker (setq-local haskell-interactive-mode-prompt-start (make-marker)))) (set-marker marker (point)))) (when (haskell-interactive-at-prompt t) (haskell-interactive-mode-scroll-to-bottom)))) (defun haskell-interactive-mode-eval-result (session text) "Insert the result of an eval as plain text." (with-current-buffer (haskell-session-interactive-buffer session) (let ((at-end (eobp)) (prop-text (propertize text 'font-lock-face 'haskell-interactive-face-result 'front-sticky t 'prompt t 'read-only haskell-interactive-mode-read-only 'rear-nonsticky t 'result t))) (save-excursion (goto-char (point-max)) (when (string= text haskell-interactive-prompt-cont) (setq prop-text (propertize prop-text 'font-lock-face 'haskell-interactive-face-prompt-cont 'read-only haskell-interactive-prompt-read-only))) (insert (ansi-color-apply prop-text)) (haskell-interactive-mode-handle-h) (let ((marker (setq-local haskell-interactive-mode-result-end (make-marker)))) (set-marker marker (point)))) (when at-end (haskell-interactive-mode-scroll-to-bottom))))) (defun haskell-interactive-mode-scroll-to-bottom () "Scroll to bottom." (let ((w (get-buffer-window (current-buffer)))) (when w (goto-char (point-max)) (set-window-point w (point))))) (defun haskell-interactive-mode-compile-error (session message) "Echo an error." (haskell-interactive-mode-compile-message session message 'haskell-interactive-face-compile-error)) (defun haskell-interactive-mode-compile-warning (session message) "Warning message." (haskell-interactive-mode-compile-message session message 'haskell-interactive-face-compile-warning)) (defun haskell-interactive-mode-compile-message (session message type) "Echo a compiler warning." (with-current-buffer (haskell-session-interactive-buffer session) (setq next-error-last-buffer (current-buffer)) (save-excursion (haskell-interactive-mode-goto-end-point) (let ((lines (string-match "^\\(.*\\)\n\\([[:unibyte:][:nonascii:]]+\\)" message))) (if lines (progn (insert (propertize (concat (match-string 1 message) " …\n") 'expandable t 'font-lock-face type 'front-sticky t 'read-only haskell-interactive-mode-read-only 'rear-nonsticky t)) (insert (propertize (concat (match-string 2 message) "\n") 'collapsible t 'font-lock-face type 'front-sticky t 'invisible haskell-interactive-mode-hide-multi-line-errors 'message-length (length (match-string 2 message)) 'read-only haskell-interactive-mode-read-only 'rear-nonsticky t))) (insert (propertize (concat message "\n") 'font-lock-face type 'front-sticky t 'read-only haskell-interactive-mode-read-only 'rear-nonsticky t))))))) (defun haskell-interactive-mode-insert (session message) "Echo a read only piece of text before the prompt." (with-current-buffer (haskell-session-interactive-buffer session) (save-excursion (haskell-interactive-mode-goto-end-point) (insert (propertize message 'front-sticky t 'read-only t 'rear-nonsticky t))))) (defun haskell-interactive-mode-goto-end-point () "Go to the 'end' of the buffer (before the prompt)." (goto-char haskell-interactive-mode-prompt-start) (goto-char (line-beginning-position))) (defun haskell-interactive-mode-history-add (input) "Add INPUT to the history." (setq haskell-interactive-mode-history (cons "" (cons input (cl-remove-if (lambda (i) (or (string= i input) (string= i ""))) haskell-interactive-mode-history)))) (setq haskell-interactive-mode-history-index 0)) (defun haskell-interactive-mode-tab () "Do completion if at prompt or else try collapse/expand." (interactive) (cond ((haskell-interactive-at-prompt) (completion-at-point)) ((get-text-property (point) 'collapsible) (let ((column (current-column))) (search-backward-regexp "^[^ ]") (haskell-interactive-mode-tab-expand) (goto-char (+ column (line-beginning-position))))) (t (haskell-interactive-mode-tab-expand)))) (defun haskell-interactive-mode-tab-expand () "Expand the rest of the message." (cond ((get-text-property (point) 'expandable) (let* ((pos (1+ (line-end-position))) (visibility (get-text-property pos 'invisible)) (length (1+ (get-text-property pos 'message-length)))) (let ((inhibit-read-only t)) (put-text-property pos (+ pos length) 'invisible (not visibility))))))) (defconst haskell-interactive-mode-error-regexp "^\\(\\(?:[A-Z]:\\)?[^ \r\n:][^\r\n:]*\\):\\([0-9()-:]+\\):?") (defun haskell-interactive-at-compile-message () "Am I on a compile message?" (and (not (haskell-interactive-at-prompt)) (save-excursion (goto-char (line-beginning-position)) (looking-at haskell-interactive-mode-error-regexp)))) (defun haskell-interactive-mode-error-backward (&optional count) "Go backward to the previous error." (interactive) (search-backward-regexp haskell-interactive-mode-error-regexp nil t count)) (defun haskell-interactive-mode-error-forward (&optional count) "Go forward to the next error, or return to the REPL." (interactive) (goto-char (line-end-position)) (if (search-forward-regexp haskell-interactive-mode-error-regexp nil t count) (progn (goto-char (line-beginning-position)) t) (progn (goto-char (point-max)) nil))) (defun haskell-interactive-mode-delete-compile-messages (session &optional file-name) "Delete compile messages in REPL buffer. If FILE-NAME is non-nil, restrict to removing messages concerning FILE-NAME only." (with-current-buffer (haskell-session-interactive-buffer session) (save-excursion (goto-char (point-min)) (when (search-forward-regexp "^Compilation failed.$" nil t 1) (let ((inhibit-read-only t)) (delete-region (line-beginning-position) (1+ (line-end-position)))) (goto-char (point-min))) (while (when (re-search-forward haskell-interactive-mode-error-regexp nil t) (let ((msg-file-name (match-string-no-properties 1)) (msg-startpos (line-beginning-position))) ;; skip over hanging continuation message lines (while (progn (forward-line) (looking-at "^[ ]+"))) (when (or (not file-name) (string= file-name msg-file-name)) (let ((inhibit-read-only t)) (set-text-properties msg-startpos (point) nil)) (delete-region msg-startpos (point)) )) t))))) ;;;###autoload (defun haskell-interactive-mode-reset-error (session) "Reset the error cursor position." (interactive) (with-current-buffer (haskell-session-interactive-buffer session) (haskell-interactive-mode-goto-end-point) (let ((mrk (point-marker))) (haskell-session-set session 'next-error-locus nil) (haskell-session-set session 'next-error-region (cons mrk (copy-marker mrk t)))) (goto-char (point-max)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Misc (declare-function haskell-interactive-switch "haskell") (declare-function haskell-session "haskell") (defun haskell-session-interactive-buffer (s) "Get the session interactive buffer." (let ((buffer (haskell-session-get s 'interactive-buffer))) (if (and buffer (buffer-live-p buffer)) buffer (let ((buffer-name (format "*%s*" (haskell-session-name s))) (index 0)) (while (get-buffer buffer-name) (setq buffer-name (format "*%s <%d>*" (haskell-session-name s) index)) (setq index (1+ index))) (let ((buffer (get-buffer-create buffer-name))) (haskell-session-set-interactive-buffer s buffer) (with-current-buffer buffer (haskell-interactive-mode) (haskell-session-assign s)) (haskell-interactive-switch) buffer))))) (defun haskell-interactive-buffer () "Get the interactive buffer of the session." (haskell-session-interactive-buffer (haskell-session))) (defun haskell-process-cabal-live (state buffer) "Do live updates for Cabal processes." (haskell-interactive-mode-insert (haskell-process-session (cadr state)) (replace-regexp-in-string haskell-process-prompt-regex "" (substring buffer (cl-cadddr state)))) (setf (cl-cdddr state) (list (length buffer))) nil) (defun haskell-process-parse-error (string) "Parse the line number from the error string STRING." (let ((span nil)) (cl-loop for regex in haskell-compilation-error-regexp-alist do (when (string-match (car regex) string) (setq span (list :file (match-string 1 string) :line (string-to-number (match-string 2 string)) :col (string-to-number (match-string 4 string)) :line2 (when (match-string 3 string) (string-to-number (match-string 3 string))) :col2 (when (match-string 5 string) (string-to-number (match-string 5 string))))))) span)) (defun haskell-process-suggest-add-package (session msg) "Add the (matched) module to your cabal file. Cabal file is selected using SESSION's name, module matching is done in MSG." (let* ((suggested-package (match-string 1 msg)) (package-name (replace-regexp-in-string "-[^-]+$" "" suggested-package)) (version (progn (string-match "\\([^-]+\\)$" suggested-package) (match-string 1 suggested-package))) (cabal-file (concat (haskell-session-name session) ".cabal"))) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (when (y-or-n-p (format "Add `%s' to %s?" package-name cabal-file)) (haskell-cabal-add-dependency package-name version nil t) (when (y-or-n-p (format "Enable -package %s in the GHCi session?" package-name)) (haskell-process-queue-without-filters (haskell-session-process session) (format ":set -package %s" package-name)))) (haskell-mode-toggle-interactive-prompt-state t)))) (defun haskell-process-suggest-remove-import (session file import line) "Suggest removing or commenting out import statement. Asks user to handle redundant import statement using interactive SESSION in specified FILE to remove IMPORT on given LINE." (let ((first t)) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (cl-case (read-event (propertize (format "%sThe import line `%s' is redundant. Remove? (y, n, c: comment out) " (if (not first) "Please answer n, y or c: " "") import) 'face 'minibuffer-prompt)) (?y (haskell-process-find-file session file) (save-excursion (goto-char (point-min)) (forward-line (1- line)) (goto-char (line-beginning-position)) (delete-region (line-beginning-position) (line-end-position)))) (?n (message "Ignoring redundant import %s" import)) (?c (haskell-process-find-file session file) (save-excursion (goto-char (point-min)) (forward-line (1- line)) (goto-char (line-beginning-position)) (insert "-- ")))) ;; unwind (haskell-mode-toggle-interactive-prompt-state t)))) (defun haskell-process-find-file (session file) "Find the given file in the project." (find-file (cond ((file-exists-p (concat (haskell-session-current-dir session) "/" file)) (concat (haskell-session-current-dir session) "/" file)) ((file-exists-p (concat (haskell-session-cabal-dir session) "/" file)) (concat (haskell-session-cabal-dir session) "/" file)) (t file)))) (defun haskell-process-suggest-pragma (session pragma extension file) "Suggest to add something to the top of the file. SESSION is used to search given file. Adds PRAGMA and EXTENSION wrapped in compiler directive at the top of FILE." (let ((string (format "{-# %s %s #-}" pragma extension))) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (when (y-or-n-p (format "Add %s to the top of the file? " string)) (haskell-process-find-file session file) (save-excursion (goto-char (point-min)) (insert (concat string "\n")))) (haskell-mode-toggle-interactive-prompt-state t)))) (defun haskell-interactive-mode-insert-error (response) "Insert an error message." (insert "\n" (haskell-fontify-as-mode response 'haskell-mode)) (haskell-interactive-mode-prompt)) (defun haskell-interactive-popup-error (response) "Popup an error." (if haskell-interactive-popup-errors (let ((buf (get-buffer-create "*HS-Error*"))) (pop-to-buffer buf nil t) (with-current-buffer buf (haskell-error-mode) (let ((inhibit-read-only t)) (erase-buffer) (insert (propertize response 'font-lock-face 'haskell-interactive-face-compile-error)) (goto-char (point-min)) (delete-blank-lines) (insert (propertize "-- Hit `q' to close this window.\n\n" 'font-lock-face 'font-lock-comment-face)) (save-excursion (goto-char (point-max)) (insert (propertize "\n-- To disable popups, customize `haskell-interactive-popup-errors'.\n\n" 'font-lock-face 'font-lock-comment-face)))))) (haskell-interactive-mode-insert-error response))) (defun haskell-interactive-next-error-function (&optional n reset) "See `next-error-function' for more information." (let* ((session (haskell-interactive-session)) (next-error-region (haskell-session-get session 'next-error-region)) (next-error-locus (haskell-session-get session 'next-error-locus)) (reset-locus nil)) (when (and next-error-region (or reset (and (/= n 0) (not next-error-locus)))) (goto-char (car next-error-region)) (unless (looking-at haskell-interactive-mode-error-regexp) (haskell-interactive-mode-error-forward)) (setq reset-locus t) (unless (looking-at haskell-interactive-mode-error-regexp) (error "no errors found"))) ;; move point if needed (cond (reset-locus nil) ((> n 0) (unless (haskell-interactive-mode-error-forward n) (error "no more errors"))) ((< n 0) (unless (haskell-interactive-mode-error-backward (- n)) (error "no more errors")))) (let ((orig-line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) (when (string-match haskell-interactive-mode-error-regexp orig-line) (let* ((msgmrk (set-marker (make-marker) (line-beginning-position))) (location (haskell-process-parse-error orig-line)) (file (plist-get location :file)) (line (plist-get location :line)) (col1 (plist-get location :col)) (col2 (plist-get location :col2)) (cabal-relative-file (expand-file-name file (haskell-session-cabal-dir session))) (src-relative-file (expand-file-name file (haskell-session-current-dir session))) (real-file (cond ((file-exists-p cabal-relative-file) cabal-relative-file) ((file-exists-p src-relative-file) src-relative-file)))) (haskell-session-set session 'next-error-locus msgmrk) (if real-file (let ((m1 (make-marker)) (m2 (make-marker))) (with-current-buffer (find-file-noselect real-file) (save-excursion (goto-char (point-min)) (forward-line (1- line)) (set-marker m1 (+ col1 (point) -1)) (when col2 (set-marker m2 (- (point) col2))))) ;; ...finally select&hilight error locus (compilation-goto-locus msgmrk m1 (and (marker-position m2) m2))) (error "don't know where to find %S" file))))))) (defun haskell-interactive-session () "Get the `haskell-session', throw an error if it's not available." (or (haskell-session-maybe) (haskell-session-assign (or (haskell-session-from-buffer) (haskell-session-choose) (error "No session associated with this buffer. Try M-x haskell-session-change or report this as a bug."))))) (defun haskell-interactive-process () "Get the Haskell session." (or (haskell-session-process (haskell-interactive-session)) (error "No Haskell session/process associated with this buffer. Maybe run M-x haskell-process-restart?"))) (defun haskell-interactive-mode-do-presentation (expr) "Present the given expression EXPR. Requires the `present' package to be installed. Will automatically import it qualified as Present." (let ((p (haskell-interactive-process))) ;; If Present.code isn't available, we probably need to run the ;; setup. (unless (string-match "^Present" (haskell-process-queue-sync-request p ":t Present.encode")) (haskell-interactive-mode-setup-presentation p)) ;; Happily, let statements don't affect the `it' binding in any ;; way, so we can fake it, no pun intended. (let ((error (haskell-process-queue-sync-request p (concat "let it = Present.asData (" expr ")")))) (if (not (string= "" error)) (haskell-interactive-mode-eval-result (haskell-interactive-session) (concat error "\n")) (let ((hash (haskell-interactive-mode-presentation-hash))) (haskell-process-queue-sync-request p (format "let %s = Present.asData (%s)" hash expr)) (let* ((presentation (haskell-interactive-mode-present-id hash (list 0)))) (insert "\n") (haskell-interactive-mode-insert-presentation hash presentation) (haskell-interactive-mode-eval-result (haskell-interactive-session) "\n")))) (haskell-interactive-mode-prompt (haskell-interactive-session))))) (defun haskell-interactive-mode-present-id (hash id) "Generate a presentation for the current expression at ID." ;; See below for commentary of this statement. (let ((p (haskell-interactive-process))) (haskell-process-queue-without-filters p "let _it = it") (let* ((text (haskell-process-queue-sync-request p (format "Present.putStr (Present.encode (Present.fromJust (Present.present (Present.fromJust (Present.fromList [%s])) %s)))" (mapconcat 'identity (mapcar 'number-to-string id) ",") hash))) (reply (if (string-match "^*** " text) '((rep nil)) (read text)))) ;; Not necessary, but nice to restore it to the expression that ;; the user actually typed in. (haskell-process-queue-without-filters p "let it = _it") reply))) (defun haskell-presentation-present-slot (btn) "The callback to evaluate the slot and present it in place of the button BTN." (let ((id (button-get btn 'presentation-id)) (hash (button-get btn 'hash)) (parent-rep (button-get btn 'parent-rep)) (continuation (button-get btn 'continuation))) (let ((point (point))) (button-put btn 'invisible t) (delete-region (button-start btn) (button-end btn)) (haskell-interactive-mode-insert-presentation hash (haskell-interactive-mode-present-id hash id) parent-rep continuation) (when (> (point) point) (goto-char (1+ point)))))) (defun haskell-interactive-mode-presentation-slot (hash slot parent-rep &optional continuation) "Make a slot at point, pointing to ID." (let ((type (car slot)) (id (cadr slot))) (if (member (intern type) '(Integer Char Int Float Double)) (haskell-interactive-mode-insert-presentation hash (haskell-interactive-mode-present-id hash id) parent-rep continuation) (haskell-interactive-mode-presentation-slot-button slot parent-rep continuation hash)))) (defun haskell-interactive-mode-presentation-slot-button (slot parent-rep continuation hash) (let ((start (point)) (type (car slot)) (id (cadr slot))) (insert (propertize type 'font-lock-face '(:height 0.8 :underline t :inherit font-lock-comment-face))) (let ((button (make-text-button start (point) :type 'haskell-presentation-slot-button))) (button-put button 'hide-on-click t) (button-put button 'presentation-id id) (button-put button 'parent-rep parent-rep) (button-put button 'continuation continuation) (button-put button 'hash hash)))) (defun haskell-interactive-mode-insert-presentation (hash presentation &optional parent-rep continuation) "Insert the presentation, hooking up buttons for each slot." (let* ((rep (cadr (assoc 'rep presentation))) (text (cadr (assoc 'text presentation))) (slots (cadr (assoc 'slots presentation))) (nullary (null slots))) (cond ((string= "integer" rep) (insert (propertize text 'font-lock-face 'font-lock-constant))) ((string= "floating" rep) (insert (propertize text 'font-lock-face 'font-lock-constant))) ((string= "char" rep) (insert (propertize (if (string= "string" parent-rep) (replace-regexp-in-string "^'\\(.+\\)'$" "\\1" text) text) 'font-lock-face 'font-lock-string-face))) ((string= "tuple" rep) (insert "(") (let ((first t)) (cl-loop for slot in slots do (unless first (insert ",")) do (haskell-interactive-mode-presentation-slot hash slot rep) do (setq first nil))) (insert ")")) ((string= "list" rep) (if (null slots) (if continuation (progn (delete-char -1) (delete-indentation)) (insert "[]")) (let ((i 0)) (unless continuation (insert "[")) (let ((start-column (current-column))) (cl-loop for slot in slots do (haskell-interactive-mode-presentation-slot hash slot rep (= i (1- (length slots)))) do (when (not (= i (1- (length slots)))) (insert "\n") (indent-to (1- start-column)) (insert ",")) do (setq i (1+ i)))) (unless continuation (insert "]"))))) ((string= "string" rep) (unless (string= "string" parent-rep) (insert (propertize "\"" 'font-lock-face 'font-lock-string-face))) (cl-loop for slot in slots do (haskell-interactive-mode-presentation-slot hash slot rep)) (unless (string= "string" parent-rep) (insert (propertize "\"" 'font-lock-face 'font-lock-string-face)))) ((string= "alg" rep) (when (and parent-rep (not nullary) (not (string= "list" parent-rep))) (insert "(")) (let ((start-column (current-column))) (insert (propertize text 'font-lock-face 'font-lock-type-face)) (cl-loop for slot in slots do (insert "\n") do (indent-to (+ 2 start-column)) do (haskell-interactive-mode-presentation-slot hash slot rep))) (when (and parent-rep (not nullary) (not (string= "list" parent-rep))) (insert ")"))) ((string= "record" rep) (let ((start-column (current-column))) (insert (propertize text 'font-lock-face 'font-lock-type-face) " { ") (cl-loop for field in slots do (insert "\n") do (indent-to (+ 2 start-column)) do (let ((name (nth 0 field)) (slot (nth 1 field))) (insert name " = ") (haskell-interactive-mode-presentation-slot hash slot rep))) (insert "\n") (indent-to start-column) (insert "}"))) ((eq rep nil) (insert (propertize "?" 'font-lock-face 'font-lock-warning))) (t (let ((err "Unable to present! This very likely means Emacs is out of sync with the `present' package. You should make sure they're both up to date, or report a bug.")) (insert err) (error err)))))) (defun haskell-interactive-mode-setup-presentation (p) "Setup the GHCi REPL for using presentations. Using asynchronous queued commands as opposed to sync at this stage, as sync would freeze up the UI a bit, and we actually don't care when the thing completes as long as it's soonish." ;; Import dependencies under Present.* namespace (haskell-process-queue-without-filters p "import qualified Data.Maybe as Present") (haskell-process-queue-without-filters p "import qualified Data.ByteString.Lazy as Present") (haskell-process-queue-without-filters p "import qualified Data.AttoLisp as Present") (haskell-process-queue-without-filters p "import qualified Present.ID as Present") (haskell-process-queue-without-filters p "import qualified Present as Present") ;; Make a dummy expression to avoid "Loading package" nonsense (haskell-process-queue-without-filters p "Present.present (Present.fromJust (Present.fromList [0])) ()")) (defvar haskell-interactive-mode-presentation-hash 0 "Counter for the hash.") (defun haskell-interactive-mode-presentation-hash () "Generate a presentation hash." (format "_present_%s" (setq haskell-interactive-mode-presentation-hash (1+ haskell-interactive-mode-presentation-hash)))) (define-button-type 'haskell-presentation-slot-button 'action 'haskell-presentation-present-slot 'follow-link t 'help-echo "Click to expand…") (defun haskell-interactive-mode-history-toggle (n) "Toggle the history N items up or down." (unless (null haskell-interactive-mode-history) (setq haskell-interactive-mode-history-index (mod (+ haskell-interactive-mode-history-index n) (length haskell-interactive-mode-history))) (unless (zerop haskell-interactive-mode-history-index) (message "History item: %d" haskell-interactive-mode-history-index)) (haskell-interactive-mode-set-prompt (nth haskell-interactive-mode-history-index haskell-interactive-mode-history)))) (defun haskell-interactive-mode-set-prompt (p) "Set (and overwrite) the current prompt." (with-current-buffer (haskell-session-interactive-buffer (haskell-interactive-session)) (goto-char haskell-interactive-mode-prompt-start) (delete-region (point) (point-max)) (insert p))) (defun haskell-interactive-mode-history-previous (arg) "Cycle backwards through input history." (interactive "*p") (when (haskell-interactive-at-prompt) (if (not (zerop arg)) (haskell-interactive-mode-history-toggle arg) (setq haskell-interactive-mode-history-index 0) (haskell-interactive-mode-history-toggle 1)))) (defun haskell-interactive-mode-history-next (arg) "Cycle forward through input history." (interactive "*p") (when (haskell-interactive-at-prompt) (if (not (zerop arg)) (haskell-interactive-mode-history-toggle (- arg)) (setq haskell-interactive-mode-history-index 0) (haskell-interactive-mode-history-toggle -1)))) (defun haskell-interactive-mode-prompt-previous () "Jump to the previous prompt." (interactive) (let ((prev-prompt-pos (save-excursion (beginning-of-line) ;; otherwise prompt at current line matches (and (search-backward-regexp (haskell-interactive-prompt-regex) nil t) (match-end 0))))) (when prev-prompt-pos (goto-char prev-prompt-pos)))) (defun haskell-interactive-mode-prompt-next () "Jump to the next prompt." (interactive) (search-forward-regexp (haskell-interactive-prompt-regex) nil t)) (defun haskell-interactive-mode-clear () "Clear the screen and put any current input into the history." (interactive) (let ((session (haskell-interactive-session))) (with-current-buffer (haskell-session-interactive-buffer session) (let ((inhibit-read-only t)) (set-text-properties (point-min) (point-max) nil)) (delete-region (point-min) (point-max)) (remove-overlays) (haskell-interactive-mode-prompt session) (haskell-session-set session 'next-error-region nil) (haskell-session-set session 'next-error-locus nil)) (with-current-buffer (get-buffer-create "*haskell-process-log*") (let ((inhibit-read-only t)) (delete-region (point-min) (point-max))) (remove-overlays)))) (defun haskell-interactive-mode-completion-at-point-function () "Offer completions for partial expression between prompt and point. This completion function is used in interactive REPL buffer itself." (when (haskell-interactive-at-prompt) (let* ((process (haskell-interactive-process)) (inp (haskell-interactive-mode-input-partial)) (resp2 (haskell-process-get-repl-completions process inp)) (rlen (- (length inp) (length (car resp2)))) (coll (append (if (string-prefix-p inp "import") '("import")) (if (string-prefix-p inp "let") '("let")) (cdr resp2)))) (list (- (point) rlen) (point) coll)))) (defun haskell-interactive-mode-trigger-compile-error (state response) "Look for an <interactive> compile error. If there is one, pop that up in a buffer, similar to `debug-on-error'." (when (and haskell-interactive-types-for-show-ambiguous (string-match "^\n<interactive>:[-0-9]+:[-0-9]+:" response) (not (string-match "^\n<interactive>:[-0-9]+:[-0-9]+:[\n ]+[Ww]arning:" response))) (let ((inhibit-read-only t)) (delete-region haskell-interactive-mode-prompt-start (point)) (set-marker haskell-interactive-mode-prompt-start haskell-interactive-mode-old-prompt-start) (goto-char (point-max))) (cond ((and (not (haskell-interactive-mode-line-is-query (elt state 2))) (or (string-match "No instance for (?Show[ \n]" response) (string-match "Ambiguous type variable " response))) (haskell-process-reset (haskell-interactive-process)) (let ((resp (haskell-process-queue-sync-request (haskell-interactive-process) (concat ":t " (buffer-substring-no-properties haskell-interactive-mode-prompt-start (point-max)))))) (cond ((not (string-match "<interactive>:" resp)) (haskell-interactive-mode-insert-error resp)) (t (haskell-interactive-popup-error response))))) (t (haskell-interactive-popup-error response) t)) t)) ;;;###autoload (defun haskell-interactive-mode-echo (session message &optional mode) "Echo a read only piece of text before the prompt." (with-current-buffer (haskell-session-interactive-buffer session) (save-excursion (haskell-interactive-mode-goto-end-point) (insert (if mode (haskell-fontify-as-mode (concat message "\n") mode) (propertize (concat message "\n") 'front-sticky t 'read-only t 'rear-nonsticky t)))))) (defun haskell-interactive-mode-splices-buffer (session) "Get the splices buffer for the current SESSION." (get-buffer-create (haskell-interactive-mode-splices-buffer-name session))) (defun haskell-interactive-mode-splices-buffer-name (session) (format "*%s:splices*" (haskell-session-name session))) (defun haskell-interactive-mode-compile-splice (session message) "Echo a compiler splice." (with-current-buffer (haskell-interactive-mode-splices-buffer session) (unless (eq major-mode 'haskell-mode) (haskell-mode)) (let* ((parts (split-string message "\n ======>\n")) (file-and-decl-lines (split-string (nth 0 parts) "\n")) (file (nth 0 file-and-decl-lines)) (decl (mapconcat #'identity (cdr file-and-decl-lines) "\n")) (output (nth 1 parts))) (insert "-- " file "\n") (let ((start (point))) (insert decl "\n") (indent-rigidly start (point) -4)) (insert "-- =>\n") (let ((start (point))) (insert output "\n") (indent-rigidly start (point) -4))))) (defun haskell-interactive-mode-insert-garbage (session message) "Echo a read only piece of text before the prompt." (with-current-buffer (haskell-session-interactive-buffer session) (save-excursion (haskell-interactive-mode-goto-end-point) (insert (propertize message 'front-sticky t 'font-lock-face 'haskell-interactive-face-garbage 'read-only t 'rear-nonsticky t))))) ;;;###autoload (defun haskell-process-show-repl-response (line) "Send LINE to the GHCi process and echo the result in some fashion. Result will be printed in the minibuffer or presented using function `haskell-presentation-present', depending on variable `haskell-process-use-presentation-mode'." (let ((process (haskell-interactive-process))) (haskell-process-queue-command process (make-haskell-command :state (cons process line) :go (lambda (state) (haskell-process-send-string (car state) (cdr state))) :complete (lambda (state response) (if haskell-process-use-presentation-mode (haskell-presentation-present (haskell-process-session (car state)) response) (haskell-mode-message-line response))))))) (provide 'haskell-interactive-mode) ;;; haskell-interactive-mode.el ends here ������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-lexeme.el�����������������������������������������������������������������0000664�0000000�0000000�00000045266�13602233217�0017245�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-lexeme.el --- haskell lexical tokens -*- coding: utf-8; lexical-binding: t -*- ;; Copyright (C) 2015 Gracjan Polak ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;;; Code: (require 'rx) (unless (category-docstring ?P) (define-category ?P "Haskell symbol constituent characters") (map-char-table #'(lambda (key val) (if (or (and (consp key) (> (car key) 128)) (and (numberp key) (> key 128))) (if (member val '(Pc Pd Po Sm Sc Sk So)) (modify-category-entry key ?P)))) unicode-category-table) (dolist (key (string-to-list "!#$%&*+./<=>?@^|~\\-:")) (modify-category-entry key ?P))) (defconst haskell-lexeme-modid "[[:upper:]][[:alnum:]'_]*" "Regexp matching a valid Haskell module identifier. Note that GHC accepts Unicode category UppercaseLetter as a first character. Following letters are from Unicode categories UppercaseLetter, LowercaseLetter, OtherLetter, TitlecaseLetter, ModifierLetter, DecimalNumber, OtherNumber, backslash or underscore.") (defconst haskell-lexeme-id "[[:alpha:]_][[:alnum:]'_]*" "Regexp matching a valid Haskell identifier. GHC accepts a string starting with any alphabetic character or underscore followed by any alphanumeric character or underscore or apostrophe.") (defconst haskell-lexeme-sym "\\cP+" "Regexp matching a valid Haskell variable or constructor symbol. GHC accepts a string of chars from the set [:!#$%&*+./<=>?@^|~\\-] or Unicode category Symbol for chars with codes larger than 128 only.") (defconst haskell-lexeme-idsym-first-char "\\(?:[[:alpha:]_]\\|\\cP\\)" "Regexp matching first character of a qualified or unqualified identifier or symbol. Useful for `re-search-forward'.") (defconst haskell-lexeme-modid-opt-prefix (concat "\\(?:" haskell-lexeme-modid "\\.\\)*") "Regexp matching a valid Haskell module prefix, potentially empty. Module path prefix is separated by dots and finishes with a dot. For path component syntax see `haskell-lexeme-modid'.") (defconst haskell-lexeme-qid-or-qsym (rx-to-string `(: (regexp ,haskell-lexeme-modid-opt-prefix) (group (| (regexp ,haskell-lexeme-id) (regexp ,haskell-lexeme-sym) )))) "Regexp matching a valid qualified identifier or symbol. Note that (match-string 1) returns the unqualified part.") (defun haskell-lexeme-looking-at-qidsym () "Non-nil when point is just in front of an optionally qualified identifier or symbol. Using this function is more efficient than matching against the regexp `haskell-lexeme-qid-or-qsym'. Returns: 'qid - if matched a qualified id: 'Data.Map' or 'Map' 'qsym - if matched a qualified id: 'Monad.>>=' or '>>=' 'qprefix - if matched only modid prefix: 'Data.' After successful 'qid or 'qsym match (match-string 1) will return the unqualified part (if any)." (let ((begin (point)) (match-data-old (match-data))) (save-excursion (while (looking-at (concat haskell-lexeme-modid "\\.")) (goto-char (match-end 0))) (cond ((looking-at haskell-lexeme-id) (let ((beg (match-beginning 0)) (end (match-end 0))) ;; check is MagicHash is present at the end of the token (goto-char end) (when (looking-at "#+") (setq end (match-end 0))) (set-match-data (list begin end beg end))) 'qid) ((looking-at haskell-lexeme-sym) (set-match-data (list begin (match-end 0) (match-beginning 0) (match-end 0))) 'qsym) ((equal begin (point)) (set-match-data match-data-old) nil) (t (set-match-data (list begin (point) nil nil)) 'qprefix))))) (defun haskell-lexeme-looking-at-backtick () "Non-nil when point is just in front of an identifier quoted with backticks. When match is successful, match-data will contain: (match-text 1) - opening backtick (match-text 2) - whole qualified identifier (match-text 3) - unqualified part of identifier (match-text 4) - closing backtick" (let ((match-data-old (match-data)) first-backtick-start last-backtick-start qid-start id-start id-end result) (save-excursion (when (looking-at "`") (setq first-backtick-start (match-beginning 0)) (goto-char (match-end 0)) (forward-comment (buffer-size)) (when (haskell-lexeme-looking-at-qidsym) (setq qid-start (match-beginning 0)) (setq id-start (match-beginning 1)) (setq id-end (match-end 1)) (goto-char (match-end 0)) (forward-comment (buffer-size)) (when (looking-at "`") (setq last-backtick-start (match-beginning 0)) (set-match-data (mapcar (lambda (p) (set-marker (make-marker) p)) (list first-backtick-start (1+ last-backtick-start) first-backtick-start (1+ first-backtick-start) qid-start id-end id-start id-end last-backtick-start (1+ last-backtick-start)))) (setq result t))))) (unless result (set-match-data match-data-old)) result)) (defconst haskell-lexeme-qid (rx-to-string `(: (regexp "'*") (regexp ,haskell-lexeme-modid-opt-prefix) (group (regexp ,haskell-lexeme-id)))) "Regexp matching a valid qualified identifier. Note that (match-string 1) returns the unqualified part.") (defconst haskell-lexeme-qsym (rx-to-string `(: (regexp "'*") (regexp ,haskell-lexeme-modid-opt-prefix) (group (regexp ,haskell-lexeme-id)))) "Regexp matching a valid qualified symbol. Note that (match-string 1) returns the unqualified part.") (defconst haskell-lexeme-number (rx (| (: (regexp "[0-9]+\\.[0-9]+") (opt (regexp "[eE][-+]?[0-9]+"))) (regexp "[0-9]+[eE][-+]?[0-9]+") (regexp "0[xX][0-9a-fA-F]+") (regexp "0[oO][0-7]+") (regexp "[0-9]+"))) "Regexp matching a floating point, decimal, octal or hexadecimal number. Note that negative sign char is not part of a number.") (defconst haskell-lexeme-char-literal-inside (rx (| (not (any "\n'\\")) (: "\\" (| "a" "b" "f" "n" "r" "t" "v" "\\" "\"" "'" "NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL" "BS" "HT" "LF" "VT" "FF" "CR" "SO" "SI" "DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB" "CAN" "EM" "SUB" "ESC" "FS" "GS" "RS" "US" "SP" "DEL" (regexp "[0-9]+") (: "x" (regexp "[0-9a-fA-F]+")) (: "o" (regexp "[0-7]+")) (: "^" (regexp "[]A-Z@^_\\[]")))))) "Regexp matching an inside of a character literal. Note that `haskell-lexeme-char-literal-inside' matches strictly only escape sequences defined in Haskell Report.") (defconst haskell-lexeme--char-literal-rx (rx-to-string `(: (group "'") (| (: (group (regexp "[[:alpha:]_:([]")) (group "'")) ; exactly one char (: (group (| (regexp "\\\\[^\n][^'\n]*") ; allow quote just after first backslash (regexp "[^[:alpha:]_:(['\n][^'\n]*"))) (| (group "'") "\n" (regexp "\\'")))))) "Regexp matching a character literal lookalike. Note that `haskell-lexeme--char-literal-rx' matches more than Haskell Report specifies because we want to support also code under edit. Character literals end with a quote or a newline or end of buffer. Regexp has subgroup expressions: (match-text 1) matches the opening quote. (match-text 2) matches the inside of the character literal. (match-text 3) matches the closing quote or an empty string at the end of line or the end buffer.") (defun haskell-lexeme-looking-at-char-literal () "Non-nil when point is at a char literal lookalike. Note that this function matches more than Haskell Report specifies because we want to support also code under edit. Char literals end with a quote or an unescaped newline or end of buffer. After successful match: (match-text 1) matches the opening quote. (match-text 2) matches the inside of the char literla. (match-text 3) matches the closing quote, or a closing newline or is nil when at the end of the buffer." (when (looking-at haskell-lexeme--char-literal-rx) (set-match-data (list (match-beginning 0) (match-end 0) (match-beginning 1) (match-end 1) (or (match-beginning 2) (match-beginning 4)) (or (match-end 2) (match-end 4)) (or (match-beginning 3) (match-beginning 5)) (or (match-end 3) (match-end 5)))) t)) (defconst haskell-lexeme-string-literal-inside-item (rx (| (not (any "\n\"\\")) (: "\\" (| "a" "b" "f" "n" "r" "t" "v" "\\" "\"" "'" "&" "NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL" "BS" "HT" "LF" "VT" "FF" "CR" "SO" "SI" "DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB" "CAN" "EM" "SUB" "ESC" "FS" "GS" "RS" "US" "SP" "DEL" (regexp "[0-9]+") (: "x" (regexp "[0-9a-fA-F]+")) (: "o" (regexp "[0-7]+")) (: "^" (regexp "[]A-Z@^_\\[]")) (regexp "[ \t\n\r\v\f]*\\\\"))))) "Regexp matching an item that is a single character or a single escape sequence inside of a string literal. Note that `haskell-lexeme-string-literal-inside-item' matches strictly only escape sequences defined in Haskell Report.") (defconst haskell-lexeme-string-literal (rx (: (group "\"") (group (* (| (regexp "\\\\[ \t\n\r\v\f]*\\\\") (regexp "\\\\[ \t\n\r\v\f]+") (regexp "\\\\[^ \t\n\r\v\f]") (* (regexp "[^\"\n\\]"))))) (group (| "\"" (regexp "$") (regexp "\\\\?\\'") )))) "Regexp matching a string literal lookalike. Note that `haskell-lexeme-string-literal' matches more than Haskell Report specifies because we want to support also code under edit. String literals end with double quote or unescaped newline or end of buffer. Regexp has subgroup expressions: (match-text 1) matches the opening double quote. (match-text 2) matches the inside of the string. (match-text 3) matches the closing double quote or an empty string at the end of line or the end buffer.") (defun haskell-lexeme-looking-at-string-literal () "Non-nil when point is at a string literal lookalike. Note that this function matches more than Haskell Report specifies because we want to support also code under edit. String literals end with double quote or unescaped newline or end of buffer. After successful match: (match-text 1) matches the opening doublequote. (match-text 2) matches the inside of the string. (match-text 3) matches the closing quote, or a closing newline or is nil when at the end of the buffer." (when (looking-at "\"") (save-excursion (let ((begin (point))) (goto-char (match-end 0)) (let (finish) (while (and (not finish) (re-search-forward "[\"\n\\]" nil 'goto-eob)) (cond ((equal (match-string 0) "\\") (if (looking-at "[ \t\n\r\v\f]+\\\\?") (goto-char (match-end 0)) (goto-char (1+ (point))))) ((equal (match-string 0) "\"") (set-match-data (list begin (match-end 0) begin (1+ begin) (1+ begin) (match-beginning 0) (match-beginning 0) (match-end 0))) (setq finish t)) ((equal (match-string 0) "\n") (set-match-data (list begin (match-beginning 0) begin (1+ begin) (1+ begin) (match-beginning 0) nil nil)) (setq finish t)))) (unless finish ;; string closed by end of buffer (set-match-data (list begin (point) begin (1+ begin) (1+ begin) (point) nil nil)))))) ;; there was a match t)) (defun haskell-lexeme-looking-at-quasi-quote-literal () "Non-nil when point is just in front of Template Haskell quaisquote literal. Quasi quotes start with '[xxx|' or '[$xxx|' sequence and end with '|]'. The 'xxx' is a quoter name. There is no escaping mechanism provided for the ending sequence. Regexp has subgroup expressions: (match-text 1) matches the quoter name (without $ sign if present). (match-text 2) matches the opening vertical bar. (match-text 3) matches the inside of the quoted string. (match-text 4) matches the closing vertical bar or nil if at the end of the buffer. Note that this function excludes 'e', 't', 'd', 'p' as quoter names according to Template Haskell specification." (let ((match-data-old (match-data))) (if (and (looking-at (rx-to-string `(: "[" (optional "$") (group (regexp ,haskell-lexeme-id)) (group "|")))) (equal (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) 'varid) (not (member (match-string 1) '("e" "t" "d" "p")))) (save-excursion ;; note that quasi quote syntax does not have any escaping ;; mechanism and if not closed it will span til lthe end of buffer (goto-char (match-end 0)) (let ((match-data (match-data)) (match-data-2 (and (re-search-forward "|]" nil t) (match-data)))) (if match-data-2 (set-match-data (list (nth 0 match-data) (nth 1 match-data-2) ;; whole match (nth 2 match-data) (nth 3 match-data) ;; quoter name (nth 4 match-data) (nth 5 match-data) ;; opening bar (nth 5 match-data) (nth 0 match-data-2) ;; inner string (nth 0 match-data-2) (1+ (nth 0 match-data-2)))) ;; closing bar (set-match-data (list (nth 0 match-data) (point-max) ;; whole match (nth 2 match-data) (nth 3 match-data) ;; quoter name (nth 4 match-data) (nth 5 match-data) ;; opening bar (nth 5 match-data) (point-max) ;; inner string nil nil)) ;; closing bar )) t) ;; restore old match data if not matched (set-match-data match-data-old) nil))) (defun haskell-lexeme-classify-by-first-char (char) "Classify token by CHAR. CHAR is a chararacter that is assumed to be the first character of a token." (let ((category (get-char-code-property (or char ?\ ) 'general-category))) (cond ((or (member char '(?! ?# ?$ ?% ?& ?* ?+ ?. ?/ ?< ?= ?> ?? ?@ ?^ ?| ?~ ?\\ ?-)) (and (> char 127) (member category '(Pc Pd Po Sm Sc Sk So)))) 'varsym) ((equal char ?:) 'consym) ((equal char ?\') 'char) ((equal char ?\") 'string) ((member category '(Lu Lt)) 'conid) ((or (equal char ?_) (member category '(Ll Lo))) 'varid) ((and (>= char ?0) (<= char ?9)) 'number) ((member char '(?\] ?\[ ?\( ?\) ?\{ ?\} ?\` ?\, ?\;)) 'special)))) (defun haskell-lexeme-looking-at-token (&rest flags) "Like `looking-at' but understands Haskell lexemes. Moves point forward over whitespace. Returns a symbol describing type of Haskell token recognized. Use `match-string', `match-beginning' and `match-end' with argument 0 to query match result. Possible results are: - 'special: for chars [](){}`,; - 'comment: for single line comments - 'nested-comment: for multiline comments - 'qsymid: for qualified identifiers or symbols - 'string: for strings literals - 'char: for char literals - 'number: for decimal, float, hexadecimal and octal number literals - 'template-haskell-quote: for a string of apostrophes for template haskell - 'template-haskell-quasi-quote: for a string of apostrophes for template haskell Note that for qualified symbols (match-string 1) returns the unqualified identifier or symbol. Further qualification for symbol or identifier can be done with: (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) See `haskell-lexeme-classify-by-first-char' for details." (while ;; Due to how unterminated strings terminate at newline, some ;; newlines have syntax set to generic string delimeter. We want ;; those to be treated as whitespace anyway (or (> (skip-syntax-forward "-") 0) (and (not (member 'newline flags)) (> (skip-chars-forward "\n") 0)))) (let ((case-fold-search nil) (point (point-marker))) (or (and (equal (string-to-syntax "<") (get-char-property (point) 'syntax-table)) (progn (set-match-data (list point (set-marker (make-marker) (line-end-position)))) 'literate-comment)) (and (looking-at "\n") 'newline) (and (looking-at "{-") (save-excursion (forward-comment 1) (set-match-data (list point (point-marker))) 'nested-comment)) (and (haskell-lexeme-looking-at-char-literal) 'char) (and (haskell-lexeme-looking-at-string-literal) 'string) (and (looking-at "[][(){}`,;]") (if (haskell-lexeme-looking-at-quasi-quote-literal) 'template-haskell-quasi-quote 'special)) (and (haskell-lexeme-looking-at-qidsym) (if (save-match-data (string-match "\\`---*\\'" (match-string-no-properties 0))) (progn (set-match-data (list point (set-marker (make-marker) (line-end-position)))) 'comment) 'qsymid)) (and (looking-at haskell-lexeme-number) 'number) (and (looking-at "'+") 'template-haskell-quote) (and (looking-at ".") 'illegal)))) (provide 'haskell-lexeme) ;;; haskell-lexeme.el ends here ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-load.el�������������������������������������������������������������������0000664�0000000�0000000�00000066136�13602233217�0016704�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-load.el --- Compiling and loading modules in the GHCi process -*- lexical-binding: t -*- ;; Copyright © 2014 Chris Done. All rights reserved. ;; 2016 Arthur Fayzrakhmanov ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;;; Code: (require 'cl-lib) (require 'haskell-mode) (require 'haskell-process) (require 'haskell-interactive-mode) (require 'haskell-modules) (require 'haskell-commands) (require 'haskell-session) (require 'haskell-string) (defun haskell-process-look-config-changes (session) "Check whether a cabal configuration file has changed. Restarts the SESSION's process if that is the case." (let ((current-checksum (haskell-session-get session 'cabal-checksum)) (new-checksum (haskell-cabal-compute-checksum (haskell-session-get session 'cabal-dir)))) (when (not (string= current-checksum new-checksum)) (haskell-interactive-mode-echo session (format "Cabal file changed: %s" new-checksum)) (haskell-session-set-cabal-checksum session (haskell-session-get session 'cabal-dir)) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (unless (and haskell-process-prompt-restart-on-cabal-change (not (y-or-n-p "Cabal file changed. Restart GHCi process? "))) (haskell-process-start (haskell-interactive-session))) (haskell-mode-toggle-interactive-prompt-state t))))) (defun haskell-process-live-build (process buffer echo-in-repl) "Show live updates for loading files." (cond ((haskell-process-consume process (concat "\\[[ ]*\\([0-9]+\\) of \\([0-9]+\\)\\]" " Compiling \\([^ ]+\\)[ ]+" "( \\([^ ]+\\), \\([^ ]+\\) )[^\r\n]*[\r\n]+")) (haskell-process-echo-load-message process buffer echo-in-repl nil) t) ((haskell-process-consume process (concat "\\[[ ]*\\([0-9]+\\) of \\([0-9]+\\)\\]" " Compiling \\[TH\\] \\([^ ]+\\)[ ]+" "( \\([^ ]+\\), \\([^ ]+\\) )[^\r\n]*[\r\n]+")) (haskell-process-echo-load-message process buffer echo-in-repl t) t) ((haskell-process-consume process "Loading package \\([^ ]+\\) ... linking ... done.\n") (haskell-mode-message-line (format "Loading: %s" (match-string 1 buffer))) t) ((haskell-process-consume process "^Preprocessing executables for \\(.+?\\)\\.\\.\\.") (let ((msg (format "Preprocessing: %s" (match-string 1 buffer)))) (haskell-interactive-mode-echo (haskell-process-session process) msg) (haskell-mode-message-line msg))) ((haskell-process-consume process "Linking \\(.+?\\) \\.\\.\\.") (let ((msg (format "Linking: %s" (match-string 1 buffer)))) (haskell-interactive-mode-echo (haskell-process-session process) msg) (haskell-mode-message-line msg))) ((haskell-process-consume process "\nBuilding \\(.+?\\)\\.\\.\\.") (let ((msg (format "Building: %s" (match-string 1 buffer)))) (haskell-interactive-mode-echo (haskell-process-session process) msg) (haskell-mode-message-line msg))) ((string-match "Collecting type info for [[:digit:]]+ module(s) \\.\\.\\." (haskell-process-response process) (haskell-process-response-cursor process)) (haskell-mode-message-line (match-string 0 buffer)) ;; Do not consume "Ok, modules loaded" that goes before ;; "Collecting type info...", just exit. nil))) (defun haskell-process-load-complete (session process buffer reload module-buffer &optional cont) "Handle the complete loading response. BUFFER is the string of text being sent over the process pipe. MODULE-BUFFER is the actual Emacs buffer of the module being loaded." (when (get-buffer (format "*%s:splices*" (haskell-session-name session))) (with-current-buffer (haskell-interactive-mode-splices-buffer session) (erase-buffer))) (let* ((ok (cond ((haskell-process-consume process "Ok, \\(?:[0-9]+\\) modules? loaded\\.$") t) ((haskell-process-consume process "Ok, \\(?:[a-z]+\\) modules? loaded\\.$") ;; for ghc 8.4 t) ((haskell-process-consume process "Failed, \\(?:[0-9]+\\) modules? loaded\\.$") nil) ((haskell-process-consume process "Failed, \\(?:[a-z]+\\) modules? loaded\\.$") ;; ghc 8.6.3 says so nil) ((haskell-process-consume process "Ok, modules loaded: \\(.+\\)\\.$") t) ((haskell-process-consume process "Failed, modules loaded: \\(.+\\)\\.$") nil) ((haskell-process-consume process "Failed, no modules loaded\\.$") ;; for ghc 8.4 nil) (t (error (message "Unexpected response from haskell process."))))) (modules (haskell-process-extract-modules buffer)) (cursor (haskell-process-response-cursor process)) (warning-count 0)) (haskell-process-set-response-cursor process 0) (haskell-check-remove-overlays module-buffer) (while (haskell-process-errors-warnings module-buffer session process buffer) (setq warning-count (1+ warning-count))) (haskell-process-set-response-cursor process cursor) (if (and (not reload) haskell-process-reload-with-fbytecode) (haskell-process-reload-with-fbytecode process module-buffer) (haskell-process-import-modules process (car modules))) (if ok (haskell-mode-message-line (if reload "Reloaded OK." "OK.")) (haskell-interactive-mode-compile-error session "Compilation failed.")) (when cont (condition-case-unless-debug e (funcall cont ok) (error (message "%S" e)) (quit nil))))) (defun haskell-process-suggest-imports (session file modules ident) "Suggest add missed imports to file. Asks user to add to SESSION's FILE missed import. MODULES is a list of modules where missed IDENT was found." (cl-assert session) (cl-assert file) (cl-assert ident) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (let* ((process (haskell-session-process session)) (suggested-already (haskell-process-suggested-imports process)) (module (cond ((> (length modules) 1) (when (y-or-n-p (format "Identifier `%s' not in scope, choose module to import?" ident)) (haskell-complete-module-read "Module: " modules))) ((= (length modules) 1) (let ((module (car modules))) (unless (member module suggested-already) (haskell-process-set-suggested-imports process (cons module suggested-already)) (when (y-or-n-p (format "Identifier `%s' not in scope, import `%s'?" ident module)) module))))))) (when module (haskell-process-find-file session file) (haskell-add-import module))) (haskell-mode-toggle-interactive-prompt-state t))) (defun haskell-process-trigger-suggestions (session msg file line) "Trigger prompting to add any extension suggestions." (cond ((let ((case-fold-search nil)) (or (and (string-match " -X\\([A-Z][A-Za-z]+\\)" msg) (not (string-match "\\([A-Z][A-Za-z]+\\) is deprecated" msg))) (string-match "Use \\([A-Z][A-Za-z]+\\) to permit this" msg) (string-match "Use \\([A-Z][A-Za-z]+\\) to allow" msg) (string-match "Use \\([A-Z][A-Za-z]+\\) to enable" msg) (string-match "Use \\([A-Z][A-Za-z]+\\) if you want to disable this" msg) (string-match "use \\([A-Z][A-Za-z]+\\)" msg) (string-match "You need \\([A-Z][A-Za-z]+\\)" msg))) (when haskell-process-suggest-language-pragmas (haskell-process-suggest-pragma session "LANGUAGE" (match-string 1 msg) file))) ((string-match " The \\(qualified \\)?import of[ ][‘`‛]\\([^ ]+\\)['’] is redundant" msg) (when haskell-process-suggest-remove-import-lines (haskell-process-suggest-remove-import session file (match-string 2 msg) line))) ((string-match "[Ww]arning: orphan instance: " msg) (when haskell-process-suggest-no-warn-orphans (haskell-process-suggest-pragma session "OPTIONS" "-fno-warn-orphans" file))) ((or (string-match "against inferred type [‘`‛]\\[Char\\]['’]" msg) (string-match "with actual type [‘`‛]\\[Char\\]['’]" msg)) (when haskell-process-suggest-overloaded-strings (haskell-process-suggest-pragma session "LANGUAGE" "OverloadedStrings" file))) ((string-match "^Not in scope: .*[‘`‛]\\(.+\\)['’]$" msg) (let* ((match1 (match-string 1 msg)) (ident (if (string-match "^[A-Za-z0-9_'.]+\\.\\(.+\\)$" match1) ;; Skip qualification. (match-string 1 match1) match1))) (when haskell-process-suggest-hoogle-imports (let ((modules (haskell-process-hoogle-ident ident))) (haskell-process-suggest-imports session file modules ident))) (when haskell-process-suggest-haskell-docs-imports (let ((modules (haskell-process-haskell-docs-ident ident))) (haskell-process-suggest-imports session file modules ident))) (when haskell-process-suggest-hayoo-imports (let ((modules (haskell-process-hayoo-ident ident))) (haskell-process-suggest-imports session file modules ident))))) ((string-match "^[ ]+It is a member of the hidden package [‘`‛]\\([^@\r\n]+\\).*['’].$" msg) (when haskell-process-suggest-add-package (haskell-process-suggest-add-package session msg))))) (defun haskell-process-do-cabal (command) "Run a Cabal command." (let ((process (ignore-errors (haskell-interactive-process)))) (cond ((or (eq process nil) (let ((child (haskell-process-process process))) (not (equal 'run (process-status child))))) (message "Process is not running, so running directly.") (shell-command (concat "cabal " command) (get-buffer-create "*haskell-process-log*") (get-buffer-create "*haskell-process-log*")) (switch-to-buffer-other-window (get-buffer "*haskell-process-log*"))) (t (haskell-process-queue-command process (make-haskell-command :state (list (haskell-interactive-session) process command 0) :go (lambda (state) (haskell-process-send-string (cadr state) (format haskell-process-do-cabal-format-string (haskell-session-cabal-dir (car state)) (format "%s %s" (cl-ecase (haskell-process-type) ('ghci haskell-process-path-cabal) ('cabal-repl haskell-process-path-cabal) ('cabal-new-repl haskell-process-path-cabal) ('cabal-ghci haskell-process-path-cabal) ('stack-ghci haskell-process-path-stack)) (cl-caddr state))))) :live (lambda (state buffer) (let ((cmd (replace-regexp-in-string "^\\([a-z]+\\).*" "\\1" (cl-caddr state)))) (cond ((or (string= cmd "build") (string= cmd "install")) (haskell-process-live-build (cadr state) buffer t)) (t (haskell-process-cabal-live state buffer))))) :complete (lambda (state response) (let* ((process (cadr state)) (session (haskell-process-session process)) (message-count 0) (cursor (haskell-process-response-cursor process))) ;; XXX: what the hell about the rampant code duplication? (haskell-process-set-response-cursor process 0) (while (haskell-process-errors-warnings nil session process response) (setq message-count (1+ message-count))) (haskell-process-set-response-cursor process cursor) (let ((msg (format "Complete: cabal %s (%s compiler messages)" (cl-caddr state) message-count))) (haskell-interactive-mode-echo session msg) (when (= message-count 0) (haskell-interactive-mode-echo session "No compiler messages, dumping complete output:") (haskell-interactive-mode-echo session response)) (haskell-mode-message-line msg) (when (and haskell-notify-p (fboundp 'notifications-notify)) (notifications-notify :title (format "*%s*" (haskell-session-name (car state))) :body msg :app-name (cl-ecase (haskell-process-type) ('ghci haskell-process-path-cabal) ('cabal-repl haskell-process-path-cabal) ('cabal-new-repl haskell-process-path-cabal) ('cabal-ghci haskell-process-path-cabal) ('stack-ghci haskell-process-path-stack)) :app-icon haskell-process-logo))))))))))) (defun haskell-process-echo-load-message (process buffer echo-in-repl th) "Echo a load message." (let ((session (haskell-process-session process)) (module-name (match-string 3 buffer)) (file-name (match-string 4 buffer))) (haskell-interactive-show-load-message session 'compiling module-name (haskell-session-strip-dir session file-name) echo-in-repl th))) (defun haskell-process-extract-modules (buffer) "Extract the modules from the process buffer." (let* ((modules-string (match-string 1 buffer)) (modules (and modules-string (split-string modules-string ", ")))) (cons modules modules-string))) ;;;###autoload (defface haskell-error-face '((((supports :underline (:style wave))) :underline (:style wave :color "#dc322f")) (t :inherit error)) "Face used for marking error lines." :group 'haskell-mode) ;;;###autoload (defface haskell-warning-face '((((supports :underline (:style wave))) :underline (:style wave :color "#b58900")) (t :inherit warning)) "Face used for marking warning lines." :group 'haskell-mode) ;;;###autoload (defface haskell-hole-face '((((supports :underline (:style wave))) :underline (:style wave :color "#6c71c4")) (t :inherit warning)) "Face used for marking hole lines." :group 'haskell-mode) (defvar haskell-check-error-fringe (propertize "!" 'display '(left-fringe exclamation-mark))) (defvar haskell-check-warning-fringe (propertize "?" 'display '(left-fringe question-mark))) (defvar haskell-check-hole-fringe (propertize "_" 'display '(left-fringe horizontal-bar))) (defun haskell-check-overlay-p (ovl) (overlay-get ovl 'haskell-check)) (defun haskell-check-filter-overlays (xs) (cl-remove-if-not 'haskell-check-overlay-p xs)) (defun haskell-check-remove-overlays (buffer) (with-current-buffer buffer (remove-overlays (point-min) (point-max) 'haskell-check t))) (defmacro haskell-with-overlay-properties (proplist ovl &rest body) "Evaluate BODY with names in PROPLIST bound to the values of correspondingly-named overlay properties of OVL." (let ((ovlvar (cl-gensym "OVL-"))) `(let* ((,ovlvar ,ovl) ,@(mapcar (lambda (p) `(,p (overlay-get ,ovlvar ',p))) proplist)) ,@body))) (defun haskell-overlay-start> (o1 o2) (> (overlay-start o1) (overlay-start o2))) (defun haskell-overlay-start< (o1 o2) (< (overlay-start o1) (overlay-start o2))) (defun haskell-first-overlay-in-if (test beg end) (let ((ovls (cl-remove-if-not test (overlays-in beg end)))) (cl-first (sort (cl-copy-list ovls) 'haskell-overlay-start<)))) (defun haskell-last-overlay-in-if (test beg end) (let ((ovls (cl-remove-if-not test (overlays-in beg end)))) (cl-first (sort (cl-copy-list ovls) 'haskell-overlay-start>)))) (defun haskell-error-overlay-briefly (ovl) (haskell-with-overlay-properties (haskell-msg haskell-msg-type) ovl (cond ((not (eq haskell-msg-type 'warning)) haskell-msg) ((string-prefix-p "[Ww]arning:\n " haskell-msg) (cl-subseq haskell-msg 13)) (t (error "Invariant failed: a warning message from GHC has unexpected form: %s." haskell-msg))))) (defun haskell-goto-error-overlay (ovl) (cond (ovl (goto-char (overlay-start ovl)) (haskell-mode-message-line (haskell-error-overlay-briefly ovl))) (t (message "No further notes from Haskell compiler.")))) (defun haskell-goto-first-error () (interactive) (haskell-goto-error-overlay (haskell-first-overlay-in-if 'haskell-check-overlay-p (buffer-end 0) (buffer-end 1)))) (defun haskell-goto-prev-error () (interactive) (haskell-goto-error-overlay (let ((ovl-at (cl-first (haskell-check-filter-overlays (overlays-at (point)))))) (or (haskell-last-overlay-in-if 'haskell-check-overlay-p (point-min) (if ovl-at (overlay-start ovl-at) (point))) ovl-at)))) (defun haskell-goto-next-error () (interactive) (haskell-goto-error-overlay (let ((ovl-at (cl-first (haskell-check-filter-overlays (overlays-at (point)))))) (or (haskell-first-overlay-in-if 'haskell-check-overlay-p (if ovl-at (overlay-end ovl-at) (point)) (point-max)) ovl-at)))) (defun haskell-check-paint-overlay (buffer error-from-this-file-p line msg file type hole coln) (with-current-buffer buffer (let (beg end) (goto-char (point-min)) ;; XXX: we can avoid excess buffer walking by relying on the maybe-fact ;; that GHC sorts error messages by line number, maybe. (cond (error-from-this-file-p (forward-line (1- line)) (forward-char (1- coln)) (setq beg (point)) (if (eq type 'hole) (forward-char (length hole)) (skip-chars-forward "^[:space:]" (line-end-position))) (setq end (point))) (t (setq beg (point)) (forward-line) (setq end (point)))) (let ((ovl (make-overlay beg end))) (overlay-put ovl 'haskell-check t) (overlay-put ovl 'haskell-file file) (overlay-put ovl 'haskell-msg msg) (overlay-put ovl 'haskell-msg-type type) (overlay-put ovl 'help-echo msg) (overlay-put ovl 'haskell-hole hole) (cl-destructuring-bind (face fringe) (cl-case type (warning (list 'haskell-warning-face haskell-check-warning-fringe)) (hole (list 'haskell-hole-face haskell-check-hole-fringe)) (error (list 'haskell-error-face haskell-check-error-fringe))) (overlay-put ovl 'before-string fringe) (overlay-put ovl 'face face)))))) (defun haskell-process-errors-warnings (module-buffer session process buffer &optional return-only) "Trigger handling type errors or warnings. Either prints the messages in the interactive buffer or if CONT is specified, passes the error onto that. When MODULE-BUFFER is non-NIL, paint error overlays." (save-excursion (cond ((haskell-process-consume process "\\(Module imports form a cycle:[ \n]+module [^ ]+ ([^)]+)[[:unibyte:][:nonascii:]]+?\\)\nFailed") (let ((err (match-string 1 buffer))) (if (string-match "module [`'‘‛]\\([^ ]+\\)['’`] (\\([^)]+\\))" err) (let* ((default-directory (haskell-session-current-dir session)) (module (match-string 1 err)) (file (match-string 2 err)) (relative-file-name (file-relative-name file))) (unless return-only (haskell-interactive-show-load-message session 'import-cycle module relative-file-name nil nil) (haskell-interactive-mode-compile-error session (format "%s:1:0: %s" relative-file-name err))) (list :file file :line 1 :col 0 :msg err :type 'error)) t))) ((haskell-process-consume process (concat "[\r\n]\\([A-Z]?:?[^ \r\n:][^:\n\r]+\\):\\([0-9()-:]+\\):" "[ \n\r]+\\([[:unibyte:][:nonascii:]]+?\\)\n[^ ]")) (haskell-process-set-response-cursor process (- (haskell-process-response-cursor process) 1)) (let* ((buffer (haskell-process-response process)) (file (match-string 1 buffer)) (location-raw (match-string 2 buffer)) (error-msg (match-string 3 buffer)) (type (cond ((string-match "^[Ww]arning:" error-msg) 'warning) ((string-match "^Splicing " error-msg) 'splice) (t 'error))) (critical (not (eq type 'warning))) ;; XXX: extract hole information, pass down to ;; `haskell-check-paint-overlay' (final-msg (format "%s:%s: %s" (haskell-session-strip-dir session file) location-raw error-msg)) (location (haskell-process-parse-error (concat file ":" location-raw ": x"))) (line (plist-get location :line)) (col1 (plist-get location :col))) (when (and module-buffer haskell-process-show-overlays) (haskell-check-paint-overlay module-buffer (string= (file-truename (buffer-file-name module-buffer)) (file-truename file)) line error-msg file type nil col1)) (if return-only (list :file file :line line :col col1 :msg error-msg :type type) (progn (funcall (cl-case type (warning 'haskell-interactive-mode-compile-warning) (splice 'haskell-interactive-mode-compile-splice) (error 'haskell-interactive-mode-compile-error)) session final-msg) (when critical (haskell-mode-message-line final-msg)) (haskell-process-trigger-suggestions session error-msg file line) t))))))) (defun haskell-interactive-show-load-message (session type module-name file-name echo th) "Show the '(Compiling|Loading) X' message." (let ((msg (concat (cl-ecase type ('compiling (if haskell-interactive-mode-include-file-name (format "Compiling: %s (%s)" module-name file-name) (format "Compiling: %s" module-name))) ('loading (format "Loading: %s" module-name)) ('import-cycle (format "Module has an import cycle: %s" module-name))) (if th " [TH]" "")))) (haskell-mode-message-line msg) (when haskell-interactive-mode-delete-superseded-errors (haskell-interactive-mode-delete-compile-messages session file-name)) (when echo (haskell-interactive-mode-echo session msg)))) ;;;###autoload (defun haskell-process-reload-devel-main () "Reload the module `DevelMain' and then run `DevelMain.update'. This is for doing live update of the code of servers or GUI applications. Put your development version of the program in `DevelMain', and define `update' to auto-start the program on a new thread, and use the `foreign-store' package to access the running context across :load/:reloads in GHCi." (interactive) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (with-current-buffer (or (get-buffer "DevelMain.hs") (if (y-or-n-p "You need to open a buffer named DevelMain.hs. Find now?") (ido-find-file) (error "No DevelMain.hs buffer."))) (let ((session (haskell-interactive-session))) (let ((process (haskell-interactive-process))) (haskell-process-queue-command process (make-haskell-command :state (list :session session :process process :buffer (current-buffer)) :go (lambda (state) (haskell-process-send-string (plist-get state ':process) ":l DevelMain")) :live (lambda (state buffer) (haskell-process-live-build (plist-get state ':process) buffer nil)) :complete (lambda (state response) (haskell-process-load-complete (plist-get state ':session) (plist-get state ':process) response nil (plist-get state ':buffer) (lambda (ok) (when ok (haskell-process-queue-without-filters (haskell-interactive-process) "DevelMain.update") (message "DevelMain updated.")))))))))) (haskell-mode-toggle-interactive-prompt-state t))) (provide 'haskell-load) ;;; haskell-load.el ends here ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-menu.el�������������������������������������������������������������������0000664�0000000�0000000�00000014634�13602233217�0016725�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-menu.el --- A Haskell sessions menu -*- lexical-binding: t -*- ;; Copyright (C) 2013 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;;; Todo: ;;; Code: (require 'cl-lib) (require 'haskell-session) (require 'haskell-process) (require 'haskell-interactive-mode) (defcustom haskell-menu-buffer-name "*haskell-menu*" "The name of the Haskell session menu buffer" :group 'haskell-interactive :type 'string) ;;;###autoload (defun haskell-menu () "Launch the Haskell sessions menu." (interactive) (or (get-buffer haskell-menu-buffer-name) (with-current-buffer (get-buffer-create haskell-menu-buffer-name) (haskell-menu-mode))) (switch-to-buffer-other-window (get-buffer haskell-menu-buffer-name)) (haskell-menu-revert-function nil nil)) (defvar haskell-menu-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "n") 'next-line) (define-key map (kbd "p") 'previous-line) (define-key map (kbd "RET") 'haskell-menu-mode-ret) map) "Keymap for `haskell-menu-mode'.") (define-derived-mode haskell-menu-mode special-mode "Haskell Session Menu" "Major mode for managing Haskell sessions. Each line describes one session. Letters do not insert themselves; instead, they are commands." (setq buffer-read-only t) (setq-local revert-buffer-function 'haskell-menu-revert-function) (setq truncate-lines t) (haskell-menu-revert-function nil t)) (suppress-keymap haskell-menu-mode-map t) (defun haskell-menu-revert-function (_arg1 _arg2) "Function to refresh the display." (let ((buffer-read-only nil) (orig-line (line-number-at-pos)) (orig-col (current-column))) (or (eq buffer-undo-list t) (setq buffer-undo-list nil)) (erase-buffer) (haskell-menu-insert-menu) (goto-char (point-min)) (forward-line (1- orig-line)) (forward-char orig-col))) (defun haskell-menu-insert-menu () "Insert the Haskell sessions menu to the current buffer." (if (null haskell-sessions) (insert "No Haskell sessions.") (haskell-menu-tabulate (list "Name" "PID" "Time" "RSS" "Cabal directory" "Working directory" "Command") (mapcar (lambda (session) (let ((process (haskell-process-process (haskell-session-process session)))) (cond (process (let ((id (process-id process))) (list (propertize (haskell-session-name session) 'face 'buffer-menu-buffer) (if (process-live-p process) (number-to-string id) "-") (if (process-live-p process) (format-time-string "%H:%M:%S" (encode-time (cl-caddr (assoc 'etime (process-attributes id))) 0 0 0 0 0)) "-") (if (process-live-p process) (concat (number-to-string (/ (cdr (assoc 'rss (process-attributes id))) 1024)) "MB") "-") (haskell-session-cabal-dir session) (haskell-session-current-dir session) (mapconcat 'identity (process-command process) " ")))) (t (list (propertize (haskell-session-name session) 'face 'buffer-menu-buffer) "—" "—" "—" (haskell-session-cabal-dir session) (haskell-session-current-dir session)))))) haskell-sessions)))) (defun haskell-menu-tabulate (headings rows) "Prints a list of lists as a formatted table to the current buffer." (let* ((columns (length headings)) (widths (make-list columns 0))) ;; Calculate column widths. This is kind of hideous. (dolist (row rows) (setq widths (let ((list (list))) (dotimes (i columns) (setq list (cons (max (nth i widths) (1+ (length (nth i row))) (1+ (length (nth i headings)))) list))) (reverse list)))) ;; Print headings. (let ((heading (propertize " " 'display '(space :align-to 0)))) (dotimes (i columns) (setq heading (concat heading (format (concat "%-" (number-to-string (nth i widths)) "s") (nth i headings))))) (setq header-line-format heading)) ;; Print tabulated rows. (dolist (row rows) (dotimes (i columns) (insert (format (concat "%-" (number-to-string (nth i widths)) "s") (nth i row)))) (insert "\n")))) (defun haskell-menu-mode-ret () "Handle RET key." (interactive) (let* ((name (save-excursion (goto-char (line-beginning-position)) (buffer-substring-no-properties (point) (progn (search-forward " ") (forward-char -1) (point))))) (session (car (cl-remove-if-not (lambda (session) (string= (haskell-session-name session) name)) haskell-sessions)))) (switch-to-buffer (haskell-session-interactive-buffer session)))) (provide 'haskell-menu) ;;; haskell-menu.el ends here ����������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-mode-pkg.el���������������������������������������������������������������0000664�0000000�0000000�00000000345�13602233217�0017456�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������(define-package "haskell-mode" "17.1" "A Haskell editing mode" '((emacs "25.1")) :url "https://github.com/haskell/haskell-mode" :keywords '("haskell" "cabal" "ghc" "repl")) ;; Local Variables: ;; no-byte-compile: t ;; End: �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-mode.el�������������������������������������������������������������������0000664�0000000�0000000�00000151355�13602233217�0016707�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-mode.el --- A Haskell editing mode -*- coding: utf-8; lexical-binding: t -*- ;; Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2016 ;; Free Software Foundation, Inc ;; Copyright © 1992, 1997-1998 Simon Marlow, Graeme E Moss, and Tommy Thorn ;; Author: 1992 Simon Marlow ;; 1997-1998 Graeme E Moss <gem@cs.york.ac.uk> and ;; Tommy Thorn <thorn@irisa.fr>, ;; 2001-2002 Reuben Thomas (>=v1.4) ;; 2003 Dave Love <fx@gnu.org> ;; 2016 Arthur Fayzrakhmanov ;; Keywords: faces files Haskell ;; URL: https://github.com/haskell/haskell-mode ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; A major mode for editing Haskell (the functional programming ;; language, see URL `http://www.haskell.org') in Emacs. ;; ;; Some of its major features include: ;; ;; - syntax highlighting (font lock), ;; ;; - automatic indentation, ;; ;; - on-the-fly documentation, ;; ;; - interaction with inferior GHCi/Hugs instance, ;; ;; - scans declarations and places them in a menu. ;; ;; See URL `https://github.com/haskell/haskell-mode' and/or ;; Info node `(haskell-mode)Introduction' for more information. ;; ;; Use `M-x haskell-mode-view-news` (after Haskell Mode is installed) ;; to show information on recent changes in Haskell Mode. ;;; Change Log: ;; This mode is based on an editing mode by Simon Marlow 11/1/92 ;; and heavily modified by Graeme E Moss and Tommy Thorn 7/11/98. ;; ;; Version 1.5: ;; Added autoload for haskell-indentation ;; ;; Version 1.43: ;; Various tweaks to doc strings and customization support from ;; Ville Skyttä <scop@xemacs.org>. ;; ;; Version 1.42: ;; Added autoload for GHCi inferior mode (thanks to Scott ;; Williams for the bug report and fix). ;; ;; Version 1.41: ;; Improved packaging, and made a couple more variables ;; interactively settable. ;; ;; Version 1.4: ;; Added GHCi mode from Chris Webb, and tidied up a little. ;; ;; Version 1.3: ;; The literate or non-literate style of a buffer is now indicated ;; by just the variable haskell-literate: nil, `bird', or `tex'. ;; For literate buffers with ambiguous style, the value of ;; haskell-literate-default is used. ;; ;; Version 1.2: ;; Separated off font locking, declaration scanning and simple ;; indentation, and made them separate modules. Modules can be ;; added easily now. Support for modules haskell-doc, ;; haskell-indent, and haskell-hugs. Literate and non-literate ;; modes integrated into one mode, and literate buffer indicated by ;; value of haskell-literate(-bird-style). ;; ;; Version 1.1: ;; Added support for declaration scanning under XEmacs via ;; func-menu. Moved operators to level two fontification. ;; ;; Version 1.0: ;; Added a nice indention support from Heribert Schuetz ;; <Heribert.Schuetz@informatik.uni-muenchen.de>: ;; ;; I have just hacked an Emacs Lisp function which you might prefer ;; to `indent-relative' in haskell-mode.el. See below. It is not ;; really Haskell-specific because it does not take into account ;; keywords like `do', `of', and `let' (where the layout rule ;; applies), but I already find it useful. ;; ;; Cleaned up the imenu support. Added support for literate scripts. ;; ;; Version 0.103 [HWL]: ;; From Hans Wolfgang Loidl <hwloidl@dcs.gla.ac.uk>: ;; ;; I (HWL) added imenu support by copying the appropriate functions ;; from hugs-mode. A menu-bar item "Declarations" is now added in ;; haskell mode. The new code, however, needs some clean-up. ;; ;; Version 0.102: ;; ;; Moved C-c C-c key binding to comment-region. Leave M-g M-g to do ;; the work. comment-start-skip is changed to comply with comment-start. ;; ;; Version 0.101: ;; ;; Altered indent-line-function to indent-relative. ;; ;; Version 0.100: ;; ;; First official release. ;;; Code: (require 'haskell-customize) (require 'ansi-color) (require 'dabbrev) (require 'compile) (require 'etags) (require 'flymake) (require 'outline) (require 'cl-lib) (require 'haskell-ghc-support) (require 'haskell-complete-module) (require 'haskell-align-imports) (require 'haskell-lexeme) (require 'haskell-sort-imports) (require 'haskell-string) (require 'haskell-indentation) (require 'haskell-font-lock) (require 'haskell-cabal) ;; All functions/variables start with `(literate-)haskell-'. ;; Version of mode. (defconst haskell-version "16.2-git" "The release version of `haskell-mode'.") ;;;###autoload (defun haskell-version (&optional here) "Show the `haskell-mode` version in the echo area. With prefix argument HERE, insert it at point." (interactive "P") (let* ((haskell-mode-dir (ignore-errors (file-name-directory (or (locate-library "haskell-mode") "")))) (version (format "haskell-mode version %s (%s)" haskell-version haskell-mode-dir))) (if here (insert version) (message "%s" version)))) ;;;###autoload (defun haskell-mode-view-news () "Display information on recent changes to haskell-mode." (interactive) (with-current-buffer (find-file-read-only (expand-file-name "NEWS" haskell-mode-pkg-base-dir)) (goto-char (point-min)) (outline-hide-sublevels 1) (outline-next-visible-heading 1) (outline-show-subtree))) ;; Are we looking at a literate script? (defvar-local haskell-literate nil "If not nil, the current buffer contains a literate Haskell script. Possible values are: `bird' and `tex', for Bird-style and LaTeX-style literate scripts respectively. Set by `haskell-mode' and `literate-haskell-mode'. For an ambiguous literate buffer -- i.e. does not contain either \"\\begin{code}\" or \"\\end{code}\" on a line on its own, nor does it contain \">\" at the start of a line -- the value of `haskell-literate-default' is used.") (put 'haskell-literate 'safe-local-variable 'symbolp) ;; Default literate style for ambiguous literate buffers. (defcustom haskell-literate-default 'bird "Default value for `haskell-literate'. Used if the style of a literate buffer is ambiguous. This variable should be set to the preferred literate style." :group 'haskell :type '(choice (const bird) (const tex) (const nil))) (defvar haskell-mode-map (let ((map (make-sparse-keymap))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Editing-specific commands (define-key map (kbd "C-c C-,") 'haskell-mode-format-imports) (define-key map [remap delete-indentation] 'haskell-delete-indentation) (define-key map (kbd "C-c C-l") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-b") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-v") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-t") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-i") 'haskell-mode-enable-process-minor-mode) (define-key map (kbd "C-c C-s") 'haskell-mode-toggle-scc-at-point) map) "Keymap used in `haskell-mode'.") (defun haskell-mode-enable-process-minor-mode () "Tell the user to choose a minor mode for process interaction." (interactive) (error "Run `C-h f haskell-mode` for instruction how to setup a Haskell interaction mode.")) (easy-menu-define haskell-mode-menu haskell-mode-map "Menu for the Haskell major mode." ;; Suggestions from Pupeno <pupeno@pupeno.com>: ;; - choose the underlying interpreter ;; - look up docs `("Haskell" ["Indent line" indent-according-to-mode] ["(Un)Comment region" comment-region mark-active] "---" ["Start interpreter" haskell-interactive-switch] ["Load file" haskell-process-load-file] "---" ["Load tidy core" ghc-core-create-core] "---" ,(if (default-boundp 'eldoc-documentation-function) ["Doc mode" eldoc-mode :style toggle :selected (bound-and-true-p eldoc-mode)] ["Doc mode" haskell-doc-mode :style toggle :selected (and (boundp 'haskell-doc-mode) haskell-doc-mode)]) ["Customize" (customize-group 'haskell)] )) ;; Procedurally generated (see Lexeme.hs in ghc). ;; This is a bit unsightly: it's generated by making a list of all ;; unicode characters whose Unicode general category ghc would ;; recognize as valid symbol (or identifier, below) constituent. (defvar haskell--char-syntax-symbols '((161 . 169) 172 (174 . 177) 180 (182 . 184) 191 215 247 (706 . 709) (722 . 735) (741 . 747) 749 (751 . 767) 885 894 (900 . 901) 903 1014 1154 (1370 . 1375) (1417 . 1418) (1421 . 1423) 1470 1472 1475 1478 (1523 . 1524) (1542 . 1551) 1563 (1566 . 1567) (1642 . 1645) 1748 1758 1769 (1789 . 1790) (1792 . 1805) (2038 . 2041) (2096 . 2110) 2142 (2404 . 2405) 2416 (2546 . 2547) (2554 . 2555) (2800 . 2801) 2928 (3059 . 3066) 3199 3449 3572 3647 3663 (3674 . 3675) (3841 . 3863) (3866 . 3871) 3892 3894 3896 3973 (4030 . 4037) (4039 . 4044) (4046 . 4058) (4170 . 4175) (4254 . 4255) 4347 (4960 . 4968) (5008 . 5017) 5120 (5741 . 5742) (5867 . 5869) (5941 . 5942) (6100 . 6102) (6104 . 6107) (6144 . 6154) 6464 (6468 . 6469) (6622 . 6623) (6624 . 6655) (6686 . 6687) (6816 . 6822) (6824 . 6829) (7002 . 7018) (7028 . 7036) (7164 . 7167) (7227 . 7231) (7294 . 7295) (7360 . 7367) 7379 8125 (8127 . 8129) (8141 . 8143) (8157 . 8159) (8173 . 8175) (8189 . 8190) (8208 . 8215) (8224 . 8231) (8240 . 8248) (8251 . 8260) (8263 . 8286) (8314 . 8316) (8330 . 8332) (8352 . 8381) (8448 . 8449) (8451 . 8454) (8456 . 8457) 8468 (8470 . 8472) (8478 . 8483) 8485 8487 8489 8494 (8506 . 8507) (8512 . 8516) (8522 . 8525) 8527 (8592 . 8703) (8704 . 8959) (8960 . 8967) (8972 . 9000) (9003 . 9210) (9216 . 9254) (9280 . 9290) (9372 . 9449) (9472 . 9599) (9600 . 9631) (9632 . 9727) (9728 . 9983) (9984 . 10087) (10132 . 10175) (10176 . 10180) (10183 . 10213) (10224 . 10239) (10240 . 10495) (10496 . 10623) (10624 . 10626) (10649 . 10711) (10716 . 10747) (10750 . 10751) (10752 . 11007) (11008 . 11123) (11126 . 11157) (11160 . 11193) (11197 . 11208) (11210 . 11217) (11493 . 11498) (11513 . 11516) (11518 . 11519) 11632 (11776 . 11777) (11782 . 11784) 11787 (11790 . 11803) (11806 . 11807) (11818 . 11822) (11824 . 11841) (11904 . 11929) (11931 . 12019) (12032 . 12245) (12272 . 12283) (12289 . 12292) (12306 . 12307) 12316 12320 12336 (12342 . 12343) (12349 . 12351) (12443 . 12444) 12448 12539 (12688 . 12689) (12694 . 12703) (12736 . 12771) (12800 . 12830) (12842 . 12871) 12880 (12896 . 12927) (12938 . 12976) (12992 . 13054) (13056 . 13311) (19904 . 19967) (42128 . 42182) (42238 . 42239) (42509 . 42511) 42611 42622 (42738 . 42743) (42752 . 42774) (42784 . 42785) (42889 . 42890) (43048 . 43051) (43062 . 43065) (43124 . 43127) (43214 . 43215) (43256 . 43258) (43310 . 43311) 43359 (43457 . 43469) (43486 . 43487) (43612 . 43615) (43639 . 43641) (43742 . 43743) (43760 . 43761) 43867 44011 64297 (64434 . 64449) (65020 . 65021) (65040 . 65046) 65049 (65072 . 65076) (65093 . 65094) (65097 . 65103) (65104 . 65106) (65108 . 65112) (65119 . 65126) (65128 . 65131) (65281 . 65287) (65290 . 65295) (65306 . 65312) 65340 (65342 . 65344) 65372 65374 65377 (65380 . 65381) (65504 . 65510) (65512 . 65518) (65532 . 65533) (65792 . 65794) (65847 . 65855) (65913 . 65929) 65932 (65936 . 65947) 65952 (66000 . 66044) 66463 66512 66927 67671 (67703 . 67704) 67871 67903 (68176 . 68184) 68223 68296 (68336 . 68342) (68409 . 68415) (68505 . 68508) (69703 . 69709) (69819 . 69820) (69822 . 69825) (69952 . 69955) (70004 . 70005) (70085 . 70088) 70093 (70200 . 70205) 70854 (71105 . 71113) (71233 . 71235) (74864 . 74868) (92782 . 92783) 92917 (92983 . 92991) (92996 . 92997) 113820 113823 (118784 . 119029) (119040 . 119078) (119081 . 119140) (119146 . 119148) (119171 . 119172) (119180 . 119209) (119214 . 119261) (119296 . 119361) 119365 (119552 . 119638) 120513 120539 120571 120597 120629 120655 120687 120713 120745 120771 (126704 . 126705) (126976 . 127019) (127024 . 127123) (127136 . 127150) (127153 . 127167) (127169 . 127183) (127185 . 127221) (127248 . 127278) (127280 . 127339) (127344 . 127386) (127462 . 127487) (127488 . 127490) (127504 . 127546) (127552 . 127560) (127568 . 127569) (127744 . 127788) (127792 . 127869) (127872 . 127950) (127956 . 127991) (128000 . 128254) (128256 . 128330) (128336 . 128377) (128379 . 128419) (128421 . 128511) (128512 . 128578) (128581 . 128591) (128592 . 128639) (128640 . 128719) (128736 . 128748) (128752 . 128755) (128768 . 128883) (128896 . 128980) (129024 . 129035) (129040 . 129095) (129104 . 129113) (129120 . 129159) (129168 . 129197))) (defvar haskell--char-syntax-identifiers '(170 (178 . 179) 181 (185 . 186) (188 . 190) (192 . 214) (216 . 246) (248 . 255) (256 . 383) (384 . 591) (592 . 687) (880 . 883) (886 . 887) (891 . 893) 895 902 (904 . 906) 908 (910 . 929) (931 . 1013) (1015 . 1023) (1024 . 1153) (1162 . 1279) (1280 . 1327) (1329 . 1366) (1377 . 1415) (1488 . 1514) (1520 . 1522) (1568 . 1599) (1601 . 1610) (1632 . 1641) (1646 . 1647) (1649 . 1747) 1749 (1774 . 1788) 1791 1808 (1810 . 1839) (1869 . 1871) (1872 . 1919) (1920 . 1957) 1969 (1984 . 2026) (2048 . 2069) (2112 . 2136) (2208 . 2226) (2308 . 2361) 2365 2384 (2392 . 2401) (2406 . 2415) (2418 . 2431) 2432 (2437 . 2444) (2447 . 2448) (2451 . 2472) (2474 . 2480) 2482 (2486 . 2489) 2493 2510 (2524 . 2525) (2527 . 2529) (2534 . 2545) (2548 . 2553) (2565 . 2570) (2575 . 2576) (2579 . 2600) (2602 . 2608) (2610 . 2611) (2613 . 2614) (2616 . 2617) (2649 . 2652) 2654 (2662 . 2671) (2674 . 2676) (2693 . 2701) (2703 . 2705) (2707 . 2728) (2730 . 2736) (2738 . 2739) (2741 . 2745) 2749 2768 (2784 . 2785) (2790 . 2799) (2821 . 2828) (2831 . 2832) (2835 . 2856) (2858 . 2864) (2866 . 2867) (2869 . 2873) 2877 (2908 . 2909) (2911 . 2913) (2918 . 2927) (2929 . 2935) 2947 (2949 . 2954) (2958 . 2960) (2962 . 2965) (2969 . 2970) 2972 (2974 . 2975) (2979 . 2980) (2984 . 2986) (2990 . 3001) 3024 (3046 . 3058) (3077 . 3084) (3086 . 3088) (3090 . 3112) (3114 . 3129) 3133 (3160 . 3161) (3168 . 3169) (3174 . 3183) (3192 . 3198) (3205 . 3212) (3214 . 3216) (3218 . 3240) (3242 . 3251) (3253 . 3257) 3261 3294 (3296 . 3297) (3302 . 3311) (3313 . 3314) (3333 . 3340) (3342 . 3344) (3346 . 3386) 3389 3406 (3424 . 3425) (3430 . 3445) (3450 . 3455) (3461 . 3478) (3482 . 3505) (3507 . 3515) 3517 (3520 . 3526) (3558 . 3567) (3585 . 3632) (3634 . 3635) (3648 . 3653) (3664 . 3673) (3713 . 3714) 3716 (3719 . 3720) 3722 3725 (3732 . 3735) (3737 . 3743) (3745 . 3747) 3749 3751 (3754 . 3755) (3757 . 3760) (3762 . 3763) 3773 (3776 . 3780) (3792 . 3801) (3804 . 3807) 3840 (3872 . 3891) (3904 . 3911) (3913 . 3948) (3976 . 3980) (4096 . 4138) (4159 . 4169) (4176 . 4181) (4186 . 4189) 4193 (4197 . 4198) (4206 . 4208) (4213 . 4225) 4238 (4240 . 4249) (4256 . 4293) 4295 4301 (4304 . 4346) (4349 . 4351) (4352 . 4607) (4608 . 4680) (4682 . 4685) (4688 . 4694) 4696 (4698 . 4701) (4704 . 4744) (4746 . 4749) (4752 . 4784) (4786 . 4789) (4792 . 4798) 4800 (4802 . 4805) (4808 . 4822) (4824 . 4880) (4882 . 4885) (4888 . 4954) (4969 . 4988) (4992 . 5007) (5024 . 5108) (5121 . 5740) (5743 . 5759) (5761 . 5786) (5792 . 5866) (5873 . 5880) (5888 . 5900) (5902 . 5905) (5920 . 5937) (5952 . 5969) (5984 . 5996) (5998 . 6000) (6016 . 6067) 6108 (6112 . 6121) (6128 . 6137) (6160 . 6169) (6176 . 6210) (6212 . 6263) (6272 . 6312) 6314 (6320 . 6389) (6400 . 6430) (6470 . 6479) (6480 . 6509) (6512 . 6516) (6528 . 6571) (6593 . 6599) (6608 . 6618) (6656 . 6678) (6688 . 6740) (6784 . 6793) (6800 . 6809) (6917 . 6963) (6981 . 6987) (6992 . 7001) (7043 . 7072) (7086 . 7103) (7104 . 7141) (7168 . 7203) (7232 . 7241) (7245 . 7247) (7248 . 7287) (7401 . 7404) (7406 . 7409) (7413 . 7414) (7424 . 7467) (7531 . 7543) (7545 . 7551) (7552 . 7578) (7680 . 7935) (7936 . 7957) (7960 . 7965) (7968 . 8005) (8008 . 8013) (8016 . 8023) 8025 8027 8029 (8031 . 8061) (8064 . 8116) (8118 . 8124) 8126 (8130 . 8132) (8134 . 8140) (8144 . 8147) (8150 . 8155) (8160 . 8172) (8178 . 8180) (8182 . 8188) 8304 (8308 . 8313) (8320 . 8329) 8450 8455 (8458 . 8467) 8469 (8473 . 8477) 8484 8486 8488 (8490 . 8493) (8495 . 8505) (8508 . 8511) (8517 . 8521) 8526 (8528 . 8543) (8579 . 8580) 8585 (9312 . 9371) (9450 . 9471) (10102 . 10131) (11264 . 11310) (11312 . 11358) (11360 . 11387) (11390 . 11391) (11392 . 11492) (11499 . 11502) (11506 . 11507) 11517 (11520 . 11557) 11559 11565 (11568 . 11623) (11648 . 11670) (11680 . 11686) (11688 . 11694) (11696 . 11702) (11704 . 11710) (11712 . 11718) (11720 . 11726) (11728 . 11734) (11736 . 11742) 12294 12348 (12353 . 12438) 12447 (12449 . 12538) 12543 (12549 . 12589) (12593 . 12686) (12690 . 12693) (12704 . 12730) (12784 . 12799) (12832 . 12841) (12872 . 12879) (12881 . 12895) (12928 . 12937) (12977 . 12991) (13312 . 19893) (19968 . 40908) (40960 . 40980) (40982 . 42124) (42192 . 42231) (42240 . 42507) (42512 . 42539) (42560 . 42606) (42624 . 42651) (42656 . 42725) (42786 . 42863) (42865 . 42887) (42891 . 42894) (42896 . 42925) (42928 . 42929) 42999 (43002 . 43007) (43008 . 43009) (43011 . 43013) (43015 . 43018) (43020 . 43042) (43056 . 43061) (43072 . 43123) (43138 . 43187) (43216 . 43225) (43250 . 43255) 43259 (43264 . 43301) (43312 . 43334) (43360 . 43388) (43396 . 43442) (43472 . 43481) (43488 . 43492) (43495 . 43518) (43520 . 43560) (43584 . 43586) (43588 . 43595) (43600 . 43609) (43616 . 43631) (43633 . 43638) 43642 (43646 . 43647) (43648 . 43695) 43697 (43701 . 43702) (43705 . 43709) 43712 43714 (43739 . 43740) (43744 . 43754) 43762 (43777 . 43782) (43785 . 43790) (43793 . 43798) (43808 . 43814) (43816 . 43822) (43824 . 43866) (43876 . 43877) (43968 . 44002) (44016 . 44025) (44032 . 55203) (55216 . 55238) (55243 . 55291) (63744 . 64109) (64112 . 64217) (64256 . 64262) (64275 . 64279) 64285 (64287 . 64296) (64298 . 64310) (64312 . 64316) 64318 (64320 . 64321) (64323 . 64324) (64326 . 64335) (64336 . 64433) (64467 . 64829) (64848 . 64911) (64914 . 64967) (65008 . 65019) (65136 . 65140) (65142 . 65276) (65296 . 65305) (65313 . 65338) (65345 . 65370) (65382 . 65391) (65393 . 65437) (65440 . 65470) (65474 . 65479) (65482 . 65487) (65490 . 65495) (65498 . 65500) (65536 . 65547) (65549 . 65574) (65576 . 65594) (65596 . 65597) (65599 . 65613) (65616 . 65629) (65664 . 65786) (65799 . 65843) (65909 . 65912) (65930 . 65931) (66176 . 66204) (66208 . 66256) (66273 . 66299) (66304 . 66339) (66352 . 66368) (66370 . 66377) (66384 . 66421) (66432 . 66461) (66464 . 66499) (66504 . 66511) (66560 . 66639) (66640 . 66687) (66688 . 66717) (66720 . 66729) (66816 . 66855) (66864 . 66915) (67072 . 67382) (67392 . 67413) (67424 . 67431) (67584 . 67589) 67592 (67594 . 67637) (67639 . 67640) 67644 67647 (67648 . 67669) (67672 . 67679) (67680 . 67702) (67705 . 67711) (67712 . 67742) (67751 . 67759) (67840 . 67867) (67872 . 67897) (67968 . 67999) (68000 . 68023) (68030 . 68031) 68096 (68112 . 68115) (68117 . 68119) (68121 . 68147) (68160 . 68167) (68192 . 68222) (68224 . 68255) (68288 . 68295) (68297 . 68324) (68331 . 68335) (68352 . 68405) (68416 . 68437) (68440 . 68447) (68448 . 68466) (68472 . 68479) (68480 . 68497) (68521 . 68527) (68608 . 68680) (69216 . 69246) (69635 . 69687) (69714 . 69743) (69763 . 69807) (69840 . 69864) (69872 . 69881) (69891 . 69926) (69942 . 69951) (69968 . 70002) 70006 (70019 . 70066) (70081 . 70084) (70096 . 70106) (70113 . 70132) (70144 . 70161) (70163 . 70187) (70320 . 70366) (70384 . 70393) (70405 . 70412) (70415 . 70416) (70419 . 70440) (70442 . 70448) (70450 . 70451) (70453 . 70457) 70461 (70493 . 70497) (70784 . 70831) (70852 . 70853) 70855 (70864 . 70873) (71040 . 71086) (71168 . 71215) 71236 (71248 . 71257) (71296 . 71338) (71360 . 71369) (71840 . 71922) 71935 (72384 . 72440) (73728 . 74648) (77824 . 78894) (92160 . 92728) (92736 . 92766) (92768 . 92777) (92880 . 92909) (92928 . 92975) (93008 . 93017) (93019 . 93025) (93027 . 93047) (93053 . 93071) (93952 . 94020) 94032 (110592 . 110593) (113664 . 113770) (113776 . 113788) (113792 . 113800) (113808 . 113817) (119648 . 119665) (119808 . 119892) (119894 . 119964) (119966 . 119967) 119970 (119973 . 119974) (119977 . 119980) (119982 . 119993) 119995 (119997 . 120003) (120005 . 120069) (120071 . 120074) (120077 . 120084) (120086 . 120092) (120094 . 120121) (120123 . 120126) (120128 . 120132) 120134 (120138 . 120144) (120146 . 120485) (120488 . 120512) (120514 . 120538) (120540 . 120570) (120572 . 120596) (120598 . 120628) (120630 . 120654) (120656 . 120686) (120688 . 120712) (120714 . 120744) (120746 . 120770) (120772 . 120779) (120782 . 120831) (124928 . 125124) (125127 . 125135) (126464 . 126467) (126469 . 126495) (126497 . 126498) 126500 126503 (126505 . 126514) (126516 . 126519) 126521 126523 126530 126535 126537 126539 (126541 . 126543) (126545 . 126546) 126548 126551 126553 126555 126557 126559 (126561 . 126562) 126564 (126567 . 126570) (126572 . 126578) (126580 . 126583) (126585 . 126588) 126590 (126592 . 126601) (126603 . 126619) (126625 . 126627) (126629 . 126633) (126635 . 126651) (127232 . 127244) (131072 . 173782) (173824 . 177972) (177984 . 178205) (194560 . 195101))) ;; Syntax table. (defvar haskell-mode-syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?\ " " table) (modify-syntax-entry ?\t " " table) (modify-syntax-entry ?\" "\"" table) (modify-syntax-entry ?\' "_" table) (modify-syntax-entry ?_ "_" table) (modify-syntax-entry ?\( "()" table) (modify-syntax-entry ?\) ")(" table) (modify-syntax-entry ?\[ "(]" table) (modify-syntax-entry ?\] ")[" table) (modify-syntax-entry ?\{ "(}1nb" table) (modify-syntax-entry ?\} "){4nb" table) (modify-syntax-entry ?- ". 123" table) (modify-syntax-entry ?\n ">" table) (modify-syntax-entry ?\` "$`" table) (mapc (lambda (x) (modify-syntax-entry x "." table)) "!#$%&*+./:<=>?@^|~,;\\") ;; Haskell symbol characters are treated as punctuation because ;; they are not able to form identifiers with word constituent 'w' ;; class characters. (dolist (charcodes haskell--char-syntax-symbols) (modify-syntax-entry charcodes "." table)) ;; ... and for identifier characters (dolist (charcodes haskell--char-syntax-identifiers) (modify-syntax-entry charcodes "w" table)) table) "Syntax table used in Haskell mode.") (defun haskell-syntax-propertize (begin end) (save-excursion (when haskell-literate (goto-char begin) ;; Algorithm (first matching rule wins): ;; - current line is latex code if previous non-empty line was ;; latex code or was \begin{code} and current line is not ;; \end{code} ;; - current line is bird code if it starts with > ;; - else literate comment (let ((previous-line-latex-code (catch 'return (save-excursion (when (= (forward-line -1) 0) (while (looking-at-p "^[\t ]*$") (unless (= (forward-line -1) 0) (throw 'return nil))) (or (and (not (equal (string-to-syntax "<") (syntax-after (point)))) (not (looking-at-p "^>"))) (looking-at-p "^\\\\begin{code}[\t ]*$"))))))) (while (< (point) end) (unless (looking-at-p "^[\t ]*$") (if previous-line-latex-code (if (looking-at-p "^\\\\end{code}[\t ]*$") (progn (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "<")) (setq previous-line-latex-code nil)) ;; continue latex-code ) (if (looking-at-p "^>") ;; this is a whitespace (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "-")) ;; this is a literate comment (progn (put-text-property (point) (1+ (point)) 'syntax-table (string-to-syntax "<")) (when (looking-at-p "^\\\\begin{code}[\t ]*$") (setq previous-line-latex-code t)))))) (forward-line 1)))) (goto-char begin) (let ((ppss (syntax-ppss))) (when (nth 4 ppss) ;; go to the end of a comment, there is nothing to see inside ;; a comment so we might as well just skip over it ;; immediatelly (setq ppss (parse-partial-sexp (point) (point-max) nil nil ppss 'syntax-table))) (when (nth 8 ppss) ;; go to the beginning of a comment or string (goto-char (nth 8 ppss)) (when (equal ?| (nth 3 ppss)) ;; if this is a quasi quote we need to backtrack even more ;; to the opening bracket (skip-chars-backward "^[") (goto-char (1- (point))))) (while (< (point) end) (let ((token-kind (haskell-lexeme-looking-at-token))) (cond ((equal token-kind 'qsymid) (when (member (haskell-lexeme-classify-by-first-char (char-after (match-beginning 1))) '(varsym consym)) ;; we have to neutralize potential comments here (put-text-property (match-beginning 1) (match-end 1) 'syntax-table (string-to-syntax ".")))) ((equal token-kind 'number) (put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax "w"))) ((equal token-kind 'char) (save-excursion (goto-char (match-beginning 2)) (let ((limit (match-end 2))) (save-match-data (while (re-search-forward "\"" limit t) (put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax "."))))) ;; Place a generic string delimeter only when an open ;; quote is closed by end-of-line Emacs acts strangely ;; when a generic delimiter is not closed so in case ;; string ends at the end of the buffer we will use ;; plain string (if (and (not (match-beginning 3)) (not (equal (match-end 2) (point-max)))) (progn (put-text-property (match-beginning 1) (match-end 1) 'syntax-table (string-to-syntax "|")) (put-text-property (match-end 2 ) (1+ (match-end 2)) 'syntax-table (string-to-syntax "|"))) (put-text-property (match-beginning 1) (match-end 1) 'syntax-table (string-to-syntax "\"")) (when (not (equal (match-end 2) (point-max))) (put-text-property (match-end 2 ) (1+ (match-end 2)) 'syntax-table (string-to-syntax "\"")))))) ((equal token-kind 'string) (save-excursion (goto-char (match-beginning 2)) (let ((limit (match-end 2))) (save-match-data (while (re-search-forward "\"" limit t) (put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax "."))))) ;; Place a generic string delimeter only when an open ;; quote is closed by end-of-line Emacs acts strangely ;; when a generic delimiter is not closed so in case ;; string ends at the end of the buffer we will use ;; plain string (when (and (not (match-beginning 3)) (not (equal (match-end 2) (point-max)))) (put-text-property (match-beginning 1) (match-end 1) 'syntax-table (string-to-syntax "|")) (put-text-property (match-end 2 ) (1+ (match-end 2)) 'syntax-table (string-to-syntax "|"))))) ((equal token-kind 'template-haskell-quasi-quote) (put-text-property (match-beginning 2) (match-end 2) 'syntax-table (string-to-syntax "\"")) (when (match-beginning 4) (put-text-property (match-beginning 4) (match-end 4) 'syntax-table (string-to-syntax "\""))) (save-excursion (goto-char (match-beginning 3)) (let ((limit (match-end 3))) (save-match-data (while (re-search-forward "\"" limit t) (put-text-property (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax ".")))))))) (if token-kind (goto-char (match-end 0)) (goto-char end))))))) (defun haskell-ident-at-point () "Return the identifier near point going backward or nil if none found. May return a qualified name." (let ((reg (haskell-ident-pos-at-point))) (when reg (buffer-substring-no-properties (car reg) (cdr reg))))) (defun haskell-spanable-pos-at-point () "Like `haskell-ident-pos-at-point', but includes any surrounding backticks." (save-excursion (let ((pos (haskell-ident-pos-at-point))) (when pos (cl-destructuring-bind (start . end) pos (if (and (eq ?` (char-before start)) (eq ?` (char-after end))) (cons (- start 1) (+ end 1)) (cons start end))))))) (defun haskell-ident-pos-at-point () "Return the span of the identifier near point going backward. Returns nil if no identifier found or point is inside string or comment. May return a qualified name." (when (not (nth 8 (syntax-ppss))) ;; Do not handle comments and strings (let (start end) ;; Initial point position is non-deterministic, it may occur anywhere ;; inside identifier span, so the approach is: ;; - first try go left and find left boundary ;; - then try go right and find right boundary ;; ;; In both cases assume the longest path, e.g. when going left take into ;; account than point may occur at the end of identifier, when going right ;; take into account that point may occur at the beginning of identifier. ;; ;; We should handle `.` character very careful because it is heavily ;; overloaded. Examples of possible cases: ;; Control.Monad.>>= -- delimiter ;; Control.Monad.when -- delimiter ;; Data.Aeson..: -- delimiter and operator symbol ;; concat.map -- composition function ;; .? -- operator symbol (save-excursion ;; First, skip whitespace if we're on it, moving point to last ;; identifier char. That way, if we're at "map ", we'll see the word ;; "map". (when (and (eolp) (not (bolp))) (backward-char)) (when (and (not (eobp)) (eq (char-syntax (char-after)) ? )) (skip-chars-backward " \t") (backward-char)) ;; Now let's try to go left. (save-excursion (if (not (haskell-mode--looking-at-varsym)) ;; Looking at non-operator char, this is quite simple (progn (skip-syntax-backward "w_") ;; Remember position (setq start (point))) ;; Looking at operator char. (while (and (not (bobp)) (haskell-mode--looking-at-varsym)) ;; skip all operator chars backward (setq start (point)) (backward-char)) ;; Extra check for case when reached beginning of the buffer. (when (haskell-mode--looking-at-varsym) (setq start (point)))) ;; Slurp qualification part if present. If identifier is qualified in ;; case of non-operator point will stop before `.` dot, but in case of ;; operator it will stand at `.` delimiting dot. So if we're looking ;; at `.` let's step one char forward and try to get qualification ;; part. (goto-char start) (when (looking-at-p (rx ".")) (forward-char)) (let ((pos (haskell-mode--skip-qualification-backward))) (when pos (setq start pos)))) ;; Finally, let's try to go right. (save-excursion ;; Try to slurp qualification part first. (skip-syntax-forward "w_") (setq end (point)) (while (and (looking-at (rx "." upper)) (not (zerop (progn (forward-char) (skip-syntax-forward "w_"))))) (setq end (point))) ;; If point was at non-operator we already done, otherwise we need an ;; extra check. (while (haskell-mode--looking-at-varsym) (forward-char) (setq end (point)))) (when (not (= start end)) (cons start end)))))) (defun haskell-mode--looking-at-varsym () "Return t when point stands at operator symbol." (when (not (eobp)) (let ((lex (haskell-lexeme-classify-by-first-char (char-after)))) (or (eq lex 'varsym) (eq lex 'consym))))) (defun haskell-mode--skip-qualification-backward () "Skip qualified part of identifier backward. Expects point stands *after* delimiting dot. Returns beginning position of qualified part or nil if no qualified part found." (when (not (and (bobp) (looking-at (rx bol)))) (let ((case-fold-search nil) pos) (while (and (eq (char-before) ?.) (progn (backward-char) (not (zerop (skip-syntax-backward "w'")))) (skip-syntax-forward "'") (looking-at "[[:upper:]]")) (setq pos (point))) pos))) (defun haskell-delete-indentation (&optional arg) "Like `delete-indentation' but ignoring Bird-style \">\". Prefix ARG is handled as per `delete-indentation'." (interactive "*P") (let ((fill-prefix (or fill-prefix (if (eq haskell-literate 'bird) ">")))) (delete-indentation arg))) (defvar eldoc-print-current-symbol-info-function) (defvar electric-pair-inhibit-predicate) (declare-function electric-pair-default-inhibit "elec-pair") (defun haskell-mode--inhibit-bracket-inside-comment-or-default (ch) "An `electric-pair-mode' inhibit function for character CH." (or (nth 4 (syntax-ppss)) (funcall #'electric-pair-default-inhibit ch))) ;; The main mode functions ;;;###autoload (define-derived-mode haskell-mode prog-mode "Haskell" "Major mode for editing Haskell programs. \\<haskell-mode-map> Literate Haskell scripts are supported via `literate-haskell-mode'. The variable `haskell-literate' indicates the style of the script in the current buffer. See the documentation on this variable for more details. Use `haskell-version' to find out what version of Haskell mode you are currently using. Additional Haskell mode modules can be hooked in via `haskell-mode-hook'. Indentation modes: `haskell-indentation-mode', Kristof Bastiaensen, Gergely Risko Intelligent semi-automatic indentation Mk2 `haskell-indent-mode', Guy Lapalme Intelligent semi-automatic indentation. Interaction modes: `interactive-haskell-mode' Interact with per-project GHCi processes through a REPL and directory-aware sessions. Other modes: `haskell-decl-scan-mode', Graeme E Moss Scans top-level declarations, and places them in a menu. `haskell-doc-mode', Hans-Wolfgang Loidl Echoes types of functions or syntax of keywords when the cursor is idle. To activate a minor-mode, simply run the interactive command. For example, `M-x haskell-doc-mode'. Run it again to disable it. To enable a mode for every haskell-mode buffer, add a hook in your Emacs configuration. To do that you can customize `haskell-mode-hook' or add lines to your .emacs file. For example, to enable `interactive-haskell-mode', use the following: (add-hook 'haskell-mode-hook 'interactive-haskell-mode) Minor modes that work well with `haskell-mode': - `smerge-mode': show and work with diff3 conflict markers used by git, svn and other version control systems." :group 'haskell (when (version< emacs-version "25.1") (error "haskell-mode requires at least Emacs 25.1")) ;; paragraph-{start,separate} should treat comments as paragraphs as well. (setq-local paragraph-start (concat " *{-\\| *-- |\\|" page-delimiter)) (setq-local paragraph-separate (concat " *$\\| *\\({-\\|-}\\) *$\\|" page-delimiter)) (setq-local fill-paragraph-function 'haskell-fill-paragraph) ;; (setq-local adaptive-fill-function 'haskell-adaptive-fill) (setq-local comment-start "--") (setq-local comment-padding 1) (setq-local comment-start-skip "[-{]-[ \t]*") (setq-local comment-end "") (setq-local comment-end-skip "[ \t]*\\(-}\\|\\s>\\)") (setq-local forward-sexp-function #'haskell-forward-sexp) (setq-local parse-sexp-ignore-comments nil) (setq-local syntax-propertize-function #'haskell-syntax-propertize) ;; Set things up for eldoc-mode. (setq-local eldoc-documentation-function 'haskell-doc-current-info) ;; Set things up for imenu. (setq-local imenu-create-index-function 'haskell-ds-create-imenu-index) ;; Set things up for font-lock. (setq-local font-lock-defaults '((haskell-font-lock-keywords) nil nil nil nil (font-lock-syntactic-face-function . haskell-syntactic-face-function) ;; Get help from font-lock-syntactic-keywords. (parse-sexp-lookup-properties . t) (font-lock-extra-managed-props . (composition haskell-type)))) ;; Preprocessor definitions can have backslash continuations (setq-local font-lock-multiline t) ;; Haskell's layout rules mean that TABs have to be handled with extra care. ;; The safer option is to avoid TABs. The second best is to make sure ;; TABs stops are 8 chars apart, as mandated by the Haskell Report. --Stef (setq-local indent-tabs-mode nil) (setq-local tab-width 8) (setq-local comment-auto-fill-only-comments t) ;; Haskell is not generally suitable for electric indentation, since ;; there is no unambiguously correct indent level for any given line. (when (boundp 'electric-indent-inhibit) (setq electric-indent-inhibit t)) ;; dynamic abbrev support: recognize Haskell identifiers ;; Haskell is case-sensitive language (setq-local dabbrev-case-fold-search nil) (setq-local dabbrev-case-distinction nil) (setq-local dabbrev-case-replace nil) (setq-local dabbrev-abbrev-char-regexp "\\sw\\|[.]") (setq haskell-literate nil) (add-hook 'before-save-hook 'haskell-mode-before-save-handler nil t) (add-hook 'after-save-hook 'haskell-mode-after-save-handler nil t) ;; provide non-interactive completion function (add-hook 'completion-at-point-functions 'haskell-completions-completion-at-point nil t) ;; Avoid Emacs 25 bug with electric-pair inside comments (when (eq 25 emacs-major-version) (setq-local electric-pair-inhibit-predicate 'haskell-mode--inhibit-bracket-inside-comment-or-default)) (haskell-indentation-mode)) (defcustom haskell-mode-hook '(haskell-indentation-mode interactive-haskell-mode) "List of functions to run after `haskell-mode' is enabled. Use to enable minor modes coming with `haskell-mode' or run an arbitrary function. Note that `haskell-indentation-mode' and `haskell-indent-mode' should not be run at the same time." :group 'haskell :type 'hook :options '(capitalized-words-mode flyspell-prog-mode haskell-decl-scan-mode haskell-indent-mode haskell-indentation-mode highlight-uses-mode imenu-add-menubar-index interactive-haskell-mode turn-on-haskell-unicode-input-method)) (defun haskell-fill-paragraph (justify) (save-excursion ;; Fill paragraph should only work in comments. ;; The -- comments are handled properly by default ;; The {- -} comments need some extra love. (let* ((syntax-values (syntax-ppss)) (comment-num (nth 4 syntax-values))) (cond ((eq t comment-num) ;; standard fill works wonders inside a non-nested comment (fill-comment-paragraph justify)) ((integerp comment-num) ;; we are in a nested comment. lets narrow to comment content ;; and use plain paragraph fill for that (let* ((comment-start-point (nth 8 syntax-values)) (comment-end-point (save-excursion (goto-char comment-start-point) (forward-sexp) ;; Find end of any comment even if forward-sexp ;; fails to find the right braces. (backward-char 3) (re-search-forward "[ \t]?-}" nil t) (match-beginning 0))) (fill-start (+ 2 comment-start-point)) (fill-end comment-end-point) (fill-paragraph-handle-comment nil)) (save-restriction (narrow-to-region fill-start fill-end) (fill-paragraph justify) ;; If no filling happens, whatever called us should not ;; continue with standard text filling, so return t t))) ((eolp) ;; do nothing outside of a comment t) (t ;; go to end of line and try again (end-of-line) (haskell-fill-paragraph justify)))))) ;; (defun haskell-adaptive-fill () ;; ;; We want to use "-- " as the prefix of "-- |", etc. ;; (let* ((line-end (save-excursion (end-of-line) (point))) ;; (line-start (point))) ;; (save-excursion ;; (unless (in-comment) ;; ;; Try to find the start of a comment. We only fill comments. ;; (search-forward-regexp comment-start-skip line-end t)) ;; (when (in-comment) ;; (let ();(prefix-start (point))) ;; (skip-syntax-forward "^w") ;; (make-string (- (point) line-start) ?\s)))))) ;;;###autoload (defun haskell-forward-sexp (&optional arg) "Haskell specific version of `forward-sexp'. Move forward across one balanced expression (sexp). With ARG, do it that many times. Negative arg -N means move backward across N balanced expressions. This command assumes point is not in a string or comment. If unable to move over a sexp, signal `scan-error' with three arguments: a message, the start of the obstacle (a parenthesis or list marker of some kind), and end of the obstacle." (interactive "^p") (or arg (setq arg 1)) (if (< arg 0) (while (< arg 0) (skip-syntax-backward "->") ;; Navigate backwards using plain `backward-sexp', assume that it ;; skipped over at least one Haskell expression, and jump forward until ;; last possible point before the starting position. If applicable, ;; `scan-error' is signalled by `backward-sexp'. (let ((end (point)) (forward-sexp-function nil)) (backward-sexp) (let ((cur (point))) (while (< (point) end) (setf cur (point)) (haskell-forward-sexp) (skip-syntax-forward "->")) (goto-char cur))) (setf arg (1+ arg))) (save-match-data (while (> arg 0) (when (haskell-lexeme-looking-at-token) (cond ((member (match-string 0) (list "(" "[" "{")) (goto-char (or (scan-sexps (point) 1) (buffer-end 1)))) ((member (match-string 0) (list ")" "]" "}")) (signal 'scan-error (list "Containing expression ends prematurely." (match-beginning 0) (match-end 0)))) (t (goto-char (match-end 0))))) (setf arg (1- arg)))))) ;;;###autoload (define-derived-mode literate-haskell-mode haskell-mode "LitHaskell" "As `haskell-mode' but for literate scripts." (setq haskell-literate (save-excursion (goto-char (point-min)) (cond ((re-search-forward "^\\\\\\(begin\\|end\\){code}$" nil t) 'tex) ((re-search-forward "^>" nil t) 'bird) (t haskell-literate-default)))) (if (eq haskell-literate 'bird) ;; fill-comment-paragraph isn't much use there, and even gets confused ;; by the syntax-table text-properties we add to mark the first char ;; of each line as a comment-starter. (setq-local fill-paragraph-handle-comment nil)) (setq-local mode-line-process '("/" (:eval (symbol-name haskell-literate))))) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.[gh]s\\'" . haskell-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.hsig\\'" . haskell-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.l[gh]s\\'" . literate-haskell-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.hsc\\'" . haskell-mode)) ;;;###autoload (add-to-list 'interpreter-mode-alist '("runghc" . haskell-mode)) ;;;###autoload (add-to-list 'interpreter-mode-alist '("runhaskell" . haskell-mode)) ;;;###autoload (add-to-list 'completion-ignored-extensions ".hi") (defcustom haskell-check-command "hlint" "*Command used to check a Haskell file." :group 'haskell :type '(choice (const "hlint") (const "ghc -fno-code") (string :tag "Other command"))) (defcustom haskell-tags-on-save nil "Generate tags via hasktags after saving." :group 'haskell :type 'boolean) (defvar haskell-saved-check-command nil "Internal use.") ;; Like Python. Should be abstracted, sigh. (defun haskell-check (command) "Check a Haskell file (default current buffer's file). Runs COMMAND, a shell command, as if by `compile'. See `haskell-check-command' for the default." (interactive (list (read-string "Checker command: " (or haskell-saved-check-command (concat haskell-check-command " " (let ((name (buffer-file-name))) (if name (file-name-nondirectory name)))))))) (setq haskell-saved-check-command command) (save-some-buffers (not compilation-ask-about-save) nil) (compilation-start command)) ;; This function was renamed and deprecated, but we want clean ;; byte compilation in all versions. (defalias 'haskell-flymake-create-temp-buffer-copy (if (fboundp 'flymake-proc-init-create-temp-buffer-copy) 'flymake-proc-init-create-temp-buffer-copy 'flymake-init-create-temp-buffer-copy)) (defun haskell-flymake-init () "Flymake init function for Haskell." (let ((checker-elts (and haskell-saved-check-command (split-string haskell-saved-check-command)))) (list (car checker-elts) (append (cdr checker-elts) (list (haskell-flymake-create-temp-buffer-copy 'flymake-create-temp-inplace)))))) (add-to-list 'flymake-allowed-file-name-masks '("\\.l?hs\\'" haskell-flymake-init)) (defun haskell-mode-format-imports () "Format the imports by aligning and sorting them." (interactive) (let ((col (current-column))) (haskell-sort-imports) (haskell-align-imports) (goto-char (+ (line-beginning-position) col)))) (declare-function haskell-mode-stylish-buffer "haskell-commands") (defun haskell-mode-before-save-handler () "Function that will be called before buffer's saving." (when haskell-stylish-on-save (ignore-errors (haskell-mode-stylish-buffer)))) ;; From Bryan O'Sullivan's blog: ;; http://www.serpentine.com/blog/2007/10/09/using-emacs-to-insert-scc-annotations-in-haskell-code/ (defun haskell-mode-try-insert-scc-at-point () "Try to insert an SCC annotation at point. Return true if successful, nil otherwise." (if (or (looking-at "\\b\\|[ \t]\\|$") ;; Allow SCC if point is on a non-letter with whitespace to the left (and (not (bolp)) (save-excursion (forward-char -1) (looking-at "[ \t]")))) (let ((space-at-point (looking-at "[ \t]"))) (unless (and (not (bolp)) (save-excursion (forward-char -1) (looking-at "[ \t]"))) (insert " ")) (insert "{-# SCC \"\" #-}") (unless space-at-point (insert " ")) (forward-char (if space-at-point -5 -6)) t ))) (defun haskell-mode-insert-scc-at-point () "Insert an SCC annotation at point." (interactive) (if (not (haskell-mode-try-insert-scc-at-point)) (error "Not over an area of whitespace"))) (make-obsolete 'haskell-mode-insert-scc-at-point 'haskell-mode-toggle-scc-at-point "2015-11-11") (defun haskell-mode-try-kill-scc-at-point () "Try to kill an SCC annotation at point. Return true if successful, nil otherwise." (save-excursion (let ((old-point (point)) (scc "\\({-#[ \t]*SCC \"[^\"]*\"[ \t]*#-}\\)[ \t]*")) (while (not (or (looking-at scc) (bolp))) (forward-char -1)) (if (and (looking-at scc) (<= (match-beginning 1) old-point) (> (match-end 1) old-point)) (progn (kill-region (match-beginning 0) (match-end 0)) t))))) ;; Also Bryan O'Sullivan's. (defun haskell-mode-kill-scc-at-point () "Kill the SCC annotation at point." (interactive) (if (not (haskell-mode-try-kill-scc-at-point)) (error "No SCC at point"))) (make-obsolete 'haskell-mode-kill-scc-at-point 'haskell-mode-toggle-scc-at-point "2015-11-11") (defun haskell-mode-toggle-scc-at-point () "If point is in an SCC annotation, kill the annotation. Otherwise, try to insert a new annotation." (interactive) (if (not (haskell-mode-try-kill-scc-at-point)) (if (not (haskell-mode-try-insert-scc-at-point)) (error "Could not insert or remove SCC")))) (defun haskell-guess-module-name-from-file-name (file-name) "Guess the module name from FILE-NAME. Based on given FILE-NAME this function tries to find path components that look like module identifiers and composes full module path using this information. For example: /Abc/Def/Xyz.lhs => Abc.Def.Xyz /Ab-c/Def/Xyz.lhs => Def.Xyz src/Abc/Def/Xyz.hs => Abc.Def.Xyz c:\\src\\Abc\\Def\\Xyz.hs => Abc.Def.Xyz nonmodule.txt => nil This function usually will be used with `buffer-file-name': (haskell-guess-module-name-from-file-name (buffer-file-name))" (let* ((file-name-sans-ext (file-name-sans-extension file-name)) (components (cl-loop for part in (reverse (split-string file-name-sans-ext "/")) while (let ((case-fold-search nil)) (string-match (concat "^" haskell-lexeme-modid "$") part)) collect part))) (when components (mapconcat 'identity (reverse components) ".")))) (defun haskell-guess-module-name () "Guess the current module name of the buffer. Uses `haskell-guess-module-name-from-file-name'." (haskell-guess-module-name-from-file-name (buffer-file-name))) (defvar haskell-auto-insert-module-format-string "-- | \n\nmodule %s where\n\n" "Template string that will be inserted in new haskell buffers via `haskell-auto-insert-module-template'.") (defun haskell-auto-insert-module-template () "Insert a module template for the newly created buffer." (interactive) (when (and (= (point-min) (point-max)) (buffer-file-name)) (insert (format haskell-auto-insert-module-format-string (haskell-guess-module-name-from-file-name (buffer-file-name)))) (goto-char (point-min)) (end-of-line))) ;;;###autoload (defun haskell-mode-generate-tags (&optional and-then-find-this-tag) "Generate tags using Hasktags. This is synchronous function. If optional AND-THEN-FIND-THIS-TAG argument is present it is used with function `xref-find-definitions' after new table was generated." (interactive) (let* ((dir (haskell-cabal--find-tags-dir)) (command (haskell-cabal--compose-hasktags-command dir))) (if (not command) (error "Unable to compose hasktags command") (shell-command command) (haskell-mode-message-line "Tags generated.") (when and-then-find-this-tag (let ((tags-file-name dir)) (xref-find-definitions and-then-find-this-tag)))))) ;; Provide ourselves: (provide 'haskell-mode) ;;; haskell-mode.el ends here �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-modules.el����������������������������������������������������������������0000664�0000000�0000000�00000011771�13602233217�0017430�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-modules.el --- -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'haskell-sort-imports) (require 'haskell-align-imports) (require 'haskell-session) (require 'haskell-navigate-imports) (require 'haskell-complete-module) (require 'haskell-sandbox) (require 'haskell-customize) (defun haskell-add-import (&optional module) "Add an import to the import list. Sorts and aligns imports, unless `haskell-stylish-on-save' is set, in which case we defer to stylish-haskell." (interactive) (save-excursion (goto-char (point-max)) (haskell-navigate-imports) (insert (haskell-import-for-module (or module (haskell-complete-module-read "Module: " (haskell-session-all-modules (haskell-modules-session)))))) (unless haskell-stylish-on-save (haskell-sort-imports) (haskell-align-imports)))) (defun haskell-import-for-module (module) "Get import statements for the given module." (let ((mapping (assoc module haskell-import-mapping))) (if mapping (cdr mapping) (concat (read-from-minibuffer "Import line: " (format "import %s" module)) "\n")))) ;;;###autoload (defun haskell-session-installed-modules (_session &optional _dontcreate) "Get the modules installed in the current package set." ;; TODO: Again, this makes HEAVY use of unix utilities. It'll work ;; fine in Linux, probably okay on OS X, and probably not at all on ;; Windows. Again, if someone wants to test on Windows and come up ;; with alternatives that's OK. ;; ;; Ideally all these package queries can be provided by a Haskell ;; program based on the Cabal API. Possibly as a nice service. Such ;; a service could cache and do nice things like that. For now, this ;; simple shell script takes us far. ;; ;; Probably also we can take the code from inferior-haskell-mode. ;; ;; Ugliness aside, if it saves us time to type it's a winner. ;; ;; FIXME/TODO: add support for (eq 'cabal-repl (haskell-process-type)) (let ((session (haskell-session-maybe))) (when session (let ((modules (shell-command-to-string (format "%s 2> /dev/null | %s | %s" (cond ((haskell-sandbox-exists-p session) (concat "ghc-pkg dump -f " (shell-quote-argument (haskell-sandbox-pkgdb session)))) (t "ghc-pkg dump")) "egrep '^(exposed-modules: | )[A-Z]'" "cut -c18-")))) (split-string modules))))) ;;;###autoload (defun haskell-session-all-modules (session &optional dontcreate) "Get all modules -- installed or in the current project. If DONTCREATE is non-nil don't create a new session." (append (haskell-session-installed-modules session dontcreate) (haskell-session-project-modules session dontcreate))) ;;;###autoload (defun haskell-session-project-modules (session &optional dontcreate) "Get the modules of the current project. If DONTCREATE is non-nil don't create a new session." (if (or (not dontcreate) (haskell-session-maybe)) (let* ((modules (shell-command-to-string (format "%s && %s" (format "cd %s" (haskell-session-cabal-dir session)) ;; TODO: Use a different, better source. Possibly hasktags or some such. ;; TODO: At least make it cross-platform. Linux ;; (and possibly OS X) have egrep, Windows ;; doesn't -- or does it via Cygwin or MinGW? ;; This also doesn't handle module\nName. But those gits can just cut it out! "egrep '^module[\t\r ]+[^(\t\r ]+' . -r -I --include='*.*hs' --include='*.hsc' -s -o -h | sed 's/^module[\t\r ]*//' | sort | uniq")))) (split-string modules)))) (defun haskell-modules-session () "Get the `haskell-session', throw an error if it's not available." (or (haskell-session-maybe) (haskell-session-assign (or (haskell-session-from-buffer) (haskell-session-choose) (error "No session associated with this buffer. Try M-x haskell-session-change or report this as a bug."))))) (provide 'haskell-modules) �������haskell-mode-17.1/haskell-move-nested.el������������������������������������������������������������0000664�0000000�0000000�00000010742�13602233217�0020203�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-move-nested.el --- Change the column of text nested below a line -*- lexical-binding: t -*- ;; Copyright (C) 2010 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; 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 ;; <http://www.gnu.org/licenses/>. ;;; Commentary: ;; This module is intended for Haskell mode users, but is ;; independent of Haskell mode. ;; Example usage: ;; (define-key haskell-mode-map (kbd "C-,") 'haskell-move-nested-left) ;; (define-key haskell-mode-map (kbd "C-.") 'haskell-move-nested-right) ;;; Code: ;;;###autoload (defun haskell-move-nested (cols) "Shift the nested off-side-rule block adjacent to point by COLS columns to the right. In Transient Mark mode, if the mark is active, operate on the contents of the region instead. " (save-excursion (if (and transient-mark-mode mark-active) (progn (indent-rigidly (region-beginning) (region-end) cols) (setq deactivate-mark nil)) (let ((region (haskell-move-nested-region))) (when region (indent-rigidly (car region) (cdr region) cols)))))) ;;;###autoload (defun haskell-move-nested-right (cols) "Increase indentation of the following off-side-rule block adjacent to point. Use a numeric prefix argument to indicate amount of indentation to apply. In Transient Mark mode, if the mark is active, operate on the contents of the region instead." (interactive "p") (haskell-move-nested cols) ) ;;;###autoload (defun haskell-move-nested-left (cols) "Decrease indentation of the following off-side-rule block adjacent to point. Use a numeric prefix argument to indicate amount of indentation to apply. In Transient Mark mode, if the mark is active, operate on the contents of the region instead." (interactive "p") (haskell-move-nested (- cols)) ) (defun haskell-move-nested-region () "Infer region off-side-rule block adjacent to point. Used by `haskell-move-nested'. " (save-excursion (let ((starting-level (current-column))) (forward-line) (let ((current-level (haskell-move-nested-indent-level))) (let ((start-point (line-beginning-position)) (start-end-point (line-end-position)) (end-point nil) (last-line 0)) (forward-line) (while (and (not (= (line-beginning-position) last-line)) (or (> (haskell-move-nested-indent-level) starting-level) (and (> current-level starting-level) (>= (haskell-move-nested-indent-level) current-level)))) (setq last-line (line-beginning-position)) (setq end-point (line-end-position)) (forward-line)) (cons start-point (or end-point start-end-point))))))) (defun haskell-move-nested-indent-level () (max 0 (1- (length (buffer-substring-no-properties (line-beginning-position) (or (save-excursion (goto-char (line-beginning-position)) (search-forward-regexp "[^ ]" (line-end-position) t 1)) (line-beginning-position))))))) (defun haskell-kill-nested () "Kill the nested region after point." (interactive) (let ((start (point)) (reg (save-excursion (search-backward-regexp "^[ ]+" (line-beginning-position) t 1) (search-forward-regexp "[^ ]" (line-end-position) t 1) (haskell-move-nested-region)))) (kill-region start (cdr reg)))) (defun haskell-delete-nested () "Kill the nested region after point." (interactive) (let ((start (point)) (reg (save-excursion (search-backward-regexp "^[ ]+" (line-beginning-position) t 1) (search-forward-regexp "[^ ]" (line-end-position) t 1) (haskell-move-nested-region)))) (delete-region start (cdr reg)))) (provide 'haskell-move-nested) ;;; haskell-move-nested.el ends here ������������������������������haskell-mode-17.1/haskell-navigate-imports.el�������������������������������������������������������0000664�0000000�0000000�00000011372�13602233217�0021246�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-navigate-imports.el --- A function for cycling through Haskell import lists -*- lexical-binding: t -*- ;; Copyright (C) 2010 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; 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 ;; <http://www.gnu.org/licenses/>. ;;; Commentary: ;; The cycling step will stop once at the last import list so ;; that it is easy to add a new import list. ;; This module works completely independently of any libraries ;; (including haskell-mode). ;; Exports three interactive functions: ;; 1. haskell-navigate-imports ;; 2. haskell-navigate-imports-go ;; 3. haskell-navigate-imports-return ;; Example usage: ;; (require 'haskell-navigate-imports) ;; (define-key haskell-mode-map (kbd "<f8>") 'haskell-navigate-imports) ;;; Code: (defvar haskell-navigate-imports-start-point nil) (defvar haskell-literate) ; defined in haskell-mode.el ;;;###autoload (defun haskell-navigate-imports (&optional return) "Cycle the Haskell import lines or return to point (with prefix arg)." (interactive "P") (if return (haskell-navigate-imports-return) (haskell-navigate-imports-go))) ;;;###autoload (defun haskell-navigate-imports-go () "Go to the first line of a list of consecutive import lines. Cycles." (interactive) (unless (or (haskell-navigate-imports-line) (equal (line-beginning-position) (point-min)) (save-excursion (forward-line -1) (haskell-navigate-imports-line))) (setq haskell-navigate-imports-start-point (point))) (haskell-navigate-imports-go-internal)) ;;;###autoload (defun haskell-navigate-imports-return () "Return to the non-import point we were at before going to the module list. If we were originally at an import list, we can just cycle through easily." (interactive) (when haskell-navigate-imports-start-point (goto-char haskell-navigate-imports-start-point))) (defun haskell-navigate-imports-go-internal () "Go to the first line of a list of consecutive import lines. Cycle." (if (haskell-navigate-imports-line) (progn (haskell-navigate-imports-goto-end) (when (haskell-navigate-imports-find-forward-line) (haskell-navigate-imports-go-internal))) (let ((point (haskell-navigate-imports-find-forward-line))) (if point (goto-char point) (progn (goto-char (point-min)) (if (haskell-navigate-imports-find-forward-line) (haskell-navigate-imports-go-internal) (let ((module (if (eq haskell-literate 'bird) "^> ?module" "^module"))) (when (search-forward-regexp module nil t 1) (search-forward "\n\n" nil t 1))))))))) (defun haskell-navigate-imports-goto-end () "Skip a bunch of consecutive import lines." (while (not (or (equal (point) (point-max)) (not (haskell-navigate-imports-line)))) (forward-line))) (defun haskell-navigate-imports-find-forward-line () "Return a point with at an import line, or nothing." (save-excursion (while (not (or (equal (point) (point-max)) (haskell-navigate-imports-after-imports-p) ;; This one just speeds it up. (haskell-navigate-imports-line))) (forward-line)) (if (haskell-navigate-imports-line) (point) nil))) (defun haskell-navigate-imports-line () "Try to match the current line as a regexp." (let ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position))) (import (if (eq haskell-literate 'bird) "^> ?import " "^import "))) (if (string-match import line) line nil))) (defun haskell-navigate-imports-after-imports-p () "Are we after the imports list? Just for a speed boost." (save-excursion (goto-char (line-beginning-position)) (not (not (search-forward-regexp "\\( = \\|\\<instance\\>\\| :: \\)" (line-end-position) t 1))))) (provide 'haskell-navigate-imports) ;;; haskell-navigate-imports.el ends here ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-presentation-mode.el������������������������������������������������������0000664�0000000�0000000�00000007026�13602233217�0021413�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-presentation-mode.el --- Presenting Haskell things -*- lexical-binding: t -*- ;; Copyright (C) 2013 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;;; Code: (require 'haskell-mode) (require 'haskell-session) (defvar haskell-presentation-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "q") 'quit-window) (define-key map (kbd "c") 'haskell-presentation-clear) map) "Keymap for `haskell-presentation-mode'.") (define-derived-mode haskell-presentation-mode haskell-mode "Presentation" "Major mode for viewing Haskell snippets. \\{hypertext-mode-map}" (setq case-fold-search nil)) (defconst haskell-presentation-buffer-name "*Haskell Presentation*" "Haskell Presentation buffer name.") (defconst haskell-presentation-hint-message "-- Hit `q' to close this window; `c' to clear.\n\n" "Hint message appered in Haskell Presentation buffer.") (defun haskell-presentation-buffer () "Return Haskell Presentaion buffer. Return current presenation buffer or create new one if absent. Never returns nil." ;; TODO Provide interactive calling options: when called interactively make ;; the presentation buffer current. (let ((may-buffer (get-buffer haskell-presentation-buffer-name))) (if may-buffer may-buffer (let ((buffer (generate-new-buffer haskell-presentation-buffer-name))) (with-current-buffer buffer (insert haskell-presentation-hint-message) (haskell-presentation-mode) (setq buffer-read-only t)) buffer)))) (defun haskell-presentation-clear () "Clear Haskell Presentation buffer." (interactive) (let ((hp-buf (get-buffer haskell-presentation-buffer-name))) (when hp-buf (with-current-buffer hp-buf (let ((buffer-read-only nil)) (erase-buffer) (insert haskell-presentation-hint-message)))))) (defun haskell-presentation-present (session code &optional clear) "Present given code in a popup buffer. Creates temporal Haskell Presentation buffer and assigns it to given haskell SESSION; presented CODE will be fontified as haskell code. Give an optional non-nil CLEAR arg to clear the buffer before presenting message." (let ((buffer (haskell-presentation-buffer))) (with-current-buffer buffer (when (boundp 'shm-display-quarantine) (setq-local shm-display-quarantine nil)) (when clear (haskell-presentation-clear)) (haskell-session-assign session) (goto-char (point-min)) (forward-line 2) (save-excursion (let ((buffer-read-only nil)) (insert code "\n\n")))) (if (eq major-mode 'haskell-presentation-mode) (switch-to-buffer buffer) (pop-to-buffer buffer)))) (provide 'haskell-presentation-mode) ;;; haskell-presentation-mode.el ends here ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-process.el����������������������������������������������������������������0000664�0000000�0000000�00000046404�13602233217�0017437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-process.el --- Communicating with the inferior Haskell process -*- lexical-binding: t -*- ;; Copyright (C) 2011 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Code: (require 'cl-lib) (require 'json) (require 'url-util) (require 'haskell-session) (require 'haskell-customize) (require 'haskell-string) (defconst haskell-process-prompt-regex "\4" "Used for delimiting command replies. 4 is End of Transmission.") (defvar haskell-reload-p nil "Used internally for `haskell-process-loadish'.") (defconst haskell-process-greetings (list "Hello, Haskell!" "The lambdas must flow." "Hours of hacking await!" "The next big Haskell project is about to start!" "Your wish is my IO ().") "Greetings for when the Haskell process starts up.") (defconst haskell-process-logo (expand-file-name "logo.svg" haskell-mode-pkg-base-dir) "Haskell logo for notifications.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Accessing commands -- using cl 'defstruct' (cl-defstruct haskell-command "Data structure representing a command to be executed when with a custom state and three callback." ;; hold the custom command state ;; state :: a state ;; called when to execute a command ;; go :: a -> () go ;; called whenever output was collected from the haskell process ;; live :: a -> Response -> Bool live ;; called when the output from the haskell process indicates that the command ;; is complete ;; complete :: a -> Response -> () complete) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Building the process (defun haskell-process-compute-process-log-and-command (session hptype) "Compute the log and process to start command for the SESSION from the HPTYPE. Do not actually start any process. HPTYPE is the result of calling `'haskell-process-type`' function." (let ((session-name (haskell-session-name session))) (cl-ecase hptype ('ghci (append (list (format "Starting inferior GHCi process %s ..." haskell-process-path-ghci) session-name nil) (apply haskell-process-wrapper-function (list (append (haskell-process-path-to-list haskell-process-path-ghci) haskell-process-args-ghci))))) ('cabal-new-repl (append (list (format "Starting inferior `cabal new-repl' process using %s ..." haskell-process-path-cabal) session-name nil) (apply haskell-process-wrapper-function (list (append (haskell-process-path-to-list haskell-process-path-cabal) (list "new-repl") haskell-process-args-cabal-new-repl (let ((target (haskell-session-target session))) (if target (list target) nil))))))) ('cabal-repl (append (list (format "Starting inferior `cabal repl' process using %s ..." haskell-process-path-cabal) session-name nil) (apply haskell-process-wrapper-function (list (append (haskell-process-path-to-list haskell-process-path-cabal) (list "repl") haskell-process-args-cabal-repl (let ((target (haskell-session-target session))) (if target (list target) nil))))))) ('stack-ghci (append (list (format "Starting inferior stack GHCi process using %s" haskell-process-path-stack) session-name nil) (apply haskell-process-wrapper-function (list (append (haskell-process-path-to-list haskell-process-path-stack) (list "ghci") (let ((target (haskell-session-target session))) (if target (list target) nil)) haskell-process-args-stack-ghci)))))))) (defun haskell-process-path-to-list (path) "Convert a path (which may be a string or a list) to a list." (if (stringp path) (list path) path)) (defun haskell-process-make (name) "Make an inferior Haskell process." (list (cons 'name name))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Process communication (defun haskell-process-sentinel (proc event) "The sentinel for the process pipe." (let ((session (haskell-process-project-by-proc proc))) (when session (let* ((process (haskell-session-process session))) (unless (haskell-process-restarting process) (haskell-process-log (propertize (format "Event: %S\n" event) 'face '((:weight bold)))) (haskell-process-log (propertize "Process reset.\n" 'face 'font-lock-comment-face)) (run-hook-with-args 'haskell-process-ended-functions process)))))) (defun haskell-process-filter (proc response) "The filter for the process pipe." (let ((i 0)) (cl-loop for line in (split-string response "\n") do (haskell-process-log (concat (if (= i 0) (propertize "<- " 'face 'font-lock-comment-face) " ") (propertize line 'face 'haskell-interactive-face-compile-warning))) do (setq i (1+ i)))) (let ((session (haskell-process-project-by-proc proc))) (when session (if (haskell-process-cmd (haskell-session-process session)) (haskell-process-collect session response (haskell-session-process session)))))) (defun haskell-process-log (msg) "Effective append MSG to the process log (if enabled)." (when haskell-process-log (let* ((append-to (get-buffer-create "*haskell-process-log*"))) (with-current-buffer append-to ;; point should follow insertion so that it stays at the end ;; of the buffer (setq-local window-point-insertion-type t) (let ((buffer-read-only nil)) (insert msg "\n")))))) (defun haskell-process-project-by-proc (proc) "Find project by process." (cl-find-if (lambda (project) (string= (haskell-session-name project) (process-name proc))) haskell-sessions)) (defun haskell-process-collect (_session response process) "Collect input for the response until receives a prompt." (haskell-process-set-response process (concat (haskell-process-response process) response)) (while (haskell-process-live-updates process)) (when (string-match haskell-process-prompt-regex (haskell-process-response process)) (haskell-command-exec-complete (haskell-process-cmd process) (replace-regexp-in-string haskell-process-prompt-regex "" (haskell-process-response process))) (haskell-process-reset process) (haskell-process-trigger-queue process))) (defun haskell-process-reset (process) "Reset the process's state, ready for the next send/reply." (progn (haskell-process-set-response-cursor process 0) (haskell-process-set-response process "") (haskell-process-set-cmd process nil))) (defun haskell-process-consume (process regex) "Consume a regex from the response and move the cursor along if succeed." (when (string-match regex (haskell-process-response process) (haskell-process-response-cursor process)) (haskell-process-set-response-cursor process (match-end 0)) t)) (defun haskell-process-send-string (process string) "Try to send a string to the process's process. Ask to restart if it's not running." (let ((child (haskell-process-process process))) (if (equal 'run (process-status child)) (let ((out (concat string "\n"))) (let ((i 0)) (cl-loop for line in (split-string out "\n") do (unless (string-equal "" line) (haskell-process-log (concat (if (= i 0) (propertize "-> " 'face 'font-lock-comment-face) " ") (propertize line 'face 'font-lock-string-face)))) do (setq i (1+ i)))) (process-send-string child out)) (unless (haskell-process-restarting process) (run-hook-with-args 'haskell-process-ended-functions process))))) (defun haskell-process-live-updates (process) "Process live updates." (haskell-command-exec-live (haskell-process-cmd process) (haskell-process-response process))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Making commands (defun haskell-process-queue-without-filters (process line) "Queue LINE to be sent to PROCESS without bothering to look at the response." (haskell-process-queue-command process (make-haskell-command :state (cons process line) :go (lambda (state) (haskell-process-send-string (car state) (cdr state)))))) (defun haskell-process-queue-command (process command) "Add a command to the process command queue." (haskell-process-cmd-queue-add process command) (haskell-process-trigger-queue process)) (defun haskell-process-trigger-queue (process) "Trigger the next command in the queue to be ran if there is no current command." (if (and (haskell-process-process process) (process-live-p (haskell-process-process process))) (unless (haskell-process-cmd process) (let ((cmd (haskell-process-cmd-queue-pop process))) (when cmd (haskell-process-set-cmd process cmd) (haskell-command-exec-go cmd)))) (progn (haskell-process-reset process) (haskell-process-set process 'command-queue nil) (run-hook-with-args 'haskell-process-ended-functions process)))) (defun haskell-process-queue-flushed-p (process) "Return t if command queue has been completely processed." (not (or (haskell-process-cmd-queue process) (haskell-process-cmd process)))) (defun haskell-process-queue-flush (process) "Block till PROCESS' command queue has been completely processed. This uses `accept-process-output' internally." (while (not (haskell-process-queue-flushed-p process)) (haskell-process-trigger-queue process) (accept-process-output (haskell-process-process process) 1))) (defun haskell-process-queue-sync-request (process reqstr) "Queue submitting REQSTR to PROCESS and return response blockingly." (let ((cmd (make-haskell-command :state (cons nil process) :go `(lambda (s) (haskell-process-send-string (cdr s) ,reqstr)) :complete 'setcar))) (haskell-process-queue-command process cmd) (haskell-process-queue-flush process) (car-safe (haskell-command-state cmd)))) (defun haskell-process-get-repl-completions (process inputstr &optional limit) "Query PROCESS with `:complete repl ...' for INPUTSTR. Give optional LIMIT arg to limit completion candidates count, zero, negative values, and nil means all possible completions. Returns NIL when no completions found." (let* ((mlimit (if (and limit (> limit 0)) (concat " " (number-to-string limit) " ") " ")) (reqstr (concat ":complete repl" mlimit (haskell-string-literal-encode inputstr))) (rawstr (haskell-process-queue-sync-request process reqstr)) (response-status (haskell-utils-repl-response-error-status rawstr))) (if (eq 'unknown-command response-status) (error "GHCi lacks `:complete' support (try installing GHC 7.8+ or ghci-ng)") (when rawstr ;; parse REPL response if any (let* ((s1 (split-string rawstr "\r?\n" t)) (cs (mapcar #'haskell-string-literal-decode (cdr s1))) (h0 (car s1))) ;; "<limit count> <all count> <unused string>" (unless (string-match "\\`\\([0-9]+\\) \\([0-9]+\\) \\(\".*\"\\)\\'" h0) (error "Invalid `:complete' response")) (let ((cnt1 (match-string 1 h0)) (h1 (haskell-string-literal-decode (match-string 3 h0)))) (unless (= (string-to-number cnt1) (length cs)) (error "Lengths inconsistent in `:complete' response")) (cons h1 cs))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Accessing the process (defun haskell-process-get (process key) "Get the PROCESS's KEY value. Returns nil if KEY not set." (cdr (assq key process))) (defun haskell-process-set (process key value) "Set the PROCESS's KEY to VALUE. Returns newly set VALUE." (if process (let ((cell (assq key process))) (if cell (setcdr cell value) ; modify cell in-place (setcdr process (cons (cons key value) (cdr process))) ; new cell value)) (display-warning 'haskell-interactive "`haskell-process-set' called with nil process"))) ;; Wrappers using haskell-process-{get,set} (defun haskell-process-set-sent-stdin (p v) "We've sent stdin, so let's not clear the output at the end." (haskell-process-set p 'sent-stdin v)) (defun haskell-process-sent-stdin-p (p) "Did we send any stdin to the process during evaluation?" (haskell-process-get p 'sent-stdin)) (defun haskell-process-set-suggested-imports (p v) "Remember what imports have been suggested, to avoid re-asking about the same imports." (haskell-process-set p 'suggested-imported v)) (defun haskell-process-suggested-imports (p) "Get what modules have already been suggested and accepted." (haskell-process-get p 'suggested-imported)) (defun haskell-process-set-evaluating (p v) "Set status of evaluating to be on/off." (haskell-process-set p 'evaluating v)) (defun haskell-process-evaluating-p (p) "Get status of evaluating (on/off)." (haskell-process-get p 'evaluating)) (defun haskell-process-set-process (p v) "Set the process's inferior process." (haskell-process-set p 'inferior-process v)) (defun haskell-process-process (p) "Get the process child." (haskell-process-get p 'inferior-process)) (defun haskell-process-name (p) "Get the process name." (haskell-process-get p 'name)) (defun haskell-process-cmd (p) "Get the process's current command. Return nil if no current command." (haskell-process-get p 'current-command)) (defun haskell-process-set-cmd (p v) "Set the process's current command." (haskell-process-set-evaluating p nil) (haskell-process-set-sent-stdin p nil) (haskell-process-set-suggested-imports p nil) (haskell-process-set p 'current-command v)) (defun haskell-process-response (p) "Get the process's current response." (haskell-process-get p 'current-response)) (defun haskell-process-session (p) "Get the process's current session." (haskell-process-get p 'session)) (defun haskell-process-set-response (p v) "Set the process's current response." (haskell-process-set p 'current-response v)) (defun haskell-process-set-session (p v) "Set the process's current session." (haskell-process-set p 'session v)) (defun haskell-process-response-cursor (p) "Get the process's current response cursor." (haskell-process-get p 'current-response-cursor)) (defun haskell-process-set-response-cursor (p v) "Set the process's response cursor." (haskell-process-set p 'current-response-cursor v)) ;; low-level command queue operations (defun haskell-process-restarting (process) "Is the PROCESS restarting?" (haskell-process-get process 'is-restarting)) (defun haskell-process-cmd-queue (process) "Get the PROCESS' command queue. New entries get added to the end of the list. Use `haskell-process-cmd-queue-add' and `haskell-process-cmd-queue-pop' to modify the command queue." (haskell-process-get process 'command-queue)) (defun haskell-process-cmd-queue-add (process cmd) "Add CMD to end of PROCESS's command queue." (cl-check-type cmd haskell-command) (haskell-process-set process 'command-queue (append (haskell-process-cmd-queue process) (list cmd)))) (defun haskell-process-cmd-queue-pop (process) "Pop the PROCESS' next entry from command queue. Returns nil if queue is empty." (let ((queue (haskell-process-cmd-queue process))) (when queue (haskell-process-set process 'command-queue (cdr queue)) (car queue)))) (defun haskell-process-unignore-file (session file) " Note to Windows Emacs hackers: chmod is how to change the mode of files in POSIX systems. This will not work on your operating system. There is a command a bit like chmod called \"Calcs\" that you can try using here: http://technet.microsoft.com/en-us/library/bb490872.aspx If it works, you can submit a patch to this function and remove this comment. " (shell-command (read-from-minibuffer "Permissions command: " (concat "chmod 700 " file))) (haskell-session-modify session 'ignored-files (lambda (files) (cl-remove-if (lambda (path) (string= path file)) files)))) (defun haskell-command-exec-go (command) "Call the command's go function." (let ((go-func (haskell-command-go command))) (when go-func (funcall go-func (haskell-command-state command))))) (defun haskell-command-exec-complete (command response) "Call the command's complete function." (let ((comp-func (haskell-command-complete command))) (when comp-func (condition-case-unless-debug e (funcall comp-func (haskell-command-state command) response) (quit (message "Quit")) (error (message "Haskell process command errored with: %S" e)))))) (defun haskell-command-exec-live (command response) "Trigger the command's live updates callback." (let ((live-func (haskell-command-live command))) (when live-func (funcall live-func (haskell-command-state command) response)))) (provide 'haskell-process) ;;; haskell-process.el ends here ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-repl.el�������������������������������������������������������������������0000664�0000000�0000000�00000012603�13602233217�0016715�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-repl.el --- REPL evaluation -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'cl-lib) (require 'haskell-interactive-mode) (require 'haskell-collapse) (require 'haskell-svg) (defun haskell-interactive-handle-expr () "Handle an inputted expression at the REPL." (let ((expr (haskell-interactive-mode-input))) (if (string= "" (replace-regexp-in-string " " "" expr)) ;; Just make a new prompt on space-only input (progn (goto-char (point-max)) (insert "\n") (haskell-interactive-mode-prompt)) (when (haskell-interactive-at-prompt) (cond ;; If already evaluating, then the user is trying to send ;; input to the REPL during evaluation. Most likely in ;; response to a getLine-like function. ((and (haskell-process-evaluating-p (haskell-interactive-process)) (= (line-end-position) (point-max))) (goto-char (point-max)) (let ((process (haskell-interactive-process)) (string (buffer-substring-no-properties haskell-interactive-mode-result-end (point)))) ;; here we need to go to end of line again as evil-mode ;; might have managed to put us one char back (goto-char (point-max)) (insert "\n") ;; Bring the marker forward (setq haskell-interactive-mode-result-end (point-max)) (haskell-process-set-sent-stdin process t) (haskell-process-send-string process string))) ;; Otherwise we start a normal evaluation call. (t (setq haskell-interactive-mode-old-prompt-start (copy-marker haskell-interactive-mode-prompt-start)) (set-marker haskell-interactive-mode-prompt-start (point-max)) (haskell-interactive-mode-history-add expr) (haskell-interactive-mode-do-expr expr))))))) (defun haskell-interactive-mode-do-expr (expr) (cond ((string-match "^:present " expr) (haskell-interactive-mode-do-presentation (replace-regexp-in-string "^:present " "" expr))) (t (haskell-interactive-mode-run-expr expr)))) (defun haskell-interactive-mode-run-expr (expr) "Run the given expression." (let ((session (haskell-interactive-session)) (process (haskell-interactive-process))) (haskell-process-queue-command process (make-haskell-command :state (list session process expr 0) :go (lambda (state) (goto-char (point-max)) (insert "\n") (setq haskell-interactive-mode-result-end (point-max)) (haskell-process-send-string (cadr state) (haskell-interactive-mode-multi-line (cl-caddr state))) (haskell-process-set-evaluating (cadr state) t)) :live (lambda (state buffer) (unless (and (string-prefix-p ":q" (cl-caddr state)) (string-prefix-p (cl-caddr state) ":quit")) (let* ((cursor (cl-cadddr state)) (next (replace-regexp-in-string haskell-process-prompt-regex "" (substring buffer cursor)))) (haskell-interactive-mode-eval-result (car state) next) (setf (cl-cdddr state) (list (length buffer))) nil))) :complete (lambda (state response) (haskell-process-set-evaluating (cadr state) nil) (unless (haskell-interactive-mode-trigger-compile-error state response) (haskell-interactive-mode-expr-result state response))))))) (defun haskell-interactive-mode-expr-result (state response) "Print the result of evaluating the expression." (let ((response (with-temp-buffer (insert response) (haskell-interactive-mode-handle-h) (buffer-string)))) (when haskell-interactive-mode-eval-mode (unless (haskell-process-sent-stdin-p (cadr state)) (haskell-interactive-mode-eval-as-mode (car state) response)))) (haskell-interactive-mode-prompt (car state))) (defun haskell-interactive-mode-eval-as-mode (session text) "Insert TEXT font-locked according to `haskell-interactive-mode-eval-mode'." (with-current-buffer (haskell-session-interactive-buffer session) (let ((inhibit-read-only t)) (delete-region (1+ haskell-interactive-mode-prompt-start) (point)) (goto-char (point-max)) (insert (haskell-fontify-as-mode (haskell-svg-maybe-render-images text) haskell-interactive-mode-eval-mode)) (when haskell-interactive-mode-collapse (haskell-hide-toggle))))) (provide 'haskell-repl) �����������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-sandbox.el����������������������������������������������������������������0000664�0000000�0000000�00000003021�13602233217�0017403�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-sandbox.el --- Support for sandboxes -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'cl-lib) (require 'haskell-session) (defun haskell-sandbox-path (session) "If there is a haskell-session, return the path to the usual sandbox location." (concat (haskell-session-cabal-dir session) "/.cabal-sandbox")) (defun haskell-sandbox-exists-p (session) "Is there a cabal sandbox?" (file-exists-p (haskell-sandbox-path session))) (defun haskell-sandbox-pkgdb (session) "Get the package database of the sandbox." (let* ((files (directory-files (haskell-sandbox-path session))) (dir (car (cl-remove-if-not (lambda (file) (string-match ".conf.d$" file)) files)))) (when dir (concat (haskell-sandbox-path session) "/" dir)))) (provide 'haskell-sandbox) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-session.el����������������������������������������������������������������0000664�0000000�0000000�00000022433�13602233217�0017440�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-session.el --- Haskell sessions -*- lexical-binding: t -*- ;; Copyright (C) 2011-2012 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;;; Todo: ;;; Code: (require 'cl-lib) (require 'haskell-cabal) (require 'haskell-customize) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Globals ;; Used internally (defvar-local haskell-session nil) (defvar haskell-sessions (list) "All Haskell sessions in the Emacs session.") (defun haskell-session-tags-filename (session) "Get the filename for the TAGS file." (concat (haskell-session-cabal-dir session) "/TAGS")) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Finding/clearing the session ;;;###autoload (defun haskell-session-maybe () "Maybe get the Haskell session, return nil if there isn't one." (if (default-boundp 'haskell-session) haskell-session (setq haskell-session nil))) (defun haskell-session-from-buffer () "Get the session based on the buffer." (when (and (buffer-file-name) (consp haskell-sessions)) (cl-reduce (lambda (acc a) (let ((dir (haskell-session-get a 'cabal-dir))) (if dir (if (string-prefix-p dir (file-name-directory (buffer-file-name))) (if acc (if (and (> (length (haskell-session-get a 'cabal-dir)) (length (haskell-session-get acc 'cabal-dir)))) a acc) a) acc) acc))) haskell-sessions :initial-value nil))) (defun haskell-session-default-name () "Generate a default project name for the new project prompt." (let ((file (haskell-cabal-find-file))) (or (when file (downcase (file-name-sans-extension (file-name-nondirectory file)))) "haskell"))) (defun haskell-session-assign (session) "Assing current buffer to SESSION. This could be helpful for temporary or auxiliary buffers such as presentation mode buffers (e.g. in case when session is killed with all relevant buffers)." (setq-local haskell-session session)) (defun haskell-session-choose () "Find a session by choosing from a list of the current sessions." (when haskell-sessions (let* ((session-name (funcall haskell-completing-read-function "Choose Haskell session: " (cl-remove-if (lambda (name) (and haskell-session (string= (haskell-session-name haskell-session) name))) (mapcar 'haskell-session-name haskell-sessions)))) (session (cl-find-if (lambda (session) (string= (haskell-session-name session) session-name)) haskell-sessions))) session))) (defun haskell-session-clear () "Clear the buffer of any Haskell session choice." (setq-local haskell-session nil)) (defun haskell-session-lookup (name) "Get the session by name." (cl-remove-if-not (lambda (s) (string= name (haskell-session-name s))) haskell-sessions)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Session modules (defun haskell-session-strip-dir (session file) "Strip the load dir from the file path." (let ((cur-dir (haskell-session-current-dir session))) (if (> (length file) (length cur-dir)) (if (string= (substring file 0 (length cur-dir)) cur-dir) (replace-regexp-in-string "^[/\\]" "" (substring file (length cur-dir))) file) file))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Accessing the session (defun haskell-session-current-dir (s) "Get the session current directory." (let ((dir (haskell-session-get s 'current-dir))) (or dir (error "No current directory.")))) (defun haskell-session-name (s) "Get the session name." (haskell-session-get s 'name)) (defun haskell-session-target (s) "Get the session build target. If `haskell-process-load-or-reload-prompt' is nil, accept `default'." (let* ((maybe-target (haskell-session-get s 'target)) (target (if maybe-target maybe-target (let ((new-target (if haskell-process-load-or-reload-prompt (haskell-session-choose-target "Build target (empty for default): " t) ""))) (haskell-session-set-target s new-target))))) (if (not (string= target "")) target nil))) (defun haskell-session-choose-target (&optional prompt blank-default history) "Ask the user which of the available targets they want to use. Optional arguments: PROMPT allows you to specify which prompt should be presented to the user. BLANK-DEFAULT will allow specifying a default blank argument. HISTORY provides the history to `completing-read'." (let ((prompt (or prompt "Build Target: ")) (known-targets (haskell-session-get-targets (haskell-process-type))) (default-target (when blank-default (list "")))) (completing-read prompt (append default-target known-targets) nil nil nil history default-target))) (defun haskell-session-get-targets (process-type) "Return a list of available targets." (cl-case process-type (stack-ghci (haskell-session-get-targets-command haskell-process-path-stack "ide" "targets")) (t (haskell-cabal-enum-targets (haskell-process-type))))) (defun haskell-session-get-targets-command (command &rest args) "Run an external command to obtain a list of available targets." (with-temp-buffer (cl-case (apply #'process-file command nil (current-buffer) t args) (0 (cl-remove-if (lambda (line) (string= "" line)) (split-string (buffer-string)))) (1 nil)))) (defun haskell-session-set-target (s target) "Set the session build target." (haskell-session-set s 'target target)) (defun haskell-session-set-interactive-buffer (s v) "Set the session interactive buffer." (haskell-session-set s 'interactive-buffer v)) (defun haskell-session-set-process (s v) "Set the session process." (haskell-session-set s 'process v)) ;;;###autoload (defun haskell-session-process (s) "Get the session process." (haskell-session-get s 'process)) (defun haskell-session-set-cabal-dir (s v) "Set the session cabal-dir." (let ((true-path (file-truename v))) (haskell-session-set s 'cabal-dir true-path) (haskell-session-set-cabal-checksum s true-path))) (defun haskell-session-set-current-dir (s v) "Set the session current directory." (let ((true-path (file-truename v))) (haskell-session-set s 'current-dir true-path))) (defun haskell-session-set-cabal-checksum (s cabal-dir) "Set the session checksum of .cabal files" (haskell-session-set s 'cabal-checksum (haskell-cabal-compute-checksum cabal-dir))) (defun haskell-session-cabal-dir (s) "Get the session cabal-dir." (or (haskell-session-get s 'cabal-dir) (let ((set-dir (haskell-cabal-get-dir (not haskell-process-load-or-reload-prompt)))) (if set-dir (progn (haskell-session-set-cabal-dir s set-dir) set-dir) (haskell-session-cabal-dir s))))) (defun haskell-session-modify (session key update) "Update the value at KEY in SESSION with UPDATE." (haskell-session-set session key (funcall update (haskell-session-get session key)))) (defun haskell-session-get (session key) "Get the SESSION's KEY value. Returns nil if KEY not set." (cdr (assq key session))) (defun haskell-session-set (session key value) "Set the SESSION's KEY to VALUE. Returns newly set VALUE." (let ((cell (assq key session))) (if cell (setcdr cell value) ; modify cell in-place (setcdr session (cons (cons key value) (cdr session))) ; new cell value))) (provide 'haskell-session) ;;; haskell-session.el ends here �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-sort-imports.el�����������������������������������������������������������0000664�0000000�0000000�00000011543�13602233217�0020437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-sort-imports.el --- Sort the list of Haskell imports at the point alphabetically -*- lexical-binding: t -*- ;; Copyright (C) 2010 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; 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 ;; <http://www.gnu.org/licenses/>. ;;; Commentary: ;; If the region is active it sorts the imports within the ;; region. ;; This will align and sort the columns of the current import ;; list. It's more or less the coolest thing on the planet. ;;; Code: (require 'cl-lib) (defvar haskell-sort-imports-regexp (concat "^import[ ]+" "\\(qualified \\)?" "[ ]*\\(\"[^\"]*\" \\)?" "[ ]*\\([A-Za-z0-9_.']*.*\\)")) ;;;###autoload (defun haskell-sort-imports () "Sort the import list at point. It sorts the current group i.e. an import list separated by blank lines on either side. If the region is active, it will restrict the imports to sort within that region." (interactive) (when (haskell-sort-imports-at-import) (let* ((points (haskell-sort-imports-decl-points)) (current-string (buffer-substring-no-properties (car points) (cdr points))) (current-offset (- (point) (car points)))) (if (region-active-p) (progn (goto-char (region-beginning)) (haskell-sort-imports-goto-import-start)) (haskell-sort-imports-goto-group-start)) (let* ((start (point)) (imports (haskell-sort-imports-collect-imports)) (sorted (sort (cl-copy-list imports) (lambda (a b) (string< (haskell-sort-imports-normalize a) (haskell-sort-imports-normalize b)))))) (when (not (equal imports sorted)) (delete-region start (point)) (mapc (lambda (import) (insert import "\n")) sorted)) (goto-char start) (when (search-forward current-string nil t 1) (forward-char (- (length current-string))) (forward-char current-offset)))))) (defun haskell-sort-imports-normalize (i) "Normalize an import, if possible, so that it can be sorted." (if (string-match haskell-sort-imports-regexp i) (match-string 3 i) i)) (defun haskell-sort-imports-collect-imports () (let ((imports (list))) (while (looking-at "import") (let* ((points (haskell-sort-imports-decl-points)) (string (buffer-substring-no-properties (car points) (cdr points)))) (goto-char (min (1+ (cdr points)) (point-max))) (setq imports (cons string imports)))) (reverse (delq nil (delete-dups imports))))) (defun haskell-sort-imports-goto-group-start () "Go to the start of the import group." (or (and (search-backward "\n\n" nil t 1) (goto-char (+ 2 (line-end-position)))) (when (search-backward-regexp "^module " nil t 1) (goto-char (1+ (line-end-position)))) (goto-char (point-min)))) (defun haskell-sort-imports-at-import () "Are we at an import?" (save-excursion (haskell-sort-imports-goto-import-start) (looking-at "import"))) (defun haskell-sort-imports-goto-import-start () "Go to the start of the import." (goto-char (car (haskell-sort-imports-decl-points)))) (defun haskell-sort-imports-decl-points () "Get the points of the declaration." (save-excursion (let ((start (or (progn (goto-char (line-end-position)) (search-backward-regexp "^[^ \n]" nil t 1) (unless (or (looking-at "^-}$") (looking-at "^{-$")) (point))) 0)) (end (progn (goto-char (1+ (point))) (or (when (search-forward-regexp "[\n]+[^ \n]" nil t 1) (forward-char -1) (search-backward-regexp "[^\n ]" nil t) (line-end-position)) (when (search-forward-regexp "\n" nil t 1) (1- (point))) (point-max))))) (cons start end)))) (provide 'haskell-sort-imports) ;;; haskell-sort-imports.el ends here �������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-string.el�����������������������������������������������������������������0000664�0000000�0000000�00000024020�13602233217�0017255�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-string.el --- Haskell related string utilities -*- lexical-binding: t -*- ;; Copyright (C) 2013 Herbert Valerio Riedel ;; Author: Herbert Valerio Riedel <hvr@gnu.org> ;; This file is not part of GNU Emacs. ;; This file 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 file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;;; Todo: ;; - write ERT tests ;;; Code: (require 'cl-lib) (defun haskell-string-trim (string) "Remove whitespace around STRING. A Whitespace character is defined in the Haskell Report as follows whitechar -> newline | vertab | space | tab | uniWhite newline -> return linefeed | return | linefeed | formfeed uniWhite -> any Unicode character defined as whitespace Note: The implementation currently only supports ASCII white-space characters, i.e. the implemention doesn't consider uniWhite." (let ((s1 (if (string-match "[\t\n\v\f\r ]+\\'" string) (replace-match "" t t string) string))) (if (string-match "\\`[\t\n\v\f\r ]+" s1) (replace-match "" t t s1) s1))) (defun haskell-string-only-spaces-p (string) "Return t if STRING contains only whitespace (or is empty)." (string= "" (haskell-string-trim string))) (defun haskell-string-take (string n) "Return (up to) N character length prefix of STRING." (substring string 0 (min (length string) n))) (defconst haskell-string-literal-encode-ascii-array [ "\\NUL" "\\SOH" "\\STX" "\\ETX" "\\EOT" "\\ENQ" "\\ACK" "\\a" "\\b" "\\t" "\\n" "\\v" "\\f" "\\r" "\\SO" "\\SI" "\\DLE" "\\DC1" "\\DC2" "\\DC3" "\\DC4" "\\NAK" "\\SYN" "\\ETB" "\\CAN" "\\EM" "\\SUB" "\\ESC" "\\FS" "\\GS" "\\RS" "\\US" " " "!" "\\\"" "#" "$" "%" "&" "'" "(" ")" "*" "+" "," "-" "." "/" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" ":" ";" "<" "=" ">" "?" "@" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "[" "\\\\" "]" "^" "_" "`" "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "{" "|" "}" "~" "\\DEL" ] "Array of encodings for 7-bit ASCII character points indexed by ASCII value.") (defun haskell-string-literal-encode (str &optional no-quotes) "Encode STR according Haskell escape rules using 7-bit ASCII representation. The serialization has been implemented to closely match the behaviour of GHC's Show instance for Strings. If NO-QUOTES is non-nil, omit wrapping result in quotes. This is the dual operation to `haskell-string-literal-decode'." (let ((lastc -1)) (let ((encode (lambda (c) (let ((lc lastc)) (setq lastc c) (if (>= c 128) ;; if non-ASCII code point (format "\\%d" c) ;; else, for ASCII code points (if (or (and (= lc 14) (= c ?H)) ;; "\SO\&H" (and (>= lc 128) (>= c ?0) (<= c ?9))) ;; "\123\&4" (concat "\\&" (aref haskell-string-literal-encode-ascii-array c)) (aref haskell-string-literal-encode-ascii-array c) )))))) (if no-quotes (mapconcat encode str "") (concat "\"" (mapconcat encode str "") "\""))))) (defconst haskell-string-literal-escapes-regexp (concat "[\\]\\(?:" (regexp-opt (append (mapcar (lambda (c) (format "%c" c)) "abfnrtv\\\"'&") ;; "charesc" escape sequences (mapcar (lambda (c) (format "^%c" c)) "ABCDEFGHIJKLMNOPQRSTUVWXYZ@[\\]^_") ;; "cntrl" escape sequences (mapcar (lambda (s) (format "%s" s)) (split-string "NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US SP DEL")))) ;; "ascii" (w\o "cntrl") escape sequences "\\|" "[\t\n\v\f\r ]+[\\]" ;; whitespace gaps "\\|" "[0-9]+" ;; decimal escape sequence "\\|" "o[0-7]+" ;; octal escape sequence "\\|" "x[0-9a-f]+" ;; hex escape sequence "\\)?") ;; everything else is an invalid escape sequence "Regexp for matching escape codes in string literals. See Haskell Report Sect 2.6, URL `http://www.haskell.org/onlinereport/haskell2010/haskellch2.html#x7-200002.6', for more details.") (defconst haskell-string-literal-decode1-table (let ((h (make-hash-table :test 'equal))) (mapc (lambda (c) (puthash (concat "\\" (car c)) (cdr c) h)) '(;; ascii-escapes ("NUL" . "\x00") ("SOH" . "\x01") ("STX" . "\x02") ("ETX" . "\x03") ("EOT" . "\x04") ("ENQ" . "\x05") ("ACK" . "\x06") ("BEL" . "\x07") ("BS" . "\x08") ("HT" . "\x09") ("LF" . "\x0a") ("VT" . "\x0b") ("FF" . "\x0c") ("CR" . "\x0d") ("SO" . "\x0e") ("SI" . "\x0f") ("DLE" . "\x10") ("DC1" . "\x11") ("DC2" . "\x12") ("DC3" . "\x13") ("DC4" . "\x14") ("NAK" . "\x15") ("SYN" . "\x16") ("ETB" . "\x17") ("CAN" . "\x18") ("EM" . "\x19") ("SUB" . "\x1a") ("ESC" . "\x1b") ("FS" . "\x1c") ("GS" . "\x1d") ("RS" . "\x1e") ("US" . "\x1f") ("SP" . "\x20") ("DEL" . "\x7f" ) ;; C-compatible single-char escape sequences ("a" . "\x07") ("b" . "\x08") ("f" . "\x0c") ("n" . "\x0a") ("r" . "\x0d") ("t" . "\x09") ("v" . "\x0b") ;; trivial escapes ("\\" . "\\") ("\"" . "\"") ("'" . "'") ;; "empty" escape ("&" . ""))) h) "Hash table containing irregular escape sequences and their decoded strings. Used by `haskell-string-literal-decode1'.") (defun haskell-string-literal-decode1 (l) "Decode a single string literal escape sequence. L must contain exactly one escape sequence. This is an internal function used by `haskell-string-literal-decode'." (let ((case-fold-search nil)) (cond ((gethash l haskell-string-literal-decode1-table)) ((string-match "\\`[\\][0-9]+\\'" l) (char-to-string (string-to-number (substring l 1) 10))) ((string-match "\\`[\\]x[[:xdigit:]]+\\'" l) (char-to-string (string-to-number (substring l 2) 16))) ((string-match "\\`[\\]o[0-7]+\\'" l) (char-to-string (string-to-number (substring l 2) 8))) ((string-match "\\`[\\]\\^[@-_]\\'" l) (char-to-string (- (aref l 2) ?@))) ;; "cntrl" escapes ((string-match "\\`[\\][\t\n\v\f\r ]+[\\]\\'" l) "") ;; whitespace gap (t (error "Invalid escape sequence"))))) (defun haskell-string-literal-decode (estr &optional no-quotes) "Decode a Haskell string-literal. If NO-QUOTES is nil, ESTR must be surrounded by quotes. This is the dual operation to `haskell-string-literal-encode'." (if (and (not no-quotes) (string-match-p "\\`\"[^\\\"[:cntrl:]]*\"\\'" estr)) (substring estr 1 -1) ;; optimized fast-path for trivial strings (let ((s (if no-quotes ;; else: do general decoding estr (if (string-match-p "\\`\".*\"\\'" estr) (substring estr 1 -1) (error "String literal must be delimited by quotes")))) (case-fold-search nil)) (replace-regexp-in-string haskell-string-literal-escapes-regexp #'haskell-string-literal-decode1 s t t)))) (defun haskell-string-ellipsize (string n) "Return STRING truncated to (at most) N characters. If truncation occurred, last character in string is replaced by `…'. See also `haskell-string-take'." (cond ((<= (length string) n) string) ;; no truncation needed ((< n 1) "") (t (concat (substring string 0 (1- n)) "…")))) (defun haskell-string-chomp (str) "Chomp leading and tailing whitespace from STR." (while (string-match "\\`\n+\\|^\\s-+\\|\\s-+$\\|\n+\\'" str) (setq str (replace-match "" t t str))) str) (defun haskell-string-split-to-lines (str) "Split STR to lines and return a list of strings with preceding and succeding space removed." (when (stringp str) (cl-mapcar #'haskell-string-chomp (split-string str "\n")))) (defun haskell-string-trim-prefix (prefix str) "If PREFIX is prefix of STR, the string is trimmed." (when (and (stringp prefix) (stringp str)) (if (string-prefix-p prefix str) (substring str (length prefix))))) (defun haskell-string-trim-suffix (suffix str) "If SUFFIX is suffix of STR, the string is trimmed." (when (and (stringp suffix) (stringp str)) (if (string-suffix-p suffix str) (substring str 0 (* -1 (length suffix)))))) (defun haskell-string-drop-qualifier (ident) "Drop qualifier from given identifier IDENT. If the identifier is not qualified return it unchanged." (or (and (string-match "^\\([^.]*\\.\\)*\\(?1:[^.]+\\)$" ident) (match-string 1 ident)) ident)) (defun haskell-mode-message-line (str) "Echo STR in mini-buffer. Given string is shrinken to single line, multiple lines just disturbs the programmer." (unless (active-minibuffer-window) (message "%s" (haskell-mode-one-line str (frame-width))))) (defun haskell-mode-one-line (str &optional width) "Try to fit STR as much as possible on one line according to given WIDTH." (unless width (setq width (length str))) (let* ((long-line (replace-regexp-in-string "\n" " " str)) (condensed (replace-regexp-in-string " +" " " (haskell-string-trim long-line)))) (truncate-string-to-width condensed width nil nil "…"))) (provide 'haskell-string) ;;; haskell-string.el ends here ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-svg.el��������������������������������������������������������������������0000664�0000000�0000000�00000004326�13602233217�0016555�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-svg.el --- SVG Rendering -*- lexical-binding: t -*- ;; Copyright (c) 2018 Federico Beffa. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (defcustom haskell-svg-render-images nil "Replace SVG image text with actual images." :group 'haskell-interactive :type 'boolean) (defconst haskell-svg-supported (image-type-available-p 'svg) "Defines if SVG images are supported by this instance of Emacs.") (defun haskell-svg-render-images-p () "Shall we render SVG images?" (and haskell-svg-supported (display-images-p) haskell-svg-render-images)) (defun haskell-svg-maybe-render-images (text) "Render SVG images if desired and supported, or terurn the input unmodified." (if (haskell-svg-render-images-p) (haskell-svg-render-images text) text)) (defun haskell-svg-render-images (text) "Replace an SVG image text with an actual image." (with-temp-buffer (insert text) (goto-char (point-min)) (when (re-search-forward "\"?<\\?xml\\(.\\|\n\\|\r\\)* PUBLIC \"-//W3C//DTD SVG [0-9]\.[0-9]//EN\\(.\\|\n\\|\r\\)*</svg>\"?" nil t) (let ((svg-string (match-string 0)) (begin (match-beginning 0)) (end (match-end 0))) (delete-region begin end) (goto-char begin) (insert-image (create-image svg-string nil t) "SVG image"))) (buffer-substring (point-min) (point-max)))) (defun haskell-svg-toggle-render-images () "Toggle rendering of SVG images at the REPL output." (interactive) (setq haskell-svg-render-images (not haskell-svg-render-images))) (provide 'haskell-svg) ;;; haskell-svg.el ends here ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-unicode-input-method.el���������������������������������������������������0000664�0000000�0000000�00000020370�13602233217�0022014�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-unicode-input-method.el --- Haskell Unicode helper functions -*- coding: utf-8; lexical-binding: t -*- ;; Copyright (C) 2010-2011 Roel van Dijk ;; Author: Roel van Dijk <vandijk.roel@gmail.com> ;; This file is not part of GNU Emacs. ;; This file 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 file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;;; Code: (require 'quail) ;;;###autoload (defun turn-on-haskell-unicode-input-method () "Set input method `haskell-unicode'." (interactive) (set-input-method "haskell-unicode")) (quail-define-package "haskell-unicode" ;; name "UTF-8" ;; language "\\" ;; title t ;; guidance "Haskell Unicode input method. Designed to be used with the Haskell UnicodeSyntax language extension in combination with the x-unicode-symbols set of packages (base-unicode-symbols and containers-unicode-symbols). " ;; docstring nil ;; translation-keys nil ;; forget-last-selection nil ;; deterministic nil ;; kbd-translate nil ;; show-layout nil ;; create-decode-map nil ;; maximum-shortest nil ;; overlay-plist nil ;; update-translation-function nil ;; conversion-keys t ;; simple ) (quail-define-rules ;; Greek letters ("alpha " ["α"]) ("Alpha " ["Α"]) ("beta " ["β"]) ("Beta " ["Β"]) ("gamma " ["γ"]) ("Gamma " ["Γ"]) ("delta " ["δ"]) ("Delta " ["Δ"]) ("epsilon " ["ε"]) ("Epsilon " ["Ε"]) ("zeta " ["ζ"]) ("Zeta " ["Ζ"]) ("eta " ["η"]) ("Eta " ["Η"]) ("theta " ["θ"]) ("Theta " ["Θ"]) ("iota " ["ι"]) ("Iota " ["Ι"]) ("kappa " ["κ"]) ("Kappa " ["Κ"]) ("lambda " ["λ"]) ("Lambda " ["Λ"]) ("lamda " ["λ"]) ("Lamda " ["Λ"]) ("mu " ["μ"]) ("Mu " ["Μ"]) ("nu " ["ν"]) ("Nu " ["Ν"]) ("xi " ["ξ"]) ("Xi " ["Ξ"]) ("omicron " ["ο"]) ("Omicron " ["Ο"]) ("pi " ["π"]) ("Pi " ["Π"]) ("rho " ["ρ"]) ("Rho " ["Ρ"]) ("sigma " ["σ"]) ("Sigma " ["Σ"]) ("tau " ["τ"]) ("Tau " ["Τ"]) ("upsilon " ["υ"]) ("Upsilon " ["Υ"]) ("phi " ["φ"]) ("Phi " ["Φ"]) ("chi " ["χ"]) ("Chi " ["Χ"]) ("psi " ["ψ"]) ("Psi " ["Ψ"]) ("omega " ["ω"]) ("Omega " ["Ω"]) ("digamma " ["ϝ"]) ("Digamma " ["Ϝ"]) ("san " ["ϻ"]) ("San " ["Ϻ"]) ("qoppa " ["ϙ"]) ("Qoppa " ["Ϙ"]) ("sampi " ["ϡ"]) ("Sampi " ["Ϡ"]) ("stigma " ["ϛ"]) ("Stigma " ["Ϛ"]) ("heta " ["ͱ"]) ("Heta " ["Ͱ"]) ("sho " ["ϸ"]) ("Sho " ["Ϸ"]) ;; Double-struck letters ("|A|" ["𝔸"]) ("|B|" ["𝔹"]) ("|C|" ["ℂ"]) ("|D|" ["𝔻"]) ("|E|" ["𝔼"]) ("|F|" ["𝔽"]) ("|G|" ["𝔾"]) ("|H|" ["ℍ"]) ("|I|" ["𝕀"]) ("|J|" ["𝕁"]) ("|K|" ["𝕂"]) ("|L|" ["𝕃"]) ("|M|" ["𝕄"]) ("|N|" ["ℕ"]) ("|O|" ["𝕆"]) ("|P|" ["ℙ"]) ("|Q|" ["ℚ"]) ("|R|" ["ℝ"]) ("|S|" ["𝕊"]) ("|T|" ["𝕋"]) ("|U|" ["𝕌"]) ("|V|" ["𝕍"]) ("|W|" ["𝕎"]) ("|X|" ["𝕏"]) ("|Y|" ["𝕐"]) ("|Z|" ["ℤ"]) ("|gamma|" ["ℽ"]) ("|Gamma|" ["ℾ"]) ("|pi|" ["ℼ"]) ("|Pi|" ["ℿ"]) ;; Types ("::" ["∷"]) ;; Quantifiers ("forall" ["∀"]) ("exists" ["∃"]) ;; Arrows ("->" ["→"]) ;; ("-->" ["⟶"]) ("<-" ["←"]) ;; ("<--" ["⟵"]) ;; ("<->" ["↔"]) ;; ("<-->" ["⟷"]) ("=>" ["⇒"]) ;; ("==>" ["⟹"]) ;; ("<=" ["⇐"]) ;; ("<==" ["⟸"]) ;; ("<=>" ["⇔"]) ;; ("<==>" ["⟺"]) ;; ("|->" ["↦"]) ;; ("|-->" ["⟼"]) ;; ("<-|" ["↤"]) ;; ("<--|" ["⟻"]) ;; ("|=>" ["⤇"]) ;; ("|==>" ["⟾"]) ;; ("<=|" ["⤆"]) ;; ("<==|" ["⟽"]) ("~>" ["⇝"]) ;; ("~~>" ["⟿"]) ("<~" ["⇜"]) ;; ("<~~" ["⬳"]) ;; (">->" ["↣"]) ;; ("<-<" ["↢"]) ;; ("->>" ["↠"]) ;; ("<<-" ["↞"]) ;; (">->>" ["⤖"]) ;; ("<<-<" ["⬻"]) ;; ("<|-" ["⇽"]) ;; ("-|>" ["⇾"]) ;; ("<|-|>" ["⇿"]) ;; ("<-/-" ["↚"]) ;; ("-/->" ["↛"]) ;; ("<-|-" ["⇷"]) ;; ("-|->" ["⇸"]) ;; ("<-|->" ["⇹"]) ;; ("<-||-" ["⇺"]) ;; ("-||->" ["⇻"]) ;; ("<-||->" ["⇼"]) ;; ("-o->" ["⇴"]) ;; ("<-o-" ["⬰"]) ;; Boolean operators ;; ("not" ["¬"]) ("&&" ["∧"]) ("||" ["∨"]) ;; Relational operators ("==" ["≡"]) ("/=" ["≢" "≠"]) ("<=" ["≤"]) (">=" ["≥"]) ("/<" ["≮"]) ("/>" ["≯"]) ;; Arithmetic ;; (" / " [" ÷ "]) (" * " [" ⋅ "]) ;; Containers / Collections ;; ("++" ["⧺"]) ;; ("+++" ["⧻"]) ;; ("|||" ["⫴"]) ;; ("empty" ["∅"]) ("elem" ["∈"]) ("notElem" ["∉"]) ("member" ["∈"]) ("notMember" ["∉"]) ("union" ["∪"]) ("intersection" ["∩"]) ("isSubsetOf" ["⊆"]) ("isProperSubsetOf" ["⊂"]) ;; Other ;; ("<<" ["≪"]) ;; (">>" ["≫"]) ("<<<" ["⋘"]) (">>>" ["⋙"]) ("<|" ["⊲"]) ("|>" ["⊳"]) ("><" ["⋈"]) ;; ("mempty" ["∅"]) ("mappend" ["⊕"]) ;; ("<*>" ["⊛"]) (" . " [" ∘ "]) ("undefined" ["⊥"]) (":=" ["≔"]) ("=:" ["≕"]) ("=def" ["≝"]) ("=?" ["≟"]) ("..." ["…"]) ;; Braces ;; ("[|" ["〚"]) ;; ("|]" ["〛"]) ;; Numeric subscripts ("_0 " ["₀"]) ("_1 " ["₁"]) ("_2 " ["₂"]) ("_3 " ["₃"]) ("_4 " ["₄"]) ("_5 " ["₅"]) ("_6 " ["₆"]) ("_7 " ["₇"]) ("_8 " ["₈"]) ("_9 " ["₉"]) ;; Numeric superscripts ("^0 " ["⁰"]) ("^1 " ["¹"]) ("^2 " ["²"]) ("^3 " ["³"]) ("^4 " ["⁴"]) ("^5 " ["⁵"]) ("^6 " ["⁶"]) ("^7 " ["⁷"]) ("^8 " ["⁸"]) ("^9 " ["⁹"]) ) (provide 'haskell-unicode-input-method) ;;; haskell-unicode-input-method.el ends here ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell-utils.el������������������������������������������������������������������0000664�0000000�0000000�00000016605�13602233217�0017121�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-utils.el --- General utility functions used by haskell-mode modules -*- lexical-binding: t -*- ;; Copyright © 2013 Herbert Valerio Riedel ;; 2016 Arthur Fayzrakhmanov ;; Author: Herbert Valerio Riedel <hvr@gnu.org> ;; This file is not part of GNU Emacs. ;; This file 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 file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; This module's purpose is to provide a place for helper functions ;; which are general enough to be usable by multiple modules and/or ;; to alleviate circular module dependency problems. ;; ;; When possible, functions in this module shall be accompanied by ;; ERT-based unit tests. ;; ;; See also `haskell-str.el' for string utility functions. ;; ;; All symbols in this module have a `haskell-utils-' prefix. ;;; Code: ;; ============================================================================= ;; NOTE: ;; THIS MODULE IS SUPPOSED TO BE A LEAF-MODULE AND SHALL NOT REQUIRE/DEPEND-ON ;; ANY OTHER HASKELL-MODE MODULES IN ORDER TO STAY AT THE BOTTOM OF THE MODULE ;; DEPENDENCY GRAPH. ;; ============================================================================= (eval-when-compile (require 'cl-lib)) (defvar-local haskell-utils-async-post-command-flag nil "Non-nil means some commands were triggered during async function execution.") (defvar haskell-mode-interactive-prompt-state nil "Special variable indicating a state of user input waiting.") (defun haskell-utils-read-directory-name (prompt default) "Read directory name and normalize to true absolute path. Refer to `read-directory-name' for the meaning of PROMPT and DEFAULT. If `haskell-process-load-or-reload-prompt' is nil, accept `default'." (let ((filename (file-truename (read-directory-name prompt default default)))) (concat (replace-regexp-in-string "/$" "" filename) "/"))) (defun haskell-utils-parse-import-statement-at-point () "Return imported module name if on import statement or nil otherwise. This currently assumes that the \"import\" keyword and the module name are on the same line. This function supports the SafeHaskell and PackageImports syntax extensions. Note: doesn't detect if in {--}-style comment." (save-excursion (goto-char (line-beginning-position)) (if (looking-at (concat "[\t ]*import[\t ]+" "\\(?:safe[\t ]+\\)?" ;; SafeHaskell "\\(?:qualified[\t ]+\\)?" "\\(?:\"[^\"]*\"[\t ]+\\)?" ;; PackageImports "\\([[:digit:][:upper:][:lower:]_.]+\\)")) (match-string-no-properties 1)))) (defun haskell-utils-async-update-post-command-flag () "A special hook which collects triggered commands during async execution. This hook pushes value of variable `this-command' to flag variable `haskell-utils-async-post-command-flag'." (let* ((cmd this-command) (updated-flag (cons cmd haskell-utils-async-post-command-flag))) (setq haskell-utils-async-post-command-flag updated-flag))) (defun haskell-utils-async-watch-changes () "Watch for triggered commands during async operation execution. Resets flag variable `haskell-utils-async-update-post-command-flag' to NIL. By changes it is assumed that nothing happened, e.g. nothing was inserted in buffer, point was not moved, etc. To collect data `post-command-hook' is used." (setq haskell-utils-async-post-command-flag nil) (add-hook 'post-command-hook #'haskell-utils-async-update-post-command-flag nil t)) (defun haskell-utils-async-stop-watching-changes (buffer) "Clean up after async operation finished. This function takes care about cleaning up things made by `haskell-utils-async-watch-changes'. The BUFFER argument is a buffer where `post-command-hook' should be disabled. This is necessary, because it is possible that user will change buffer during async function execusion." (with-current-buffer buffer (setq haskell-utils-async-post-command-flag nil) (remove-hook 'post-command-hook #'haskell-utils-async-update-post-command-flag t))) (defun haskell-utils-reduce-string (str) "Remove newlines and extra whitespace from string STR. If line starts with a sequence of whitespaces, substitutes this sequence with a single whitespace. Removes all newline characters." (let ((s (replace-regexp-in-string "^\s+" " " str))) (replace-regexp-in-string "\r?\n" "" s))) (defun haskell-utils-repl-response-error-status (response) "Parse response REPL's RESPONSE for errors. Returns one of the following symbols: + unknown-command + option-missing + interactive-error + no-error *Warning*: this funciton covers only three kind of responses: * \"unknown command …\" REPL missing requested command * \"<interactive>:3:5: …\" interactive REPL error * \"Couldn't guess that module name. Does it exist?\" (:type-at and maybe some other commands error) * *all other reposnses* are treated as success reposneses and 'no-error is returned." (if response (let ((first-line (car (split-string response "\n" t)))) (cond ((null first-line) 'no-error) ((string-match-p "^unknown command" first-line) 'unknown-command) ((string-match-p "^Couldn't guess that module name. Does it exist?" first-line) 'option-missing) ((string-match-p "^<interactive>:" first-line) 'interactive-error) (t 'no-error))) ;; in case of nil-ish response it's not clear is it error response or not 'no-error)) (defun haskell-utils-compose-type-at-command (pos) "Prepare :type-at command to be send to haskell process. POS is a cons cell containing min and max positions, i.e. target expression bounds." (save-excursion (let ((start-p (car pos)) (end-p (cdr pos)) start-l start-c end-l end-c value) (goto-char start-p) (setq start-l (line-number-at-pos)) (setq start-c (1+ (current-column))) (goto-char end-p) (setq end-l (line-number-at-pos)) (setq end-c (1+ (current-column))) (setq value (buffer-substring-no-properties start-p end-p)) ;; suppress multiline expressions (let ((lines (split-string value "\n" t))) (when (and (cdr lines) (stringp (car lines))) (setq value (format "[ %s … ]" (car lines))))) (replace-regexp-in-string "\n$" "" (format ":type-at %s %d %d %d %d %s" (buffer-file-name) start-l start-c end-l end-c value))))) (defun haskell-mode-toggle-interactive-prompt-state (&optional disabled) "Set `haskell-mode-interactive-prompt-state' to t. If given DISABLED argument sets variable value to nil, otherwise to t." (setq haskell-mode-interactive-prompt-state (not disabled))) (provide 'haskell-utils) ;;; haskell-utils.el ends here ���������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/haskell.el������������������������������������������������������������������������0000664�0000000�0000000�00000052471�13602233217�0015764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell.el --- Top-level Haskell package -*- lexical-binding: t -*- ;; Copyright © 2014 Chris Done. All rights reserved. ;; 2016 Arthur Fayzrakhmanov ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;;; Code: (require 'cl-lib) (require 'haskell-mode) (require 'haskell-hoogle) (require 'haskell-process) (require 'haskell-debug) (require 'haskell-interactive-mode) (require 'haskell-repl) (require 'haskell-load) (require 'haskell-commands) (require 'haskell-modules) (require 'haskell-string) (require 'haskell-completions) (require 'haskell-utils) (require 'haskell-customize) (defvar interactive-haskell-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "C-c C-l") 'haskell-process-load-file) (define-key map (kbd "C-c C-r") 'haskell-process-reload) (define-key map (kbd "C-c C-t") 'haskell-process-do-type) (define-key map (kbd "C-c C-i") 'haskell-process-do-info) (define-key map (kbd "M-.") 'haskell-mode-jump-to-def-or-tag) (define-key map (kbd "C-c C-k") 'haskell-interactive-mode-clear) (define-key map (kbd "C-c C-c") 'haskell-process-cabal-build) (define-key map (kbd "C-c C-v") 'haskell-cabal-visit-file) (define-key map (kbd "C-c C-x") 'haskell-process-cabal) (define-key map (kbd "C-c C-b") 'haskell-interactive-switch) (define-key map (kbd "C-c C-z") 'haskell-interactive-switch) map) "Keymap for using `interactive-haskell-mode'.") ;;;###autoload (define-minor-mode interactive-haskell-mode "Minor mode for enabling haskell-process interaction." :lighter " Interactive" :keymap interactive-haskell-mode-map (add-hook 'completion-at-point-functions #'haskell-completions-sync-repl-completion-at-point nil t)) (make-obsolete 'haskell-process-completions-at-point 'haskell-completions-sync-repl-completion-at-point "June 19, 2015") (defun haskell-process-completions-at-point () "A `completion-at-point' function using the current haskell process." (when (haskell-session-maybe) (let ((process (haskell-process)) symbol-bounds) (cond ;; ghci can complete module names, but it needs the "import " ;; string at the beginning ((looking-back (rx line-start "import" (1+ space) (? "qualified" (1+ space)) (group (? (char upper) ; modid (* (char alnum ?' ?.))))) (line-beginning-position)) (let ((text (match-string-no-properties 0)) (start (match-beginning 1)) (end (match-end 1))) (list start end (haskell-process-get-repl-completions process text)))) ;; Complete OPTIONS, a completion list comes from variable ;; `haskell-ghc-supported-options' ((and (nth 4 (syntax-ppss)) (save-excursion (let ((p (point))) (and (search-backward "{-#" nil t) (search-forward-regexp "\\_<OPTIONS\\(?:_GHC\\)?\\_>" p t)))) (looking-back (rx symbol-start "-" (* (char alnum ?-))) (line-beginning-position))) (list (match-beginning 0) (match-end 0) haskell-ghc-supported-options)) ;; Complete LANGUAGE, a list of completions comes from variable ;; `haskell-ghc-supported-extensions' ((and (nth 4 (syntax-ppss)) (save-excursion (let ((p (point))) (and (search-backward "{-#" nil t) (search-forward-regexp "\\_<LANGUAGE\\_>" p t)))) (setq symbol-bounds (bounds-of-thing-at-point 'symbol))) (list (car symbol-bounds) (cdr symbol-bounds) haskell-ghc-supported-extensions)) ((setq symbol-bounds (haskell-ident-pos-at-point)) (cl-destructuring-bind (start . end) symbol-bounds (list start end (haskell-process-get-repl-completions process (buffer-substring-no-properties start end))))))))) ;;;###autoload (defun haskell-interactive-mode-return () "Handle the return key." (interactive) (cond ;; At a compile message, jump to the location of the error in the ;; source. ((haskell-interactive-at-compile-message) (next-error-internal)) ;; At the input prompt, handle the expression in the usual way. ((haskell-interactive-at-prompt) (haskell-interactive-handle-expr)) ;; At any other location in the buffer, copy the line to the ;; current prompt. (t (haskell-interactive-copy-to-prompt)))) ;;;###autoload (defun haskell-session-kill (&optional leave-interactive-buffer) "Kill the session process and buffer, delete the session. 0. Prompt to kill all associated buffers. 1. Kill the process. 2. Kill the interactive buffer unless LEAVE-INTERACTIVE-BUFFER is not given. 3. Walk through all the related buffers and set their haskell-session to nil. 4. Remove the session from the sessions list." (interactive) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (let* ((session (haskell-session)) (name (haskell-session-name session)) (also-kill-buffers (and haskell-ask-also-kill-buffers (y-or-n-p (format "Killing `%s'. Also kill all associated buffers?" name))))) (haskell-kill-session-process session) (unless leave-interactive-buffer (kill-buffer (haskell-session-interactive-buffer session))) (cl-loop for buffer in (buffer-list) do (with-current-buffer buffer (when (and (boundp 'haskell-session) (string= (haskell-session-name haskell-session) name)) (setq haskell-session nil) (when also-kill-buffers (kill-buffer))))) (setq haskell-sessions (cl-remove-if (lambda (session) (string= (haskell-session-name session) name)) haskell-sessions))) (haskell-mode-toggle-interactive-prompt-state t))) ;;;###autoload (defun haskell-interactive-kill () "Kill the buffer and (maybe) the session." (interactive) (when (eq major-mode 'haskell-interactive-mode) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (when (and (boundp 'haskell-session) haskell-session (y-or-n-p "Kill the whole session?")) (haskell-session-kill t))) (haskell-mode-toggle-interactive-prompt-state t))) (defun haskell-session-make (name) "Make a Haskell session." (when (haskell-session-lookup name) (error "Session of name %s already exists!" name)) (let ((session (setq haskell-session (list (cons 'name name))))) (add-to-list 'haskell-sessions session) (haskell-process-start session) session)) (defun haskell-session-new-assume-from-cabal () "Prompt to create a new project based on a guess from the nearest Cabal file. If `haskell-process-load-or-reload-prompt' is nil, accept `default'." (let ((name (haskell-session-default-name))) (unless (haskell-session-lookup name) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (if (or (not haskell-process-load-or-reload-prompt) (y-or-n-p (format "Start a new project named “%s”? " name))) (haskell-session-make name)) (haskell-mode-toggle-interactive-prompt-state t))))) ;;;###autoload (defun haskell-session () "Get the Haskell session, prompt if there isn't one or fail." (or (haskell-session-maybe) (haskell-session-assign (or (haskell-session-from-buffer) (haskell-session-new-assume-from-cabal) (haskell-session-choose) (haskell-session-new))))) ;;;###autoload (defun haskell-interactive-switch () "Switch to the interactive mode for this session." (interactive) (let ((initial-buffer (current-buffer)) (buffer (haskell-session-interactive-buffer (haskell-session)))) (with-current-buffer buffer (setq haskell-interactive-previous-buffer initial-buffer)) (unless (eq buffer (window-buffer)) (switch-to-buffer-other-window buffer)))) (defun haskell-session-new () "Make a new session." (let ((name (read-from-minibuffer "Project name: " (haskell-session-default-name)))) (when (not (string= name "")) (let ((session (haskell-session-lookup name))) (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (if session (when (y-or-n-p (format "Session %s already exists. Use it?" name)) session) (haskell-session-make name))) (haskell-mode-toggle-interactive-prompt-state t))))) ;;;###autoload (defun haskell-session-change () "Change the session for the current buffer." (interactive) (haskell-session-assign (or (haskell-session-new-assume-from-cabal) (haskell-session-choose) (haskell-session-new)))) (defun haskell-process-prompt-restart (process) "Prompt to restart the died PROCESS." (let ((process-name (haskell-process-name process)) (cursor-in-echo-area t)) (if haskell-process-suggest-restart (progn (haskell-mode-toggle-interactive-prompt-state) (unwind-protect (cond ((string-match "You need to re-run the 'configure' command." (haskell-process-response process)) (cl-case (read-char-choice (concat "The Haskell process ended. Cabal wants you to run " (propertize "cabal configure" 'face 'font-lock-keyword-face) " because there is a version mismatch. Re-configure (y, n, l: view log)?" "\n\n" "Cabal said:\n\n" (propertize (haskell-process-response process) 'face 'font-lock-comment-face)) '(?l ?n ?y)) (?y (let ((default-directory (haskell-session-cabal-dir (haskell-process-session process)))) (message "%s" (shell-command-to-string "cabal configure")))) (?l (let* ((response (haskell-process-response process)) (buffer (get-buffer "*haskell-process-log*"))) (if buffer (switch-to-buffer buffer) (progn (switch-to-buffer (get-buffer-create "*haskell-process-log*")) (insert response))))) (?n))) (t (cl-case (read-char-choice (propertize (format "The Haskell process `%s' has died. Restart? (y, n, l: show process log) " process-name) 'face 'minibuffer-prompt) '(?l ?n ?y)) (?y (haskell-process-start (haskell-process-session process))) (?l (let* ((response (haskell-process-response process)) (buffer (get-buffer "*haskell-process-log*"))) (if buffer (switch-to-buffer buffer) (progn (switch-to-buffer (get-buffer-create "*haskell-process-log*")) (insert response))))) (?n)))) ;; unwind (haskell-mode-toggle-interactive-prompt-state t))) (message "The Haskell process `%s' is dearly departed." process-name)))) (defun haskell-process () "Get the current process from the current session." (haskell-session-process (haskell-session))) ;;;###autoload (defun haskell-kill-session-process (&optional session) "Kill the process." (interactive) (let* ((session (or session (haskell-session))) (existing-process (get-process (haskell-session-name session)))) (when (processp existing-process) (haskell-interactive-mode-echo session "Killing process ...") (haskell-process-set (haskell-session-process session) 'is-restarting t) (delete-process existing-process)))) ;;;###autoload (defun haskell-interactive-mode-visit-error () "Visit the buffer of the current (or last) error message." (interactive) (with-current-buffer (haskell-session-interactive-buffer (haskell-session)) (if (progn (goto-char (line-beginning-position)) (looking-at haskell-interactive-mode-error-regexp)) (progn (forward-line -1) (haskell-interactive-jump-to-error-line)) (progn (goto-char (point-max)) (haskell-interactive-mode-error-backward) (haskell-interactive-jump-to-error-line))))) (defvar xref-prompt-for-identifier nil) ;;;###autoload (defun haskell-mode-jump-to-tag (&optional next-p) "Jump to the tag of the given identifier. Give optional NEXT-P parameter to override value of `xref-prompt-for-identifier' during definition search." (interactive "P") (let ((ident (haskell-string-drop-qualifier (haskell-ident-at-point))) (tags-file-dir (haskell-cabal--find-tags-dir)) (tags-revert-without-query t)) (when (and ident (not (string= "" (haskell-string-trim ident))) tags-file-dir) (let ((tags-file-name (concat tags-file-dir "TAGS"))) (cond ((file-exists-p tags-file-name) (let ((xref-prompt-for-identifier next-p)) (xref-find-definitions ident))) (t (haskell-mode-generate-tags ident))))))) ;;;###autoload (defun haskell-mode-after-save-handler () "Function that will be called after buffer's saving." (when haskell-tags-on-save (ignore-errors (haskell-mode-generate-tags)))) ;;;###autoload (defun haskell-mode-tag-find (&optional _next-p) "The tag find function, specific for the particular session." (interactive "P") (cond ((elt (syntax-ppss) 3) ;; Inside a string (haskell-mode-jump-to-filename-in-string)) (t (call-interactively 'haskell-mode-jump-to-tag)))) (defun haskell-mode-jump-to-filename-in-string () "Jump to the filename in the current string." (let* ((string (save-excursion (buffer-substring-no-properties (1+ (search-backward-regexp "\"" (line-beginning-position) nil 1)) (1- (progn (forward-char 1) (search-forward-regexp "\"" (line-end-position) nil 1)))))) (fp (expand-file-name string (haskell-session-cabal-dir (haskell-session))))) (find-file (read-file-name "" fp fp)))) ;;;###autoload (defun haskell-interactive-bring () "Bring up the interactive mode for this session." (interactive) (let* ((session (haskell-session)) (buffer (haskell-session-interactive-buffer session))) (pop-to-buffer buffer))) ;;;###autoload (defun haskell-process-load-file () "Load the current buffer file." (interactive) (save-buffer) (haskell-interactive-mode-reset-error (haskell-session)) (haskell-process-file-loadish (format "load \"%s\"" (replace-regexp-in-string "\"" "\\\\\"" (buffer-file-name))) nil (current-buffer))) ;;;###autoload (defun haskell-process-reload () "Re-load the current buffer file." (interactive) (save-buffer) (haskell-interactive-mode-reset-error (haskell-session)) (haskell-process-file-loadish "reload" t (current-buffer))) ;;;###autoload (defun haskell-process-reload-file () (haskell-process-reload)) (make-obsolete 'haskell-process-reload-file 'haskell-process-reload "2015-11-14") ;;;###autoload (defun haskell-process-load-or-reload (&optional toggle) "Load or reload. Universal argument toggles which." (interactive "P") (if toggle (progn (setq haskell-reload-p (not haskell-reload-p)) (message "%s (No action taken this time)" (if haskell-reload-p "Now running :reload." "Now running :load <buffer-filename>."))) (if haskell-reload-p (haskell-process-reload) (haskell-process-load-file)))) (make-obsolete 'haskell-process-load-or-reload 'haskell-process-load-file "2015-11-14") ;;;###autoload (defun haskell-process-cabal-build () "Build the Cabal project." (interactive) (haskell-process-do-cabal "build") (haskell-process-add-cabal-autogen)) ;;;###autoload (defun haskell-process-cabal (p) "Prompts for a Cabal command to run." (interactive "P") (if p (haskell-process-do-cabal (read-from-minibuffer "Cabal command (e.g. install): ")) (haskell-process-do-cabal (funcall haskell-completing-read-function "Cabal command: " (append haskell-cabal-commands (list "build --ghc-options=-fforce-recomp")))))) (defun haskell-process-file-loadish (command reload-p module-buffer) "Run a loading-ish COMMAND that wants to pick up type errors\ and things like that. RELOAD-P indicates whether the notification should say 'reloaded' or 'loaded'. MODULE-BUFFER may be used for various things, but is optional." (let ((session (haskell-session))) (haskell-session-current-dir session) (when haskell-process-check-cabal-config-on-load (haskell-process-look-config-changes session)) (let ((process (haskell-process))) (haskell-process-queue-command process (make-haskell-command :state (list session process command reload-p module-buffer) :go (lambda (state) (haskell-process-send-string (cadr state) (format ":%s" (cl-caddr state)))) :live (lambda (state buffer) (haskell-process-live-build (cadr state) buffer nil)) :complete (lambda (state response) (haskell-process-load-complete (car state) (cadr state) response (cl-cadddr state) (cl-cadddr (cdr state))))))))) ;;;###autoload (defun haskell-process-minimal-imports () "Dump minimal imports." (interactive) (unless (> (save-excursion (goto-char (point-min)) (haskell-navigate-imports-go) (point)) (point)) (goto-char (point-min)) (haskell-navigate-imports-go)) (haskell-process-queue-sync-request (haskell-process) ":set -ddump-minimal-imports") (haskell-process-load-file) (insert-file-contents-literally (concat (haskell-session-current-dir (haskell-session)) "/" (haskell-guess-module-name-from-file-name (buffer-file-name)) ".imports"))) (defun haskell-interactive-jump-to-error-line () "Jump to the error line." (let ((orig-line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) (and (string-match "^\\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)\\(-[0-9]+\\)?:" orig-line) (let* ((file (match-string 1 orig-line)) (line (match-string 2 orig-line)) (col (match-string 3 orig-line)) (session (haskell-interactive-session)) (cabal-path (haskell-session-cabal-dir session)) (src-path (haskell-session-current-dir session)) (cabal-relative-file (expand-file-name file cabal-path)) (src-relative-file (expand-file-name file src-path))) (let ((file (cond ((file-exists-p cabal-relative-file) cabal-relative-file) ((file-exists-p src-relative-file) src-relative-file)))) (when file (other-window 1) (find-file file) (haskell-interactive-bring) (goto-char (point-min)) (forward-line (1- (string-to-number line))) (goto-char (+ (point) (string-to-number col) -1)) (haskell-mode-message-line orig-line) t)))))) (provide 'haskell) ;;; haskell.el ends here �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/highlight-uses-mode.el������������������������������������������������������������0000664�0000000�0000000�00000007612�13602233217�0020204�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; highlight-uses-mode.el --- Mode for highlighting uses -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'cl-lib) (defvar highlight-uses-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "TAB") 'highlight-uses-mode-next) (define-key map (kbd "S-TAB") 'highlight-uses-mode-prev) (define-key map (kbd "<backtab>") 'highlight-uses-mode-prev) (define-key map (kbd "RET") 'highlight-uses-mode-stop-here) (define-key map (kbd "C-g") 'highlight-uses-mode) map) "Keymap for using `highlight-uses-mode'.") (defvar-local highlight-uses-mode-point nil) ;;;###autoload (define-minor-mode highlight-uses-mode "Minor mode for highlighting and jumping between uses." :lighter " Uses" :keymap highlight-uses-mode-map (if highlight-uses-mode (setq highlight-uses-mode-point (point)) (when highlight-uses-mode-point (goto-char highlight-uses-mode-point))) (remove-overlays (point-min) (point-max) 'highlight-uses-mode-highlight t)) (defun highlight-uses-mode-replace () "Replace all highlighted instances in the buffer with something else." (interactive) (save-excursion (goto-char (point-min)) (let ((o (highlight-uses-mode-next))) (when o (let ((replacement (read-from-minibuffer (format "Replace uses %s with: " (buffer-substring (overlay-start o) (overlay-end o)))))) (while o (goto-char (overlay-start o)) (delete-region (overlay-start o) (overlay-end o)) (insert replacement) (setq o (highlight-uses-mode-next)))))))) (defun highlight-uses-mode-stop-here () "Stop at this point." (interactive) (setq highlight-uses-mode-point (point)) (highlight-uses-mode -1)) (defun highlight-uses-mode-next () "Jump to next result." (interactive) (let ((os (sort (cl-remove-if (lambda (o) (or (<= (overlay-start o) (point)) (not (overlay-get o 'highlight-uses-mode-highlight)))) (overlays-in (point) (point-max))) (lambda (a b) (< (overlay-start a) (overlay-start b)))))) (when os (goto-char (overlay-start (car os))) (car os)))) (defun highlight-uses-mode-prev () "Jump to previous result." (interactive) (let ((os (sort (cl-remove-if (lambda (o) (or (>= (overlay-end o) (point)) (not (overlay-get o 'highlight-uses-mode-highlight)))) (overlays-in (point-min) (point))) (lambda (a b) (> (overlay-start a) (overlay-start b)))))) (when os (goto-char (overlay-start (car os))) (car os)))) (defun highlight-uses-mode-highlight (start end) "Make a highlight overlay at the given span." (let ((o (make-overlay start end))) (overlay-put o 'priority 999) (overlay-put o 'face 'isearch) (overlay-put o 'highlight-uses-mode-highlight t))) (provide 'highlight-uses-mode) ����������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/images/���������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13602233217�0015253�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/images/haskell-mode-128x128.png���������������������������������������������������0000664�0000000�0000000�00000044250�13602233217�0021266�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������>a�� AiCCPICC Profile��H wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺�PtX4X\XffGD=HƳ.d,P&s"7C$� E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI�(L�0_&l2E�9r9h�xgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/�$ZU�m@O ��ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h<X.d 6'~khu_�}9PIo=�C#$n?z}[1 Ⱦhs2z \nLA"S dr%,߄lt 4.0,` 3p �H.Hi@A>� A1vjp�ԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a �ٰ;GDxJ>�,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 <y}'ZZ։6i{L{ӝ-?|gKϑ9w~Bƅ:Wt>ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~��� pHYs��T��TyJ��diTXtXML:com.adobe.xmp�����<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/"> <xmp:CreatorTool>www.inkscape.org</xmp:CreatorTool> </rdf:Description> </rdf:RDF> </x:xmpmeta> Ǧm��<IDATx}x]ŵH:[]mnl0`lP<J/w!! nRn |jBl0 w[r,V쳎O%"a̞=mZ֚5k愩,#-(}ho >( 6coO?Ҙ\{_9Ozo &s}g wCo4,q{ȲNif'UkRg!qifw*4فj>3g̴ITrw͐zVmnJ@3d|uʍ4y Ƥ茻f$Í4YB7fy t&@rgJLE6O8/LgEž1.4CCR64q@;pB-H`\N}`�.KS\ؿIK(m L˚yqRFox.06.qt 3d^qGϟ??iڵf*..NOOJHHHMwѳ�}___gwwwKGGGKSSS}EEEݑ#G7m԰6devq; l ! R qd ] 4vfzxddd]wݕΙ3g~fffi|||^tttzDDDX>hppСCO>N-!@DdЎ |)+p,]UY !ٞ�v4:C]4{w%(((XX`; EW{{][nc(//? B(C)cߌ#9 ׊U$2B>=ӟλk]Y>JANVVVn}W޺7 t<D ' �}P'07e3r [bEC=vw B q#Ϟ=w|M۶mG} "H(HDa66άx"g:)3]�tu?|SLPWu>ӯz{ W.bcTBbV**Jwg4MӐ^|7K݅I2 n"PwC@xR7C2gu<7AR{vQL��>&0j$=0b I@D5%7E 1v H]ij{ 7oq$@$ 2"'$ [G'/SJOROI=,...[e݉_?�h}}:U٨jjZTN=˙F  _4CR'CjZIQE*++I~P-[ӟƮ eD;5P$8ǡA7;!YO{G~_vVV޴v zЮ-c& ]d⩙*99"'x_x='K/l5ৱ̸-!=Oro|:g}D^^^҆ X`.+9ӬRէ4ɻ/,AdRyjK]{}n}uu5L$B "[J@3:(}8ܧzӧ�^{g0tUzrkIء'Ў}@ߵPԩSuuZLJߚn[GKhDH[۟us3^I= 3tz ׭_P˦x-'TuuNtRTtYyƍvM7<B ,ACs0fv ׿PҥY F;|$ #]3_h2 8!"PN=;W-ZRNB~z_R=MI8ducB+:' }9^#5 ']GdL' X KrvԩS&d"&5@�_Bu{1`T~G.s 47Q@bƉ:iT><YڻLՔoP7|EG݁]H.)'0=;ʺ{f:Wտ`KBmUoOUj3K9~-(ԦCP#ꫯ^}q`GsNy 1zD#L#RRRf<pZ!E-߻#5zzb"\nӧOo7K|ث |.#. g=\ƙ$/ m>'oܹڶ90(�GI C#Жa͚5 7؁ x;, y(G��CB QyG{g -S{rz֞Y.qOkĐ́暚 ('$0jT9 =O0g>z1qv Oqc板RGk/ A#1s~*{F9z^Vo,YF.2*D<wbk|"i~o…wڛA�f܁ouT2JY"1ԩ4m`�[ |wu䨵:gϞ.Z\ v PYd. t[ N 8&nu+%R,S?7e.wA]rP.l2 M\;V#5z|!u$\~,?s|8ۣM܀tN82 G7T@�/7>?w;vqڽl޻5VXJLTI*/7M1S}}xEi^? @Ҙ9fA}ںUss^'Q86eaçMq PIx?z S�_bp?vamyc7~0@$T}ݘEC�xlUqq6=�Ta6krܫ ^9䠥kfY;^EV@v@ HhJ?Bx>I}s[o}uƌ[ΛonIFiʕٞZZzcgΝՎA*jn[~YXԩFMƗumZHhf:Zj7vc@fDsno?iv_^c@hhAAF@1D^-g X]ҒEW  sQQ@xu%ChnupJ*TRRTC.S-*<+kT)Zv1;5eʔ901u, # # #0M_lFرc02^ 4UI\8>%9;Go&%j$̽j aڭd0f#Ҿ8ԍq`= V=UZVN<Y* GT 9 CyyOmVC*;`GͶ6Y)PNF!=C(�Yӟ|9\ϙסA LJ24G.UDײL?6Q(\9BKPi\Pr"� [h}kXO�NPsrp9~/ [ a"} 'MpTΔ5k]vQDQ4hh d>ZMkӧqD�.A@ Šy8!<"L%ǨXaq Q*;!Dz8ç{`֭[ ~?`A:d,y~!@ͪ-r3YhfcEDR{RZj:eUyY=< ǒcz%V@_"0R! x 8ɟ3f'?|hn>=U|��xGuvvkv}hs,9[#  dHXf& !�s� GnfEY%{U}4 %YSP} M\qsL9zd a@XHH`:!5|/^ bҥY8#zj;U٤*T Y}z&cd2U3QQ1" `L9c#,{` S'YTZ< 1{'̶)iA!@BjᢩXΫϞmUUU5Xuj ul?2P~ ({c!lt`~ɫoT 7Xy d:!c\T,$,?=*e#CtC�"˗_] lqXDgz&@[{Ֆ'/ UkoTO5rH#q R�jyj,p b9)P gl\S#h7JVvR&�=VcٗØ3@1X`l:>vFf?. ;kG�-q`5LkGV\$3C8R΄~^7id)(Q"e){cOB/�^ Fd%"KDǸ)SY&B)5ɛgna޼5kN -Ao/eh 8*8v L!褐�_(@3]U *�RZUoxxziN֪dߵRS {H %Xs삌@E $vQ  BƩegBxXّ#Po~ RJO"ǘc1g& {�B>tB]wu%%%iŗJj7T) 2{nVJp@"]eTWG `P+Ĝ!NHƖq*(S))9(Ki5  ߎ-}x8ahaC!]&ի3c:, PEFď^zg%:ݍdd#Xfٺ&?|X+ܥǫCdAmf8"asHTWý>` ) jˎT#Vkf8͋x ,+kǫZ8$)Y&Y34bT?X {kϿYM7/yyNAcF_ٝݷV� 6}:цg Q*) ɍx|0N8si^p:WO1; ~1߉_<nяէ^HEL|BڽJ?13;P} +7~5ۛړT&3k x._+PmNSQ1+05k4aDX!]OZCG,6G:Y"w~`v7iڱc7nF h?ȅN]vvMMkO'a11άy hVvWEF%lOpC*)1Y bqcli^{q[8_HDO}�Caj:Pc@�?V͛7̐/m[73 [cCڻL_ɒ+]ߜK C[֨)Ŗy#496KPhQa;9|YGjj"F9Ӧb458 D2.i_3'Ɋ#{zz<G{+ !A�yBX�_( #|ܹ䥄5A܃LVd]].z]~H f\ugB7B Ah =k0hYpVttz`+"}t~<Ǟ0;7<{ML[@J%0@(Lh�-q& n Iw?ofr9wHQ=0AQ1-ѯ@oVpR k!XfHvkbVQ d\*V"H?' +KSBOa!ӄp ͆t{߉e}wQзqy[XqgyTt,xh`i;md|>}PB+ (8Q@:Ƅf0AhS5'66^q 5 z\|0 H E^�6/ ,d t/RLDQk֬aEJgv�1߅׀9y6 l_;T(&q)%]=Wk>q2cKikW_SA]֖Dz9.ήhj:| ^m/v.pl k/4g�XUv6ڞf)zE%Kp?a&l%ye={v&yhvxD=Kd&gS3q�#Y_N>pZSI&HuT~MA[ԇ+9z;w/ ds;!q;wd>jkIP9ևd9y|upZjhoこKVMSoVB:ޣfc cu,K֪}Չ#3,4�,>JwAOSA=[}g1Oi3qgNw.IH\ZG UW{<x[9^"H/}zxmrH=:;b^b N>CMzRlll5@Ш°WpfW�|jDh!,ӣ'ˀah"|NJpWbg 6_+F#<<d;33 ʒB5&x: #aŚlz0(%SXeT>l-@~`T<5Q:�Vj0(gV�_~ եjFH&V<h`}Ѯ(5޾^m"o/d |[L$ /m Wc?;i+P>u"oVW9)3gg[Xͤhwߩ[w8d`y@:̼!X1h.g)W^6l^XݐȰ ~S 03g?l=q' /=�3Uncw�i,@ϥ9_B=_f]6>' $B=m0+v))tYA KT@tlC S6:7 LuuW'z;7L$LzaTgs 8g 13mF#*IMKKPw ګԻy>)^EcUr^PFZBVP|[18GgR0"R5axG379^*爸dFa{ 7̴ ggZc�OAB HO؛'OLQeɄV扠n ~CL}^d^!OҜB[xX,ըl]P\Lp~/4'㛡 *k8*8UGrZ1a.^} h26&>ł/WDC~ݹa& "'dd�$og}ly1l|sv*UVV z%! 8:4!!<!qyh4TIPOu>k++UF:QɑdZ tSYU&\7 Kam,\&~{=g `G\wfa7^ vջNtiKdфK TZ�1?j SW!]3z3hZL5A Q0Kd&4A`@FA D]h DwW'\? =bj;Cc,80TBf嗷 ]h��*gv@n�o~e< C0KM./<vaU_g~Aa|Pa]1]m| |UץaIⲗq\4֩dL 0 #UK8 1':"�ߖ}Ug q0wH/s-‚bh ,ܭ)OY=:f�/n/HT.rqOM#d%%90XJPU (hDDAxa"� 3z%}^s v++sS?ѓl0�?U6O&oE}/DFfBgɟa}{Oc/?`]3GhKg@hŝF{q PQpT&A\ry`m"�  "##r2Np׮ #WQ )<A] ASR{p`91bUJCtrA.%.. :@c  j2NT" B ܋1.Мa&,@`.yuZX�%o?yX3s x[ k!>q;H&kD;ۯ2|lOG4B=S*Z(o,VщZlN|; 5++zu *zTAdب%P"� rf&sTu�&fu :uEd,Izm[edqGiOG|8~tf6OwE%pӹڭ` DKẄ́7U gw4㒲"< "9 :1̸F_Zc~ ڟ)TXnc;V+fG.(gdu#HyMKs+z;I6xIQ.)UwUk?- V_9C <aO[12Fx͍oL* f2*]ɨ>�k!9%Vk8CFx{[NglyxI>wޝ�}eI3|RB (8tcg-Vޥ^z}DT)YXɀuj `dӦBD.ktJ`�0 ,LGXf4/Xi:j"�M~z.5y:cakG-q OrƛJ *u+;ۯ=%|4Q1ӠyBg z@> EZ!ea3L{5teςJ5/6BF%  V;Mh֓ݎ�|afdaAޗ/H;3q>!>Ym ^/|^o]D{ 1pXиs(1 3fs̾2km R4[Ij q** P;p?XkJa` HsS{Ǟ0;Š0C:aa`LKaVЋ{z9ZX,9#=zЫ|/R:0ʄ"e&h8��ș,{e $5\ҫ>>q&D_?UY"�+7M/UsiVI9& +lΎ� 0|xJ#4/j{>@*>>ߤ~^ ]aa­5.S3gfcEX�P ˟A׺Bv l;U-YcKd>3"l%+pg؃Vv e"JǜcO؝V^}ަ=x"iaOAa8<rgݱf*~GEa}܈k~89^be }77ZZÔ�) ďGZut?4Z-NlΩvJťjKJ${>\ArrڷM4]�OPd$ h/ZP@I hYGGaHhH`{_4 Ɔpl:}T/6+ 븾7'l P1b|E1jL+H"M*DM˪vdkn%sv!{4giw8:~<M^.䷣G=7QmطfPH\O;|Ixykk:};Vͦ ÊKps,o~x?<��7جIBq'mgUUN>FdEW}o@ͮH=3o7S7܋;Zysuno54x 3ռw?~!svZ5$?M4v^xy9P+!/Z'y0@;7@ۉ `EDXW}b>U &Fl%**BaGL¬>bpJvɣ u�ʏ8wWb<S֮~s_ ,x~\ !xFN <SWⲬw !T?�#d7 39MYkvҡ8;2 vfΎAU`],dpڹQchv>mz[8Foqѷj�9he4q%%%? qo~X;='1Ԉ@K:S)sťI5_)7ԪтMm[G"lҔ'H,! g �Kwp7Ferټ@=@�Aq9tܜ̟2ձʋ.(\&zZL/_F0$:p8}=B#?ڨyA<Cp5<~񣳫3sX["9sS $﹂6w:TSǕJ,[JS!}-F9pݬEWkCzG!PPq#?A y>�/Aj==�N2FlذM;,f,;2{nA^]`}Mji|X',owagG⣓ 4fhdI?_/$%W\a|G%f>>,-(_<� NA*|6(jEsYP�R Pጻ h<\ԣ% ;*G2!A I͓aФEbi@Ll H 7[mXhR<%?±3ogz//$rGf?‡Y1 ۷|5x!,-x;H RL͆>e)T {}l{[NAp/KK@YXLo>~Gq{᛭#'aB A ~P/` HA�ommTwIE BDhP+72h$I!Ǫ\-l KHO3WZ7#3|YXxqw`38}K"J/1v wv ٢#X$H0szl6l⋿a8g hcT�37 BL 8/?FWw2?iGY' 6�wTS#RerO ,;8qσ΅clwat-| Q rj\=І3op7ݼ�4y} Y@[X ײfs66`5p;[ԱM0("8A0sl9Ʀ_=aN3~ |']'YS�>N4\R/ںu7V\Mf4~]f'Z?hL4[pMq 0qw*nNKO'ATx!\`znV'Ni^Q:NFqʨ�NV }2,]0L kUݱܧ;!#"P�|G/H@pEz7Y�ǣSpjnMOfDڸߏp?p€T''5,o挿 ̟ciCD4X B;؍M$U4QJO,x>/q^;|x=t _uUW}�4kFDŽX$@Lch'O^wu?³DZ7}f[y , qS>@xV5ry &qn�6r#[eGDS .âaUk| )+=a]ns,g8 aB0N/Я ; њ _]_˵A_b BpBc|qW۽_*fÑ72fYtCOaYx fYv}3ggco %pMx|# o} L ϰ`]?O{ TpW(A:N .@]{1qˤd+S83H>.Uڏ]�߽J[K(#Yn4`$`q">;7V"uzcpI" bܵP䓕?Wvb  �y?B(Oy{B(29}Ypth|͚59WiH޿QsN[L>}B\uOo34~?�?'eYe@*%M#>FeӬYV{Az.v põOJzFB5n_C-s=[P͙O>hO8 q3<soo/[/Zjk۵eeWP_d޽u} % Ziutrp˘f{n>i(kEaE~7?fzh8/!_ezCKSNjժGȾ�_?sXHG; M`y'ae0r](_6w}ښ8TUSC4 |4s1W9K(Avy҇ Ch 0ѣ;`7z/>K *shKDKf[b-;QÖCwu}_0Dx( hx"k0ȑ#;׭[~<N$l=FBpM:YA; ַF|| ""�r 4+6UߎB*4ΝݸF}DƏr!/)P㾵6n477?'|R@xIh=wYeee]vLs22p~ b z7# ϴ_wU5tD :]w}}o }2`֐:פ<CzT4[6Zxq /paaxvt*qVmQ ;Id/Vktn&Bn Ѯ_f |KslS�:CH@o"Ha; 2㑱gEч?i Qt<Mh+ygv4H2uի}40>Jv_f?+;g೰�8Ԁ'"@ i}7{“.mhJÈC-KE!0a/š=qƟa濌L$欟0S9 X8N.駟.V C.ȓf]f<jy36H x K|R�}G;sVہOOw1E؜Rǐ^d\ ApaL#=k|׶UV�"B2sbk<uusnAĵ] Op 2 $&' j&w2I4@Aa D0̄8smj{'^rM.7O?)K.)ȅ>x'؃�]�/$7g�]`M^RQdzH ¡(Am}]vٝNmG`kPoo$"dJ0,LjtYNX$9L-[PwH�]B1PcOa[!E``^裏ބn(i8qX:y<ͦvp*THAv;'=İȒylj뒒cp%Wdw sTt  eS{/`4=] e FG`Boϸ xd LW_}> n3gΧ@63^ь$o! J l4Ss8Wz&xԴX}eСC/>^zvg=;&gQ3qs&ƭRvD B"%lŊY88�')ݽPl|7m۶ǵ<T�O`3x(21N�31{*m "0$D "2a ;늊.Uąyl?YYYW^y;^.K` |za(щ\|:= K`(@` P)--My<NZsKK`ph UUUp0cc=v �2 l Cqf\&$42! TڕPz B$d{p}]wݕͦR 333K\4+sv�6UMռ|}Mʟ|$CN@g Х�\Bd9?N�p~Znlq' $ [`<+$ D& TӳsXU@9EPvBjo-455WTT�op߽e�M i`Kh^gř@8/ :4b|&@،KS\ൗJ|^` 3=.u0]0{$i d�.X;0. f(@ J]RVe7 " ͸�6X2RVB%u1N d�.xG}8C7*H<t{9>Ih=�D�eHIttc {f$nֳ M2>Z:: II`LO;L38?ۛ 9f3?iOJ'2);S>˳,&q{hS|o<;<6iCI s=*Ҙ<{_9Ozo &}t07{``ͼ>l0&~ܱ)_����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/images/haskell-mode-256x256.png���������������������������������������������������0000664�0000000�0000000�00000120716�13602233217�0021274�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������\rf�� AiCCPICC Profile��H wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺�PtX4X\XffGD=HƳ.d,P&s"7C$� E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI�(L�0_&l2E�9r9h�xgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/�$ZU�m@O ��ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h<X.d 6'~khu_�}9PIo=�C#$n?z}[1 Ⱦhs2z \nLA"S dr%,߄lt 4.0,` 3p �H.Hi@A>� A1vjp�ԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a �ٰ;GDxJ>�,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 <y}'ZZ։6i{L{ӝ-?|gKϑ9w~Bƅ:Wt>ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~��� pHYs��T��TyJ��diTXtXML:com.adobe.xmp�����<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/"> <xmp:CreatorTool>www.inkscape.org</xmp:CreatorTool> </rdf:Description> </rdf:RDF> </x:xmpmeta> Ǧm��@�IDATx^Gu7>i]z-˶d8bq(@b =)$ %|16˶dޥV+i{}jv{&vv{fΝ;wΙ3gΜIPn@B_l,f7Z ֝d UQf4~S#Mf[u>>//-bGcƸbAb\2pEQC=)\0-3İ٬҅/zM'"ht[1hp;E svO҄!=8)/= u_Q@;Iՙk@x;̆(n^ҰCi[' |֮n8̰﹅1ޫsCN;.X8{ެg{fY;f@xY=3_%M $p<O`{fhP!W`g3n~ qa: uC.3,.{[جּ7^;D,[͎772l4Df_&eξ?Z٠ʎ7qa-N3L';KneƉ?tgƙ~̰[3w 3NtB-#&J#8z邅YxL#qtr y5H&4̕a ig`~'u,4Z Ҏad1cƌw3N=I# *~̰qttvXbOoߓYmh3n~1q_śi:p5Č4藋E?8:i;sC3Nr?u18M'7ZtfMhŒ+Kax3M(?_G҈L˳ ttfz3,~~I~*ap55F60oBpDn/%N M$ ݜ rF4[|8ofoBϰ8uպ`jh7Oh6Қa 'ϰyO'X^$%''''|̤$>>;96 7h^tn&y 4Ӹ! dz%,PMhv=Ͱ 432,pF\r{o3N_ܠ7 {czAxgiwqGU,X7gΜ‚,_FFF,<'0!!AQ8ď\===]]]--- On?x`+b1,/:y/Qޒξgޗ{nq' >r_t[fF&f m F@ayB$yw_tɒ%UUUJJJE&Cv@.nBƳp'?^s΋O>d|/: @qDJę@n?![fFٹD}%,~} LM7TT]vŋ׀u_D/<'1 ߏD'N߷oɧ~v֭-0D. v(g4f H4tgޟ~vQ ]츼gB#&^:GY_}mnnn% {23a wmx)ik - } #> tBί[yZ3gO(B _]$lBΫ3}{_s57ƜBLt7@Pt`޽_|#7k%HۛO",lcJXތ?~ na$ 2μdfX kA ;`>|pݚ5k6,Kazt>SEc bљ=%,P_]‚/a,G yOܓ3dOb=/w̃&» 7`> #|:ULCX$DZiKA@i m.DfܴulؙELh/~AvH{3.־mokܹBZ_ܚX]h{g}B<'ߎH.nM MBF$NFw! ǰ7ҠӮVCLH}H܁Lw7,szs\e@ ^ַO~rMb`I:AvB.Dl" ~3LO(H/~Fr0ؑ>,?/Z^HK7bXMh<yw׾v򛈟P„n ?NNAi9Ee]*i_&߾�Cz!ݾYR򕯬*++7BLJ+KT_Tj`�pa5::FGF5KJJT *SRUzzJOKQiҒUZ*2RUFz\(u־/>G"44^|a\im[J~ḫ m?Â7?n#=_׼}{wEEFէ!8"poπW}[u� nNK_NpCZk-NoJNNT $ YYi*ח 0;;]e"r9 ׿'_H謀 0h 0t<tOixV_.h#=E/  e;OQf 6ڭG>CC# 2]Au0WGWgθ$BaA*WE yYu=FFFd~}">]0 _$�Ca'M#4tzϔ 7/!&/'/ 3??^ﯮ8@.P߮;TgW?~ȏ܂ǥaf1u夫\5"!GeƕC�!譩y__} oK$g Oh�0~ t ciqCeJ؄ŏO?}Hnm0z-{v~;.^hW mbsy[YF<%be URSsҲ<1lg~7Q `ƻ!�MB dvbد ֤07& 0~5uNaBq FUw^^s.Yx1}02s@#4/S͝W,,Qee1S7{pw"G0B 켄 �'4;jAV/[$P.g @. 7!ӌO knRg4Z[{NK/,/afz5  Tb5WQqw4C_׿կ~(1 M" @ du~W/t*`nf~6$/aƍVWW<cb`sGi=Gӧ.NH0vbR4!XaHQ%%>p;BU? om aA~MBy!vX]Qh"U]/3Lj^Dn!�nҗtG>O@W:cZ ?r^4bn@g{B&&PK+ rk/~qd?ߍ="2#v6aIwŠXWVv$lB"/' #NI VgÆ >fE0:ToYQI FFjBuuZr.VbgՂm۶}W5>݄� P� @i;,W1$:I؄e"=E.Ap)NjaAuwO<ŕ+W,y"mZv#>Z=L6#D=.u ӧ֖,/Fy# ={8 +,F$NnP 4vXJ"a7B�x'Bw iEȮ׷CT]mrqs|P8T(ͭ,T+WUzZ!7:p׿@E$h^/? ^!bE3"~+ (#??>\HƋj׮-HEf]ZYq몡[D|;n�mB oB!� oC!q_1İ&ڈ߄󲑟/{{S{yECZ_Y䏨9zm̩ UOnLHBYYZl^%Ã@>?tmi&T^eXlg64n?>o`k đ =uGiIKFllsXfF| GpB% l(//!:~%Ty5Vhen/aB2aB" ?y߇OcnR~.qZKQgh.qDt=0V,1Y~Ni9@>gOJNf%\^'wyKuJ˖!?d' $H/<r 7|Ӆsp9u9uS(FիUkiH nod.}B">$�|@L+" HIE] '=Be˖?3Ҋ78f%NV Ux-U96Ep;z(9R#&G Āt D4*Jm#mgX0|?TϿW <Qob+nWt^NicVhʙMzŀJD|C C +̙3!h+lc?W� WDȏrX !%-뼾ڿЏBY7=[@+a3˅jp jÇw3.o­VLET|Yۈϰ/~?m_%P^*cB/IإɈa9-o�n 0!+/?S0 V8N[e]2a0 \`L ;};/ư%N^I�ܐ_b|~WǤdU[^;zeh6bZ�U)%T.PfڵM$,8`[y?fp^ B0\B�mg=e%>v-^pp+Ioh@,n NDxjrJ@kJ�&ߋn븫pnD-;Ʊ9 �b%/u3_F~A|Bo|_[a`h%wD`nz�19n@TV iii6mZ{~`x$#"7I`I|)O?^ @A|D|s~_ 9^8`?뮮 聍V͘fq E:x[` KX3b7_aKF}B7_F=,/Dͺ=lga KҘ 8*}X/'go"Dzu~l{ 귯fl]-@"j6Mµ>U"Pu7Ⱦm"f"]xf-~B}  %@ ϟDÏ{yBu- - 7ݼXx0~a7JkPI�lAmZ!L?y d]eH"^Q{mImwnV实t r'L`wاMg#6Ӛ~ƙ~3MTE�l!& ~_W` Q|/v!M0Z@F]]6>w.-yj8dεx֌$i[DtAPlM^dx�'K_ 5C禇z`3896ޫy9AfXДtDz>S:L ,Xns=wϱ_Eu@DMrVn1l~TJ~  !-?a8<p PgADD6!2ku1/qȼh)'55Io OM#cxTj9 Z«Mfvkj8IR׬YԩSoBG߂_E $~7'v/Xgl' $, 'UWWg|/J-)aE1űz4(cRp%Ƌ+9%߉sqHDD`3HsVA�544mta'yYx] N#4!QMDy xIxcϟ?ΕbMMMۄqPP n[`P0H'a'`H0a%~B 43>? W%788<T{ᲲT|}BNaa>bH~%Gم<:5ZLŦUۆĄ� m7߻ZUVHo߾ǰ2KD&"Lg^!D\ӄtDX9Az'HoBA|BM" cwg'w-JHxRp zuYu|AHQ_/\32RqwZ\OۺƩ492@@vg`K+V?=2>,-U(q"�&_/N @"=ޝ/!H?OuwM}{SqF{0j߾X<u�6=GOOO[j2;�kIz5Y6mp`X0w^c9p-\po7ЎrmIbg8"L<O(_ڼџo^XNI߱cǗoV˟NytvZGA0Fa54<8sq@?TYc///VsԼy`UU^^l Վ`5 B@>s0I>_j^ߴa_~<c* Q&0"I, †Cބ=D~k=rm}*'`?=eN 8$ C$ CAr g=9X*>DBUΛigկ BB|~Ι놡6dY9d’lٲ7nZ!��BA8a2!`C^.)�_F y/#@auX<S9>[ E<()@J\+@ˆ]9$@jߥ>v<mۯ9=]jS -KTvyyY8G<Ѡˬ/?WRa]˥ xu+ƾ_n3駳 k'ac>O}/HOh"p�Dŋs8Z=9n/aj -A@3 /(;aHOtOiC /7K-_Q֭⪘ U.i?tθ;wW#"{4ilҠU. ' „RI$$BFlg>B�џe؄$2._VݯrԉC3)״aozz:+aL+%\J.kI)ӀK p)635ՎaJ¨VV^nqq.86Es꩘ TxRLݸsk{.f+ilL?yv$�B� 7ag>˞,3P(ԞmEǍj%8jqYќK,:[\Hg9K0=:D 7 BTzZ&ꞥ21eHKJBڻ:yV-Z4OO<䚬|N56x'?xgת5DEz`agb-K{zzo۶8n/HoØS_|NddeOy}iJFo^=G/vX;jգԧԬ\tHOB7` K\AOOy=bVPЙ. YTgG;\ǟx G;>_&>==R{nܴL]{mc55N<$@B 95Ke 8Hn{s$ѱpnL! # q7Ojo|ŻhD.,VkpR(cq�֑I�zБM hA_|)}9~u|6pt! AKK+i:CeU8[IJ�%,o:"O!Ǿ>wHO&n/ž _Nw D#!�״f%M?_H~7ob_<yQkbuUzZ`$_Q%&rĀjO t$4gMErB ,8�xFaVfB\ `%h]aQWYSypb/V,f@Ͼ>׫^ڏ}}̉" Q0H=0Ng.`gjVJBL(D@(~�}ؙ ]K1HK=殹x;v3KJ9I#T?q؁ϕ�p`#"B^32tujjI1ds XeGJ"o? C7޴Suo6^`(.@:AG/\n{֞p? |@Mw.,坉H$U#I(bA^pA$ =`QO9X" K\^n64#'`6e\K\^Wf +BNo^DpmBT#? �HRq_E>} 55ĉs- 5/[0CůB* +WR>p# �1~ͱo^ޖ}8�HK\a#q BH'$!%8'~Dy<9fc!B67__G2 ɋ@~-MR煡WLL)F $GZ7S3/MQU8@\@z#<KRap]Y?<BzYXJZ)�%Ch8Z~TGqnS)_QUY/8@\@ ;6^ 0<93 PކOvQuxQH}4qbA!ݦZzuғ'!qa$[qa9fKy/D??w|ڻV2_{<.lŦZ[:?MżWgw8qiɂ '@1IY_ 1.c8)D*7+LW5PK32#W%wEX쭳.8v ax~71$Ѫ8A@R!N 󗙅0B/q& K\NK&L{;עjju8"I4 ϳ.ZlJQQTfp\fee 5ߘRN�KfX (?sν]2 9UIVw�}:Xfyh]Ap 2 3PjR}+WI :&!<" 3Òn23Όa*(qB>c0fV<;YWmm]+8µ(/~]mHJw>`f_%^ 1~ĭq8ONO)DRX (%4)+pfe}I)*a"ǼV3&8BP}G ZoN,+A%Q z̄"gԹF(T PپPT^qO/d{-.& 3tsf*P*-D~M<O-3;S'.ϥAn3jҙϟoRa.7ac*DQ\Z5` Pƾtff(ek?d/j'O< ی[Q~�-.W,}}ۭC9qqCZL@3%n (^?U?yو?3%+[*~lqK/QÍ1G#ܳ[ԡC<`#rf}hV͋ ᡡ1mo`lHGsSx옪rN iA Y*??Ĭ�BUq TAAnL544= `= C#>a[g۱/Ov`7H %LlfM?ݝW0/qY9P~CRJ<#oi[Ry5Lter̓~DlHDt6vkG�rDz~k@ Mtb[.$FY8R 5`b6)^\ӈ `�%W$<Oש`pt˖]08ګrr/V�Ʊ/OF! qh$.!l[!tz߼gfV~R&@Bx%;v1GHG޻vg܅LD*ZIMS}`=-ֆVymT I>&`~iٓo =s_ 30(p=24ap 5LI4v`$9!^0p[0 Ü9$ Eئ 7tvts3 Ewic`JAɰHkInNG vXdqC\~6'e?K* 8=h`^|F.xs%^8�K~IoT@f]?st \"ƛW'活Ի޽׋ܑ' _ZP@e|F ~*!aPee8uE;H2` ꑡ Cm= $=}!89DT$H(أp1`9 hcZA; ,]]q@-$捰.c7nXrsC@!<uS6T@^-) H>߮ǰtOz>aq? {4 6g̙sPz[tfcY1#?iU|_/~ a& br#Q�D1�Q58n e Xvcr ȥe>LUFf c)$/OnZX:C?W4͈%o_*pg; �xD~K"U!{T  37Vdi .mqaC:H>y9xݪ4#܈_?/af&黎%\A ĜAy8$ qGEԞidL(Г^Sr\- s1miYZfڹ,,[5Uk\n/_n8(q?SN,s|HgX*E\>UrsH׈3p=Y%M WRiOnLo;^v^eڰaw aaqx?d:Q7�IDZ*<fBa*�)v/d20 ?w4H([�o`S]A"nbUR c r.hdfg_;!Z+3B;N=q_!3@s3N*b±zh^D'] X6nP8UΎa_Q=\̽ΰ8@w":A4>^*2`'旊̑hp+1Qm ^0Yfž>ξwC&1qKt3B0R))k׮%s?4a8BWaP7pޙ3^;k=t;VR3m,CSp>][ `7 j"0Q4�Ǔay+;9g'\�W֭uaV)bS,/2^((xgCf8OKxM(p|'O?�v˾sXO>M'X.lp*Tss+X1g3pFyE:z|; G!gOKԑ)Gc-x_L a[tvb.O=n]X2aiG H)# R)zzdZC$g%?2N;/'H/O"Ͱsvʕ+s KCumWP'xx�*Pzwe*#"b؄ܡ%i &'SYDЌTة$XFHF"OAA>R݉sf&:,h.^R9bO< *d�3_ B[ay A`T8S%%l*AJƒs|jS_Ҭ:%}M�|r*@ee>F!.XOCϽ/"}.T(c&^^8J~f"sOLm'KȨO8~ܳG}^5ߕS_?x#G'*4Պ@+r-}9S,KONn ũ#Ṕ"PLY)`S2ʶ<cXz<ݏ }鐞FpxJQqh-SQ/9s'@h:Ϡ&�LHy 1೼l">ϯ[ߍTݻΨV^O9E#4tjj/bJ�عz^U+V%"f@)e×J檔PTQO*I p*PR5x{Y�e[ĪMcWPr900?_Ok3l3MYD|[ne :9E)pݹ6PdmW{pM<7Kbϰx=Ԯc%<})yCcj\T S;dqU @*  ö*yϳB9q <㠕6`f@0i޼ykm=_j. a z@}D`n)nJoqyo�fc$P N<{l\X٭ڽ3ޱ#vb%ضy#k]/ΏS&G;K7\i!A@M2�Iv[G?¼Oflon8EI<Eo90$ҏ<w8 V;A-\XQy4يsӯF0Y'&lu@w{ s*v)\�$*@b3mU�ͥujPIiHT.9^{Y&oI+lZ^zG>&Q7n4߁^A@&%Bܷ^&\d?3",F`Nv9a#zNt$�=d)`}骹CbMHPaU s|)- {Y{\lN1Nj1BIfӳԒ%e!_ ˁMMMoKH̖h3ISwuDfqҼovan?յ#3*sN -Vo9U- BG0VlCM;? fEgT`  tjc$̒vJaTi6 ѼT{VąP8E rOdX~f$aj`Vt-=@#Bf0&%baF*/pY}_+DV"G6bp0Ah$�z^ ss3T<ձWGqwwcG+6nZFUW7fǾO .xq~"-q'6r_Cp%`f" 0???IQϷk-8uS2GS5Hż5/v6hRCxPzuϽ+4i(@g'VIȪWU kaF+ul^p;CaxI-W9{ <T{}j/EC xgܣ? E� m8z}Ch3gpb1~tC%W=ԛ꿾 (Dv� o_ ,8R:?]]TB,~,"ԥUlnJޑñ \R `*�"04{^S4.xq8 d_]9a:DD'R./*A )4Q5CĠ:x7 /vIOjB(P@Zz)(@05%6`/pUZ;rVp>l[ghbn%= fj0hrKAȱYD8iӵB 0̙3ux N(~x'pEB 6,@g g{�ĊN&0wki PiS=@ i`}UA@ mF-Fpg[1Ӽx8)?@㺨WD]�ys3A "+ uW;`A23hݐ FΝL_'@>L|q"//@qn8(q[AiIǰ'Ep0A ^tX~lGF@R¶9w@ZRzD{[ {׿܋4uzxSAL:Tn>vj1$z*6C\eTm>|Cy (OhMepRˍzU $ aTRYuBpvS58@E�XaU A$ K< #r2I?-=zm[gϪ\KWdF25A(ё=X0AKJs,ӝNvI|]/!1'`*,,Uz׿zF,XR=p|mJy@OWhǟFc< ҂P%ݝX`4-SqѦ;*� B]Ϊ�Lsc} xuj+&'OL�A8FMIN8�[B'tVQ Eg;RGPH=8bZrXC>0EsׄDl^dx1vNB M@p-PֆphF',’wvC={(RV/_Z=odBqB婇T3{ad64lA; = Ta*Ђ� sۋ�``Sy8TVO2ҡތ{FT؀JnCRv=,p.4ׅ~ 4N.8F\Ao/ *;70~#plÆ ^OmYLKi1bgC §c..Qs*w!U,x9}$ UWWk8@zzս~6ٯ Lt~;��y twj*PnĴP&c9Xr% @(~&�QC@.`j1H&<07>%rp"tc5iC ȟKatnP [jU*$ ђ!]>?cZOKK`Q86M[4wH\x�QHo] l35`6zW[Hsg\K9͚tB~Nx[FN%\Va/39W 3SgiJ_@<g��@�IDATՄۇ0P׬+@ǟTukS?݊:cҙ׍ ,S]#,K5"N:t(~=?-Է"@��$چ�rʘ .D¾^>t '>#;.-_QOf=pLbe]nuG<u bܮ~ԡ x;!ζlLux0ktS՘ 4cU�SR,r)gjzS,t:�O'T�DwU+dDpxjU"bd0<U�5Yx|58F\ :(~78F�cf`b<!n<O_-بD|yM7G_sk>LCD0G~<}EC̃̂n~d)ppAKTF(aU Ҫ v40Ū�7nX�, 4*V T8<2(RčP�9яkM\ #>$C H�B^d_NAJ"nN%9*^V%̈6< ݛW9yXv af;gOW)܀{LU ˆ*Gi;:Ց#P~)BbTVd*PՍlĜSt½ .'JEcqM> |vq3 \FJG y4Y9.DZk$WH#D{]5A:݂fֈ E*@3mXM!=#H(~!LƆU=9� SCY\=Ҝ^5I>'$qzA#<�Cd4s6BAz%]t҂@߀YpU=c2GW`BaUM7'1~c*Ga*�`:yj=-)�!Od@6{x@YH C8! 8փ!- `܇u8Jgw>pza4|@JA]`K6̼l !0iA*:wܵ}S8RQ\�{5L+Aea(�Bd^ׂ⣑OuÞ cׂq1%!]/?K|HR6i<:5Z O܁-S Hrdjo\MN%�gUj D+Ř ӧ hԶO*ӆ {ƆTp*p lh"1JzuU*^r 5t7<�\ʎi&|E�-c|t,0 [q|IfCj9~ݷ'pUU KNC6Ly@aqt\]HوQ:`*Uh trWSbH#<Lu6Bu4Gx83 �qwxL#oM@A[ vHH< qS?P`-=<Q/xDA01mh2aV0jݷ ۱I|b! yO*6% pD$ ,7ё nxtI9=g@5SX)a+=5p?>�܈s5;vrQi&$aԛ0ys(3/̃؛`1='1N<֫:iZ4HJLoY&ԛ{ td7+315:rX5ZO2w9Ms&`$U&~<F8%@hmo#kwbb,7lܴ;<؉LY:;| CX Ee)AoFL{~81OLc<%0L@˃<56ɰջ(N(ӫw^pbcRӒS`PjҫE1S6x<6`ݽ8qJ;'&<�Lx0s]\#1`|<R;bL`N4[Za5/ށ=h�D6Cȍ5J)nr8yth? uh4Dx!߆~AQ79CDM;"rt̋\R]vƨ;qғO`@ SS|+Mo�,8L* �*d,;;HϑW(GDX=|V_߈M=5Sx4PJ�Qd+BLK#R'A2N&:=os8_B|-πwNNɂSOϐ/ڮ##8mZٰ\_ C 6,́iqCcAAZm Bpҍ�83zvCM'�jbO|`=$?j0~tO.)X&SGhݺ{ΝՁ}'cg`,F4,Iӧ�q2XlAd'1@bHFP" y~?RhoD̬AǝjO|>p <Р?Wݘ]3k mw-+Ф.rjNr*Lx%~oWꀢR_'J#iѻys/oj<uNj0I-4X7K)d1SF*3.!MtvOMRh*N Y>gƏg#:�wC>?rUy[= kzo 8,{@=b[r C̹@C`Y0q.P/J�.,D9Ŀ8G<ãxcmٲGVh`nJ'`πXzt$^d9ҏ+2c'&ELg&%W bF!Y$<$vgj` v%1:K fG,U\X}ڶ BV8 H߇zfW-MiFzp\ Dh [;׈sZF � qcy#|IvP{9z*`qT) ۲9&׵iSd~~K0IdYIc֟8](΢h"OVkɏ9o>7CAt# [5⌁|ԫӁ=trgŅ8�׈sֻu y!�2vg<ti'XvG0{r2G{gךLTǶ&ԁ,a Cs;yD/Tijt uď�*-ST:8-wO"87$q-QX� (e�ÆQOk@+g豾Q}_~l6E=tάy#FRʩsVѳ<_R_ č[k\ hӂ L_NG̛U2+$T nďs0QD>$W x_ҌJOv339sR^mYJ�.;w`[s&LY}$~+B̬Ȃ :;8" gS[8@B\nu[ 8@L9COTdDt 5M< q_d`mEGx um券pE}WpU^^ԑ 1AqBz`8%%"nczpoCX !Y wgX6g- B6LUzQ}@K<~c A@=<ӕ klP:~Om>�D&˂}ِ#}PTηRqO.a2-w {S5%%}8őSu18XtԿb^Z;p*P]]Ǫ@G{#XĊ_qM&iv7<TkAFc D�=$zp^#O!%ٱں Vz|k"]IS#'"fcC sU!I]WhRP4R' B8 wOGS#pHs!WB̺&`Mz3 k$ipR'#'g0HИzM`ė|`YaT>z Vi{#O"~JzAO_X`BEMXFowꚵHL| T*Xwd*@@@(Y6qqnH'ُn�tfZ k Y8jNG?{3RS1C̄|qDV5kP蹤gmfE}xYJԟ X }\ F.yAu\s 1vL8e9hQA#j NWGXnqËQp08fK,�:ܹs$�Gx"ztw Y9'%6hucy2<%$:ɠ~a)DIS1H}ǀTIF̄S$uuhuI9r?eԖh*Jr$޶ MP^ {5Ğh]l:: 6ߐC`_�qÃ$<(`0`fQ�9ڐ0.ٳCCC8$*$Cヤa+m'8枘]gjk'fތ%>"'[;#89Śxi׬-ЬGEQ P'@P20Havkz/2|5G?|SOC9;t?8̼rػ<45Fy^'qtdX8q _Ҏ`@nq<H�pGs-P#I)U3-j?:0,pDs:,h~?Ͼ񋪡RࠜNMEKc1oioiyy%nD:#o$SSm[kQonG @)qVBb_q;LjkJ &34Om۶urFڀ0PX5ɞ[XG0#w#+Ǭ%'_<gf ^ߎSVI|㟡OZ'L/k NRNL!K>~oO+`JS6w4k+LGN!*΁8LjkH˗6q{Jq#�vK*@___$9~|sWuLWWԾ}5~0W ^벧NH[쏀YH1FZtHSZ藊c23Vx5Y$;lFFڼ unPGr}k] q‹#אvϙ ,4 Ihgd/pF \Ce؀{!tlƳjc8yv$AiǛ%]< K飗8шs:?YZ�y4럣RT$,: ՜TSs /X8G1G 7#-^8MINȄ-8F!89L|L]5Hùh򀑡T|VAbfmz3eˊ�p$N}JZ~(Ĉo>CEgf]=]56v9+HO?yA^{vbA,TIIVZvq‹ �PP2v?Z;\X΁9&pZhP}/7"#s*?yk0%= ѰK]J Z_:ǑG3YoJ bNg6YsM>;_X; ',tv)8V{v#Ts ]|l|/ wa s(o39}bD(G"ӹąj XjB)H )Rݻ/ D98zD ?B{U󾷯U8Un.p{(hp:FY#m-?vQ] i R.{.]%ҩ[hOXւ?Ԣ>6FwROv q*P"~x~[�q-�q ߎM `o\~C�a^=\*3)jbM�!QDAR>Q/F /L*+m]-]QG ںix?7Ao�mykPңYkbis/J?fR@7X{g F*�|T18}+TcHKYHMH$�ؙKxJIkkkP J '*a-L3'Nr@,~ vޡ]7O+hB�Ax;f2~`F}BQ[VeSkg8IwC⟋ڀL;Vvq!#s3ki=ZY~w}�q#nǐ6PMe@]3o 98qbKJ`]OJB)86WTo=Oi/u45X>!(K~HQa}9wS̞CFEŐgjOTǎ^}.> 1e"GqY~f9^/<N@zQm*hQ>F� :}8@\Ed$+ϰc8Brr1V\q7FKbݹ6ڢDÄ@V0'O8Qz*J%e,ju4sr1v>!V#3γ(&KNLLĺ\Lzz_19&'F,lJ?8: y3ܹrIFzI Q594 nM bSO=K/ԀDh"Q0/AzBq84& 'OVp2=P Ipx]`MXQH4 fa7'Tt\ځKKKQ6T+Pf!P|_XHy`{W۶6,�GEj~urXd,P\KVb�r.ַGGeUچ,oIݧ 1#%{YTV.jkk/v80]/ovE :/Dy%'oə҃9,vbNISLRT',B]} ^ToهѸ_͟_ިT; G5.YZ*+gc`$ 7{ȩ>t6͘cږ_"r JW儔d[[{Y<_�k4ܯ Ұ6(#|\ԫyp;4-U}o[e >?CkM"=^.f fdc`C(:wܾ).P588"!9k9$PRIjj~Rvu׷Q㷩MǴkNQG&''"}{ g6=zQ՞m2C"FP_r/^Q2+9!~9r^1@1wt|Yg]]ll\8gepE(}{3 B=?~CpwĹ+PXlM] j8m<e1@^dİ}$X"o_Ӑ|}d7D0!s $eZrGswTYYщJ C`q|+}f[cp+HQZ>�$ 9KT|ӪsHk֟hhֿXU/߽ 39Zܕw==Z\ y�b$ϥc*P�ڀ'4GC_FR+BV'|?|M0a0 7' tyO WrCCC?|' k"ԑ߹&&-X-5w.M5ܞt*,K ju x0!Lp&D:LoTgi:tb:D -9Þ _nX@χ{P/MqiS"LDTGOSNQlo*/"S~cc#7֟A Z;!ud)<,~)P]x *L 뭐ݺc>Ω>C a- ' :o߿#]|-{"EYYn1(Aś6Ui ozz` xjD_^|cjkWug0;A"X!HAt$hQx[=|t(@?%Q'=3ہ<L�j1)PN!A }N.^THuSM @m D1w_}/DBZV^P?aH2~mڴ){wԥ%Nt=JMd-#0u4<w %WqGe0]VnZ(ǪdVw8I;3pAi~UsӀ?$$:mϳLreoQ|<+w6_M֟_S}0Աmw<)0>CN<9=\ůrU `wU S"Zxr'Ǽ꫏=GqnM DA�3 �fB�"=m3m!Evl?l,,ގ U;l0 ~�#Ũ&_13 &W(Cn}嶅0UyG@K%wuf�ɓU#ˮNp cia*gэ~-X`sQۯ/GQ^#tl~VDwD{8՝CI)V \2%*ȁw>x}kݳg9�~P"P (@5xB r-/\o8GH `xRPBtao|}>VQ_%rti9>e8yI+bK%Rc" ac_q.-1@6="Dz=b/ôdFZϗ;i;vadj"A1=�W>{+c`=tDzbG2N.!D|O@8|.3e!tXy ۷͛7$��^;Wq90fJAw�UN$7yiss}I=w_a]>佴x$+O^. h O4yFC >c>sqɵhrHZ _|}C|?鷀ӀZzsj~2og@H 0Kůeȩw`5ePtcoD/5'Ȕ0s=89gM/7d@' LB&?G?M6uxY */>w S֥WS|$N #ȄZj?Ŀ~3Gn\%bXg 9 ĺ!HOªOG{!`j$DN5=Є23#sc,F[q('<C=C;9<fȅɽt)XwrZ<}݋Ҳ8Y\cnΌ_.eN5> B)B8h_ZyTpz`>#1=/^ /0g'm:;҄sڮ{[KI mv})�3~G=s,f`ā3T�ЭBmܠYYňC){(% qk iCsG9܈K)e TWիb)'>_t*ڣ[j㍘B@JBǙs} ;�n=m4\V@>,~Br&VLC.4Ҏgtq> B�'qcuy|XbB*aXz뭣RoePgj֣ SiUt\檪*T7Av@X<j`p}Y K u-V> wطWW<rsT@.hB0`8vK`ޣ_.7(̕�i±czɒ%=àQB-gz0$vAUa^C'y0LT+* Uii*0XU|CwN̯`RPW ؘ h[q=?x8~ϗ.]HL鿬�/A@#\9@S�>L"`fd@YJ%>3/.\W+O F5t�S kL@  V& $F35!zgg1cXF r2T1KJ󰝸Tͯ.q(H}: \D};$u Wa iZ^%& KE"չ!P> pHE`0 g%`V׺nff䄀%8їçĘ/{ˤ1AMHohPfdj覙>(9gӧvAZvUu_vMᲲ"MV7ѿ4zl>8ŏdpQ{ 2 :*Ass5v8@'зoiplpD|P`{eYߨ ~UU/fu ?YBZ[h\r _95د%#G{jp�[ P#DN]dēZ/ EJ(8nv…<yr,0u ne 74^�:j9SiA+PaX4 Koz 1{U/N<qqʰGqO~2�aFUr?6+L*peNŞZ(/|*# A FP&Vm+%[ѵFVnUj0�b48\<.I8qÁFͯtT4;l?؈Qe/~\ }]x\iڟW Ek�?;ba|wo7.a3#{Y+R y晵xq̘1Wڥb.iAp?e6Q{h%>00πpSkD1+cl}0\0u�AM85-6߿#I؇Ts,O`[b%^xq871 qm3u-eg+(9ss> Ⱥ~(J5 j<tTPB#9!u Ӆv#T #2pu^�_즑z슭]һ}2 {55i@]Ѓi[V9<a,V-q/1l!ďdaw03 pQVJF@@7R޼VYYyap5M￷= 7{|҅7y~81)H1(ʇT\* G)w:U!c!0C vLt>` �G۽ʂ`ݺXN`3ѮU3+=\llqܚ5k^#FX KT5yRt)8>1f)c ˫> Ι3登l4N# v /�w<Iq�C`}<"�-% 3�67@G.dZZ802-= YA�g8@KKEC%<ddu>$@8e>OY,Et'&Ө't )WзOq7 |V{nu G`t^ +zke.\v+{=<{bp <|cTZ&{rw}.i^&s/ed(d�D93=�fdg3V)=+Ǵ(;k_W_OBN Y#o1oơ{ j6{Chz|X{[uUU5g}'|0=`<Ǫ�m mUWL fk?vȃ:H3QNg/Kצ%o=鯞@﫬<zw{!X9(�Ylnǃ0݃}Ќ�l]ݙslb^e\wvqȷ::nޱc'NBi)>g3/qO~nӓv&,-@{||bŊ?<[4\#?4Q7 @._[PIY9ʈT[QV2҃gtr&�T/9)C1"s[ dzގSa?6W陥X[]OKh`=?7.usi xh] q ΋P’Rxt ±�{Ͽo1C={p(Xak~fmmp [q\W5pg{_x.&puԣ@"TǕw PqAD˃=g.O+lz^z� Ü緆 9Y|^W6U�>ңQ p. ,ӭ;HC?<' \g44֭k|:A-`}7sF 4kGh40D2qա,>|sq[l{76k/JRݍo!⼿Z!Q̫y*F $gXDzLۘUww<p?QG>{l)L W\z�̜;SAjH^pEw|N *SQ*чp^7b.mN2WJp|] [B89Pp`Pǎ:4҄|� XSg@?Q Cۙ9=7�nܥ!8 K+u_~m4.qO1 3 Er˧~X  e,$׸Q�H '^�{͛7}ĉ7~7RM需K{8Y!pz2 a3̗|_CLp$+_w?R#@'ә5R(xv™g=Tn¥�ecq􉼘7|I&̈́?ߨJ=�]gijÛlؒixc`ư۞z޽`ȳ.8_Z>l'p R!ΩT 29Ԥp0D9T>$bA.>U _/wY씻?d/RFjZ%igی몫#=uQ|a?<<y9>q KSްdE4v]8@xpqm4!]||:n7ծ.8ڇ nߎ'u>|'y#6һP&եiJWq|J}~@F@@'ES:y/YFZ(` IlX2kڣkOWdy{w9t}QH^~8|ױ2ve{ /|;l~}t 5�̏MNMOLԂ]Eԡ{jʔ)0kt^j8DMv+ǦN�7ܫ}@Ы?Ao{�Y^&@xTc@dy׮|(a' -\TUD935'Ȯ6^/( nL+Ua zϜ>}S>ū Ћ5�z[0%P^o,O*))9߽x8;on owpGZM6CqغunG)=�ei6�@ ~~KFZŹk052SU\, W0iЬ&  "}g?Ê=}oVf# }^#pA\C �+a1G^^a(ןs9***❟RbJ|b<" U.r�p郃+ϝ;wW_<Xv-|/29,/Ylgpuh׀_a{�~yb{9ٸ% 䢁pkklJc[fFY|>#Y.UΚ=�<e6,JGYQMM-[||OfLJb8N]/: PeK4P UǠ_݃wN uϧ3fWom5lO OgV^( e\i|Z"W=z+>z*=zt?}wɹګbB�ИN~wp #n}_F ooU:"]c�0 r Qr튋/҅yHqǗaOjMpkԉ<@f pjo259U!`_O~tO|bd53Q<eQKRQxI_~*aJ,\ab[bűͲulෘPex P%쓝2mdzth۶mp^b,<lj^l]^WurӃnMC ic\q(Ν;Wr-{fH 8g:3S 0ey4�*)+Na^q/Yd{߾}Wr)C<v8j-6_(O\LM_zs_)ql_ƀeF0�pm6e/š &T:t *'�l}e//n \G]q2KC_~k} Zu&W\9*]Me�XId6/~'>«@;)>8Fp{,Z7SDhY{cu~dԩClq'h=d6oIiyP<=}L{_9j#{76sahhp?F9w/LOtIVT|?6E2Fi[9_aRɔNaX\rɐ0: ށ ޟ}gӃig> . bYg7_[~߂݂_[[^Mi�Ta\ܧ~6o޼wߝׁ9+ /YLۤ[󌳂*sVv-+_Z-'#��IDAT}t>erK>4`\d +W ;}mfxo-^>ضmW(Zi<#in(۬Z|u}_4ug} ~5|7(UiƗ)\3wXbN:[*}Jc7Vb嬒*5u!p`,|<tC=?nmJIo2ව|G�F2ǭ+8Nl,@p1_/� VeڇH\�G̘@=SlV[կ~{leJf>շTY5:S'Me�XVfyœZa\ p38cLΝs2\=~ kI?gWViqnKo1Μ9L۷ok_=<TD3 z x3k?|X= hJ:[�'ߺzw�{`h }elRn'V m ,;& 2o{~Dl>}'?a=E=JMm�Xy ng1˖xѢEX6ֹ;k׮mBu&LlNbɢL?Kc� ns fzUif.SO=w~L}j xkTw �o.sQ@1%&u� bq |[>ۭ:ĵ4 p'O9,.?W\qŽ~Oz�Ry Yj �o).? 7;77D E"|'УW^ה*'ׂ[Mjܚd!?K]˧>?lX_tgLW5 ?.I>O#`A/ٓ۸F \+藭0v0 s0v0y..a|w7/ccǞ?8óf`7Z=qNnz/-\F'OEy?)N-%3@O|�:�J>04;M/_aR료o 7</v/XF9Mzsg.B[fr]| pjyAW Uܼ^z+M I@�خxŀuu�!=NW|EtGJ_>,\ǎKqR,= AC$k> lL^ׂltsE_Š+7\y)AYϮyV[[G_8T&zǷTA@O|QMt<éb-nYEɢˊO-[6N;6Ӹ<ν<{VpWbjpoGziA1^8_0:@IeHzQCEQ]>)(@5EQeغ<}x} 1ZTVVZ2jԨ+qP >W qO!n'mHRJ";\~ǎI8O!B8ǣSO GWX#? 2@/~ xQ`MU^r(l)yLFqqED9]tm(pގO<r\,Iiδ ;N{|p?~h,6ї%v ^>'x�:.y�4 Ȼ(ؕ¢QJ2`�.߼qg*Fqwl~tKx5dI@ʏ)=wэN . ~~]w{=7 [/[ʶe=S{ң7.j~pOxī 08.8q y0/mSs"Wc_ֽs0 ? C^j9Y8T7nܕQ^>>?n+|TisH>ZeVEym;5k{Dވ#‑2߫W;3f vq'n>1O={xp-b@�?яꪫ^o/0g?Aٶl<);._`5E0(o{' 0_8~:LA6elP 羱<`8@nl{<Pnn�_ ݻ{ObMO V~܇isud�0Nড় ¼�zoÓ.cc_ls[Z^Uv@߱c,-&TO(2=?YA57}JzSFG 0uoN`j30R�d�D` f:p_޽ |2wP^ZۘC{cwsOSObwd cڳW^9{9/薷'e`=ELW\<<kwx*l)yyk�[/¡?.ϗᵠ*&jgŋֹ#>ݰ;`4)ir9\߯?bْ' 1U8:wqSs @x (`Ȣ9,F~} x`yoCΫ+++lA\5k]`8f)1>oZ qA3p|!9o�~x;(�+(2"|FwX}{~ % k/pɝ\fKh[lY2>yLɂ{\sͥS`:SؘZ|-X|!wq1qߙ" z>qqN.E'|^L{=YzD^jի8o~.%LTT�'OGIbR_wI}a�22��=SI8LwIxdM[q`EuSAmG9@;F.;y@ ~qg`AyyOw&OYT4a k׾^so,Dil&+&/Ћ FF@WƵS#*_aK2R pE o@:sgbq歐y.O=]Ap_jjՉg}(?Y/- :w8n:1Bw9ѽ;+]?՜ nK;0 r">0Ӷ'ʦ6L^al, 2Lghg̘1n_/>;&H ޽{ҥK8k֬xHA 7;ej’*pfd}Hf)y߳Q&# �_Ɖghw饗馛3ܲxR2>qyj�=:|Ň~9sPNkP[%rzQb'iю{R\<tQƓWX<DARcp4,(: yMXqxz|F @vQ2 le[TX mQRYlX<i:o�Ӥ32�(e#)믿~<zg3:th(E}UaxyoO{TQU�/T@)uhmy?K(J2�X^2Tr1`ӧW|_<ygsDG1hg>… O.9s*ܗxЖ>L¤ C(oq<ukvٰxRyB<9}j8?o.a'bx Fa'>fwz['"{o~ӟt5[%mZVa7щ|TVؐ[Gɢ(e<8K qDY^N4i4ѣG9fc"[\~o7Vc[RU"k7_J] oN)i( *Z OuEQy� $SO;2b^8C 6a ^Хc̮j9ҴKqj�_& (?.y+,>E#�ϴiZ|-2>/O٘)VF>*˔",2>80U`v70Cʋa!N q+:kS mBwI{SX`&ċ2E)KYēQ(Uڢo+OEQq-ĕ1�ߌ0tkz9t ϡ9SQ G㕂9μ)�^ po߆wꚚm[lيs._|ŋKt `!AZjy+cz]#>e}/rE4*FՖ][xR JoEF<x_Dm:pEVia,*ťmu;wy.av阧\Q/0GlyEyxQ+S62:aŹDtEuml37qt`-yy Z+d[^Pޢ҉'rjL) KZЊ[mg%o3,ڬ÷5Ӆ”ɧv:C)xR:,/CL|h:p>,IFJ0to:mKt:rQ˳@6(2:;ɢ`eI3/e]|L|2֩Vfy56 7N7VS&y)($ާ~ G1|pذxL,KO8)c>r4ܦis|ʣx,2Yu4). kA#R3Ws ۴Qdf':*P|ɢͰtmX|&ge)RgNׇCbe3Ѩ8+<Kf8J8K}>*L CH ka͗۰ƦP0VKX4n*q֥4 o4`'lL dҟgQdxFY3L|PQ@(>,8^ڸϠ "CITJtpcHJL܆g}lh8Ih dk Y.Oh ^ކ-E(뢀2sclAż,I28]/,>,]8pQ84G:y8ɠF!y@ dw()Nir4.(t#i`uqu-]x)5n: lZ'�ȵQ$45v]\*?\5Ih51$<4ߧ׫ kCW=Z` ZIvY4\Y~\RsSKO-dMTy����IENDB`��������������������������������������������������haskell-mode-17.1/images/haskell-mode-32x32.png�����������������������������������������������������0000664�0000000�0000000�00000012270�13602233217�0021107�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR��� ��� ���szz�� AiCCPICC Profile��H wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺�PtX4X\XffGD=HƳ.d,P&s"7C$� E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI�(L�0_&l2E�9r9h�xgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/�$ZU�m@O ��ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h<X.d 6'~khu_�}9PIo=�C#$n?z}[1 Ⱦhs2z \nLA"S dr%,߄lt 4.0,` 3p �H.Hi@A>� A1vjp�ԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a �ٰ;GDxJ>�,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 <y}'ZZ։6i{L{ӝ-?|gKϑ9w~Bƅ:Wt>ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~��� pHYs��T��TyJ��diTXtXML:com.adobe.xmp�����<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/"> <xmp:CreatorTool>www.inkscape.org</xmp:CreatorTool> </rdf:Description> </rdf:RDF> </x:xmpmeta> Ǧm��IDATX Wklff_cm)mZmF)mRCp+TڿAԢHZ%hШUE!!ƀ16(Əůއ13sf=IJgwι|svC,O<bݙMo+<�`g:thCyy;r0=wPWW$M-0=`f/S4I5gc5Kkc"SnuBcb|"d7IVk ܨ,aPmgNvJD&Z4V;^tHcc1r*DQ@Zd7MwE.44lf +W:OٳmrY j�h޺u}bP_͈"AaDKCU`<jOO5HzgK{{ƦW4+#͂vMl)xJ Y @ Ž3g/s%�ނɓ[^SѬk]dTbdԢJH4΂[jfg˜jX9:%>y^+n6:::FE<D`ҭ:+ }mg9,+ghc)"`0B *֢722F#࣑n5nΑ0)<ӧO;L!�i 3f(Q sP.S02<TR ۡ `[lmy5-߿8<<CLϜ _;%`(Y@q U5vܽgl8M>c#9孭;Bi?Ǎm®U@BQ%�& (-c]Eaf_}ͷ@hnn.'HED|1B(I =\6v6h`~JM9'~k(B )9% r*++=,J]Ҳ5زŃb 9V0jҼ\E`.ܵab `sb(3X|2sHKH.,2fkKZ-ꊉDNZ &X(;ip:Ul %%.|1EϽi%B4T4tH[U]\W ˔YS}p8Ӱd)X`q0[Oa~rIS>9�\RA C*@}xyr+ xak)Q6dJD"++8;.܏fRS0E_|!V\:gҹƉN^&HL&:Ch7W`ݺlr4#(wùhCMn({>ΆS #GZZ?@m?s ĉRl[S5VHDGd#Dn+q%,"In=ߒ^khZ0_RINj;O1YFq 56-CdwGAu 0Tը#ɜ()4Ix?zs~̌ŏ.^PRjS+*巰ȉl iCw e@6۰[L4lH'(/DbQb$t|#N-~s<Gun݂lkBR3aDhLEH2ExV[=7H�kmH9H ~JJtQ a71<RE(]@hO+(gӗđЛoWiV k Hዧ3;E"I᳻D*Ԉp3.z=JbFZ7ZZ~aMhg� K-Ywkm?/7kg2 /_}eݗ'/ԨnPK]%[ �1~zHCC㱡o_]ə3�8{C*OĆr{ʉݻߔ>nKwwVSW[W.deskF͊ D/TQ~[+37 Pcr|KcrO1^Hfowú[1YpXkVYYq8NV A`]=yϬˡ _oc%'r_2ϧ~����IENDB`����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/images/haskell-mode-512x512.png���������������������������������������������������0000664�0000000�0000000�00000177534�13602233217�0021274�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���������x���sBIT|d��� pHYs��B��Bn���tEXtSoftware�www.inkscape.org<�� �IDATxy|יŀDb q&6I83 f|IH qf2`Ovl`;kB U-ujtI9u]t;S( EQTA P"W!da"C�O"!@b5@ }?H( C�A}uHMA"�8`izt$l}/" A� kl2Vf{X~"0!0z.>㆑kZz>DD� 6 m-A@g� }svQ`b2"  D� ][o\v|AJ7>"��%Eo~M*9 Ϫ>f&!r"�9EV?JT1z`}hHn�B֓ѷ5 FمUFT^VA@�!!l|1':7š(HU1@� d 6tuLT+a*Co(HE1@i� d,2T̴cS5uLq?"7`B!L~z U}RmsH3淲ͪ>fFL�D�F} Ѻ>jZKƊ$9FԌ6Z7GM]@nʄ4A�vL~;QlJmz{+=ؙܜ 6C�6,6v}FL?+JmjJh*cVRZֱM`D�,%M}Fj(H�3`�H[-=ؙܰ B�0ڷ)C+9 k3!963q,�BJXh5b7c Fյlr_*F㩖Ͷw&7pB @0Aßh?]t)+ `d5rD63e=u6=;9D� AïtjCocJmF+a&~.WUǬv KHn@ЅEߎѾ13emF!yݛՖ\SWjSkڑ : J W=@oY&R?7;Gvt3eRZЎOP�,6~3TGrtsV+kSjn`T e7Jf>#d @ *.T cJmza4&m˵e~DZYO]}hGr'A�@~VKhbq˵aS6#{䲞VЎO��Þ,3ZR1V³jK.Օڬ Fz-W1S+kH aJ ұTGVo+^9+)Q:nX<j7##zFfv#{6>Ju!0 1`S5zGvz#Ǭ z'~޺RfFVK$hS+յ;c0 `%?^c)C1clee-..抋B-((p8Ntr� `0C~|ax<ι>+ͷ{zz;RMee~reR~eV{b'b D� at63_1~x=7n\.*+++++...+,,,+(((w\ep,[y zCPo =>^~ܹs=Zٳgqnяo2z ޿zZoV-յ;Xv6k6fSFc0qĂ{=cƌG1bȊ‘9L(|Jwwk׮_pÇ_{ӧO]SǗS1fB&RR,D/D�))V{ͼڹ)ozoP__XYY9. |BWW׹Gy饗Zyh�0OաMn,WWjډ<bw!o)v|_3wqƍPVV6tV`0xիWϜ;wݻ[~_vtt`7"� Z 6}rYV{b'b0 "�4~Q"@Q<##xSLQ[[;x EQ,#"xZ\r죏>:?/; }8o8Pe={\]mh'b4"�3fF߿yꩧ&.\p㧏1bg`0xڵkϞ={w=f͚'~DB1hruy�qtl1F |/mo,۪o}[3ϟ?{ԨQ+++2 !kD".]:s=N1(٫Jmi�Q0WjK7Y*>ϸ}yӦMkr73 S8# Hѱرc/®wȧS�R[6RNĐ$D� 6FF _n瞛`c+..+so}[ sh*ڔJm19�!,kr=nb 뮻*VZu۴if@"9Hǎ7|ƌcFtC[Vkډ!M~#?l1r^geO?Yf-MQ-Y)( 8;λ~/zTzeR[bbXr"�r�OnS�J^-U+555<쳷͞={QMMdzA(W^ݷknn1c.1meĸd=D�d1˵Ym֩3g^z9s4MO0 |GG{xg?tƍѺb@O.Օ;#aoD�5FFju֭[7kҥK4\!twnݺ'8�eCf͈ɄhZY-14Y �Y ~-f1F�zɒ%=O>EEE r`^Ç_m۶uASJhAMԖ؁,"C~=#Tnr]dҺ>!_|o۶mUT<^֖؁,bԯffk-_fժU:u' ~_MBثrP r^MO}DdD�d:ݣ~#}6cw|L}}B2u (_w �#@@ :jed"�2LU~#}=?˲/x%KWUU|뇶m۶GyY/A*!hje�e"�2M.3~v~?a?zh׆ ̟?9I#^Ν;7=c.\>` P{@@h~k֬Yv7>p85>aO(# #``"|A1i/@>MS Mf=Ma(0,K؜e'cj z=ǧzjcKvzR^6xC@+Y2/_ܽz766.iک A@�}e?<�0AiB4 8PRZJJ PRBI EE.дW#Be3<M6ŞP0HP82DD�ߊQ|h /{lҥk֬ܤIiL@ tuyE_~x<Ao(;QRRTTUp� O:zW[n턲aJ  @,W+ ! X7bS2l[xqڵk?;eʔe $"ۋ. eԲB$E`1#?+WBh Q`#`�HD�،.3@koѧPMMM?O)a 5>&qmmh܍n@` PQQu@3D"#G/}7V�9OB9�6?nԦ^gΜYaÆfΜ˲EN\ҋmݸ֍ugP]] W ,dlyϡC^z^>H؛Jmj�2} SVCg= A�6asl_motįX.//glٲlpW9 O2q/kQ.E]$Rt~ pΝ;_6P� ( �[BD�6`OeM7nlz/..(ڵ~GG\p<#F@_MxZ_~+VhPCw 1�:răXY�bC߈?W17wMAsg`S"`Q;|CPUQ}{򓟴BY�0 H%$@2�x`$ߐ՛J7nܸbwԩ+h9d#4NpcҤZTUdtL#"ĉWWX1(%� b� u=t֓?b,� Hs_M�O�J"@Wݲe} ,x2J| Nӧ˛!"LXkQX3Rp￿xxj J2{\= 1^)C@d o_k/۶nݺYOdƵg<sp\n&PW_Ij1v܈U>h匾@a(8%�0$7ku__cc2ז˗{pT;Οp8S"d!`8i$s-Pliiyi\X@S@ h Ћ'D� ~z@*q~%?^Zt}t8מ5tw{qz>BQTĉ0E>݄B-[}衇v@[F�jZAb CAl6zҴ> ej֭[d]]ݭםa9Ӂӧy?ӧCG`⤑03,|O<7o|Jb�*ujmA3�ȀOo'cYٶm .˲Y| h=//]N%MSPIj1f숬!w}K,yEUBLX@n\Vk<Hn�I_KXדܧxlʕcy晧*++gh\sFD:َC[%%.̼i &02Xuxk֮]{:PjK>&  @i+�RI.ݱcgΝX6?#x2Ha3f4`A Bx-Z@ ^A%� hQ'$M"�4H�~5� ԧ>~矮q#q%=r@8ӧC rqqz8*Xy_w^y(�S"�*dM3mڴx)ry@ #/6,/!q8XLV3Fgm`8f@[:AP,WO<H"D�(`W'd_u<yrk/Ը֌q2&!7`Ya(ҕ[ZZ^{~|  3ހd1�cJYx:Y�"㯶7$� L]r3EEE ךv8tN^!%44Mc ydtz/]vO?}�JYj\= 1vC  'rgΝX=ۋZr,K+(B7n5&E߽{o FCfBDX �Ih�d?".]Zq-ڵ~<p]3v4k,FȮ+V֭[;1h0(LYn\ /"�ro:~0F�;v ;3}*B3?6 %%L�`7q%%_}5ȵر.\xACp`y</,Kc챘1s4h�BE^+P2ZB�2e}rY��Yg$Ə_}UcǎK3HmmeTWdT8/ٳg*$�>,W<@�Yl+}tg|wF˙L 4NpiD:2}*�3_uƍmП`GH�2e}rY>x`a-� f1Z@u˺c^x?3,f<HE;z #:p8X<g8 ڷ(y׿G}t'ԍ1^�^<,�Ǘg� ~͏̞=Qg;~ݓS!rb|| p2}*EQܿ MMM/=YШ'�dr{a)�Ro7*��cƌq}ώ5j`3@{vĉ˙>!<k̊/]�'ZLYmzah �9POd˹ŋWbFNݻZz q8̝׈&eT}?۷o#r#~°�Yjя򕯌Œ_O7A 5nw>TUg<|>UV}g?~%1@D@V rR_BÛqWp8{Kd^! Pi7œ[ƃ㘌G8[~7|Ƀgۓ�`�i~?֮`6o|}iX`nx8|`N@9SQWAoٲߖ-[~5! '�&\&qX0z �s̹Qq`yw BQf<fAq׮]hjj~33Hy/�rs{Fcc=z|v} ۺ3u ! ,Ĵ. ڜ9s~~o��Qd!�]__ܳg#G~\[K[[vl??S  8hTWf?[ikk B.$D�#9n'N,7bĈ9:DQľp@+qY EQi<g\B׮]OB%�H1_IϞ=ZSYY9][ۏ'oO L0rd9>x y#wySCD'3�Ƞ7)oW_t_\؅o#9a'aTCfB';ݰN "@&�&) [1O3K.oq.Aľgq@kߚ@ XNHg?[vbk�3Ed!SLY.5桱;`A_Л3v2#G \%xAcr |c2|koڡO"ŀ(C@�'1J.9/./}G?Z6ppu8qyES0*:~DZ 9$G8F�X׊+q~$k׮w:i =[pЅt-@�3f-sW\N '@,B}@ �4fF n^ל�� �IDAT 1!@ /|qp5LYnԘ'3/ qeGҥK߯Ow̿ۋ78'η%Y@Q w=Ei}_wӟ Fg �24 yFotԯWlݺu]v/x?0q8ݒqҥK"h&`dv�2�"O.O.p -oM<oG! aYwu#қ{ʸł$P@W+6i~&NX^+xݏ N )ܶp &NMvuuijjztTN$�a`oEƿ%1z֤{m#/yt%@!O׮];k֬JwN�drr*Q�ؑW[oȾ;~wTݻZp`k:ߒ@ 3oN:_%5K M-`{R �i⸿^6ל۟9s766cM!"NjO[gҤXprZ hiiym„ @#Л8LQ ە*\@ssiy^[o!Ɵ@ ԩv𼐶llls:pjݏZ}mS NԒ�=z=r3Л7os޼y_"y\hL[<Bk'x�A>m9o޼/n޼N{XՌZm!'P r*\_ث&?o4͙nxABSQYMi[5P=/g`#9)C<ؘCF5gS&�Wk׮9qiYiLJ7^;Yݏ@ XDq ws ~poʕ_~vjvPK9bXM�1uГ�/^\?? L]A^ö7~z\.K.{k]4fՒ,7^�&]zrI~Z@y̘1b6Hۥ.ea@ ewKf~TeZޯجY@7 0F�TP)6q$F5˲|lի}0^KUTTLeYV+PuOכ(WV{. z+#�޽{Wf#x۟@ }܌<Ip߾}̙SX^�pד\rG�^xaٳwփփziyٳg? /̇f=r$ɕ @+\Jr^}ȶbŊ~t<^�'$wT7p 4@Q?bŊzC~& \:ڳ '_1�3~<_ZZ:Eu?:V[i<i28,Gca@hESҗ@Q( (( 4= hiO�~ 2֜R][{?;3k֬/={PVH@mf d�1_mʟ޸�8w3cǎ@Dea'+e1p:Y8,NN p,F :5v,;0u|å]t:BH0 `x1fl5nɌ<;o7n5@*k(RlBcK@-q'F �;v|o_i cq<I4 pܠv898 N0Ng=.eyH 篡3%%# pH,Z<5-;]h+P�f@B�=7Ӈ�`O>cXgp@oCЉQ hhB g9\ߏ-Wqyɢ4k (7q@@�ȫP@V �\Jn5|yҥ#^~ N ۇ~ oD((*r] re('Oa o>I1s ?mݺ � P)C<ؘEF7׿Z!.^z+ǩcv A�A!"EU%9uuBtEE>Վ={Zu~zB~itHߧ@CCʀ4l8@)!0P��zI_O@777n޼yBuwnF1HHAD!D$A ,QU? =ڍ,\{M#4&csvϦ_!Y$*`cl�zpZ�|g7͟ş^O(�!jc"^ 1A @aZ[1cGbp: }:f@(&" `Y?nw#"}+O?q �# lB`V�GF]I'O.ڻwWMwnKV81 �A!a@HH$ND06(wm5ƍǸq0n\=k_Ũ7 .AE0{qΜ98q cIr q`Q⟖02?sill ցUA/(! ! =A ĉQ8Ø1u7Ǐ wi|~_zh 3]X-(*wMKK&L0@=" U�uǗu+ M6-z衇VZmAī Y/f zbDr"B A$ %<eLiĔCA ">#u Âaܧ /cBA/3˗/u`$gz d{(ԇ�Hc⟜�So"q%X;[| iĸb��(B 1jУF]3C!Ƞ kj*1y8L2S4$ ?8wò`hY`&p# 5F V U( ?�P�F]tMkm[ː~7  Bb8 / xy$ D0ex0y< r{=ݻ΀e90 KD@ɥ7a̘j[#ijgf7�Pjea8 7߹sMMM_2x<f$ X@:% I p@h!avA$['(ѵR`xL8"ev}{D.>݄bzml�V$8_rxi ?Eނr&`0 1p0L080@$2C@34Əɓa ?~&7V-|8XeA7+؛ B_k׮=u/@*S-KVѿUS,˲+++gp4<}{ADON-t0( &J <ɇ11QPS1c7e1*X%|9lf@WWa8<(5^l�&e`׿.[x]:.\-| BV't$ EA\=>PVV[M767?"<5_=,o6Fw۷; |�=�Rp�)J+d-[޴iӯY-LrUzf!ނ%{gDbE<q9c^en^s �m X&[y޷|7okD@7B`VxE�X5כj0mmmVWWwkjW(xu>\n-y AP$"||G\x1?~TS8w$We7oy/s�xj`NzҺ_O1Tk%& 5P饗i`wYukff>l(�jph hP4a@34rpNB8]Ep(,,AaQ) KPPTWa1E8Ҏ5"[PN,,CgC@#9ucw١RWWwK/*|#6&1l)09ד'`}_;/WWgMZi. e{G  yB<B0ߤ>>omAGˆ<x>0!̇1cF#yFw \8gR>�!( ? r .\psss/GF$&E({ S'4 � / E4ϗ_q v] #J0L("G}}@�^ogWk6 / H!0@8P8/<kH$��MP@PX?;=!SYzD@.B=@m �[gkѿR=3rd֭[7n.)QyvEQ=71cpXu( .CUUlA׏n/ۇ�DQ,6<2%hFH BD2xr` >:vG3p0 bϞ3`hFZ@ѹA77}ؗxuO쇼1no/$ vq*iq0Ŀb/ؖ {W v5iDD]]2cڻYx^@O]^twKۃn?l Ea!B?Ӎމ,/@0s'8=xb;!PW�H �r9 ;–-[_ԅݻMvIu'aL*,KC.{|AAQC 9�Q h6x4o__�^E=e�#GVc tvzGgHy� /uu5ʞ|[loś<�${Q= oGr^yl�&E@Ԯ7 0[T`nj^^B!on;IjwKfg N:QtQt{E_o� CP6m@ L.D4fpe-O;q,Qd d]|A ß!x,XXSS_ ja�J2EQv{2j+h۸q l{-zr;?ej9-]4M9�GJ@ĶX#m>_H+{ [>OjE�4pӜq`aϾy20",fAS"DRg b,Xx-q\ƍWL:ǐ\#d(HE9U�a/One@9?W:f<Ot^#"n5-8 CeeʋCDPxA|A|>` ʘX()?1yH,`BEx0�ZA˄m0ejG YɓWO~s~9_r `kꕒd]rn)KUMޞOihbm@E!|+ ?8 E_=0 SaF.)m<Wpl)y!9.kwtt4֮irIzL9~\l48 0V6o;֖ƿȉ}|bO#/(j A?=yC //_.5#0 PSSjDEe "ڤ"D;ֆimy}ݴqƦ+V@|�$-؉m?wZ^#}7pISYl?6!H ( 0i mL2|BDz2(r;7 ÇBcc \.{V|'$7 +Ȗd/ x]u-[ye1L! MS(.vU(//DI N8XY�UeSQ~omS1[lYq-bF!XƱE�aWtgΜY<G ]{p%dcnEcTu?!w1"q4 ҖY=zP9sf13bs<v=$(<�FGjJ $l6lx8[(bvtZmV$EEn1ɀe㶭q\ QZN^6AI`�@_K Yg̙$C:x׮i@Y!d ~AQ0kq^̙555B`' /@6x�bQPJt+,ʯ"^o;?<iYJ(�D8$Aof3'Z˲?}/@FI�Hp¨/^b韲JdxLNRQD([KOz  C<{$bZxqyṞK\ڇڵk?02n)pu<nKgP�Bv ,$ɓx-0Lڵk? k�Hٹdld2u!Zn! nҥSLYf5�}{GvtPE=L ߟ ?B$"hw4)S-]g("ԕXH2BJJkmHk֬0]3Ⱦͼ.M JwW( ~7dbak֬L 2u(ԡ6` S HE.^|{ҤIq!}}~j>߄ŋD�@b~(vf,I&ݻ|r7�F" ImiCR6ŷ ի?OӴ-kIGyIXIP~ >q ?3-AQ(ZH2![6]iV^y`s6$^rYզZ>5f]iKR9::zrՎ8 bә> !Z $�(:D^\EGG-ظDeF�rvO ۾ Q6F.f͚e4M|6Bؖoےm3>| (P�㶻,쀦i5kB[)ko%v �~=-oZͣGvxXsI\L-@R,ıӈCOiP4f@4b�-#g;};=oѣG�l0в)�0!nOmذa(7p~ٽ HT ͠y} oFx=M3`4Ɖ�u/v86lXP ȡlE!�Gr9դvL²,=]I==>8?$"}R\y! ᕗM`h I"f@SRȊ0<9q==>[^{Y2ǡR;䲭_F7_%bϮs:ٸQACcV~|a^.z{=? fl4qdolDAĞ]`EEE /0'$ԦĐ>z2v̨W\d-�k㥳XF5MӠN]F[[gO0L믽;hYXpii&{(!9~ (X�� �IDAT[^;jKT 2{9EZ�h0~0F-C~SfZya19>"dZڼIT(J, }<7yufXP4PtfȖɍػ젪jw)6E_RA_r%�&ɹH |sӍ‘Eɀ +h=agKpߋ>tvvʕN\tϷ".]nx~2}"Y0 er8˲`4ME͐-ۑ`Qb& KT�?@rė(ز5 D=p(bKg! Tt5Csx?}O"._K.urU|~||$/#yccY.8r9*pr+;VPDIi1*+PUUbgDQ~;<pBr38 :%?b` �C{6׮_|M6]8 ?"햘TFR2m/e�z~J#?#)jժOReynC0ƁVlVCQ� "̀aY>)SFgLsB;ٱfVCBiCgQq;A8 n!aTVU娬*.a7;wC`Y90@??Io-vwUV}rӦMh7=v+hz�xGƞfؓWQK`d⺺^*((p( wOYY(E<F(Ek_�N#ӧ/?܏oƹs▐FE˂0>z <>jȥ]^LG;ѽ(qQ^:A$TUfD%F5b(7 mTVMho\\Ep ti 8F � &i~;*++ a�M'o>yL2e1#WsǷ֯_?Go9_6'z^?x}7XvkOM�^xx|(::rd4#M%cQq y0I0D$ TX=ި#܄2ꢈn/=hii"4ʊQ?ʍQnjpc(7FEaP6~}�ԠY� LOHdsyXpcׯ_? _ߐ@?nK*W('hX^dRcC/9@.-²>njĸ#3|nD"~عgh4Jưde4EKh( GGC[d@mr\@] LJ}NF=R{yE)F%q((x~|>ծp,Y .n%�~^[YQӌ9�r0!=٨'~5,C�t+�X�̒%Kx?PeW#g8?W2H$ 𣤔׾)* DQec掳\<reDGY&~|IhDlWh|ĕb ~$ _H6a`/ '�PYUQnԏD(7krY+ DQıg]س(x> 0q� FFq_`kDQضm['$>@և�Fj_);w|K.F\[ob"p뭓q=M>!߰qf  >9`9'8~) ``F(feZ V:p:ү^�<p(HR'!Ѡ "@2(dAl" *J%aP/ { 6?߆v9ӊ< iҿ kP\\1`~ُ`P6 aλa,>_#DŽ�|�-Ae?Q`hl_vӧy(""v:km%WŹif`A?Q_?"g7(x Jԍ 8gH0,_;*w9? \`~H/)<:@0A$"@ca`/ X9=z6!PUUR8rx<zzP@r|cߧ?&J1gnjj#袴žyCv:3@Fmo0. `�v�(Gt uͲcӧ;kC&ria ,Ax]Gf+W:q ˁc9)*\܀9ES4}>__DIЇ0 BA$EGA D b  GoOHdXN F ~ ˂eĄ #0m,gvDMFи ޡA1HD@~ZK_aݺux}H= ^�ݒxƊCXYKڒw%>$) #ezoތ{Id@Y;tH``85h~܋XyFFE;UЯTAz ha|bP!@ , bX@H){^hiia)aOc0,8΁qqÔjZ;;3jqL!+`H@O@q%��,]tO<q�lZr? ;=(H U(_qn3g,jhhX5p5_6特rr'{F`M2}z8it{hsFcH#l|%8?vh((,'baDxB#"< �0 D |H^A83E iԎ,5"\v:$%?NgDQN0L{AϹPXh% gΜYtС>n[G^zMӖJˈd?hdD㶿k+Q[[ѳ1#G/Y4ÁYP4 Pt["(^o%JˆDs�H^)׀BA}Tܚ1É!^Xx%.8Q\@ieL;΍qqC 5 oV <AG/9c-}]W^p�j6O+ ` l)JLy̙H5~o*q"@ `80gTf>O1Ԁ#W⌞E'@@qjgASp8p: QPPV K*[[”#0 e11nMX "!  '~ vˣ2uȔlÁRɲ&r'WP�覦=٫pӃ+3&eTtq uˏ_/ YcmAň 9Q틋aD>O�DA�C3XiξIu/CVr9R2('5ە^\ TJҖ?4'ot}h<AFz)(JZh. oeWFϬnn[x`b@2 Ey*2} 84jX{z"A"}'(+-RcG{2.0nG0G C0χY vif}gtn豍Pi7._Xr?Sٳ-wG2-ZsbbIwÅlۏΙ{[�CD ]F\<Ė,%(*{K"@ B)ŋ�Bo/LvX<B ?C0� K3 d6[B;Q{9=!c)�$O<?`> ]Xy 5@GqNp_q-s( O1H$]&~܂( 2 A " x7r'{r9pǝ |PHDqj#!Bk[SSs ʠ y,�0R-TO?uK@lE5ؤDWqpND~=VfԱXcAD04]Fgd1aB5>"@5Gwg5L0 &!!"! ͺKw(b~0?OxZ#@Rjf͚e?+V0 6K fZnKY날hM. /Cy~_? i}}?חg7ᠢ" 6+?:yu0R%j^x,h �X]o¨뮊ZnS' 3-hzYÅ y3VYsq/1'c(}Y Z A{{KgN{+P;f# HB&C0�wl[02}]wU@l�%OZ@O:�x�̨5\mժUQ, .ᄤhiV�ˁcp8 pӋt3) xӷaTCx> rqtGQ<r;],&N`(�phBPQɮPI0:iV@`?6�!?OQjժl�ĕ<�OXiD&eL6=y G:X']>*xz?=uuaDxB$>FmZ3El /CE~o?~/"</;, , BAO<;z:<6$yGm6ʈkòP@I(._v;jjj,w5MdAEgį/=/lx BX.(pnpKSO5(BW�Qx{ ! �dY(;P4  dF%6jjjjfnm� u#60@g_Zs=7aוֹcG?!sD�qS8z~[2 `9qDk(x+ Rb1qP_= ȺY&5`đѩP5r; <s3`:FQɍ](v<}+}z?ީ@QA fDB;v?fBY(,w.F#Rb`$\Ky>o p?&_|AQ9=Nwy3X|k vZ?:Xz&5?drұP^+ƌdI?{#-0yW}/=uNUu컖HEImlYm 6$͍f $呐p0yk$0;68*ɲ־HqkQ9U'0Eu q� $ j2* z 'L h1Qw#*KY�jޛP.WBȶ~xc];I*j\L DAőCg>D"%-,]w_Y&0 -'&�H lT9;iRH '"�,ƛo 8w!9iJ LrTo@<?؍ʔBrlC_P\L)z>яn?58dvг9K�Jy`ٱ & _܍{?yzzK�O̅Q$RC*.*`'AP t* hlQ^{ D8iyzُdRũi�GF- g}9(ط,0MoYbECԜ:O 8D01G9k6){Zð,;8_T*] pyx}&EdlBh*Lˬ5CLӄ#ʙnL(7AC�uww^С7YGd-,06+_?ZQ*nn�`vB02* ly'4-tzJQo1Rs* Eujَj/`(=/W9�e6+t�?Ӿw__ﲲ546Nm8zgZ&Q�PPA$x7ʼ%hh`N ӕy,L!9^* J@QRE8t dTu@dNB fu;zx(pR _7J@�N\r&'h۸qcN&Dc L[GOtv`a,^Ø=~<* |T+z`:鉒Q "躚Mj=*`CU <1vYUR9+DPN20=lSZx 1<?F:];Xܽ Wn:e�RvB<7@:M`Zon�"2*ԡJnPoUUPP^�]^L)dqvAc-(YKSFX%': ޽?=\ $/؊40~ Z[e(jʩX<*`t]kj&7@=*`V2x<NQzF_H)ӕ`9DY(�ƚiZ8zd*YH `40|&]˸òeסX� ~d0R%@:5MM2DZw8RtXĩ:i'Yk^oGF`V{F>/C2 J耲0Tf~}�ꪫ7?60P;2l�RW 99axJ^j-X' tv7=Z׉Qf,=�xv ?",]$J@R0 e>0 ?<Ȭe\~>,-j.5rl[dIU:NQdA"ŏ~^ (p;7@Ї &Eb<dQ Z&CQ.*@/H _�UM9TRf)! Ṳ>O  �үfrٹ}Cak9@ e! 1<[Wd2]Vc^ֶSLt9!'j pjb C**!-\USVHzYڪYh�{S;r,�j_ᄏW Pny& X.aPD'NUGWW3>qX`/`<Ts; ҩҩtMeN' L7 `.醪4 ]捨uc`9eYn{Q9 �d ݽ#{>?zdf:Jf* JY%@4`tL}lۺ#$5mCVU4)&E,XЊVN u`vTlw^tɮb4�P\&NEƖ@1T?; %@ DX7xO:<|sGیx+<AP+{��DaT&zYjGv5/Y>e+p؁A`5  2r$)'~:W~,}g43 b,pkp@BJ eY R\Џ%Ki% hֵUP�U+9V+ r�p/EAHUt<9V;nLPyr<w뭃. qGƦ��hI1>A UA�� �IDATLExQ߰ ?H'Ǡ*zzzD b8N y `)8�fs=V`_SE\,/GR4K h ?gjʿlf5>r $T�A:J5VtZJ y˅4ũn8T@uzؖÇ,B=ӏ@e-ݽ,/ fLV(Gb(~=D˖ⓟǰp" im X~^4 H+ *=2*`~,Y+NT@lp] =!\2,S^ŋ/p|%qi_n! D YBpE`c/~s,["44?~-_`Z,;`,%Z-m;*Jgس-X?W�pfHáCa()$T= JÊV-G@2E1b@\ ��s*vIӧ¨cjpg%$:'~rMJ[n]pQ+W¶ ^+ *`[(\x:0+pL#h"GZ"uYXD�9P ̺C\iBB²΁ED~F?GjZZZEyA!8% F` 8Na/@:kY MxcP+cnJ J:Mq%;Yӧ d;SB5��lڴ9 ǃ\@/I"޶m{_oaǎk:ήfr|6~x-t�#3: ulN kOCA2BM65%P\A Y*E�mQ; p�Qp%�Bq|GXyЇoDccCMF+I _v& P@ 7f* Uh3RX?wJ:I`Ltwk 22Tc~ `L|ߒXB?qN! !#ΥO?ʗ@]N!3i)-ŃHV\([׽0H#@ �'"Dx|ŕW^X^zٹ?1> +0C)Q�{'$S6x3(C`"$B iX6o˺j6f/VZݻaP&: �/vE<7 n.&0l�<נ #^w%l!a_JX|9}Ԁϟ``<SU BA\ aY uK|`.>s.i5+(dcJpa+Z[* 55o)-tT7x N*Tbtd#@ KUb($ClL{)ڠg@푶$R) DmT2M�wH<B i@Dn'ϟYXLGp3|>,q3\PSQ(p>WmPzs tآ�tT 毘 'N'CHg>PJK90GrI(T(yA�b(ٝȽ (JH,3H�I!K LM3ẗ́uײ2J@/2'ym;SPIPF4]?y/ѭXtAc X׎%hA g3@ 4Cτ H+ 0Qe"ؾu/j}G1,G$mN&)]M5MA̶'=VX#dYE2KcR}�,[,*IRKP28^j|e|4*=5A$9=#(zaXuGA h4݄Kcx8K9J{ LJ!P 23{@g|y\8yr.Fhm )}a_+1> Q(> ,qMOy 1A�# q[AaT\كF!0$\9=xp0X@e˖Eߟ@q �P D1�~�E!>&}曻 HDD{{m \зdzc `LB4Z^˲1:H C $1<p # h:7,LpE p-]W[ګ{pGߍ /:8>qu^=Jm͚:%@NFDj<<AI0&QQA�(F-kc[y k* c&4ΥThQa[tMeZS.~7w?IעRrн,`HJJR} իWjdNg }A,oGww3;3*䃄 s&  3'p&W*aЇoļy3z<QK`\ aB Fs]NOK�!4iؾu/|.1e^{vѣ#PJs㧔bn$``VM x%�ۆ>6ՐL;)R*RVK)e7$TЛECKk۱hm;{fxx}}&&8| :q :–a#[wܱ 2MuK1o~+btDW]�06Gk{LcA%sAp#&&*Oyr0G T KA3T@@hWmA7Tdj GZV^HRi$@I@-�ecl<}1�H;ѿMM3+fXj!VZ�0 Gx{qwCxܳqquN˿R̛׆OFG/`Ș@JEC\5?{)% *JC?�(:CF\P*2 �2 028NWmۆa0Lxl< ˲!=W.V#o]{1SQSgw=imm 065�4l0Fly7V%K;P7V (/]ؼe �1;n;|nąΜ@$*ᮻ7῞zO-6eU8 GCD.* %BDLx�#|T5Kg=: :T� (BX*<]4Gr֠}lX4Z[cבi8yחp/:PPί*�s/]Xz>ο`d93ftv6ce+��G;ǰtC 6oY<t%`tm ]׊K!-J`bq*Ԡnހ|1CPJ S-B .2��U�\2- CXgYIeҢ>\ cXruܛD$\xʲqβ^|7;6  %@NEN)Vs* /*�@sG\6$g[SA d0xIn8zdZ1`F:Yj_h,Y :\�1o~ q%>s֭_\g)c}a%NUjfTe 2TN'(I̽oZ~Xv)-ꀦIhZ:{-&o Uf:]DNva h!IR˒%K"Eӱ}J�N*'FT8[O|W˗֝�3-u^ B,䊀eYއI02 Z N'Vu9v Nzy Ą$V`M^+`۶a9 ߳2<ؑmӒSm' Iŋjr_[޳z\xb|3ף- 1m,AY8Jj<W4]q侄�;ZMM uJl49ӈd-�c5^fdP/FTS�N\|Yswww y`ݫ𧟿[� oӂOFX tS@Jp#̰QwB( (l|`�۶bs)ĩ�8`֩"(�sE5dGψ0І}ۛ9IH&TMsv6^g:fdYć 7{5l:UmKhȨ6P4Ja, j言w߼`AQPt]q*C)2<*NL Q9eNz>!3Vٿi+ )\�*:@�U5`VmKi Z6Ooƚ M>Qى6}|3"1 4`ZlذlSk R*u*@ )2cvP$5 M`Z1qNL QΝKۆa ôRE.y\@!P*�V{)D&ছVJ,[$%u ,Yҍ~&8ZeGTGw^'4UA:=5-x :^ }}4T%MM5X{u*bd|���GJmdbUBFٚN, VH[Ԇ>/_Z.uhl^+\3PA02:�djDI*`do�r*@- 0X2f,_LyZvxd[�]EPl 2h4P'dZt nz*{1#[nr0fNL/J LIu՚\TRNTQWo^]W)Z9Q,FT}7-~AвÑmSU<T�LG(KD"S�!){>ve}_GMj"|73lᗧ@0<i'=m4*<'* L@Q m'n eXUMAQ`:LVRA"DYŲ-g4mAp'wҪDC$OvM[oo>~&̛xcu&|OnĚ5x9ӀmOnM޶-3JO۷ T%tjk8y"| neIN ^ʅda9 ( ۂNWŚt{P[ z߻WG( I +~0- NL:T4C^;ϳ$̷VۆE$B78hnnk7oł䌝`=n*040MAB-+>�Ed[�2 t:߰gM_GpŻ…>Ą A6PU`L#"PtNta[VEc P)Tð3*|˰k8> DP@Boma04 M™3Gsl'khiia&_.�Tt- ܣVI.X[u;? ?38�WmC3QVEm8y)$0&-|򄂣GX[nـol`DG/ �hnꄪLnN�ձ/ZHD+� R*]BDߢ6uu_Gc6<n 䨀JtJFbBC1<k㙧9@J%O�b`gW86oYf;(AA`@5_HR_B $9Txdtdf R-,��Ӌq|䮍`,/:(B}EC?|j@7S*gDu08.4D&t=Tr J�+N��!"r TZpd\hfՌߩ8aSSS i܋1{#pIrp䧯C{G i²C 2 4-ųHt8B[n%55 x.8 [/!;|d\�<x<.әS�l\\tt?#0 Uatw3r [6o3} ێa0 i2&�( A"DLA-dfG(iXCxVzm(j;2 RTmØ!49ZZؼe vPU'*QP Q`�݄w];#uTJA)5o Eyx ʌ!΀(eT@!m e6"Q3cF`&4MAZIB#`L( .Fgp%˱{Q81A9wMT@SG5(eܴ}j0nbU�"PhuU0<<1dL J 봂T2TJE*4B[7E2Ǩ2Az~vMζItmL@D^/�9AOX{ e0M e8&tqy50\Z!-ـo?4-X6QZjJ@P#Xq5h*�{~ T ƪ󱰯RhcGq Όadd#ǑJy+9O�Ϻɞ9K9oY>og ^ۧ}\]l%N2 8eT& ި  ߲llzՃG:P*Ukc--q\y5(AB Ր.+}{Q~ղ�L)! {>� ltiUQGqhGp�~Kl}gg΢ *?Y'X}}xO=d˂[?"8˻YhHy FӀs\(Ccn,YڈήBK֝ݻq'*@t|T@(!$70BY`KvVku V}غuxc/Nsq UyL]΀ 7SΜR=',OOn,s_@{�YW9jL?6=A @�d9QCb ք ؈o?T5͕�&Lհ�TCMR�dYm6.mo}[_ߍ`ϞY83+D<oV;f}r{�d',y/g&B>Eo֖5e'~k(xXL~egC4YRqR&0hmP<*I`<LƄeSQ 7J]kz sCCضun݃bb"xBM+" y�0Y-`&{.O�]5ۗ{eo2 !33t^8" A7/YڈpX>G0*:JM$Gq_`CqNe̵TB�xe̷m 8vx]8rx O03&:ߩL}ZN,�Bv'%f(W Oe4I^e? t$}{Oe-9Cfȱkg_nB[s)P4(� BD_턡IhBq膎T׭ G)̡2n:]iZ @C,}/0L<v< Y?T<UgW }9&fji9S&Vӿm{M.M3^'xl*m55&^ 8�@)CՈF/!;!㦃j)�ŦץP:%Nmۘ Ca_O3\gϓ } 7ϟ A#�� �IDAT\+Bh߽$'0b9Yn�c2m?>L^pv:TDSg6qXKcYLh�6|R!xܜU�Z<NʘCϛW�T0c/`lfSfbyL9~ex׌?7m~rTfNa r0\8xB[oDh*H :F*#x@udK@^կW�STF߮$^'&&y;ewfYnuy}e\xxY\i׏�_A$<I|YkWo^'Ue̥`O~-泒 M\v,%s\v2f/ 򫄔@"5N�ԩuëw8y Y2f2B{1g^\\l7gP0f3lLL(B#Dzw̭R7]`dqﳑLRX,zL @ F5dG2nڊLZ�J P�V ?o?(^}G𻄾#3!Leݳ|o|Ʊa3%S /qEP?1kg Bg#PT6,D�^%ฦh:˨�4ɛ* >�eʸ{y9>�*E6 R)q翃iZ.O/9}fyyx{Mqd6M vIC$)gL87L^7e�f/hT~5 cg`�@udXN0}pQ�qldG"ٍߎLJ16�gB I�w eǫf`BGWLo<DBy($qӿx盾/wnpy H8vTb W?Tpd\hgATCFFF�zUl#?y_`|,RƘI:IX g,E!2癹Q[tvL}�Fy3hasj'!ݶ6 j +0Mq\W0n -tJՑ7m9]TP@>=X\%�`7< a^p2lB$Ley~'콜~e7 vɚcN(`.hkoW“O AKYS.j8;�4ڈ8!&�bgy0, �aIX`+ ##N7N+[z3*r/YrS6H:*P' {ߋK7ݻbhT!5%g9e@CC0h<�5A1u�mHI4-PkZqc0 D3gF l۶T``L(ʎ?YnMB#_G. x xY'OɦX‹ Bލ�1jeRA$T -v#hQDeo n{t�yo 0Mo<pg4M7qЉ̟ #9/Jr67ynu [SBa~Fd9H$YMJcU/ۛi*hZaG o X;n"��ɄM>A[� ȶb'z+�lL+`l�P%X @Lm;X?ݟС!2$F Jng˻9nO8xsq@(`,YC_/mDSFS+4qPIaidnRI|�U�\,Y8ETvϕ "t:P)�>͘w:t:<)Q_zų<q/IQnc/ʮ\CMjpK;L|LE}/!ĀrK{�81f$Z:;/pd[!Y 5A>]* W Ӱm끪#L7aPcD)I@rr6@]>45h_MRS_w݆EGCiZʡ47s H�B�eDв#*"P;X?)D"p xd? #Hfӟ(E!x ,tvNige~^K7-w.�-P4T5 MW`:lۂ\I[ kHc"`L{*hQ@U*Q�Rtl� TDD*8t qJR)k/s ˕u :f#CfǡCȘEQ.nR\xq{VBp68d$@HD t.f{Tko1Ѓ <IdT6^~i' r$0&+E~mfZs;V7J%Gn$Ŝ6<Om$M~hUVA(j s*9rK@żǶ;ȶrNd>TJm<88x~ֶjs4@?6__>31,gc63i�_vL~xL B£T]~m)М�Q Pu_LY�Ǘį@5dGʿ˦I۬l̵O+�mm g!يw?٫琦aؾuqUs?O+Zs=2<9Ç׆19Ke=xսxWk=,8pl[w%}r㘚Ƙ%f:pS�p{2%W6ӧ*`XSi)ͦh_SgQǐ~iِ@ 8uj֠_s�J/Տ8 [o3ך[44[_;zfL HrԓϞCL# <�x8xpCʢ^ MQa '�mǪˌ`6 ,dVڿWضT-�9@g8p@4mTƆT$!N{?}Xч ;Ú@D"2, go�v}?[Mg۷"@,G'Y1#<EAQ^½J+eԩ)XAM@S; ˜}:Ǔ td@ӴǗ##OF-yUKr�@*:P-dܹy4|yЃ@CC *[1-Be?q|Gs˚pSau^~y7yx6  }f6o9-{}eփARNN<"rx zfCGV&&KϐR. >AˌT*u+ጠ\; Ի,(O$---=%�@`Lɓɏ*wfӎw9pZ]z4!3Qe~F/8ŮbBtk: :Zp妕x"� z{AQ!cG2#Hd ߻o[e)S�}!_t_d�` ,X` CGKk @`YQrV�{S O>.ʕULwn}!drWgzeQl$E-q BfgzւAIp?{y2P+VbϮ8u*S%`2A4@u+_2A hi FFFP\ɆJiJӧO"@AKs>T@`T$<_ԩj/9]lنze-lcFqH&YPnurP\B8By 1IAd2 ۷P�[:e5i>}&OK8 Joj[^j=�G ]Sn#e) _E2?6l˶yӚZeWUۜ\ !1ȑ8D) 2cXi$9)%QL(v53gc}r�MWL>Ξ<e4۵..s} Π}lL>!6�ر#P ��ttTe&2NN;Y-+v ,Ӏe5`yo}T:IR'42/ Wڌ?k D1Y$LJSU%+޵=MAO4WQ YigY) �P"TU^\�=Ao%37o?嚋;.i,3HsRhx##8~lɘxNG"և*PXV̙y31;x9nw)h`@rBrtZ �mL- یW@�¦",&qePmr()O>a:yJ�;U _Qtl{(�dg2!@޳J/_l,d) Exl $Q-?mՂ+Z*0Qs +�߿?cr+%˕ҝc^y&ygCs<&F ?sAV\~ Ka0-n`לë7D ]28F#(�"F_8}2?3PT= >qYk`w] ]=P4-UW`,?ݵVp2E5|Pt{]Oro>XJAFcLi$WO(~xO8nx&,SNN0Nf1 H<k(ź !3x;f0IO$E!10nA02a.eд45}PM+:,+P/GƖ#w}1U;Z)m%O{>{j?Ǐgc+ycJd4kJ/ rs�Y&0-9Q6pӿQadNؾ8+RKbĕ':!ɮ92] "1)+E1Y,W!Qgd堻WmZ MS4 Cs|~j=2%ʖ(,ClEr&gΝo107�f'fL(Foo|N(˖/x,iiMe;۵MdCh4_)zbѷ(\Gq+T`E~*ql xPj%94MϷc-h�YO)rd�HB;(lgw[oA?AeL:D)gمo|Qlko&zZN0p6an=!3<8'��D`L,7@XDȏ#Ch߿8B'7KR T > Аo| nrXZpK}e]dݵ{y!%-J[�駟SU5PbwLNFp:@r^ym7dM$!5jp8CXjV S:o; ̯[cNȑp6 /gLRɩ_!# pU+; :PUu駟s-*K X�2yll@i<cy %@*O/>:x`a_;Ͽ B,O9)DBϼp_}0tCD c`T'0"d'<n pj*tu5BRP�s1A �d+$@Ox @9fJSTsԩ@�?%ؘ¿ߪ(R/ނ V)uE`f6```Gz;E". =ؿxւ/s *v.*}w\%`nF6`Ď 4TtS -`<x0P ��Elfb' }EmQ<G3T@AWw3>q9-`d [U ?Ұ}11SM;O1#T~ Y ;b̝g׎[0>]iŕW^�]S*IN誧`n, 92vZOw |v/^QwJo ^=W^y%pGe˻u9tΕ(D) QGCP//| Gs(UcpzC0  $^GcT?EZ;<\/J'.wa?xMi᪫W+kIh:-[9s0`{+{S� =h۳۲m;is:kF@sh6{~طhA 7ݼeY,:[Uw> qwr7?r^\R?9tApꔊݻFV0FX4 uNP@`9۶~/^rww,j'.t@~$```@O$P4*b 79Ex}xt(Ex(PO~ %��޽qǝ%RWBk[Iol?<"_Yi'"a3%�Zȅ3vnmÕW+9`a+Q1m&:}v!_TC(WS{{-_]{{ v$,XB?3/|O}*j IbtK#w]FX˴`[[DDBKaD?TܕgQCf*N_$ Q0'.*F`υ شqnPS5u'Z^#l{(̽~OSD[݆ݻwT0ƲlyW&2I<B@f;?³ϼ9AK _*,^Ӳ>s5Hmp;Sνx 8( n_Pl,|};=HrMOh% *m'O(ػ'<?n0- NlyWɑ]]d{xzwweaB(ݽ ?i {L &C 02:@c0t|Q|た L/Z� W^uQraAL ol?!1D#Mn x) BW_>d2<T@CMT�e, ^tɮR/b2q*2lTקP�{ɠ3JE{ .%dd'aWd)݅>�{6p(4w~`=w㮏nIJe�̬@]A- Bh/iZ�K#y\*Nr[>Ov8$?L4T  jLI VTUu{IT \?/&/+A�H)oܧ_ӁK˻jowm).("B( 1$&?/ OҐź^~(;y캯 ߾A9fcI#!2apDqiq <RGc8:ɇG*[[P*}w\ƣA�}[^Kfe^PV??^-;[l_u7nء'W�R*I�� �IDATŎ{Gy:;㚫lĭ]{{߅{bò39,ذyg׿p'& O+1rD)"PÆ:o8 CljRe D�I?t TxyxוCZe�ȬB?rR맅fۧ~W�CpK )K lğ|wOQ Z&W+VRl-uBi1' loQ4n>ȘI#KΘ ]BȨ7EGg4-YT+@)WvdV2H?zox{2&>L< 54Lcx\}RJ { ɪ!#lۆe,i04 PaLS7\Z{F(:vy۶]'&ٿs B5߳{*PHR X \R^YEhK#p PI!mD,ڌH$$Ѐc+m۸rS7S&qߏAc<E ;NEEpy䧯ti*---7$ 49,B-#ݟ`#Yd QhDyQ- ˗wc١�%<&9c*0躆> =&>[pӻ/ax"%k&z8o=o@:g_DsAhkC%MT!|/(rq6l I?y{Y_jA�ʹ�xS7hbv BRT%,7a%ûqXWjE{ضmX*EF S 9Fxg;vsCn©#�N}~2(~1W/;փQ >=O`֣1$Zެd)dg~L6^~ qLe~&f3[ǒ3+B?R sf5]0<v"=D7]glycǎ3{B!f~ߧ`_|ŭ^x]SoA-jC$"BQ_[r d N.5@>^s3t�cVZm:4=Nb8t`{6f2O ]Jfsg `L'/]tK{o1Gvr;e~%9Z\I<0Kj=�A~1c 1tV$"oQ[} t/({|�LP~E) ~`'Jw )|l e2 в0p_Z=Pbؽ{�'^Ta{ikXhy|7,ۆ@ޙIQ{WU;300 . Tp&*jT0U(Ęk4AVÀ 0>l][uuU=3sNU=ss 11KE-%�Fsl}]3^~iϿk+l&!Ɩ�3xQ�V+nU(}.llx&fM) {3^c:Ζ!ob� HZW)?"wjGUUtf/}ey.;#Wgq`( Mbxc`h3v|شa~>jL*L6Cc|�@m%,?hil$XMGqNe96l==Qn׿5Phk49z&_3B]m:35Z"ery*EPu5yŦo6!!�9׿gH6 -�#DGm`bށ/(=܀1#|CjjƎ냱8TV`9:x*,"8DE,(- qv$&0y<j[\FrmqZE]++7MVd\(*jBV C[⍿X)wyyyhWIE ��[o}ʔ)*Oܼd'Z=nՐv{A'MpP}} R_F髏*(Baa: q CcqX5)q/Qkځ&XcHI1#5Պݧ6R_ׂQ4dvY!GɕS}]3>?h0)X۟7OU}P֭qKN,,xy7~�l t3h0Q+ !цܼdݏ[om& 辒1�(7&@SS{܅ Q�瞔,X 'kai#t&fHΩHNDòΜCQ 8zZ[[wy8]@8XSHK"-- β Z@SQlxť"6&=ُG8\qS=z',CLLblXcYq&`N'u툉I@-g:ir?r|"!!?'ֵ'@akxʲAyWl_� v7 8]�1091sx8Zi ((HI��uPQqG/gN׻GDSP(;dq Q_@MuK`RSΎEVvL!̆YZljzSbQg}<mV0QBQî=cR%OSZ֨j ǬrkwY7_I@.ݳ{(~͛7o4h5^,)Iٳ3ц~xAQng'M 2I@οQ=:\5nXsQquy!� z jg6?c@0#5cGuu:dh@mu5#%AV qu-(Gc%=PȀ?%1Y_׌l(c&ah3 ayv/g t\u�lkb3Dn$~͛7{jl mϪB �P k(Lxi&+++̙33 F櫃XG= [ct zGඹנdP/KΜѣ.QPQg(f I@f9#˱,/;Qc;%M 蚲p~1n|N/ŋkZC*[,k upL9ּiUUUwz H+��ƟK@C ��Ξ=V<5P?rg ,zg^۲]Wl̽rH/Q[{+*z |PY|I8]qNkGl<eFvN,9]q K,b%7 ͳ V~p911IFC^7�yy3ǩS~9c�K ( K0Iɺqܹrssv yiQ8ޥ| )9gi(qy8i_|�4@ee5[ B+Dՠ8 ':~U<QY ofpͻhca2Y`XwSK :َa9iANN,,?Ղa\djv3ܒ+35cgi~]"X`ig1 p0E{{U|kVS(ަt7�P^^ l>|tq� j��%/@@k6Stu(;of~Os-:YOث!`0'**.*9|ǏU+<857tM@d6[5$QZ&ez+r,y ~Q銻_q?z�qNpp>s>ウ5o FzLةSk /WW(�hn ;W\pՌQv}dowC4>uxk1iaLr鯬 8N 8v"v=xӐuu:8&V+b^~WW iG{G Z[vYoj"!cӁ7 p+ϝiİl˳`땺xPovi L+nb.@[w@eZ]j(v\vx f�E3h3hivTU5_'7E jL fon8,N.*T'4ܻxę,,W=\'9�{ �h4c.<L^ P .awI Lf,nAp\\(`y@Y,ݻ7@rLM^m@�Bo(z�ƍiӦO)=t<ʷzq D(v#N_;o�u6},&L,ˢD tѣjyZ^|π}AQ a�m[p]hp@n)`L0,0m0l 7M0aFVX6LV^qw] 8DŽ fnٲ�̚m_sv@oϿu h8<յyN[8/�v?!]7SFA;Ngwi8^/}3^NL,ho�F46  t7ϟf[LSRb 3t?GUUG ?_ �Ug7|?DA/vpu*�(B|=ۉq�P h`),v;>dv8-h쑅ŸQX=}4iC؊}{`q9w8A,ŀ(厸w9ErRiW5G1`ֈ$BCƮ]jPHm@�Y PRRw}FӴ�6y.DG p9'# X00a2Qq88t<9?F]]An卼⻵k37 '7Ic,;veee _��7P/6xz!''JU7%ϕdeއB X;ՓeޮIyy7~^5Ka8C?I;y4JBWGT<Tݏ{ܹ> m_T �BlPjޜeΝO�( 'O UsPq,hKpN,,t|oÐ!1lx1/F޹DA9{?<m៪rf!z(ːܹ3?DI �45(5 6,q׮]4|�ëQ/j#=c p/h71 xXk 12Çc3P[{ ۾MGP[BNMSx7!!qY9r{i|_/?DIU��uT#T ��'N<ճg)oD%&{Fvy|)`}#&aMNX=z|bR +Q'EE' ɢJ܏sgD aFJoq+++),,|5@Mۿ@@@!4Q@Lja׮]]�ۋ ѠŀĀoX׺m=[E塨O{]{Wfh\9\{~</ñ^ bXck׮] uF[ΦW} s=�@T`�0hX5՗<lD{<.x<A +J^ςG 9kC\铏Ey'Y Hp ~>?'E�!xҥSs\zt Ϡ4|߾}JJJ N4 ?ۡa%> (6Ҿ� pA:F{;'Q8giIMG^~3Lgf# A9( /45G2A�طo:%-|-�.Pjv@97:uj_|C;,{S׷yX@�5z 7X̗x<�<Os%!7/@^^&3NāJv'>_#\N^H !$'` 3a2;2q믿jH'GM?)�4DҞ3 �0@(+|k! Vإa  2�7g/1 BA7x>!TFa\ꕃ^rѣg6>8M^�ŭsFbʵt?3g6?uJMԿ´f7f� >5 ---]{=.�O(q]C}? 4j2Yo�'Apq. [} /4bǎCk( yy(,F޹(,E9[ld$aѣcj&"B#.ފ 9vii?| Z#�@6 fkkk?}ukc=zw|YkwZ(X_5e/-\of;AA,A X m3Bj/ �BX1kn>X㶶VnkkCߑ"�@ؚ$;wλuS2t ?E[]C#yaLgb�zxq^1zEr1pP/ FfVjX8YY?,Yhy�bK3p�~aQC}� ?��FoyL�9sd+)WUCWV#XWa !. \en1ہc5hZD  Çc5wNVVEk-@ЛoY7DZvۭ+V8?V$//6R_Lx/�?@Jh<uԳ1á o>p)U+A%QNQ`08i$n*3,O$|f'>LS‡b^�p O!?5?l @Qv_9?0WM_0c=�HHb"އ& %ܣ\iwܻŁ iB`c:wcN'.|5߳Nƌ)o�'tƍ/2!AMp _UkWMZOTLM;W?XSScHϮ{RB V[hBy(M1i4mØfddddd9K,,8X-qZ`fջ-q}1ؽ1$=&]7АcyB>~2]gGf%/�%XCYt>LHIŘyQM*( U�� �IDATSx (<{;fD {?Hmsaذ>^HJq4mE1� 4BaHI5إ+ S 3B¦C��j7H ʴ�Qap]wm9s)�[*TJm+�6pf)HKEFVƀHKK0#MSc#8fЌ4�gTo"ڡi ]?Ȑc_t]wݵŌX-_X&E>=�š=.sRǻ8v۶m+G]m>4iB|e㐖T:-iHHuvt8d09�펧D х4F<o۶mP2rQ¼6ʅiCk! �94sO#Gb$k)\?miyj3!6ւX b,-|\1fz{z҆s0l~ `(׻:::RH@/jj0 W! $ `O<ٶ#G[򑛗# Sz#[, V3Vk|i 6 Oj]fF݌X Mc%<dY0I Y<w�>ydD^X. ЕHy>(їm�-Zh_=i0mp'�¾ AhPi0/OS`h׾2i0& &`L4 >bkOlfg`2xQu cuS%H?!Xn�lEVAYI (zaq1R�(=z >Pf�ju3B!!0|x>~}ZCDvN" FY+&2ncNӼ<MFc#Ν60՝ҽPAЕ>" 9vEEEz俘QW+.@EX_i@k@YOO>|p=MӺ7v((?އp\=]6 }3з_6Ban?[xXUe+�C3`L&3L{N�{!*mw2,ڟ|wkqA0p Y Rh#<xpAo>Xv?V}ۈCsB8 砨O&zDB-җK"ttQ6|8wE05X9f & xZ�dBy_ł'ȋ]&��]@vӧg^z08,zb-ΟkA?k%ށi23ѫw&dOl.F|<47՛r巨k9dGIdX0f2�A39x醌t:g͚5gڵ~PgH"iWF;VZx@T ۷ﷃM[ xo8tH�' g8䤠Osѻw 2Hjj?*Oúugk6;2dPɞ«7E#Nن{2/P7ُPm*HU�PB1 '*X0yԯj0׷`{ #~�뙝=C:Gp,o|v4߲jF^~: 2QPLd" 6oKa!^?݃kZ{=Wcu͛�4sEI!7 9l~6g~ƿPgą@gnOm Pؽ{Kn5V<ڍ8F?[E+7 3EQHOOBAA zfB,df -- qq9t(/?w8|$Xw~dIg3h Oڈ1c 3cwGwWW,0*6 PRRe˖L&S|*7_ވCؤ4A_) {bb,HOOBZzӓ^$ z?vǏñgp98~mmv\]5~ݭq�&дkM hg'/ǔ7yܸq?D0*v� (VEΝ;]vet�X3O}'k8|��{ g lw|1_�� HLCF@(d$#==|rJ1!,pd;nCY45H졼}5ŸO6jeiw ױ -葊4mo~X>jԨV_4DҮu4�ZO/laÆ%|PUG/bɳQ:O�D@1AQ3l>A )^i�`L4RSD$$"!!HLCbbӱq./ZZP[ӈ6xӵ5mDMujP L[L Ӽ~io3� i1I$<Tav{_>{Ϟ=M-SFT1M'-Vp8ڳz2-::={m 6%'&G8|ܶ߯[.4^(,|55M ? 1Hp@l1l6l6N[,f-&X&v5l+ܝNNN' Ó9yy ӉmhkiGk[;Z]mhmiG[[;:ڎv5gy_S]< >E_IS4(61 jRq 3�m۶ mi'DЇy�哓-Nz'>>g*Fss;ghnn7"3@\g^a<;c@<9弴6! D&tj.௄D V~*ίۯrPNOy>/J34y]<VK3-�ʂ;;<O/w\rwRhw*N|2,qx߀<{sͻv 1{łp-fEETl7@x^>%l{C3?8xvA[9 75꾼34/-RX bB_B 3�re𥌹аC&-$jj� "^�ϟ?RVVVI* ?%h�1 ,s|5p~^И󌿘UPb Ŀq#@yMy~r_> P^Cϫ �Awx>)O],;;{!'k@x�|BdɒeK.EQς;.O|!/8P~.;ČA9BB(~5<VR__31ؾ>R~?-K|4;.1sXd2Hk7o4z�{<�4�Ӂ~7`[BUI>x{|]zШwb<ryo/(ygIE  7Xw#DR{ao_]$/f}J=!\;u�qa?x�Ե 2�x/T X�v޼y7o<l6't~tpl^#߉V�|jZ7xt.o{`W NW(%�qCY"D7)n7̛7o9 x0Cv?�`@9`7]}x<p/,x|_٠K^"{RJA,q' cS0~�o}eɫZTA�2bB X7={!ޮ$ڃ՟1LCN̺yf4̰755ͽu]]G#�PY nDpBYľRH|z0cP -E`xQE @wygissSp`{nM&WqX<�f�~^@ nG}QQ ݭ4 xⱵhhh5ЩHJsK6�TTTӧ}O^N,5$a�a��7&P(�w񗎎fIJGFI#8CGGGwȻ=Dʄ9"f0 �$ A^lԗ$@YYY5kto g Ǎ,d! Y"8c ΁YfiYYY#C"ɋmV>X~E}G0{ gϞ䵪b@ ,̺ٸ.�p٭g�w>mGL�Ub䥔!J<8:4D[8YB}Oǃku8-<+f$&#F^�a/MXjՅM6䵪"%%fa]B4BQ}XCϳiӦ7VZu@=Dk@{T�\�qi)E0LeM_v>#OA QC0# =GmmެӜHZN,@$_ Ӿ4hQn>?s/,kp/SBTз_&nu`Y־xǘzCfHz1rGA E-K.=cǎ7uCo`i0ƶ{رͥKnZ H Q!"M�ޓ#y5Tf3:ujizzO/;ꆢ%P(E`|CS]]`~[[g_Eʛ,H{j@y��ujI /Twsv)ԛc|\u(YBDr 7v{3/uARAj#V& "*�T*NbIK}9J_x��W^E7?F@ Fq Ã�`/~UPvkm6Q"Y�hSY_̙b]pIHK34I`cMEEź9slzv)إ^D=kSkM?nΝoʜ9Ӏghnj74` V<G^^tҩQFsСKPG.BZF MڮˡCZ.]8F^^.IF% YB(X,.pqcҥ:pj'V65+�;W\q}*p:YOE 04^4Æ~۷=WDr d´0J oTx��"0EWR;qww6<w,.@ t ( cbwO8xgC=i?E SK[[c޼yϴqs|_w\iYB(.sW/Ѵ̛7^?55z\RNE4xSSTz?Qe U?w9B2}v(qW^#<ڂr@LiuG:�!W;Y�D>@��7lpĉ}x/[yp@ T3~Bqa9ƍN4c})/&8h�IאG:WÓs(-R_$2iҤON8uw_;#.3"@ hbeսcr'N|=iҤO-_]VxP:C/ET �¼ #'ԡm/566^5g[0H 2�G'O~w#VHS=D��T?06Ou);ve;C ��OA^A$ YB=d,X, p4-XcǎGhI%VDi �a,\L\<@@\[ouw̵Fmm ~sTW_2TGzzy~RSc ?q;wh 9(L2ik '�`x` ܹsݗ]vټ`Y g4'ב! B؈O7 Q<G=؏TS �4ŨY 񕔔}Mg�yIxj5"@ j56M%%%oCzz�`hS<={޽)))i{/NQ@ 1V ,!Csr#F<XYYjJn.)�kS0%@SLɓS?쳿Ɔ葋xah"Agxkѧ8#,kii9{7k|vH´֮A *8lS&R,_n…FnQ>xiHOB7!==<7-ln7.\Av/NV.WYw :�P96Xy0�r�Z믿~rٲe,kvgLC~AJ8NG 8)xvɴ,k_lcIWud;uDM� l4x׫Vv֬YO 0.]j|?]BoL)իtM_Cկ/%�P3y+{'^صTNI #G`We۷o{II{�rz]̠v:� 'T{=hQQѴ n;(N{;lx$\$ ߿}=TTT|ާO\_mПR_0@'�@"@xB/+�x>'''<3g{OTAg<<ww|_&W#� BWI iW�cȍ@`w~1##y|v?g:WN  ;i/^9bĈEgΜiW/gD�D�i=b(..+++cjj 7_mɆ!aO+))yȑ#lWKПyWa'6Z��D^g\<@7`ȑ~Ҥ~Z;v:W^"~-#zކvjZ>R.`ҾNn@;8�AE ľH6#~�ڵq̙777.`|<uHH[$$X3ׅ7779s"_k~5˃2]N/� {I؋Y�ƍΝ[⾙xiHK i Bg⾙a=oKKs.ظqc=4/E5t&�a x2͖C|i=0@F헉NFjZlXV__<ɵtv>A���儀b`[teV5Míwb}�Ѕ(`!{ǨoBhB׿by߆.b8��O T#T{p{�`OlB$!7#/+ڪ,X0_�b_)Oנ? �@{ q4HT~9_ odKX 8t*ܧ&@?< iiiii9_z_s0JdPHѕ?�T<�?-g@x�P5h?W{iu]p:YpVCN En9 pEϝ;wڵk��IDAT~p1d"�"IC$-wvAc�-VZ1P6>`ĉ)~=NwƟ_݄ƶH@ @b .#H?ṡ7nX\j#b oC4]R��Zz(#G&~7/{@-X 8P~.'A0pP?< P[[oʔ)x0ZWA�AtXE@qqqw}$sx`Yk>Y#@Po? {ŋw;12Iri?��:p"g3Q_K $'1tX^Įܹs]~O' o?1a�|"@mB 99ټsG{kW6`޳ `\hSb"v 5e~oC7]^��Z6 +ȵrn|ݤI@ EaG9# 3n())y3B��BP&( XjՔ3fMfU�;?-ے=4 DXYooL7?b � !ET W^ye߿l6'z�jǿ>_|^>%!R4 ^e˖=C_[_(2i@\}QV�j <7M^z\U N؊I?*Ju]p#I~)1 �Gn'�jDɓSV\AAp{ :`/5+[~:h3RA.yuDٳm֭OOP|�Ԏف %L �E;k/OtUW=[YYنлi֐oư[ �@P CĔ5rȻUܟtw8~&җB t:zJï~3#})8۵k[%%%o;1C˥EOcrt[�*jci�[o5;xd2%(=aY_+LJ{/@zbb͸meA͏hz} ok1D�@�t0�#y^}(=pPWׂ܎[*"})Brո"uHIB.X˗Ap~=\ �v{�DI@;v Uzbߞ߾3 !jK¯{, hg?N8ɓ_:vX s'@�pe"@kl n0aECXp8XY#::!bX,&2{8f ��8slڴi٤I>zWZ?1Q�<"(j./Y՚ƅ MX2|2җB Gļ_ 33:^k-[#<C�"@L�(W`˗/:==}c+Gc mХ(`(񣺺zyYvm5Է kzD�a�~:Gf6n8wDKS'=غ +LR4[GJ/;vxsĉ9Z?Tow+y @Egv 2Ds=7pO(k9~= Ac2јtu_̼y(#6e$.]:tO<g쥌~0_'_G�@'I??]QQ jj.a}ׇN Մk --.җ#JEEźiӦСCF+K~Wc >1:@ :�ZLڿ\@M+V8k֬Ef9zx46ag`B&&֌7Ab-җ#noZzs}\jbb�2y!@` o喬OD[ K:r|~2!HHbڍq gHR]]{?Bp~-~9?d�1a�IF Y1`L6lm4hosO%җCƤƙCpjZ?XرI&}od?1a�!eJAZP#mO>ԡ Qv']~.4Er݈̼y(f3ˑvŋ_\t 7RF_(9/fŌ1:@B" !Z L&t 5L10N'+#ؽ4Ns? Cc|L #}I8M61uOy3i1F~5_/UHj�HD0%@0!W~M7ek^pQAcClo:җCc7(j={v<ʪU.@?XJ1 0Xxjb_w!GM1c|ŒpQSظ6o<KB'"--'I/H娦v͚5KgϞ1JH´\o#1f! HT� Pȉ�O�B$mQQ"p{a#(vmm+!!͌18@ݟxUTT|qwڢ+ "?8�0-E��^qwOHHpQG{N`#ػ,{CQIŸ0#hjj:;,}v#|z~d "�t Yki~1 Ǜ֬Y3cܸq$Jjk[yQlx'+"}90ңg &L,}1-[9cƌ5B %��dY˥ "�t"DG|*QPRR|ym ilp[7W5җC0\5'W神[39:yZ 1\:@18ֻY (A|*QxQ 'joY{ÝX3 ࡹ2$= Sѹ*[dɲ?ϕb 1a�@\04 ,<(/_^r뭷St XCыط=CA&&F,24E}2@ӝinn\ry!4/gtR'.(�s\�?Fxɦ5k4f̘fś?]goY9|LY!L&}3?}ed#}Ybm3VU2jkZRw"�00RebjA{ o6ll,:%:P}\XE5XMMS]2Cr`Nv"h޳gGsG{iFh|-~)!�} [Ce#1RAI$ # )JJJ׿|Ȑ!0 9CUҁoYwN֓ahH!Aوޙt۷_�?\^A~b5|ZTo#1PB@q ~:�H{^b<yrҥK0&a*InwzTV֢Dw]_GzINAT]$GD;zt:<j_ |F_{j0K x�#xȍ!V_|_hvHPy'+kq7BU3lMSHOGfV<ѣg z ~bbc_oX>|EvjHrmJ?ZXZl-o$F)lf l �@G@q=gΜŋh*M#ɢ.\hƅ&TU5y/65jM&I1ȈGVV2xE ze'|+VT!8W?~~4iDtoWA0y_|ϲX,gbGSS]KsS{@̽�Ldb`vM&ڽ,HH!ѽ'Xbb3G_hѢU~# ~z|1 ;D�Dy5k%o@(b]ѣ7ߜ:f̘9qqqJ@,\tԶmVs='OlC^Km_J�@E942�1Ao�?e +FP�hDWM:uNZZ0C D-555{JKKWu][9cR'.�Q@Eg-%�ʴzBe?_M(4 3glzw?|BqbjI˭reD"�ʴxʕRP+(�9s2.\xoɒ~DBdhmm:p^zi݊+.@AWSW[+ľPHRejE)ezi#hf1˖-=u鹹Wv gϞOiiG[[ڍq_Z?@4A@xe` Ԧ)�ԩSS~ r $K.ڻwg}Z71)LdRe;UDY% mڈӧO/((@t/X8uԦk׮}v#ZC ri2J�b Z�?U zX<5lذŋ5jԤ4M&Bа,먪ڱs O><J:|0 ebi0-*߁N@2)QI1$ᩧ?rIx8s\p]vmxg75A[\MY8q3 Aog+`*�7.'0bĈI#IB]wsmڲeK7Z"0IB@'B�Zb@ɐ+D]{) .?hР1#y^.lp®m/毿34F[j ZW+ ܉N�0yʔ<tB@oq VV駟:nܸ+ E|ĉ۷lR3쭪@pFYo#gm_'~�¼* zn˺4hPIVVe >>BgtTUUP^^^[om=3鵄j(ʄۅeRy!1OY-<j.gyf1cFIMM0Lt:jkk>}z߶mv={0H}VKw SC@ �~Z! ̇SUt,̢E'L0wC222Z4"F{{{ŋ;vlߦMG=5\/\Z,/U1"�LZ}t32q]w̚5kfggIqϗ<xpի<%SjhHY˥Re;e Z�Lw@\q mלeկ~sEzꝙ'))7h؅ ?~؎;*T �e*VP"20M'b0D�tQ ৃ@i{0Ǘ6ĉfϞ]4x>yyyEbccs,K21---jkk9sbG?裊76wRC*ʵry([Mw"KB@F� ~^πѢ@\iӦe :4G9)))]A x |ss/^<w{=W9rս4B+A}YKKBׅn|(ZoA,ItZݻmڴiYzJJNKKKJJJJOMIlI%b$L8ZPSSPUUU?رcmk5rjkJ@HE<{QV+DCnD OA `|jKZ.ONN6ӚbJMM$&&XsLL)&&bZV �v{kkkGkklonn766:jkk;匎\mUO1U|biiRN(t�D+S2F`UJZ6y`PBV#䌚ۦ8Ji5eriRNt;� V`�Rk?ױʴʤڮe2JzyBRi%Wf-U&T^<pGb%D�ts y5PjmkZ OThن*�ĶaC1Z|5|b !A�@ 2=jB9R\ZL\-Zu<bez'R0&T#y@�A@~:TQP }$kZ܋!<Jkj}2RyOA�Aa^K,V&U&~j_Zjrۂq*5+W*ܑ "@ ! VZ6iTF �a^K:\PjMw$/x D�T!! !Pކ>T㯥L>j^jU"@a>Je´T\yNP�M$iqy5F BMʴlB`'UmoTm;:AD�"B@ eʴ>Pbӑ* &&/UfEN"�!Q�ښʍRik&W*7 n`kơ4`w&/pB@6 BI至AkmH1&mafKm D�tEg! (1 MO#W󼍊GOA`8s2-w&/l@00xʵXx(KɕKQ@)x&/U&W-pg&� W@<TcxrejiL0/PJsn2rw&/g@AX1 VG!ʕ+m f?!j_v1FCujb �BD1 UֻL6-C(1R,Sv{ȋ� D �ڦ'Aȕk*׻LJly"�!Ā^zP^n3N>B�!*1P (6-#mC-! !,;@Z3 =CqvoNa �MY\�\H0#l�0e "/T[{ge8^/4Pk3Cٲ3B(�,a/WVrwT܍7 �P"g O 3:j�T]qH .ald@0$4T f"Q�ZA! ٟda%ٙ�?_G_qV!Qzo �|РG5:&CG�a)x:WA":� P !� (y��v+S�`"t r����IENDB`��������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/images/haskell-mode-64x64.png�����������������������������������������������������0000664�0000000�0000000�00000021547�13602233217�0021130�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR���@���@���iq�� AiCCPICC Profile��H wTSϽ7" %z ;HQIP&vDF)VdTG"cE b PQDE݌k 5ޚYg}׺�PtX4X\XffGD=HƳ.d,P&s"7C$� E6<~&S2)212 "įl+ɘ&Y4Pޚ%ᣌ\%g|eTI�(L�0_&l2E�9r9h�xgIbטifSb1+MxL 0oE%YmhYh~S=zU&ϞAYl/�$ZU�m@O ��ޜl^ ' lsk.+7oʿ9V;?#I3eE妧KD d9i,UQ h<X.d 6'~khu_�}9PIo=�C#$n?z}[1 Ⱦhs2z \nLA"S dr%,߄lt 4.0,` 3p �H.Hi@A>� A1vjp�ԁzN6p\W p G@ K0ށiABZyCAP8C@&*CP=#t] 4}a �ٰ;GDxJ>�,_“@FXDBX$!k"EHqaYbVabJ0՘cVL6f3bձX'?v 6-V``[a;p~\2n5׌ &x*sb|! ߏƿ' Zk! $l$T4QOt"y\b)AI&NI$R$)TIj"]&=&!:dGrY@^O$ _%?P(&OJEBN9J@y@yCR nXZOD}J}/G3ɭk{%Oחw_.'_!JQ@SVF=IEbbbb5Q%O@%!BӥyҸM:e0G7ӓ e%e[(R0`3R46i^)*n*|"fLUo՝mO0j&jajj.ϧwϝ_4갺zj=U45nɚ4ǴhZ ZZ^0Tf%9->ݫ=cXgN].[7A\SwBOK/X/_Q>QG[ `Aaac#*Z;8cq>[&IIMST`ϴ kh&45ǢYYF֠9<|y+ =X_,,S-,Y)YXmĚk]c}džjcΦ浭-v};]N"&1=xtv(}'{'IߝY) Σ -rqr.d._xpUەZM׍vm=+KGǔ ^WWbj>:>>>v}/avO8 FV> 2 u/_$\BCv< 5 ]s.,4&yUx~xw-bEDCĻHGKwFGEGME{EEKX,YFZ ={$vrK .3\rϮ_Yq*©L_wד+]eD]cIIIOAu_䩔)3ѩiB%a+]3='/40CiU@ёL(sYfLH$%Y jgGeQn~5f5wugv5k֮\۹Nw]m mHFˍenQQ`hBBQ-[lllfjۗ"^bO%ܒY}WwvwXbY^Ю]WVa[q`id2JjGէ{׿m>PkAma꺿g_DHGGu;776ƱqoC{P38!9 <y}'ZZ։6i{L{ӝ-?|gKϑ9w~Bƅ:Wt>ҝˁ^r۽Ug9];}}_~imp㭎}]/}.{^=}^?z8hc' O*?f`ϳgC/Oϩ+FFGGόzˌㅿ)ѫ~wgbk?Jި9mdwi獵ޫ?cǑOO?w| x&mf2:Y~��� pHYs��T��TyJ��diTXtXML:com.adobe.xmp�����<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/"> <xmp:CreatorTool>www.inkscape.org</xmp:CreatorTool> </rdf:Description> </rdf:RDF> </x:xmpmeta> Ǧm��\IDATx[ip\UzZ[X c0'lC6 UK�PRL*"aBWRbbw#ٖ-˶}kVιOjIVH%u^wo&)aфM|555~W7uE'd7kMv}+W7q934@3&=+縝T4Hjx.zӗ3Е`5`+󷫦&m…ũNӆ6|Ẻi5 Bh,B\.8^*Ul? 6,/++[Yp8,l6M&h4;{c;w<sϝ }9"{M \4pvV>#_0?�~±sqN=\{XpOV' Y>;wKKK7XVbed$(#200"^_#<T,Un$=%.P(4Դs۶nz *'dnTqЅj<SϞ='`m'T纤Oz{D"lN,dJYydf+| o믿~($ID`?Vf{M}w@B#SB6K[k!KJI]g9Q5n¢ YDJgel[nM7C%Wh婕$/5xsyoUUUw KkK<pVZ|�Rpco(+8SMEB>}nN8щF!ނ\Й<S!:+~lADH9OƉ4I@=̙ HA~Xf^|m-83:_ f0 }7!''g9(\vap GCJNnڡ<%7n\uX;i"\�D=ݵe˖/ \c|�CC>X̗sB lCRPA֭{IrO_s´tֺ!vz1??OɧPZ'?SmaUNNf.V4UXw;P5wtt_~ hR1:L#� <P͛w'1dT\.%rC'Z۫ijxMKȩSϟ?/pKND0I'L%7|k> ΎAywQi:Im' Oa;d;&A<IsJAaT-?^c+WDFotKiiT/_E]Ŕ9v*>}w1/w�<9x T\%9Iufnoo dwrPj`2OAEGfٳGfSmB"p$j6/U[[ۏ$&.H}ʺNΝ;Wury.GF!v,_Q?>9wwn7.1Ip8-n7.QޟsF'tWʕe~b)RubK,DǕ-O<J w&uRtrXޅ^dx>vY%MI IC5*(;03<S`2LTߚq=>XAz%ߪatv^r\+uz3\7rʱ;1`gTÝ9ȿl<mpG='/NKIiE ӨMJ9R^m6buOZd/%#.q*S?xĬQ $+j/z(f{U by饗c1VFDBty{&$.Tv9b@<t3S:slyjVy7�Hă"CpJ6\F'6 cWaLn<[hJsSL9 L�З&xD wjqǫɓLc,q9CT).ʕe9̌p8aOC͖< {`:A,Y]3fy̛6p( Nm+9{g!b-UhC>/n`G\Spّg&UH8WZN6ɗ~H0ij<4hNF"fKP[F16~Ev h&}Sm, 2X)hBf ڽ{w++dU;L,V%%1ow3)$:.~ȶqhPq{r]5fM`ȚzP@g[zMR,=rh(7$GK0~b3]{g!b­hܑb n+ÿ.0 [߷HMOn]0a( Z;1zf8FmrQ- u.+n)F; yb o J0ȘA]^Dz~CinI '#Y� :&·x M!�D)6;j,($>j ӎyR=9M-9xM{{ULLĆ 3Guq >>t:S׸W *rA2zotY ALpm>#9 ֍"W k:*ҩ2@`S÷Ȱ@>8 4E|< ]Gܙ unsTYl!&bC5-ZJ9i_߈:eI%jTg�7d l {>LxW)b|~FR@d *.<EioJ,W(wNKc!sEtŒb ,Go=` 67� 8S<Jin%3˥_񯾦 TyG.@$7. ERZR&nwuuNRH>D$7XfGLĦ~@Mvd;qD8-uHy^$ X>i B~ v 8�6iNIp6")Z\d!Zg|H1Od(Ĥ_O"|0[LHK?t[wqӯg~ 1�ʳ nwD$#s$&l?ՏR/LW3Su|GhB`Cm8sl%,2?]?',qB56m3fxA(QXׇirMP^'XtP>Mi 2Wi)b"65IM�Moi8- ;xQ/0nqGÇLw|4,`ewPA#^3xCν0p(TTJ>kGzD܍z`@g+1X^@jDe "$)N՗Abbl6MB0'g|C9°>=x'z`69 0y}xD4GLvLj9)FPsGk6^Q;v[&E92WԸG �1Em6\>kwU+ٞ0N#�d}&]irݺr;4enEBvc*c2!k~P(p@Rlث-5G�HѱVU&�("R# e~{ ?ny*c'w'o`cV81af'''BQGR2 W'%\J{C#JA|ӰCrvN 1L2f as� <~cklll<·NI:52n7~}b�]w?`,]Z , 9#�p.=,>c=/㓫pRrŇ`}N`48*}A9U7DXrĒPN ,c1Fp0" 7ܰ'c#k11YF̦ㄴϚ0+``K`"V#L-rgK~E`YCR֞> Y8}(W0"VwW�ӮJ9cDdS"1[W%琠/f`IShZɃgϾ嶸3:Em�^�0E᪪b8S[t76܁$J;pJRd/@.Pf3yuz유fޞ$=HZ3<f@>ncD 'Ă!ޓ"l c?ユŜ*OnR;8v)ȄC,e凇ޜI\98M`s>9zYv~xB.41~٬LaS�XFFpiK iyt… < 1ᖶch$+Zho+G4dYAA~.銂;O[# @md asej<dd8fW5/ڍf|!D%g|x5L,%p i *e$Iډ-*|iSrN\6'燖¡|9BMd|o[ (>3-#etJ2(}3-c/̂v n.\) vI)jKO?}#[~ f#Q}<)PTtQs!aS<Q LeppYF(Vd_r!W01`"!�hoh@'ͿޫCVאrasX#i bE*JЕe х1H~:\|BcHQS$jL55Q1:;;C$#pϩʅB+Pē [XmvTFbN%p >ZC3삈88CM*9"[xZ%zz衭pi!?U�)`ڋFȳ2GA02YB?[ܽv<N0b~~WoPsر'|3,IgViv4ń$ow)}@> E#?_7Lmr?Cd5᛼k9?Hb/7-\Pw]\^[Od6o޼ -M*3@l�& 544ܴijdXsʳf"{ 6 C.M! v~z<<?](O7%x+6u L]wu*$C/)NJUp8|[MRw;99؟nT/MO{78xG*OR|hd8@D&~8a/0␝*k߆3d^УN~#Xc߃>m4x$OuNWo:S~*5LD9 3g$Aּ<qE gw)Ej>Oe%�$NXZo}QBJbpv{ fU9돥UbCW"awo|[_UXMegBm!g)YSo|f5'$s|2*_X UTIs(ZTl0Chv|[ab|KDēJbAxoFJDl ЕbuVŊ&&&ѤB+:290٢7ldijvVmdTM$5;5e ՛&5]xRTF�����IENDB`���������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/images/haskell-mode.svg�����������������������������������������������������������0000664�0000000�0000000�00000056171�13602233217�0020353�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- Gnu Emacs Icon Copyright (C) 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs 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. GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. --> <!-- Created with Inkscape (http://www.inkscape.org/) --> <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.0" width="48" height="48" viewBox="0.171 0.201 512 512" id="svg4768" xml:space="preserve" inkscape:version="0.48.4 r9939" sodipodi:docname="haskel-mode2.svg"><metadata id="metadata3183"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1042" inkscape:window-height="626" id="namedview3181" showgrid="false" inkscape:zoom="4.7339512" inkscape:cx="6.8604697" inkscape:cy="15.749086" inkscape:window-x="288" inkscape:window-y="153" inkscape:window-maximized="0" inkscape:current-layer="svg4768" /><defs id="defs4770"><linearGradient inkscape:collect="always" id="linearGradient3906"><stop style="stop-color:#524e9b;stop-opacity:1" offset="0" id="stop3908" /><stop style="stop-color:#9a98bd;stop-opacity:1" offset="1" id="stop3910" /></linearGradient><linearGradient inkscape:collect="always" id="linearGradient4429"><stop style="stop-color:#bab8db;stop-opacity:1;" offset="0" id="stop4431" /><stop style="stop-color:#bab8db;stop-opacity:0;" offset="1" id="stop4433" /></linearGradient><inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 24 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="48 : 24 : 1" inkscape:persp3d-origin="24 : 16 : 1" id="perspective4109" /><linearGradient id="linearGradient3294"><stop id="stop3296" style="stop-color:#6376e6;stop-opacity:1" offset="0" /><stop id="stop3302" style="stop-color:#222989;stop-opacity:1" offset="0.50094414" /><stop id="stop3298" style="stop-color:#00003d;stop-opacity:1" offset="1" /></linearGradient><linearGradient id="linearGradient3284"><stop id="stop3286" style="stop-color:#000000;stop-opacity:1" offset="0" /><stop id="stop3292" style="stop-color:#000000;stop-opacity:0.49803922" offset="0.84845906" /><stop id="stop3288" style="stop-color:#000000;stop-opacity:0" offset="1" /></linearGradient><linearGradient id="linearGradient3274"><stop id="stop3276" style="stop-color:#000000;stop-opacity:1" offset="0" /><stop id="stop3278" style="stop-color:#000000;stop-opacity:0" offset="1" /></linearGradient><linearGradient id="linearGradient3262"><stop id="stop3264" style="stop-color:#000000;stop-opacity:1" offset="0" /><stop id="stop3266" style="stop-color:#000000;stop-opacity:0" offset="1" /></linearGradient><linearGradient id="linearGradient3242"><stop id="stop3244" style="stop-color:#282828;stop-opacity:1" offset="0" /><stop id="stop3252" style="stop-color:#808080;stop-opacity:1" offset="0.39253417" /><stop id="stop3246" style="stop-color:#d9d9d9;stop-opacity:1" offset="1" /></linearGradient><linearGradient id="linearGradient3202"><stop id="stop3204" style="stop-color:#2b2b2b;stop-opacity:1" offset="0" /><stop id="stop3250" style="stop-color:#828383;stop-opacity:1" offset="0.5" /><stop id="stop3206" style="stop-color:#dadbdb;stop-opacity:1" offset="1" /></linearGradient><linearGradient id="linearGradient4966"><stop id="stop4968" style="stop-color:#b6b3d8;stop-opacity:1" offset="0" /><stop id="stop4970" style="stop-color:#b6b3d8;stop-opacity:0" offset="1" /></linearGradient><linearGradient id="linearGradient4938"><stop id="stop4940" style="stop-color:#000000;stop-opacity:1" offset="0" /><stop id="stop4942" style="stop-color:#000000;stop-opacity:0" offset="1" /></linearGradient><linearGradient id="linearGradient4898"><stop id="stop4900" style="stop-color:#bab8db;stop-opacity:1" offset="0" /><stop id="stop4902" style="stop-color:#5955a9;stop-opacity:0.99159664" offset="1" /></linearGradient><linearGradient id="linearGradient4876"><stop id="stop4878" style="stop-color:#d3d2e8;stop-opacity:1" offset="0" /><stop id="stop4880" style="stop-color:#5955a9;stop-opacity:0.99159664" offset="1" /></linearGradient><radialGradient cx="20.951529" cy="-108.96888" r="266.76535" fx="20.951529" fy="-108.96888" id="radialGradient4892" xlink:href="#linearGradient4898" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.2360499,0,0,1.0147165,-3355.6485,-2448.9898)" /><radialGradient cx="233.8876" cy="471.26172" r="170.49393" fx="233.8876" fy="471.26172" id="radialGradient4944" xlink:href="#linearGradient4938" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.3677169,0,0,0.26302246,-64.518757,297.35882)" /><radialGradient cx="299.70135" cy="371.76376" r="76.696358" fx="299.70135" fy="371.76376" id="radialGradient4972" xlink:href="#linearGradient4966" gradientUnits="userSpaceOnUse" gradientTransform="matrix(2.9787108,0,0,1.8616941,-4206.9798,-2987.9057)" /><radialGradient cx="289.44067" cy="390.45248" r="17.67668" fx="289.44067" fy="390.45248" id="radialGradient3210" xlink:href="#linearGradient3202" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0612461,0.84462994,-1.2946187,1.6266412,527.27366,-778.11758)" /><radialGradient cx="283.50717" cy="382.14804" r="17.67668" fx="283.50717" fy="382.14804" id="radialGradient3238" xlink:href="#linearGradient3202" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0612461,0.84462994,-1.2946187,1.6266412,786.90593,-1072.094)" /><radialGradient cx="418.45551" cy="181.18982" r="63.068935" fx="418.45551" fy="181.18982" id="radialGradient3248" xlink:href="#linearGradient3242" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.16778338,-0.15283029,4.3173605,-4.739776,79.325705,478.46043)" /><radialGradient cx="354.51709" cy="357.33591" r="33.712105" fx="354.51709" fy="357.33591" id="radialGradient3268" xlink:href="#linearGradient3262" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.4055116,-3.3440123e-2,0.1034174,4.3988695,177.23251,-1191.6649)" /><radialGradient cx="510.58469" cy="223.55537" r="132.28336" fx="510.58469" fy="223.55537" id="radialGradient3280" xlink:href="#linearGradient3274" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.1339874,-0.1146812,0.3079048,-0.3597394,444.23592,395.03849)" /><radialGradient cx="284.4671" cy="-158.17821" r="110.2972" fx="284.4671" fy="-158.17821" id="radialGradient3290" xlink:href="#linearGradient3284" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-3.1981763,3.5310397,-0.24640846,-0.18674452,1365.1782,-1085.382)" /><radialGradient cx="425.51019" cy="356.62274" r="143.34167" fx="425.51019" fy="356.62274" id="radialGradient3300" xlink:href="#linearGradient3294" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.25799332,-0.20695541,2.7497662,-3.4278966,-325.16737,1103.5776)" /><clipPath id="clip1"><path inkscape:connector-curvature="0" d="m 0,340.15625 481.89062,0 L 481.89062,0 0,0 0,340.15625 z m 0,0" id="path3190" /></clipPath><radialGradient inkscape:collect="always" xlink:href="#linearGradient3284" id="radialGradient4407" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-3.1981763,3.5310397,-0.24640846,-0.18674452,1365.1782,-1085.382)" cx="284.4671" cy="-158.17821" fx="284.4671" fy="-158.17821" r="110.2972" /><radialGradient inkscape:collect="always" xlink:href="#linearGradient3294" id="radialGradient4409" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.25799332,-0.20695541,2.7497662,-3.4278966,-325.16737,1103.5776)" cx="425.51019" cy="356.62274" fx="425.51019" fy="356.62274" r="143.34167" /><radialGradient inkscape:collect="always" xlink:href="#linearGradient3202" id="radialGradient4411" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0612461,0.84462994,-1.2946187,1.6266412,527.27366,-778.11758)" cx="289.44067" cy="390.45248" fx="289.44067" fy="390.45248" r="17.67668" /><radialGradient inkscape:collect="always" xlink:href="#linearGradient3202" id="radialGradient4413" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.0612461,0.84462994,-1.2946187,1.6266412,786.90593,-1072.094)" cx="283.50717" cy="382.14804" fx="283.50717" fy="382.14804" r="17.67668" /><radialGradient inkscape:collect="always" xlink:href="#linearGradient3242" id="radialGradient4415" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-0.16778338,-0.15283029,4.3173605,-4.739776,79.325705,478.46043)" cx="418.45551" cy="181.18982" fx="418.45551" fy="181.18982" r="63.068935" /><radialGradient inkscape:collect="always" xlink:href="#linearGradient4429" id="radialGradient4435" cx="-127.65727" cy="-5.9579082" fx="-127.65727" fy="-5.9579082" r="33.252045" gradientTransform="matrix(0.98850563,-0.42528733,0.29299938,0.6810247,0.27832845,-56.124782)" gradientUnits="userSpaceOnUse" /><radialGradient cx="299.70135" cy="371.76376" r="76.696358" fx="299.70135" fy="371.76376" id="radialGradient4972-5" xlink:href="#linearGradient4966-8" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.9121621,0,32.654948)" /><linearGradient id="linearGradient4966-8"><stop id="stop4968-0" style="stop-color:#b6b3d8;stop-opacity:1" offset="0" /><stop id="stop4970-1" style="stop-color:#b6b3d8;stop-opacity:0" offset="1" /></linearGradient><linearGradient inkscape:collect="always" xlink:href="#linearGradient3906" id="linearGradient3912" x1="9.4451628" y1="27.865551" x2="9.4451628" y2="-6.8625436" gradientUnits="userSpaceOnUse" /><filter inkscape:collect="always" id="filter3972"><feGaussianBlur inkscape:collect="always" stdDeviation="1.6585727" id="feGaussianBlur3974" /></filter><filter inkscape:collect="always" id="filter4026"><feGaussianBlur inkscape:collect="always" stdDeviation="1.8434645" id="feGaussianBlur4028" /></filter><filter inkscape:collect="always" id="filter4058"><feGaussianBlur inkscape:collect="always" stdDeviation="1.0850001" id="feGaussianBlur4060" /></filter><filter inkscape:collect="always" id="filter4066"><feGaussianBlur inkscape:collect="always" stdDeviation="0.42833379" id="feGaussianBlur4068" /></filter><filter inkscape:collect="always" id="filter4082"><feGaussianBlur inkscape:collect="always" stdDeviation="0.54" id="feGaussianBlur4084" /></filter><filter inkscape:collect="always" id="filter4090"><feGaussianBlur inkscape:collect="always" stdDeviation="1.3150001" id="feGaussianBlur4092" /></filter></defs><path transform="matrix(8.4187318,0,0,8.4187318,177.17151,169.2659)" d="m 33.621367,9.4877434 a 24.567608,24.567608 0 1 1 -49.135216,0 24.567608,24.567608 0 1 1 49.135216,0 z" sodipodi:ry="24.567608" sodipodi:rx="24.567608" sodipodi:cy="9.4877434" sodipodi:cx="9.0537586" id="path3926" style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.12637710999999996;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0.50214592000000002;filter:url(#filter3972)" sodipodi:type="arc" /><path sodipodi:type="arc" style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.12637711;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="path3924" sodipodi:cx="9.0537586" sodipodi:cy="9.4877434" sodipodi:rx="24.567608" sodipodi:ry="24.567608" d="m 33.621367,9.4877434 a 24.567608,24.567608 0 1 1 -49.135216,0 24.567608,24.567608 0 1 1 49.135216,0 z" transform="matrix(8.4187318,0,0,8.4187318,177.17151,169.2659)" /><path transform="matrix(8.4187318,0,0,8.4187318,177.17151,169.2659)" d="m 31.350328,9.4877434 a 22.29657,22.29657 0 1 1 -44.593139,0 22.29657,22.29657 0 1 1 44.593139,0 z" sodipodi:ry="22.29657" sodipodi:rx="22.29657" sodipodi:cy="9.4877434" sodipodi:cx="9.0537586" id="path4244" style="color:#000000;fill:url(#linearGradient3912);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.12637709000000008;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" sodipodi:type="arc" /><path d="m 124.94329,341.81299 c 0,0 13.57421,3.94145 31.64305,6.19466 7.31747,0.9125 35.15898,4.10189 56.50553,4.01818 0,0 25.9982,0.0295 40.34907,-2.00908 15.01592,-2.13306 23.52308,-4.8553 28.25756,-10.28783 0.12331,-1.2953 2.28522,-5.51755 -3.55157,-9.58929 -14.92239,-10.40987 -34.2137,-13.2593 -71.68472,-22.15813 -41.43572,-10.4177 -53.81872,-20.39348 -60.00498,-27.61302 -5.865,-7.23552 1.1009,-22.26237 34.48928,-29.63399 16.90485,-4.11378 79.86605,-4.86966 79.86605,-4.86966 -18.06319,-14.3411 -51.97483,-40.01654 -58.90654,-45.47674 -6.07939,-4.78885 -15.87613,-12.13784 -16.92925,-18.70506 -1.42062,-6.39287 8.64222,-9.47093 13.96961,-9.82608 17.16604,-1.18386 40.60655,0.8287 61.44257,4.97224 10.47335,2.08276 12.31219,1.77579 12.31219,1.77579 14.91669,0.71032 26.51859,-7.10318 25.92665,-23.55892 -0.11843,-16.69248 -16.80792,-30.07742 -35.2792,-30.66208 -17.39446,-0.55059 -60.2587,2.48611 -60.2587,2.48611 49.95911,10.29962 58.12629,12.92803 60.73228,18.94184 1.53902,3.55159 -2.57086,7.0828 -16.33735,6.39286 -14.98739,-0.75111 -45.69716,-4.38029 -45.69716,-4.38029 -29.24144,-4.49868 -49.60391,-8.7606 -58.48288,2.84128 -5.80082,7.57965 0.82869,16.81087 3.43315,22.25664 11.6019,20.2441 31.66392,34.13308 44.39496,43.92139 4.79018,3.68294 19.41539,11.83863 19.41539,11.83863 -45.4604,-12.43057 -81.68661,-5.44577 -104.65362,6.62964 -26.400199,15.62701 -21.884189,41.99775 20.00729,66.65157 24.74274,14.56153 37.06226,21.5568 77.5739,26.53044 23.67961,3.77575 27.20804,5.32066 27.02808,7.29164 -0.25339,2.77495 -28.02718,3.82653 -35.66126,4.35303 -19.42112,1.33938 -69.64822,1.67423 -69.89938,1.67423 z" id="path3984" style="opacity:0.38197425000000002;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;filter:url(#filter4026)" inkscape:connector-curvature="0" /><path inkscape:connector-curvature="0" id="path3976" d="m 232.0892,176.32677 46,68.66667 -40,60 c 9.74227,2.17726 19.37247,4.40185 28.66667,8 l 45.66667,-68 -42.66667,-64 c -3.92787,-0.43126 -7.83808,-0.79659 -11.66667,-1.33334 -7.69319,-1.23294 -15.53375,-2.44216 -23.33333,-3.33333 l -2.66667,0 z" style="opacity:0.39055798000000003;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter4058)" /><path inkscape:connector-curvature="0" id="path3978" d="m 373.02422,250.85926 15.33334,23 45.66666,0 c 0.94283,-7.4444 1.66667,-14.96631 1.66667,-22.66666 0,-0.11211 2e-4,-0.22134 0,-0.33334 l -62.66667,0 z" style="opacity:0.39055798000000003;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter4066)" /><path inkscape:connector-curvature="0" id="path3980" d="m 295.55586,177.10338 c -1.8186,1.35199 -3.54574,2.47938 -5.66666,3.33333 -2.62681,0.92768 -5.28453,1.41716 -8,1.66667 l 42.33333,63.66667 -45.66667,68.66667 34.33334,0 28.66666,-43 28.33334,43 34.33333,0 -91.33333,-137.33334 -17.33334,0 z" style="opacity:0.39055798000000003;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter4090)" /><path inkscape:connector-curvature="0" id="path3982" d="m 350.42254,216.92425 15.33333,23 69.66667,0 c -0.50538,-7.82978 -1.18716,-15.47623 -2.66666,-23 l -82.33334,0 z" style="opacity:0.39055798000000003;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;filter:url(#filter4082)" /><g id="g3900" style="fill:#000000" transform="translate(2.5832045,1.1607838)" /><path style="fill:#999999;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1" d="M 21.40625 16.34375 L 25.71875 22.78125 L 21.96875 28.40625 C 22.882088 28.610368 23.784919 28.818923 24.65625 29.15625 L 28.9375 22.78125 L 24.9375 16.78125 C 24.569262 16.740821 24.20268 16.70657 23.84375 16.65625 C 23.122513 16.540661 22.387461 16.427297 21.65625 16.34375 L 21.40625 16.34375 z " id="path3195" transform="matrix(10.666667,0,0,10.666667,0.171,0.201)" /><path inkscape:connector-curvature="0" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;opacity:1" id="path4111" d="m 122.81502,338.46147 c 0,0 13.57421,3.94145 31.64305,6.19466 7.31747,0.9125 35.15898,4.10189 56.50553,4.01818 0,0 25.9982,0.0295 40.34907,-2.00908 15.01592,-2.13306 23.52308,-4.8553 28.25756,-10.28783 0.12331,-1.2953 2.28522,-5.51755 -3.55157,-9.58929 -14.92239,-10.40987 -34.2137,-13.2593 -71.68472,-22.15813 -41.43572,-10.4177 -53.81872,-20.39348 -60.00498,-27.61302 -5.865,-7.23552 1.1009,-22.26237 34.48928,-29.63399 16.90485,-4.11378 79.86605,-4.86966 79.86605,-4.86966 -18.06319,-14.3411 -51.97483,-40.01654 -58.90654,-45.47674 -6.07939,-4.78885 -15.87613,-12.13784 -16.92925,-18.70506 -1.42062,-6.39287 8.64222,-9.47093 13.96961,-9.82608 17.16604,-1.18386 40.60655,0.8287 61.44257,4.97224 10.47335,2.08276 12.31219,1.77579 12.31219,1.77579 14.91669,0.71032 26.51859,-7.10318 25.92665,-23.55892 -0.11843,-16.69248 -16.80792,-30.07742 -35.2792,-30.66208 -17.39446,-0.55059 -60.2587,2.48611 -60.2587,2.48611 49.95911,10.29962 58.12629,12.92803 60.73228,18.94184 1.53902,3.55159 -2.57086,7.0828 -16.33735,6.39286 -14.98739,-0.75111 -45.69716,-4.38029 -45.69716,-4.38029 -29.24144,-4.49868 -49.60391,-8.7606 -58.48288,2.84128 -5.80082,7.57965 0.82869,16.81087 3.43315,22.25664 11.6019,20.2441 31.66392,34.13308 44.39496,43.92139 4.79018,3.68294 19.41539,11.83863 19.41539,11.83863 -45.4604,-12.43057 -81.68661,-5.44577 -104.65362,6.62964 -26.4002,15.62701 -21.88419,41.99775 20.00729,66.65157 24.74274,14.56153 37.06226,21.5568 77.5739,26.53044 23.67961,3.77575 27.20804,5.32066 27.02808,7.29164 -0.25339,2.77495 -28.02718,3.82653 -35.66126,4.35303 -19.42112,1.33938 -69.64822,1.67423 -69.89938,1.67423 z" /><path style="fill:#b27fbf;fill-opacity:1;fill-rule:nonzero;stroke:none;opacity:1" d="M 34.65625 23.3125 L 36.09375 25.46875 L 40.375 25.46875 C 40.463386 24.770837 40.53125 24.065658 40.53125 23.34375 C 40.53125 23.333242 40.531269 23.323004 40.53125 23.3125 L 34.65625 23.3125 z " id="path3199" transform="matrix(10.666667,0,0,10.666667,0.171,0.201)" /><path style="fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M 27.3125 16.34375 C 27.142006 16.470499 26.980087 16.576192 26.78125 16.65625 C 26.534987 16.743218 26.285826 16.789108 26.03125 16.8125 L 30 22.78125 L 25.71875 29.21875 L 28.9375 29.21875 L 31.625 25.1875 L 34.28125 29.21875 L 37.5 29.21875 L 28.9375 16.34375 L 27.3125 16.34375 z " transform="matrix(10.666667,0,0,10.666667,0.171,0.201)" id="path3197" /><path style="fill:#b27fbf;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M 32.5 20.09375 L 33.9375 22.25 L 40.46875 22.25 C 40.42137 21.515958 40.357454 20.799104 40.21875 20.09375 L 32.5 20.09375 z " transform="matrix(10.666667,0,0,10.666667,0.171,0.201)" id="path3201" /><rect width="512" height="512" x="0.171" y="0.20100001" id="rect4772" style="fill:none;display:none" /><g id="g4788" style="display:none"><g id="g4790" style="display:inline" /></g><g id="g4806" style="display:none"><g id="g4808" style="display:inline"><path d="M 349.098,256.651 C 348.833,256.397 386.735,284.256 388.519,281.663 C 394.881,272.411 470.565,188.526 473.303,165.427 C 473.545,163.424 472.787,161.331 472.787,161.331 C 472.787,161.331 471.597,161.187 466.462,157.017 C 463.77,154.825 460.979,152.436 460.979,152.436 C 444.925,153.434 403.094,193.995 349.917,256.004" id="path4810" style="fill:#050505;display:none" /></g></g><g id="g4796" style="stroke:none"><g id="g4800" style="stroke:none" /></g><g id="g4774" /></svg>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/images/star-history-700.png�������������������������������������������������������0000664�0000000�0000000�00000273673�13602233217�0020757�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR����r����� iCCPICC Profile��HT+)Л JR%@P# ]DPTtUD�V,XXu`CM@˝{g�hP%�¨@fBb$$�&yP- uKIEcDBN䱳!�d �:`N@o! @�d XK)2DBLei�(H3 i0�5Cك@CY 4<i3e<'6βH ُ'b?,XRӅAQ1yۗ"a9O #tQP�;`�/2K!ʌe[P p^~p(sF<1N\ T^@0dУ12^\8dȝy! }|(fCoSQ2L=;ol\%ՠ+?=&H%pBǴq~2 ˏՌ5["ȊǪYQyDv&qkjL?N#ӆ ?"XS@�O�X@�XZ"-|OH\7#mh2n=-A@ B5q O/Xmqge,8+џG "u,Xw۷HSB1&AL B`+Y?>8Del^L0.`tt)07pq ,q{8oZW(Wm.O1FU1wsā!?zb+#Xv�;5cI 'ҕ0[T[&󱮳Y s%7G0OKKgz/2g[MbZ8 >o6¸͖{�RhLfc�p)�wlZ NHX P"@�S8&[܀SA`t U RPZ T`à �gEpt>\}0 $ D1B,[@P$ ID42 YT";ZW8rt!wy|B1ڨ1:uF4h!ZF+�ڈE7Q1�&10=s|, Kń"+jz>D3qK>XUx%o|JWB0!FC(!.GxG$Dܛ |*6b K"H$ ;)"JH[HHIݤ><YlK '"r9y?<,$g$*!Ǒ'Fn\5>a2ńNdPR*( 7.yK+_HUS}3"j^]fL%iisG t+`b*FnrFފ (^SPS2VUb)-RR:t[iHlJye*$cJ.s*tn@}DU` 2Ճj*jjqjsժNØbafb|={w 'WU/UoPIᯑNI&i9Msf́&'N<<e5_kV֐v@{9NFS:t]]FӺ0՘,f<sPOK/HOSCoXD?VHA `Aa:{FrFFFڌ/7n2~nnlRhRgfikZczÌhliͬ5w0O72fZ8Z,YtM"LrğT3%۲βNJajUddr&Mj`eT"׶l*v4�vv-waZ8:9  :vVut^|ɅGWG|îYew{>d w),bG'˳󱗁k3o3 /}}>|.=uW? H  tx&.vv0;6xpԅSχPCC*C C[аaÛ"@DpĆ&M#NV5iMԂhzb|b܏5Ŷ)͈{>^09aaDD^bs)).iOt雦pQ2Lsg^9+kيY$'fEjXC))[Sپ/FN?ם,=u}4 i<_^%UFP{3G*L9] A@뚻)wP"ܓkWGv'QOGAU9qsU˟>|y  go]`邞 w.B,j]lxqߒ%Rf.Ⱥh}eZS]BrW+x+:Vڭܲk)JuYyUUW~թ;8^K\_{k}q#scƷfo\n_}3eh"yᖵ[>WWެjتu8ۺko/ioǝ;kkwwz;nw/οS^^}kjkk_S։8y`seFC!pHt_u8p#Gn=F?Vڈ4klJo7'6wzŭoV=w5(O.<=tFpfl٭%q~ !.] xͻ%K'.^>~JUǫ~wXcG5k͝.-]SNu{vwWo{w8wͺ^K>TzXHQͿ vi~/œ'Ҟ?}V?BbxO?4}y/^ _^F޷o["~7Ƈ}?}lxg/f_Z|}0=2"` Yң�+ �( ;?&- %�3J5FWrx-yv\Tx!|y �/‘m##_vCw8+I wXIC7pUmh��� pHYs��%��%IR$��iTXtXML:com.adobe.xmp�����<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:tiff="http://ns.adobe.com/tiff/1.0/"> <exif:PixelYDimension>1138</exif:PixelYDimension> <exif:PixelXDimension>1480</exif:PixelXDimension> <tiff:Orientation>1</tiff:Orientation> </rdf:Description> </rdf:RDF> </x:xmpmeta> rH��@�IDATx{\e7 &jPyH+q2 FIF8#Ca9mL琸m3iN{tiњ&:蘖Pj**uZ@Z ^wX}yݭ?>\^wHq@�@�@�@�@�N&Х"� � � � � ` @΃� � � � � )wig � � � � �y@�@�@�@�@�:�N9 @�@�@�@�@�9� � � � � @ @)A#� � � � � @�@�@�@�@�;3h@�@�@�@�@�P@�@�@�@�^^>)G%'TzZg#"LI=kxbRoB_@�@Hq`� � � � 6 ZA=o#/SqK XkjeF b%'#� � � @` ~Y<~' Fs|,s`Ѧ%:u?po@}IϬڶ1Mn&s|=6u2]V)Ba {,5EZb6=᷽˷Ŏ#YK]mjҗ @޶Ԏ� � � �T`U^x2Vmi&˟(ޢ-\Ml}I(g1M|9 :llej))U{B[:ۦ м+mo(mۼ^v꣮c|>u'!� � � �ziBY/6YGSH{-<񇅻/L;"Cg]lC5op#m*dU@�@�@�Y/}/}oq#xygnB k6-Oױ{TB X#e � � � @;l9Ew0:7qT1v#aJHWD ,e*Vmm"ݫ"oZc:^ml_bJ z߱ZۙzKբk;h>yWف:Mun{-,-1Ķ<wy۶XTvLF EEFGw|qڑeWsNmcI1Io%xQiaU]Գj<eF~[͋mrˍ1/ٜmy� �V$@�@�@�8Yꃩ2{/m?t'ΡJ<XI F0pXkv_1!FW(?I#5tY^?/ 1Ƚb2t,o;5=$Ƈc|h'44,ZI㰍%!6R,SQߡi O*5ղCN}Bt&;hG5+)"C ; :.jӡӗcClϣJJUȘ9is4^9}h9NR.JmZ6x?8윗13ǼaLYu>۶t\ϟ&W~q@�@�@�H?|&CAIYr홵@&%kQ~E<qO<ɂyk=ۖ<3xfs r4ex/*<ObcRrb g=Z;=R7OcR=U n7e٭ \%5>7mf,3Ow,bk.oTQ /^)6hO,4cy5<6D! Ր@"%"=14V3ԯ/x&ǎ+eL{N`3c<8mr=� � � �FݢZ*p7y^z*Vuafޝ5Σ +wac :V Wɮ i3]S f9ipjT[]Kg (z+[-8Qj I_j+r._%6JqVя<axF)(4_#IX'S`ۗ?g:l&6LorkFb{*lxg/՞*UWxίnm{D̿Wdj23Q]GK5Oi [CK-Iy4G2@D @�@�@�~}.6lۼ(k5{݇mDM||"ђk{罯1ا<4BC+{eyt{ k c/4"NcSnV`K$%kjGp<mf838.fP3MoU!6L~umts3vƚ>M Yg*37fab|3gxSf,pEnjɣ#f?~oӯGG041Γm<Oi>=QiK35(.J1[C^6-CN iܠ837Hӗ5/V;B//1p1;?E3ʼ_<\3j?w{E�y@�@�@�@�8~Lm*qe=;?U3JTr v/nqeXʵkQkiWx>wF>L;TYc4F3w+ЍU[`_oLQrm-mxto-.-z2r։lY;ۖX+'ˁwiHq#6{?)s*Jt`)ixpVq5{XCt*MS=Qq"gm1P?(8sYos2_ZtAEo;4[ӿhv$bt@Z3\8 >@�@�@�@� 0ynX+xآŸoFD)>1xgZJ٧}^%ZGO5#+YU9fؖ~&ݧS(&zs]}yV0oBŸu ;jn"a- §DMR[#TQ1OvU׾CEڽkr\9ihMhqTUU)e czϣl=gwRXʰ! f30،ؖVJ8 e+n+tqϟ9~G$GD@�@�@�@�? [{#�賑Q`5ڲk +6ո>5wbu^b~l͇v_9SФ[wh|Gh9G& j<ífM&;)tCcF }՚-z$i=8㶏Kmx|߻k,? �y-&0�O*4r#g RÍ\Wn]kpïB~#� � � �A/0w[&j~Sů VO5BIA7u,hLcWQv6oXsf-YCV+9H/PZs*2S גKKғU]磻aJP[8֥mEqਏ.j-O{`f[¹5'" h 18IW]3P7\?=˔5r[bĞ- 7U|wKc8uSmDȶEŮ ~{we6.Yp  y � � � $l>^K#596=[ZLӇyk7 ,Z+޶]ڽBwfNSac?f>j{@ۖ}iJD;eOflSxAbG8o~*E w;;^rg)֖wLJta۫f68&>ho˞7=ӕRe Ttn:i%qܣ2^w.6^<O<o(1VkO.?R=mkpʹ{Q+.k]s!`xIgLA�@�@�@�`gwxem2 7VLan{ǥJh!"itjfгoAxk^'1z\%;odbNJ~#W*:YTp%56-Mco3:_P':;xߙ=zqCq p7ŶaEZ'gԀQs2K;]{[M1ƌk#ttZRyߑEk F�yLA�@�@�@� 0v+[8hc#ja-+kbE[UYSKߡΕֶ[><d/wc5t-T(KQZm5׾uvFX=n䱚84~rVVmyOyJM[TcRWLWRL0ol{ԿTXYm+vDo5ڹi yuȸv5RY ]O]GOצR,Ƴ:Jg5y&:s/4'#YӗxVk,Z5'MS\eҶϟWS�:� � � �.0>nqbb(f]ܬ Slp6)m*.s3Ri+4#5Y}HXndnY7 wH P ][8V;-u΍=22FWxdtf-7?4v=T\X=w&$ߏrh X OS㕢*"@  yyJJ+59Aa!!hƟ*U(j~5u3F+xV#V;q1ϟ4` @3G@�@�@�@ `.l7,AG^x]R{!뾱{mjlsEr#mvTi]#]-9wAm];e^8J~);@s] ŊVfcE*݋ںnyUez|+vcwXf0jy:o$zVL;w-{_y#^Gٙg#Ɇ=*۳ƙ@_lOmz^uy s)/K#uU~hRKve-UA]_ș*+ȕ8Jhur>޲?fI@Hqq: � � � {>?l_6r7)<EtX޽h]؎DFX:2:Zb�2xغ7{s/EȨKj~.խ{TڨB,Ͱu.6x&.y,/UEm~؄~3ތ[kF{d�r0 � � �tt/ȋҪ oI VhW6�`< � @L(!� � � �#pzN+j[uڱ xS "JL5{ � @@�@�@�83VQ}RJNDl7zvp7|Uq@$ � � � � ��X|[@�@�@�@�@�V @JT� � � � � \ȃk- � � � � @+  o%HA�@�@�@�@�.5_@�@�@�@�@$ � � � � ��/z� � � � � JTO长nәn_[Ms@_$H%S;x־qȞ[cԉ#H+* � � � � @3eE&nծGGoզdž+uA^VmȨY_# lm-FƵ @�@�@�@�@�AX ap/<,rm*8n+X7Nf� � � � � A=@vk՜J3Nj񴬕Z2^|z8E�@�@�@�@� 4MU6>?UժՎi^i[ԸD5$e,vn약vx\Mڬ OMiObk)oz{]@�@�@�@�@# {܆nlx>|ުqR^2 G1#;@ g"� � � � �tpZScgHV*<w&Sty]Z;=񶌧k^9A�@�@�@�@� mPj|bh(R|mSՏNKdt(/=WGjXm5l;g � � � � �E �V'<<ӴyQNuטAq[|!肱Va#sѦg5ýd~qgaI#5q@�@�@�@�@ ?@^wtM3o#bw뽟;T& UyR[>YNBT� � � � �  ~FiXu-yȍrsmϖ1#l2%%E�(---N@�!}r �\�ߣnF @RI|U|Y8 /rL;E[#w6TzTr5^ԁ� � � � �'cG}+eix,N{ŷF M_EgWb *..F[۪zۢyD�@�@�@�@�%qOF#]B՛jׯ҂^۫Lձjϴ{VE=RsQ7xD畮QbZ}jC�@�@�@�@�(ung^=YO ?R=M ͚W+y(csPҵu9{[堞ՒF�@�@�@�@�!pFWMu ѿ}j;@t3w}n}_u8md`MŮ9d˽ZX;W8@�@�@�@�@�_f??<@Ve|]Zg? p %7 f3TwxxJ;o<ɭrPH#� � � � �m,vۧz/ӝUqԿОQ[$ߜ ]@ݣQ 8s%#MVŞ񙒩{*~I"� � � � �'pz֫]7qV⣽s"Gg,-VEUaѽӬmURR8@fx3M@y|6ω\ @c|6&u@c <@z}w_[4TFZVܱ.dt-BޘDD@�@�@�@�hU0㶊3,x3J3G@�@�@�@�@�&-5f7\ah\S o; � � � � @ (rvێz"zLO4� � � � �DF,*9k&CBi׫ϥ-S%@ީ"� � � � @G8m=g#ºQ.(kqy0 � � � � к-(5+ 8nj4? [@�@�@�@�փ>юJ/Lh�[@�@�@�@�Sߣo=4~^8iڲ:z49Ucxe,?ɢ(;Pw7YnFdTݮcTTo u&?Ab-.' � � � � ?\xXMWXWvӾyiȰ堞4Eym­5h3UK24zVNϓ2Wb4y%ki2FA7CZBӆ/ՠ . � � � � �~a~9zX=הpY_Qm?+){]j.Wp<k:V+ e,:s~w,ۘf)e 6v=s� � � � �Oƪ/}sN%8JaZY[Z?uƟ?v,Ms-}L</uS@>Q'Ԗtɝ@,*Wjn<9+Wq5-ڱ,:H!� � � � �ww[X9Jr㡡>ůh\2U½]JM?@wZo4_ f޺ys+YQJæ=lBYrrWL @�@�@�@�mQc_OzE$Z&�. OkG4fԔfڕzҝ'3^izǵx]้QR W|"� � � � �XS}xK{]Bt՗+݀ fܙ~i_8' M#D劯WՖzJ\R壔n!2I � � � � �olƽf3见}E9,$.P Mv^=Yw6?9^lLy'=Nmef܈s � � � � �A!R=@Μ׶OS'~yцeZl;eߑj=~q1]?T/JOJ9G�@�@�@�@�N_k?0U&&+<yD@\~bs4)#},R}5|n⣐"P/Nv,A/--mv2"�67x@� =2?J#�| �'Pcq[{o銰V1N+{Cs]˼3 V;F|*G"=iBX73cagf � � � �  zuW-[ W ̱/|hl]B<96!we7>m e_Anl](v@�@�@�@�j[t=J^Cs?<1מ8UK Wh!gpG݈NYwEIy=:qp+@g& hB@�Fm @3m&@��_fџK?7{60>VLVOu}/bYѠ3psyz!D.+mT#~SmG7հUȠ4%huw@�@�@�@�h}OTw[ZH ^QyoMȫ>v~L6杈;/{ [جk&Q~,U0O+KТ߯mr� � � � �c7lѼW>֎Jf/Я' UtD{_wmWyVoG SFk9,9},_RڲdsԕTiu wwjY~}ʢM*g)e8-fH � � � � �-xz^[TXr«.!J^xz1}`}NZ_MMZ5v]Iӈ$wPu瘬e.HrFo?֭v25Jb/AuU~#� � � � �-8yƱ}!5=u}=Btm\\?8nge43Jlm>P2d2ؼT>JiͪZ6Q K5l+ � � � � @K,>D|.Hi&M%BꌣZkņ,*9nUOht㚱jQqq}bӌxJ;ڔCU JKK1i lGMEF@�ߣ>Y�]/;?Ӝ?#$DѭJ23w[@>*.Q.t (%kj � � � � @3楌[Kw@�@�@�@�@�vϿ~SϿymMC  o܆; � � � � @PX;CԽ[nb@�y }A�@�@�@�@�'PRYmiu ;,N2(!� � � � �o+7Oc.fI_� � � � � @(6|Pbn f � � � �tP'O#))F)2I_� � � � � @'s, )C � � � � �!@=i@�@�@�@�:N94*:� � � � �$`={N/{rX3M"0B@�@�@�@�8GOhK_*A~fD` y � � � � T_걿C&ixblu�yǛSF� � � � �,'ezP+=.Ʈ*?Z,&@0SAG@�@�@�@�@ NT TiO[_u @8sAO@�@�@�@�@ >?Q4QzpUz`߫Gu�ysF� � � � � h&ئg~3iy}D`  w � � � � gpVjl6}k0�D)!� � � � �lA}Tr~'<V?<R_[/'.@<g!� � � � @&~J14MJt [@�@�@�@�@{}ǽch~-H-0 � � � �tV;ҜvwqCL#@�@�@�@�@�vsڅ[#8S`pF�@�@�@�@�vv 1$S-Vs5 � � � �@UM~H?g[b3G_N= @Vԋ� � � � �A-PmW{XKYյ^cyxT_%_y5NO�y=F�@�@�@�@�6زLs^- C?Z}>^9 N9o@�@�@�@�@N{Zudsu$9w xu!wid � � � � p1c|ŕJUXͪb/_|ZM~Bv1;<2 @�@�@�@��sq=~3i }n�?z� � � � �!<+:=ƫctǵq} u;\2@�@�@�@�hY߼>QzX 7Ì9:�1ό@�@�@�@�N/`o>>fZܐprtMӤ3%wf � � � �tReeC8i HLFp| o1 � � � �JlC&o Vh.ʂz  @�@�@�@�:[+#újd;4\�5 � � � � @w׬o "8nj @3� � � � �V}Nh3MX@�@�@�@�@�'pzVoXz9PE$ @3� � � � �J}WDiip%CL�y(� � � � �"PWW#z{߹1A x  � � � � �A!PfѾ_c}rh߱T]{֫9z}$k  @@�@�@�@�^`cz/<U{޾7,y:w{= � � � �A#p?Qtӵ}4ɘA36:qU@�@�@�@�@WgCh eۂ=/Vwfy; � � � �A$py^)#s\@)D@�@�@�@�@=l۫l;tl03M @~rC�@�@�@�@�vX_dn;:\ki  s@�@�@�@�0ǝ{k 3~r?4 � � � �_`秕%fݺiD�yK(� � � � �m*Y)=:m=go\Z|IG�ykF� � � � @P |uڪVmg种P4۫<rg 7@�@�@�@�:suw+@]{7;n жB,޶^/>,bQ}+ɚp[?5U6[#9MRA1J[+arrŢ8.MBüe@�@�@�@�hzs_MI9 ZC^5lnZ5Ne,.W W9I+UzVjI[Wi c^+#ar+Dr͛!Qig@�@�@�@�Ow23J%-V,Z;Gp<Mkrn|%FGt9>-Gy㶌vw,ۘ)f3<%� � � � �~jWq+ӻNDU r:\A3'ikW[Js1w2q@ӅoV?!Qf\UoxJǍghLWKZ,C@�@�@�@�_` }Ǎ׮L4T!!!Z~[s&+7J\w-t>Sy8oY._/#P}:OӴ<k"75lv67+WH"� � � � @ |i=j:m7Ya]ۯ?@^S5 ~Bߊ h;=wUTTzӽ[t(`kz]Q#oRHw[M6  � � � � f5g%ݺi#fmR16{g}&ZKe*=c3gXJۊEsު%OhP? sh[q�9K&A|ܸt(Gk2/@�@�@�@�@�6xt}v~.n*=ynvi�thXokQwuA&5wu`+Jzf9ƽ%Jaڀ\y5,*PYu{Aef괫v>@�@�@�@�@ P>μo_1l+s ~]Ax\g�;Yl8gX=<|bS2t]6TkrƂI̹UJb#t8RnL� � � � � a772DMyNhT+fO-K4v=[NʼgnO}eM[Y/=^]>nz`у;ױ| }l!w[<H$Nv,A/-u5b t>7:ߜ3bh]G[ד@ =#,_vG^̛bV`|||5-u38J3S;]/GG ZUWUiGpQ*BcV 9wvۊus]Qagf � � � �Osc?_j;'SmrQ%Oq5[꺻ǚ,3R"|jӖ%Qiif0#˾vRѰˈ{I"� � � � @ <}V?*. o_K»mԎvb%umTZGZmmSoZcbQq;1N]ǯ๽fcTuGNw<k#<<ܞv`r@�&<9M@q hDF`�4SfB ]:eUֵ0m'ƶ{_h@ Lf{~39߷mF$'o5b{%())Ao/Uq^r ~S YUګ2iJ`^ݜ"� � � � @K~׏/jMJ&8nj@#(#ͯ(w\Ez:^,cYrae[rn;2`=֝ ?tg^0O+U-8�۽8n@�@�@�@�Z"CZ{7YchZR%eh@ȍ.+�.}l*jUMeV +#}R۞ wxΌdYE5>EVvBF\3ncG9[[dݨh&+ճ^, � � � �\ 2n{М$@HqhM4U5cד󗑲Sy[v,uN&ܖ/%Ŷ#s-Sw]h( M�\�ߣE^@�ߣ M�E=N9kčW]?fެ0^Ye_V4Xt)>)%3[+2%FLeu;mL^_i6L^YUM@�@�@�@�'Pn9Vm7 Ejo"8<>rVfUyqDꭸo^YZjPmSu^��@�IDATq*륌X[7 z"Xs~#r �M =ڔ@� =z~#r @ Ԟտ-ߪ|ioGx[tm-#ھ@Զ7COqHLܾ2 Rb?P6#� � � � p!]n"=;FHv+2:A�@�@�@�@�v?oǽk{$2@�@�@�@� HD}$$@<f � � � � У >0N�@� � � � @ 8;t9{awmrT�yN B�@�@�@�@ Xjjj*Nw% !N*@N<F�@�@�@�@5Ɗ٩e_٫ ߿IWto6 @ަT� � � � @_?V/AzP :<'@  ١o � � � �oROιs7I } � � � �(e1=ngi_׬;$0K@�@�@�@��y~stʶʢC@7ω\ � � � � `Yj uYǕ1Z A'@<覌#� � � � ڳzUe=Cr*- @B@#� � � � ?ҮN؇%D)4wTg>c;2,@�@�@�@�ZS෯ӫUj}`yN` @F@�@�@�@�hGw~g-N%IFyN` @3G@�@�@�@�h+4fK)o_g@ w@�@�@�@�P㧔=[go>Qն9@�yD� � � � @k UƪT{tFGxhk7E}M�i@�@�@�@�=٩vъݤ"  @~pC�@�@�@�@ Xo1I Qwd � � � �m?Ԭgw Էst$i6  � � � �-b֐zCd�M�yGQƃ� � � � @+ Kd[V� @C@�@�@�@�@�V�yR; � � � � @  Љ[ � � � � �m+@m}@�@�@�@�<u&Kgh�Q@�@�@�@�$GRsDFitDЎ8(Ƅ� � � � �8wN'"7{0I XAg1!� � � � p>2&R |5`ypF�@�@�@�@+]ǵ}7\D N-C�@�@�@�@giͶO͌�9qD`y`� � � � @cǪj􃜝i=Kۮi,;p;ܔ2 @�@�@�@�/qhN}3醄Kstt} � � � �~P 6kq_R~rr@ @ޱ!� � � � @ׯ}b{^MNo ; 3>@�@�@�@�<X\]yeÏnUst&.i@�@�@�@�.l՞u/U}.$  ē@�@�@�@�:1=w<+!BD`N7 @�@�@�@ T*ROu]6$;3f@�@�@�@�N#~gz|G=i@h�J@�@�@�@� 8qVOoګ?=.Jrq4i:�N7 @�@�@�@# <mҊj($ݘK#$;3v@�@�@�@�#PclXϽYg5~huF8 N/��@�@�@�@ Tptjgw_{!D�yR) � � � �m/P{4/{ث+c"5k�7Juup  w[B�@�@�@�@ ޡ-{>E')ׯV7e д�}� � � � @ em }IC#By� � � � @ ӂ{T|ٵ75H <s" � � � �~8{NwQ*eݻ$@yțD.@�@�@�@�&PWW|gO8Տq[*^( L̈́" � � � �xc1OūtӬ;{H 4_�yȉ� � � � @ Wt\^mFGikqkw# (׋j1_W}5~jsEZ}!Y}󔑵RV+'wYRQ5p]t i $; � � � �(PUSkE>=b/5 rcWs15k՜;w*[=Mq^w_ѳr'+Ulb 4_ H)QirWbi @cx3M@y|6ω\ @c|6&uK`GGuiS|E #85Zr]#Kv g-]523dW\Kei\e6K)cxU+) � � � �~8{NOoܫ9;xxhׯCoh-eNMYï?D.'krw3zENʵhh/͵/8OѺ~RNM2iZA#'*_^OrrU5<Q*%{(T7+p�`yȀ�4)h<D�+yȀ@ l[/Uݵ,}6@� rs'+7jmеN9Y)38.e.#W/;?;F)-rmM{ZΦfUY@�@�@�@�E`Vm ꥿dv )К}g?oŻ=wUTTz9W|̐2L1CTdy;zX6Ouu<*@ / u'� � � � @ :M.ߪ=m/7߿r?5#vDM jˆ}VCuw4K3Oٳ4Hj"hTcۛ.!Wd([F9QӵR| � � � � 6طRy}1ºhD8½q�/rpT] s7%={V/ܪ3sܕʰ ZQfȍ9 � � � �~(֓+JUWJi4J,}@=Gx\%/$+s=ҡW<ױJάRtVObEoU{VLW/s3G.!� � � � ~}K7 ͹kuh{m+Hց3/v۲DIcgN2٠"է__V)~EF_aۂ-ӎ%o O7|ph�ߣͦ"# SQ,\DoywIp=uO_X1^[*;@|||Ǩ%K*0cfjGřřgt~A侧5^4~ͼWX&� � � � @{ ǦQf6{MGpܼB['Oqa_w8tcÕu[H*߅@�@�@�@�V}f7鮟qyN#[DNiXsjA눞W+Ÿg|)LN;VKUҶ>wȞUJ7BBF`yIgؼ8Gx4!Xh[ @#|6e@|6l@MYϻ}wXnºU$@.F^moo=ڈ$>?maw ˝i]zնٸqJvSoU7հU(d4;� � � � :sVU΅ݻu}g񋣤.!rEg뇭-]09d%4^R`w#c`?,~L}3 ?t**}C;K߯>{qV � � � �%ƞcf.j@� -wjɦBYVTi՜Qʰb;(%ѹI0,9},NJmY2Uc6d1J^ >)>䶶(ʢMjTq{e"~!� � � � 2ri=I7]eI Bػ~OZDZZ#ݱncCBMN&J;P)M\e]HJmGtǑ Ļ.�`G(\B�.@ "+ CQ(\B'mU~C~ulw>g4+P2I 1 B iTPKPA-t@j[[+~V[h[ "&L2@ d<I}NY� $9<kZs+k{YpK r`O|N'dn+4mrQpM MYZ?V8n??ڿnş0k:'ٞc@�@�@�@�.$++Oߍ&w` q yڔS־' QtUZ^ʴ:J!1d}%[22N8Xz}x\Vby}#@}ةOz@a|6̉V @}|'C=-'p>gGNμ sLC'ձCliMi� � � � @i Ehim~ � � � �xB``hOܖ{"@D@�@�@�@�*pئ mN;�5 � � � ,|oN-qL,0&Ɍr?yL@�@�@�@;8kmd9�%@@]σ � � � �@~4 ߔ � � � �-/PTZm:O3r[.J� � � � @-/JAAn {a8 � � � �%P^^٫#Ѝ}}k2� t@�@�@�@�N \fV%48HBy_Is%Gy\* � � � -݋7+tFěc  g,~>@�@�@�@K2N?fKG˰@.VץB � � � �8]P0-og) osb � � � �^"PXR;o:yΌGl)S@� gH@�@�@�@�<,PPboRv?M_q?nE _@�@�@�@�IV3:uL⥜F'@@{ό#� � � �@Bd6=v1};p 3c � � � �-$Ӛ;Ƶa:  5 � � � @3 dk˟p<U~~͞ iw -=@�@�@�@�|B 9uL2rUQQ9쨈4uŷy0Hh�yÜh� � � � iZ|:g[)C%-@@Ϗ#� � � �\_/N+q'A]tn8@� ,@�@�@�@�)`B噷_2=Ttκq@g,̜�'@@ϔ!� � � �\@`=zn: ӟb9@� g@�@�@�@�p}PWuuw=tS_uU d � � � @-Ҳr~5MNLj_13D�@�@�@�p طU{(2,X .TUΛi#� � � �gͬѠ@` sg � � � @@ TX{<ZJ-Voto)eW<p=3G�@�@�@�F`ŖPc!K9ߙVO> = � � � 5{<u2@ p3s@�@�@�@ Vm;6\{uL?O@̛I"/lD @�@�@�@�p)ܚU!><�M)@@ޔ\ @�@�@�@iŖ 30S�g�@�@�@�@oyLE۫Wod+C� 4 =@�@�@�@�n >^hP@��9@�@�@�@�Jؙ"f}uۼ[s�g�@�@�@�@N-v _[G< \�r@�@�@�@�/[3e`^@�@�@�@bNЩs:dmb/gXնVic+L?_13D�@�@�@�B`\-+G~d Kb^L<'@@9{� � � � 'jc 4wlS<0;F�@�@�@�|NVV6֡J2Gn/'X+ p! q@�@�@�@g J׏qLC0S@�.Fb� � � � b;h:SgdX~>-vn�+@@ϖ!� � � �>/uPw-XJ^mխ]k@� {0@�@�@�@�: PL8&<Ds}.u h�y� � � � O>g͝^:\W'7@�K TA#� � � �4}٢?MM8n4( @S 7$A�@�@�@�d[~z CZi/\�)@@^Sc@�@�@�@�+eّ}&S@�RUS^k!� � � � p1 Wu#L @XA`*"� � � �4@v~68rt9*H-z5 PKc-{VG 5ʊPMiSJ^^\o0 wTr\ϖ iyVWTTg]1&MkBj@�@�@�@�K9WBw y<ބuP�M/P#Enw=i};]YP9_Wi5'iv0seڠhy˗htiMZվf3@�@�@�@�F t^t΋EktyC:S�46]x.=Ѧ >l=;Z8<G+T 4sAc SMՀժ;@�@�@�@�W [{ OѨ>ry;<D]z7A7T&W;lU%q[@^&g/0S\g+jZsRU= :Hќe[~> � � � �$_+_գ^v9�g-S;WN5qՊ+v ǫrnG{:}ػU'Dn6.Z2;2tSZTy:3Ez~ � � � �4fx)S@�<!<?KudK>C+yF';+imz~#� � � �4\~}a[۪t0@�Ox$ ?KKon^'!AA rzzՎkf<& 4D?de+AjDǭs F3@�@�@�@�.E\q9.wK}@�&H@ >mL]"׻7Rk wkrY̙sfzi_cm9abSM@�@�@�@vbj]d9�xJy~ +=EJYFKOrHdV2kGiZ2EkRjsq{IعUJ ' RumJ � � � �*pئ~rXܨq 7(=8rcA<+Ѐz9 ȓQycuݷ랄qJפLիwj(5IN/?r4v={tlG/MUݻzZGwU~vM)W.AʺA��{#>SG�&{I�ߣ=4V*~\|rQX 55qHGgӍ<"zM=<JSUPyqJDX-LeVsOQEE Z8^0B?Ps\RVk}{Ъ_IO;:O@�@�@�@�&ȷVo tK;n}ӋwsMxk.�\VW7$"Ηf'ݣd-\E6EDMG/%/LּC R+ � � � �4\PNҿ>gDZsIhA׿#<C54@�lWQaJ[wV\kOvlm+W~~ qf{"ësGn=ygUoj9Z?Gxxv`( y  P�ߣP�4PBѬez(G<wvMOM쪠$ IU{m\3gSs׺SVWѺa^kNThlǚrrge{TYXRWǮ{7~'Y}W@�@�@�43fZi\'Ut^7|@�/h∺,yk",8ga|@GcuҊ5ELuVMnG NVp6WK7L#Uȭ&ߥnp< � � � @@ <˷չZܾ]^@|h%^Vd@?Z?E$j{m,װ[ٲYG[Ąn 'm+S߽ϱD=zeYlھ uSx6so8WZŸwOt= � � � �"p|a[8%:B_?mݤ%uVʟ 所 UXV=z|h'տڪ=ҀI9+wɉ.x:i+Uxb%%%橩HTQ@�j c-*@�F =(.#�EBE#R>̗?wV?}g~t9x@˯ DsZ9ZBԉ/q{S涕Z^wdvV8no2ڿnbSy񪖔@�@�@�@�ؕgk&ԯ egVW',UFfcۓR]1ʵAJܬ Z[;U||G{jGv,'պuj+ԫt+܍h�+vD@<|S @m�M8[P%eo�sD{4.1qV^!QֽollO#� � � �~/wpMx4ıO "@ x> Xz&� � � �xۏꃽَI5ڣgBhg oh� � � � 2%r=]fSG%  t � � � �rXy>aw5M@� g @�@�@�@�& Rd6(B� @�@�@�@�شd߄; �^(@@!!� � � �-%?uia@�e 3?@�@�@�@wOWlѢGH-zZS��=Sf� � � �\P`͎|fH<mm}4@�E_$@�@�@�@�(fךg*s2G89UHH3 4@�@�@�@�,pwrp!zA�`=Q� � � �#L+˹p\}:?<RA5 | � � � x}Qb&kǭGW<p=3G�@�@�@��X~ UTTN_(G#K8 &'@@^  � � � #j tҊT`vL4K7 � � � /rXnwe\PHqBZ<?G�@�@�@�X%C~}ޠnm#62Q@�]U0@�@�@�@mv/qk8ḿ=i�* K? � � � EtHyc+_f7(@��9@�@�@�@�?ƃz?lN5"7&@�5(#� � � �>*↯7wۄ  @ !kp� � � �hޚ=fbkt1�%@@^ u � � � /hGlS+2ǠP@�@�@�@�@�o?5üW:eZ:  � o@�@�@�@k_OϾ[|pkC�  @�@�@�@�= w}F?jEreO@! Q  � � � %ϼߌ[Wt  @nEK@�@�@�@ 0cHQp<< F`@�@�@�o֒2'-<La!L@� 7΋ � � � @ ?}oYw(�\�Ź @�@�@�h{~t;Wvp<4 p G7@�@�@�@~Nm!s߻J!Ƅ p)䗢G_@�@�@�@***47em0WupW-F pn@�@�@�@�&~}asCPp SG@/ݐ+ � � � �M"`}-]l=b8={�4�ybr)@�@�@�@bxQs;v3+Ǎ @)țRk!� � � �!` =8r=}g"�4�yӛrE@�@�@�@eV8_hgU]Ww;+(= IC@"/. � � � @SJ<\{Г"7"@� o>[� � � �+`++׬W>Ҿ6m&' @ț#� � � �5?[U;m9F�h> � � � @-R+?>ڝ̹)Wc  �-#@@2@�@�@�=zgq=m1@� o9k� � � �,Pb+OVlӺ'_:S@�hYn � � � Ŷ2M_]{G@ �x�< F� � � �~(PTj˶fv?M_~p܀P@�<$@@!xn� � � �/`OaI3ٟ_G9� 9rsg@�@�@�c{8ÿ}WnY7^dzfj o b � � � %e߶hq }1@� {0@�@�@�#~Vm*駟&1@�C;@�@�@�@�?XQpq5[dvL/V5f� � � �xV qF }L � � �Ŝ8Ì>]kS� }bŖ]#գR" WAؠeyM[wTԹ{5޵ښra2-O٪VκbMtyӋ � � � `wwבGColp_"�ǒ=i}?ąbL+6<?Ucf.75’siKxJgmY4|NnєUwq] � � � @c+Lo먎Q xl6]Xgۊ ϺsTʊJr]iTM}~3[ώ'5)Z8aS%F7@�@�@�@�@�ZCy7T&WfiJKKkSUS T\l-kyV/ԓL{gh}6Ms6K9O[]} K5;8qN W?cksm9jUנ� � � �\HBe_@�H3-S;$ZqF/!!!5khb1CzF>X ՓdxU륡SBBԙ)r0%@�@�@�@_mQn4oՔ) �xg,mvz:d2?jڍKkʮB̐5y௩;>rm<<A;[(nWyZ^m鹳?@�@�@�@� jҭڙgE7_S@�Nw)Uz  !߯Wm :<JZIWMem:5.v-JG¨核S@�@�@�@�''IDh+MVo͟h( �x@MLZni͔spG]Zrv<,ܦ쌪_Q*5 m- ȭ̜ � � � dK>J1׻-~w:EU՜� XA^_Tĥi/Rʚ5Z:LK*us%y:Uɗ8JX@^m 'Y@�@�@�h SO[eFICǛk �-(9 ȓ/cꞻo= bGHWԔեwO׳S[e:d[xu5ip]qq! `{? =zi~F�m?_d_?:d.<eɮjŜ�x@\\eQB+\];?V SfٯN(ΫKXBL@�@�@�[Zwt6>Z: 5u@�|Gy%NHDے+>޷lnݜUZ& iɱ^Ww'F@�@�@�(,-o>2 kGo讐zp@<ŊM**SiΊc|dNWڇ<G{:t cbV&nz9W0ѡsW_;0\@<@q Gz`F�(hجLo?Uœ[j @�QWg۫Su{|S&ޫ܃~2V+9ۦЛέ͓G'VQf߄z_{ٔ 5}ks@�@�@�@�@uj9��@�IDAT~Z== pk5yD@#a |@nm{bݦ`O<K/Ιj7t}&;kYxɄouׄj?OK}Z?@�@�@�@ 08Wl׸Ol}#OxH+={=<HAAlr' -G$jn-װ[ٲUEOL٩N+t[ogj1TS]Rg@˖߯:;%-Rr{ه|xǽru?W{_}@�@�@�-`oة@oY[Tx~uK}cOQF�a /ڣZЂ8qvoyROщZr~+j+TwKJ<T≪~HJJ2HTQ@�j c-*@�F =(.#�Ercgّnm^E?'w�@?Z~-+T<N|Q#ŅhZU`m.4K ߻X-R4k:'7ק� � � �~)Ip֢SgR @gVW/UFfcۓR)[:FToQg9?;Cl B+cL*m8ḗK{ԷlZGVWà� `Nh�+h4@�$hmoRv4g\^ -@�|VItsO-"FnGTxXB!Qֽ'Ps#� � �  ; ןkz?uf�T xfSB�@�@�@�<"`-ɳ'&  @`sf � � � PCGX־JBld"��?a� � � �Ni[MczW6 @`sf � � � PM*樱qCjg)"��y<i� � � �F̔Ec  �#@@8Ϛ"� � � @!|@�S<0;F�@�@�@ |g �I@�@�@�@�Xyu9Z=>,!&d@�B@�@�@�@�8]P:3$ᄎkk) ��y`=of� � � @@ =զ'V}+8B�(zL@�@�@�xuQttxH+u �!@@ϙY"� � � Pϼ~ۜFQ}b5,>F!nm8@�,z@�@�@�ؖ?V};ѣkDX ' ?�Lh�+4 � � � %v*_M3{?jExct g3@�@�@�Xcn?qqȰ`=3ix;s9@i2@�@�@�PLA澱Co|eVfvP)#�4TRC�@�@�@�v*,1V �5kp� � � �>#zm{ :i@hSG@�듡@�@�@�VVV3q̌q8=1@�.$B 8� � � �xr LJwa2@�/`? � � � �Gs {%_`  �  o@�@�@�@[2NVN *[8@�|HC"� � � ;2hist8Ѡ� XV7V � � � s%Mf}#c �!@@ϑY � � � %e& 7L7 f �'+g˕@�@�@�@b"Ǜɖ"�$@@HO"� � � � �rCA@�@�@�@�@ i3W@�@�@�@�@�#@@n(( � � � ʵ}:<ƅ� !>:n� � � �$7k[F1L@�`@�@�@�ZL`WV!qZk1@�.Vb� � � �x =M@�? t@�@�@�7 WT۴ {C` � � � PzIJo@�!#5 � � � rgmzlYZ!y9� _}@�@�@�@J3[Pj?GS@�@R/U � � � d+Љbkuuw=1J[  �$@@~I|tF�@�@�@�z(-<_5m �r � � � ~U7==1Q7&@�VKjZO� � � �)x^zݧѠ� ͡5@�@�@�@TiYU鎡} : � h@�@�@�ZD=)((EM@�W<p=3G�@�@�@xx  N@�@�@�(;O38@�`<J&� � � o |[8>kJ0j@�`O=.� � � :c&e_ 6u@�h. � � � p^*}caӮKքF @s 70G�@�@�@�Z ۔vjx.Qmk@� o.Y� � � �u lwR?v߈Sw$u[  �.@@�@�@�@�\K><yk&UVr� Ђ-ͭ@�@�@�t?9bNQzaP o,@C � � �\63NAښc  �WE{?TApv aSJ?+<<.) qLra2-O٪+FߤIwMݶkS� � � �/Ↄ/v\ </qz"� p5R䋸BSuМZ^~L]y̞i9?"4emnc8 ˗htiMZվf3@�@�@�@u\䡛PlpsL@�OMkӦsЂj'BM16] mY=ֳ㪅srMJ2:lC  � � � ЄOՃ+kXf0( �xLzAdoxV]8.LSs?#uj2aDHմ7,5+h˓5z6վf=Esm#W � � �4ejAAֿWUPB�@C_AE?3[J{ػUQWz8.%ֵk9pY3tSZ\H:3Ez~ � � � \eAtp|.zg]9/^ �M%PԺب#+WM5wkx ޳Yy5`ChK y%=YJ7sZjv@�@�@� .(NY[j[i<j-~Kנnn0 �xT+�{gu׮M0d z^[2 tY<.QuE F>ť5k1g( � � � @])SnO=_p ~|%x]!�xT˰g|7t$k9gyA7+:fqyft.iZ`9+wɉױ0y^q  � � �4Nf`^>;RMUc#5Ghs`\?@�Y7>يiJ7 /\l^6i=xrZM<V)2= � � � TTThczz='WXvCdkm@�oH@52mOipą ΚFG +OUݻzZGwu~vM)W.AʺA��{#>SG�&{I@S~yhb#N .Sq)eٌJ@�/xf(-y92Ȟhf 135q9J5STQQ¼<Wv,וRVk};0W 4� � � � / unIC:zs@�ohӍC扭ziFӗ;-+]kCU׫6╼0Y{UҾYAk_@�@�@�8@*()w4 o~"߉ �x@ FwrΝڬndLomEWqf{}"ësGn}!w\edf9  8@_c{<PB�{@� 4hΪOoUI @�?n1LRb[VpR-.%Zw⇏ *7._sBc;ּ@R_Yhb5,QJz_ُ]'n6OVJ~ � � � .m]m( � -Gis58ݾ?ymYo%ݪ W vJ5ӕOnG N\-istt=r]<==|V9@�@�@�@ K١6@X#�@xU+Kkl>9_>=Q^E_ζ|m_:m.JW7{̍ZX3[,8U\ � � �-Vzwqcԝ  6@�e/ ];& WV2'LAZ*(4Z&5sVֽ--_1y>MQhP'׆,RFĘkP@�@�@�@�La~P7S@�@* wl"sfVj~'kzrbg4ڿnk}f-Z|gT � � � @xs;f9:\T@�P r2Shmbߋu;mUꝏKF +Zj뗔T6:5 eL @m@�{3vzs%Wv1@�V>78+nCߛF{@�@�@�p>cZf�t$ � � �-(Pb+ά3~/t}ڄ,� _ _ϓ � � � `SV(gTl5?nf ��_<F&� � � @^xy;;ϋI@� G@�@�@�4Z1oӣwՆ @�E_$@�@�@�@K?:3L#{!k+6ᦎ �.@@O!� � � PC`gݿwiҰF @ʓf � � �Xeږk,vjŵkm( � (' � � @ ZGGr F @ g � � �'Pb+٥e#t WRN@�p $� � �  TTThO)3P۽_&("4S@�@ 3_@�@�@�8[\--1XQD@�O>@�@�@�Aώ߻r~_J*,~|]Oց �.@@? � � O طPs,_?X)S:WRVkN}:W @�Y<>sG�@�@�Y٭@<\I5Z 䫺)< @@ cg � � �."uQ muە}lC% �H)@�@�@�@Kͨ#B[>4wBϘs@�@~m8� � � ʵxvdю3`I3k5Yy> � pa @�@�@�8x6˶</q+jU@�@� _؈ � � �ƃ15[  � mB  � � �(()5#anQnYXvT � @D+@�@�@�ZD ۧ~r{j}j( � _!W@�@�@�@/ᴇ\_g.i{w'7"@�h:J � � �4Zzۏj{yЭ訅\w�@�& o"H.� � � @c>ܛ߼SOsڵmfWw_]Z�@�N, � � � 8WWlbkp><CM=@�hq � � �W7);M8iczƿ �4�6!&B�@�@�@5M_<LS@�@�h2. � � � oruۘ2@�h9N � � �8PQ2� �-/@@@�@�@ Zo<ncBsB@�oV � � �,8 |+S@�@�%-@�@�@�TĦGNj@�@[ޜ;"� � �Ҳ7v)lq͜"� | � �  ;S_N׺'fe{7@�hi~ � � �~/PQQ|rXڣ63.z覾s ` � <E�@�@�O'WӴ`Csn6  �xP=ϭ@�@�@�GVV?o<ݫb[XiD Oho( � w{s` � � �>,#f[wfY Ҵ14ƾ  6@�@{ȽY0@�@�@�(*-i_Œ~PzD 6u@�@Ƚ0"@�@�@�)=Z{>!p^_K|@�@Ƚ0:@�@�@�//*{|a^Oݑkq> � % � � :WdF9{tWP @�|@CD�@�@�ݿw/rzb up�@�|C7D�@�@�ۏw٥fڄmq ��=3F� � � Gs w能nwsh7=v@ s�@�|O#F�@�@�hF -ۜxgAI15oGSG@�|[ܷG�@�@�hB}'5{U>mjQ w)260@�f@�@�@�.M\?SiYXNmD]#Q@�@� gL@�@�@�.B#54}y, ҃&QXH+SO@�Kܿ'A�@�@�h@AUT-UijQ @�@W}1n@�@�@�ظ漞#9CTkV � #f � � �.3[O?AO>XGs� �-Uyў74+U9\]8C#=A:|Es+tjuUlڰzl|WTg]1&Mk۫P� � � skv|w*l{֡z춁8rSG@�G xtmPh-p &YVkDlT!O[STⶬ m饥r4eh^UHJJ2LO ++˜3e  � {aNB� +c);nnU'_mQx@%U6{3vh[8>gJX(_/o3[ώ'5)Z8aS%F7@�@�@�|^u㝣]o_>И� �-({؃q.0l-lg$&:`?nh?LK)3iԪj҉sRr2vFy@æ:ziβ-Z?ci@�@�@�_8uNr=ûWPtD]˲ܚr� � [1Vx~;y3&w6w^ E/f8E`+TO֒9pyv蔧й<uf\� � � ceZWH<m3pǞ)E�@9<#bad=>+޹f~՜ה]!7j`_SwZ!}x<y<FIwztG/%� � � Cӄ?}'ڭb[c䭂Yc4W͆"� @Kx4 ?j:ս;;S'5<V-EhWW,@]%^J5B*.u2@�@�@�_VgRߍJ<c<kh͹e"BM=@�@%=moI *1+E \ӦLSWjJO̖sVf@�@�@>=ٯ@93VqC_` 3c� �)ࡀ<K'ݙӔ6ot u*Խu\TRҠ.u @�@�@=o>:i1f@�ha[Ps+q-G\h֭եwOթg:J :iUxu5ip]qq! `{? =zi~F6:щU_J;(4`y8ߣF'@ bdkLk95y6cjHRh<ܤ|CES[ 3NO;*U9A@�@�@'Nڴãz\~3!ZLNQUր@�@dتo}p+8}r:i.>B9W}V_ҾYAWy!Ǐ@�@�@�R/sp<Si:Dtڻ� �4JrklUK;]Un%g:~G@^Z<EV>9{٤[g^*r$HHkT/-VP+؂nv nwajW(v-nkE-^! p{ @>Ig&L&&<O=y~GyVq [l9MEbM_;1@_c{XF�Z{Qܢ p^s~]~1S0G[S@�ga.;4EI)RߖyzZhd,0W7ΰ.͒<9ڱ=zhoR'%5}5>8˨Or<ˢi8IJᔺۏ� � � NzqR?UךgGƘu@�@�ps@/lԌ6Fr[CTڱ^͖Q^R1.4aƗ^ӶM{)^ӿge]%cVoE6s?/ϚF4>@�@�@�,p4N45'=21^R7Sr � >]=Wjz۶xSB5w8uK_;_sBm#cJOYuȭ-N|T G⦚K,b-֓@�@�@�"`o</nvLJGoөr' �#{߀KhsIZeX5_ÍۺWNњ4v6\Ng[yje@�@�@�N<UEoсM. ۇ#͞dG�@�ta:\AA�'jeg,brKY GJ4c:)ԑ +YZbJVΐY-/> � � *kjxo8I"''_I8jtC�@�SxIA,圷؂>nReeٖX'.^QHSRf/ /�5/k) �O9 OvTB}# 0 g<G/ύ@�|O-Q޷ٮ3?i}vC#@�@�@� Tw赝<~$ P � Yw"� � �t*ʼHD zf@�@P � � Oާgv2v>V1XLv@�@�+ rCz@�@�@�ϲJIE*:<DOq:  � -@�@�@�.(sˑs3~ὣi,†� �t�yWsm@�@�@ j_֜>aZD<YG@�J � � |yTێVi TZi1g'=6i宑`S@�@�Z�G�@�@�<TS#_=P,F 34wǩD�@�R+6 � � =``d0D2LA@�j\@�@� 7o1yX_~=`VL@�]0C�@�@� `}RsÕ � :~u� � �b/E�@� {ʌ@�@�@�N=9u Wkr@�@?@�@�@N+Ϝ#<$ܧ� �x�k{ʝb � � @ P Pi6Z4eT#� �'@@~yn� � �x@iev+жy}ya!ZvzOKv@�@c[*� � �t@eMvga9m;r^{Nkk\\d E�@�<@nCD�@�@�:KLqu[*K] uZ797'wXpm9� �x�'%ƈ� � �tlw??illn1Ӎ }#8նT"� �(@@w1#� � �$0,- eX?tU_Euҕ@�z�@�@�Zc?;e^;X-:s � ~ � � Њ Uz~vXN[Ғ*@�@{Ƚ23@�@�@U*vNVtܧ� ��/e� � �J*k5q8宫Dp@�@� [΄@�@�@*kzqJ*jL_̸FdS@�@�|Iܗ6sE�@�@�lEkLqv@�@}3_@�@�9RcYJs }ʴX � xי3 � �@eM^vXV娊ʛUYuup0` � /1@�@�@~I饨`:v@�@�_ ;ϼ@�@�@.TYt|9}}cYYO@�er_@�@�N^z\M?f˪48/B�@�DJ8@�@�FEZPè˪$tc@�@@" O � � {s5.*0gc]Ve#uqU1Y( � ��IA@�@�<yz'~ԙaZx 7( � �8 ;z� � �tkz>YqZ_=pӿ[σ!� �A;ƀ� � �\DRmGY}dZm=r@V~=[=N% � �{ � � @8wA/|xH2Oeյ+,8@ck h � �& � � �B`on<4~uF(>@ 𢡄@Bq'$*@�@�v& � � @W4{fߞ }xRQ!qM@�@Ƚv2@�@�j9O>@�@�+ rCz@�@�@�\*'H]KE~?1yKAg � �9 @�@�@�n$WZ+>Qum9L=}  � � w# � � �.<Ul!<*%}  � �{ � � @+ճ?yCM  � ]oJ � � @*k5wN*0 q}  � � w)="� � �jf8'M6NOy kw?4D�@��y8@�@�p }珻74>@�@�N@�@�@-z-| p|AmQ� �t�Ow*]"� � �xl8^`k`7ic.u@�@�\(.Ĥ+@�@�@̦soN 75( � � w5WB�@�@�lU]05Fe) � �O%Vg͕@�@�@�}j,jBuyAA�@�.@ � � {9EZf6>0y]#A�@�p@ZuJ۸K 2M3MVlxk�e^o"vبV{4*,ڼI۩ ﯫ'ݥLwnFT#� � �+y! C7т;F\n� � p-R+gf.u:cͪ@IZE'L ZtCŲ5!ʬnܸ۴Ƭ֬]Ծe3@�@�@�W '̕ � @%o8K+uZ6/> JzDkRi]"6 kWSK4-_x-iZMW� � �T oKE @�<. 7;s6g}SfhʍڵbXּ{lg-Td(^lSkTSSa?ͫ'Γb1>=q콥i+;e>@�@�@� k_n'u � K?j/ىV/MohLߙpJR5 rcg')iXQT`8VUjՒڬ9??c8 Ҕ9Yc � � @; ˪yvvejwV*RyuÙ9쳃� � 5y;e24P n5(JRC{5:C5SRkL%͍<h<nm\L>@�@�@�K dŏ/xh1uO6s�@�@}H]=PŎJ8W3Q&o&ڿx۶mWگƗPZuQ$^X8W⛥r:5I͎k'bS@�@�@�#WZl8?}zR6񁑡J(M6=@�@ ]E~][ϩ1OBv_|SҸ�ju]sК~;ggyI٘ � � 25OY% ԍ }l5`l � �Oz!un(1 8N5’eSc<:��@�IDAT޽._^UQb[*|+ۖ2n � � :zt8`l � �_c< 8L:&FH*uW+'+/6EnN!=Ccq#^?G="6 <r UU |Y _\!+飳*jjnI$R\pskPy7! �T 6#t<,NGk +EzvFZ$ck{ 낇'Q}}*JJY8pPM^\K^Kef2@�@�@�WΔVۺ дߣ+ � @g tqz뭵y0Y@Mkx.O5>1'ȭ%5k;6@�@�@˵nOyڂ[)*a @�@�%V,*ѩ3g6xE;!.&n/lxr,*--UI?>\^qXHSxnÍX$n%e -izNDX؊A p1Ť8�.h.v/Oξ(=vǸ5@F|g �pt{\O7V|PkKI /$SBBN*Te{n#[_iloCΧY; M@�@�@U=AQW##  � �np@m.{t2+[7_uYx{mYVyxmgݶ;^ӿ7.cVon~_/x> � � І@}}~^vlqۈhL@�@s&j޲%m>Zh/ڭ4)+@bSݣ25_iRo<kKIlvGe}gHT5f˟*7 ) � � @+5?/?8$#'mҚ*@�@�.g<`kj9o~ڞ&4{Oi[on]1ʡM櫏+iVÚwSknmK7F'�8 棳 5 @Gm)p|nyӿ &^G}8Y}{5ȝcZ\Lыp @�&?Anv0=+Oi5Yiku15ZyM44[>[ԑ +s7p\$ojI @�@�|Yl[2 Gh?M$7E( � �'5O7w,TVNm#9W8E6.Ҽc07Kb)55R6UqllX%++ٵk5;F'ۀ6i8�Kv1 ;Ǽꘁ[} t'G`, �YItg>4Jâ:|X#YƵXilG�@�@<8ai_wa � t}@邌@�@�Z`,_sXk5+V� � pWLH � � Muy@;թ sz1!zf8qS � }= � �Hʢ=eVQ=^=Za@�@S=1n@�@�p .ɿgDh<HKRhPq*@�@�<Ws#G�@�@�*,n ƭD3@wWU7� �x�WN&� � �_xhz_'??vE{@�@� p@�@�@u֥U>>oКylO  � @֣cp � � @' d/ӯ><d><ḩA@�  ,@�@�@o<>:ںzUL  � ̭f � � `"HK7e<*FzH@�@�|Ln8E�@�@}f8>66BL!Q@�@� Τ@�@�MjK b5=0ܧ� � [ӷ7E�@�@gNW聕܅j <gL  �  AL@�@�_v䜞*(k ǧ% TLxQ0_@�@�f0("� � f/ & 2#@�@� w � � I5_xtx~7+Y7$i0V@�@�N $XE�@�@�X#Kl>1I1,w � �Ctv(@�@�@ʪ,f\?pԠ� � `  � �xuy?;e-<_51( � �"@�@�@Kibq͓ !� �\�q6 � �t@nQkonIçQγC{:u"BwD�@�@&@@@�@�H'i{UX^sO;@S h"� ��owf� � G PF8^F8#(@Fh\\<ܣ@�@�:Ol@�@�:AX=.3 ԸX'.RcP|X^넫% � 7 {d. � �xE;tbt#u>@�@�+ކC�@�@�RR[ CwM � @� � /.w h4XV @�@� \9C�@�@�Uho|YySF@�@�.Wr8@�@�"{p<xoߜks@�@� @�@�hƃy^{n 9M  � �W$K:@�@�@ʫo3xqS � +]H � � rs\Ze@D뎳!� � JrWj � �D`szc)8 aH � K]H' � � *ʚZ[fw_K;F7) � � *rWI � �DWRvAAɴ.N@�@�h)@@R}@�@�R۳ъ1) � � JrWj � �\@y0Xiܬ˫!� � Y%K � � !5Ɠ㏾Su ϯC}@�@�wD � � )Y պ7+4(SG � �Xa@�@�@�Z*Kmk?MT]=,� � <A7!� � 50jqS � @g w.}#� � %˫|vl+_t51( � �t�y9 � �\J`[*cc#tcBKq@�@�\"@@F:A�@�@�xs)m;zv$ϔ˱@�@� 7ώq � �H"GnJиHs � �-@@� � �m |y<6,Y� � ;ݡ5@�@�@I=x9˫$rjC � �)@@ޙ� � �m nfy68� � Y%K � � pQ]Y=2@�@�%@@.i� � �{{h}*6Q@�@�@]: � � ` USҠ>@�@�%@@.i� � � DZO% � �-@@� � � � � -rTZuJ۸K 2M3MVlx#+<Yv?RЫu7[ Y y+ZSgKIwi5*ͳG@�@�@�@�@�<Z˒7Q̥NxkVJڌ-z8eJn_m 8EyUrZnܸt֚UZ:_Z@s[բv@�@�@%uuz{OWN6@�@�@KX}!O]\iӲy)v JzD E7!_x|r5Us5;OR~5Y8DMY;~vVNE�@�@� |xା.ேn⢞@�@� tI@ߙ\?2CVnԮҴ݃f;A'SH}|{Im,إyg-xN;JN߼Z3b1>=qYZJ`J � � :*]ckxL/s � �p@n9K昴Lߙ0o?T{sʣAw_hưP󘢒iz-=^ǫCTZr9?r xVSǔ@�@�@3OΜ}#� �x6e2!mNK5`Yr>iMMa Qܩg_CNcƅSkL%͍<xsz/٣� � � � � ]PŎJ8%f?pMB_IsrnHpJd<zzrIli)Ƴ&p$EC^Uc;~ � � յ-}"� � a.[Ѣo-jd_|EIWk\~ŢĦg*[!ٮub<3 72s6@�@�bjKw1sB2@�@�-y: 1$xęw*ԨЙn76*gYm)4� � �]"ɱ:wv�}]2.� � Uc< 8L:[e<CnR|.x10liCcZ]*:[yBzhyCUU v<#�|og�2G̯m}rCzmw9=W^\ :Oγg@bcQ\> W漰>EzWuY'̟YviqJڤ}sڎ)23NIQ>@�@�|e5Z8 \@�@# wntzk>kq C;y Ϫƺ%r_ĘOryW>@�@�@uB9{у8`@�@�7 tA@nQanN95,yq7 ր\J,[?R۾TJy7 iX;ͳ? r̊ 4 ix(v('\Lq1)!� =ںKwׇ[NÍ3==1^O<D.{ԅt� m'5M=*IOoҞtrr*ƑI /pxc/I|Mx^c,QnR'%5}5X<ͨO7xEpR4)u@�@�(ƃ-`<4c!褡:n� � @ ѶeOXJ֧|fM|\[9{5^R٢muoWF؏kge,-HϿhOg?X) � � `Ϳi{5 w8A~J6V}b-ZR,8j@�@�D[bX{~GZ_[Oтtz Twh.1n t+uXiR~Dw,d:Ii@~mwj棲O^x==7xa[TU[@�@�@�&-їw_~?~Z`ߞz"ed-:%4Q@�@�@ e9o~ڞ&4_4SG$W'ouG*4c>$K?[?G֩b6|zcF_T#��k>�2G̯3ήU9uxr6z`ܜ)$0a@|!�x Rӳl^p^-qkD8kp)O|xlXVTrp � �>(pB?&>AVC8'1:Fki]paa � ' t* S`[H'.NQ~whi~r[dGQ{ml)UVV^kjiZ oA#;Q  ж�ߣm۸EÖz'jWH?H2TCkH\: hh� N;'4JnGxtF5_~VwÍk5Oj*@�@�Q:19U0OuSq!9 � �.j=2~@�@�PZyRΖT96ah=:i_ƺ*l � �x�H� � @G<SPݧTes8=$_Ӯ?:TD8c@�@�o ;<@�@�h@}}ҿǵ93C4{͞BS� � 7 {d. � �!PVeћƓo8_*1.RsoI=5t @�@�Q*sB�@�@.]P?~׌5K+-.;@2T7댳!� � kvǙ/ � O<QwFƪ*[D =x 1=� � / f � �^-Pmho`|_n\EԷoJGpq*@�@�5r_@�@K,=K.T;o~ztP  � �� � )N(:䯯_74"&CgȰ@�@�\w@�@�\*PWWǵXS#CMuc"ÂS� � �MM@�@�%5Z)[0~i m[Fe w:N � �8 ;P� � @8~Lg,g*uWInjů1r6@�@��yǼh� � [9eT6s^t7ooߜNǩ@�@�@� ωV � �t@eM텛/m9Cg/8]op1B_Р�T � � @;Ek@�@�\.pRkgi͎,8'>2F2TFs8 � �\�q6 � �-Evdޡ =j z:c@�@�\#@@GzA�@�@]:v,t:gPT0XANǩ@�@�@� Β@�@�hSZ[OLIS=-~7UaC�@�@�N tb.� � ϖm'Ss״kIC566; � � o@�@�|L^7Q9M9>W0D~F @�@�Fkܹ* �  W['sƏ+s5^y5 w:N � �Wܽ\ @�@ N돟dOO0Crw?jp@�@�Z � �,ىd<-3wHxh~}s s< � �t nq � T[NF^zB{s=_O1Bgv@�@�n$ػ`( � �W*m)|rex?=6)A)#cg†� � �^"� � ЕNhZykbhICuupc � � @ "� �YXP|<X_c睮?"DLLЬ C38 � � q% � J+kSZ턲 ʝxޚ{KM�T � � g {b � � uL/;UV]p�?M7X_|p@�@�lrϾ@�@ =g[FźJ}cGÂ`dǃ!� � W{md � �Uo<St^zFrBS� � �#@@= � �\D Rl'UPV2ed5QuD1*@�@�@;Ƚ2+@�@�@Ʃ"a mO,u0q ͽ9AWE @�@�|Ln8E�@�|EgڕU4=m#t @�@� r߸@�-ԞSNs!!ʶc(8 � � [u- � >X=f/>..; � � }= � Uxp<$_L׼\P'@�@�@� ֓@�@�$p\>wF;ϳ U7_=pDvp@�@�<R#oF�@�|[`WV'" ^Q� � ��IA@�@-uZfPۼqh=f:n�ḃ; � � Ж�y[2#� �t;zcHz?SQ1ˀ@�@�@{ w@�@�ӎcz}h7~4Y<efdS@�@�@�:"@@-"� �U=*8]7yHfOw@�@�h�y{h� � VJfKjj;,Hw7y!� � �)@@~p� � й75!4Pw(`s@�@� 4@�@�OȻPm7߼NkS@�@�@�\!N@�@�W ɽ*˨`L@�@�p�OJ~@�@�HFi赝+iPF2) � � � w$ � �\ޜbm9`x ; � � *rWI � e Pof8~<"J_O#._NB�@�@�.%@@~)!#� �t@Ieg1ʫkm ׏6FWH@\N@�@�@�FF >@�@�&Pj_}aNW:\󩻮#㕛P � � ][ ﯿwYK?f|-|o2/HVUW+y=bjBm^֤Y:u4mj@�@�+{/@ � � @;ԷK|N]fI VC|=Mg8T:,^EzKf͍Mk]񨔒bVe  @[͟|mu& w XU?icg=jRP@�.Kb$@�9f[uᆱxq|fo+fk%qkȰOWSKki¦{Qx)@�@�\+pLfC8~O@͹eC8ګ � � ж@s= m\H3LË^PMڏf,vMU4M9QMOx\}߼|<iI*?k\>=FZ=*MK^x  � �.pଦvΗ=֫o^gS@�@�@�-m\d:۔x9N'ӴpSB~!{$% 1ʁ t 5J}j}7UܧЦJ3-?H MY͎QD�@�p U=u38@;Z~ � � �!\AJ$iM#h*XɃ{5:yn6q,XNhkc:]c,Rʃ^fS{ � �+vP=1I֥U@�@�@�hG!ҢWkQZGtTT5 s~62'i¹ި븽ԩIjv^+%<(7Ux@�@�v W[t,LG/hc7_Ցܧ� � �tK64sUcMOWЖȕ rk yqgɺzv([<3 /jO@�@�+((\ON/GPtqE39� � �S[䅙/+mB=KΗ){*>@yqVfV|FE糌aK7^@�@b5u-Ə-/I#م*(mQDhgc� � �@Ja4TO]I&Dr zmds)=Hw,nx|G@cRHf뚛=PUznnnO% `j[R*ire̻PuA! U|P%D5BN+; B�m@@lll*ypb澵8GUYZ𖫉jZbkǰSRrS9; � UXt2ϔ 3p ` VlD,k�oF8祚L @�@�MJmwtǂ5}B`+xcx.Os "2ĘO46tcC�@�EgXq2f ߶�a~[~=GQW#� � @€To<5I3_l\%\z#a*Y*KUZZr|Ja!MOp?%e͛傜,6GHHv`rQ@�45V7.!p@N>v#HipTk~Kkthsi G62 @�7w+)Zf$ʦ'w5%� 'e{2<V9fQ;JU҈e#� �UB٥=l, >..R{QJG{tNXT � � tI@~JJXfl&D7nSZV<.hAjv۲xMl-oKz|-YDo|}%; � @P ˛uD?>2FCzklld?   � �Y3/R1I|Lс=m IA?x6EVh5~RϵO}MKlvT䦷حTz==9|3OLϏ@�@ W(yg喘#[u@�@�@�7HgsGS}+,^EF|,Yw@&Ǖ<w8j[3Z]4%%<#=1R7( �NDB@`DZzyZUƚͷ~VOӼc|zc M&7a �t{})Ą5> .rv<j+-Z+)6K|xlX+6"xSKJ �  ?O׃/8!4O;ONp\@�@�|UO 07KXoG_G˪y Kdelv;mr�6`F�v )}gtLi猍C7Q굱n=mh�ߣ! 4=aQF1+~+w � *hᡁ~maEچJ@�@�@� xl@)@�5uolt ǭK24P$ThP@ C�@�@�<H܃nCE�@�+">Yh<U찮uӯWWFF+,yǝg � � Vw#@�ZwK7/=21^Lw&C�@�@�p� @�h+7k>aJ[tVP� � � Zrz � Ц/?<ںza2n-O6B~B< � � �#@@9� �, 8w/jٸtz&׸' � � @w:D�@�(ѱ2Ϳ`9wA+PIEӄ@�@�@�p�{ �xcut57ҪK.Gxc6@�@�@� Z� �&P~4^-w3@w(0kG;@�@�@3;S@�@kr*׿vcɔ`#Naѽ4,kԀN@�@�@ ȻK#� @8S\iݧC5Ŀ4P#{xLO[(>(*L~R@�@�@&@@@�@.p|k')j@#�C&WLD1v@�@�@�<KܳE�@�NH"GK .N>@�@�@=1\@�p@Mmzyۉ6;J_h#$gC�@�@�r️@�.C`GAJ2qT|0er  � � Ȼ-b � J2*3`Y)3q6@�@�@�_q% �>+PYS=E}H[ӎcew!!J̓* � � �/@@"� SF^h weնě S??p9 e@�@�@G}F3M@�|Aoz/9kE~4@�@�@�NrO @�3^P^²j?F̨?:дxs1WV)#� � ��x� @wEs!/2qy^!zx[ ~ފ jy4B�@�@�-rߺ@�n%P][on7u.@�@�@�Kܻ'A�@ T[t}yTsK:4ވAf V',X뾭8c,r � � �)@@Y#� 2)Oi_n-ϕb'rewTOknQ7!� � � "rA  �.`}桼R*2BBxR,ƴ= @�@�@�R+|@�ЪM u.}4/nDp]ݳ]@�@�@�W J~@�Aܢ =zwVgqvHoF ~WVD�@�@�p�:u+7C�@jjzmg6W}ģ{h|BDi||oTt  � � �Q;Ƅ� @7z䜞:_V4oߜ;ZANǨ@�@�@�@; wǻ˜@�Yq??i~{K&MGͰ@�@�@�h]uj@�@@~i}ʬqhk4(*̬� � � ' {b �t@eM^ٞߥQay9W%75( � � �x�'5ƌ� /|lza-2h]Vw? 3( � � � x3 �(`1ꅏ+JzgHҤA�@�@�@=1f@�:AĹ2xb]d]o'&7o�(#� � � {8 �W&pB>?Y' XeÂۇ[7%(4(a@�@�@�hr} @� *,ƃyFnY:b=Y=1^N^!u e@�@�@�_s/  �m TYjK긱J[[RFF(eTl � � �x�7]� !P__s) WH%ܐB0C�@�@�@g}V3Q@�_6QYW_X6e5 7M  � � �(@@w9#�x@N?>֖#:X:G˧8� � � >yۙ4 w?Uw? ?T蔸vN0]ٞOp3r=ujqw]i%u^��@�IDAT.?i訣R B {so@r/O='|7<7Nm;N? ;@� @�U@@>X{u @x@Majܐ{ @� @�m6 K @_ _C']82 @� & oD�Sƚ"NM2'1.] @� P&y�BϾ/oW!oWsY @� @�: ;B�R/p߽y@Q[k)㊶[!@� @�: ;B�R%z]C[_ZVCQ/pD,iz,vТ}V @� @�䝻J�Ω?f<*>F[?#*lm @� @@.`l&@�R`ϡG/ Ç /W]qv @� @�] Ȼ�];Ͻe#*F/M1˜ cڄEa^ @� @@佷S�/x>2m.f^_mB� @�9 ț퉿o?䚹 n9˫;gG<Ƴ%S?˜ô򂚎Ŏ͏ņg<G_1cll @y"]*ϋO];)S[!@� @�F`HsꛪzVˋr\]}_*o>0&;8n\hk~e8кtpG,Tu4վT[%UUU۷- @+wM/YsVm׎g~$,Fy J}tPu%@%@U% Hw?ZW-YlSg_ޑ_,բp|MQquucמ)*+ǫW&窉ḇvŬ @� 4^lp'<x x^ @�(9A߼cd|6;-K7O_]m򛢦eKu'd+j3U长FdV"=K͎u-+e2C1-{*W3RܣKcRUwƶo9 o/b�3 s&ϾZIY/}"^p~&vM@ ! @`@ y˱%7ɒMxFzؤ&7< _o逆=?Ȇիc[8;vV|e窖"ֿ}v!~5OJźmxYw~%Vgo_VR @@ 8nK ~뚧X/!C"n~qL"@� @�#P<*bꨪXGs_ȶƦl~ۼk?+;WӾi.״Dϕȼs'wGX&@�g#n~ekߛ~+ G7MVc>FT[Y @� ?kČqolgx02>pEk}mqݔIwĈ1:bCfn7R*R1s#ZS0>[8+>Z|eˋq`LÆ_}IWǦOɺ @� P~g;*nm<9rA\=)Ħ8@dc~xaxjKy{ @� ԾfY2bSȸÓ_~\Oc, @� @�HU@~l5~/F;Oįi^*‰#噞Ul'@�}*^Nm>8zx4*_wETwf7ӫS @�8 ȏf\^T{ȸtd9Nt|c.d|Eœ'[> eGp^͆dȉxWϵ̞W.ïzp`J},>Ǡ#@` .wI}@=0mŔV䍫Wm!Y8f]z} wE;_8?}wkr{~ cI�߉G3xׯ;�,3 Mcd @� @@q@۾iن.Z3[z}~uaX\>ף1A! <sظuZ @�3 ;?|XL-~b @� @�)8y}<~Ϝ,oy%tNOzD]$Dtgh7[raI&/;{1]s :ϟ, p?cu8 T?uz§ndqM Mx_L*,_8үc ,薀hD�.G� t+ ( ǫbSwb̮@F$_㧻ܹugD6kSٚIkQ Q\)jDꨜ>Nk 0^;v<뎽g~}Ȣ⺩Z$<~p Y!@� @�z.7E4rI<x~(opo#-lٽcj;ڕ:x(7}m1 Ӷ;UK~ mGWU?X {Uo\2Rs:�{% @� @� ys? kǞ-?ԟlۖ]:lGYfWVƆL}Y||\LYD3?٨kCKxƏDžO}7>wôd}ռd<zku% |wc_~'sϺrl0>2m|}6 @� @�S`Hs*gorLnrΣq٩Ww1Qwg+'b໿4* ClktϪ|sz~t0clhJJySq!՝LOFfM^דא!7N)1w] (hUOp]  @>՗wG4qX{╘q׺vAucnp<s +ΊtW~xl2�-yxc'Z$>Tμ@ G]1频w['@� @�@G[qHSTTD 3.&Os6eðw[<<h 莀;Qc2?9ÿbUFkUG}n^} @p  @ó_( G09fLaK'ai @@ޣxWnYfڔ/0|bkL}D\9~TrQq^r  @� пm@޿ٵ�Vh ͥqxc WM|_Q]gǿox74Iɽ @� @�A/ � zzd3%8-.̽E� @�膀H!@�t|>V<;屢Ew?8h @� @g�ι{5j_|ww?n=_L)ϓX @� @�z C  @| O_y#_x=2s^74^eiU-mN� @�艀'Z%@� 54ƽj/IH5eXsq @� @�z$   @5ē0zxХg3ƒ8;�@� @�X@@c2 @cwZc-/z;_aC_͙w%ϯ( g� @� pT�z%=]c3o @� @lg,Xbߑ7: :$lL̺ȴ=_ @� @@wݕrt[ wb7 y'e;1~/OuظH� @�譀r @@5NjK3veO~yxtnXx=*` @� @ VPy R5??'ȊbQ1 b bţ]ށ @� @�z 0U|eˋ]^aCcڄeCQI 38fD @� @�S@@^Nm"@@?hHFgN7W^{J.pD̞<eYoL -:  @� @ m @ %;?x'вwxQ@� @�H<=}(˯)_U噇 dqP8ޥ @� @@i!#@@-^sg*S#Wߙvq|䟍 GUtz @� @�" /=#O6ž7މ}Gމ#d?,1~~2$ƥqӌG!@� @�# OO_h L<g7>u+.%7&}LN @� @_ H>ui<Y0grL/k"=E� @�î�~-U ~ӏ3S\9nTLxTL<FvUv @� @.uA7Ɩy o#[BI|IC7&%@� @�IUH�Cևd&ӢHp!xGl[ @� @�wa8@a^_ǫo:C~ @� @@bS�* 3SdD鋑Ç +2seJ2'ecFe~n @� @;M B] @� @`^vt*?9 C #"hx\|4C@� @�8sZ@@JOM@L2e|{t(_դF- @� @�G@@z!>9[2{\E @� @�R$ OQgh  ;w� @� @g4}$ Ndi$x� @� @Ky4v ']8" ח> @� @�"  2E@ @� @�3 $d?OALNi$x.� @� @} Q@>{5 @� @�  5,d{8dyT4WSSS.NB @� @�Wιw @� @�T@@Ҏ,=( x'%#b$H)F+K� @� Џ4up wz @� @� Z K�ό�g$x$@� @� ywCgG1dȐ>U @� @�я"eBu @� @�D@@ M#U;SEcƜe ށ @� @�g% ?+>@&xއs_1nTĔ$ d:- @� @�R$ OQghʹj$d$ .?7 @� @�+ ﮔ@BP"O� @� 0䃰% jϺ. @� @�U% <pN|0%< @� @�H<e9 $Ƽ̃1} @� @�Aۇ{[F ?zlNp!o- @� @� Fy{e!dB>@i\ @� @�2 ˈ=O 3#Nb$| ~& @� @�^ Ex{ z f )v?9vq~gmNAҚŎ͏ņg=Oĭxluͥ 3|~wn @� @�N]|iiӀXlYqk=};W<3?X|!%a]wW]GYmǷ?l0 C/F @� @� R73i|g3_8W+c]$=ųG7GA^x,0]B @� @�$a{b}:Z׍;@m1XԁT|amuxʕ5NsҘx]R&V>Llv& @� @� pNڒ2~bM+zt_z){|eTN,,e_5ďQVfl-Ju,H}YMO}i~<'9G9ի647e.psP! @� @�@q\U.?F̾iY~[g |qgv'IhzӾlq%x+c/T)C2/pD 2,$ @� @�H@7R4bxDW.̚ מDӭsG쌚}9}LR.|q\? n:{Vϫ=sMd5E?nQY( |Hp!xi:P @� @�ks\X4/mkl[|a_$7yleyQȲ^htP> ;? \|A)B @� @� Y@S-Y$|1Yy^kZJ9qdYK{zn s#K1\p  @� @�-o_T{ƈ얛oLgCwb;c˒W%$~|,h|7FMGy*J:o,7$xEm_Wd'9p?:ޛ+P�s%psuj%@p"8ߩ  rI&o^ Gϼ3EC1l#bce?1+ }-bzO-0wOQў= @� @� K~^߰NܕOQa&Gu>y渳} VPy @� @�_M Q__u"L^l-qxuoSxh~1]s7th y1>GSd^:fD'ӡ䫵@ (3V4\2g->zք* @` o�O�:v9M>rsˡyBސ8:ZFIkbQ Q\)jDLuTNo מYV� @� @� 3l}mbDz%IݒuO_XԺXp?i cm1=⣬ @� @� @�7՟l|>pWe8T=x|l_Dnĥr+nxݱ'Rqlϓq"8| @� @� @`�2 q&޴<ObȊR1&fz_~M/Cr6.n** qW͋܄,dS,~l  @� @� 0Rjg~Ƃ$nmEiסx`m٥ +[DU=l :}g'D� @� @�D 793;؎Iڟ5W'R#ӪtVɴKc[ؿP+#7ccl`F� @� @�S 5yOyNJ6:&O3xOO� @� @�()V"k"@� @� @� 3E� @� @�%W @� @� VyZ{F @� @� @� @� @�* Okh @� @�T@@^R^ @� @� @@Zi"@� @� @� Kʫr @� @�H<=] @� @� PRyIyUN� @� @�ig� @� @�J* /)  @� @� @ v @� @� @@I%U9 @� @�U@@֞. @� @�(*'@� @� @� 3E� @� @�%W @� @� VyZ{F @� @� @� @� @�* Okh @� @�T@@^R^ @� @� @@Zi"@� @� @� Kʫr @� @�H<=] @� @� PRyIyUN� @� @�ig� @� @�J* /)  @� @� @ v @� @� @@I%U9 @� @�U@@֞. @� @�(*'@� @� @� 3E� @� @�%W @� @� VyZ{F @� @� @� @� @�* Okh @� @�T@@^R^ @� @� @@Zi"@� @� @� Kʫr @� @�H<=] @� @� PRyIyUN� @� @�ig� @� @�J* /)  @� @� @ v @� @� @@I%U9 @� @�U@@֞. @� @�(*'@� @� @� 3E� @� @�%W @� @� VyZ{F @� @� @JZ{*?xx5[]>gG<ƳL@| c Ӣ j:;6?jR/Dz1R]7 @� @�I[ob#5-Nq =r_Ēqt1ަ;b7FR}wEu4վTJ @� @� @H+ṂKc]muEćw|(_fSl\U-_{&}?_WWM[jb|X<{q<s]1 @� @� 0m@^'.^ȇcWdM.[ێ%=5g۪;c}m]\Y'6? n%~x[Z/+ka� @� @�9 o{(*ZM`۰z `;+sU\^VR4sˬ;ɷ/\34n @� @��, ?|7Ʈ-gUM/^X]ymOޙOs3TϏkFνs'w =� @� @�9 +'iuu ~¸f?Fvu\7Cҝ<sz̩Rw22McoԼTL'- @� @� @v.mǢyi;YjwulaĞy{ @� @� @�9AoANįi=qEgC;đCvrM @� @� 0X򞁏KMM$qԉNY}#\bE#;;}hnnv  p}@�p=;?  >{�4iRW~2<ԛuRc_C7k_/[ @� @� @�$ O<[GcWgqMlA\_y2  @� @� @`)V"Og{.̌ 0xioˇG˅%x[tګGoS5yCƻC?;sY @4q( Ѕh06 @݄r z~2<v;9T$k?OQ9C� @� @�@ ''cQVao<ygkǦg&/dKw0z$[jm1}D7 @� @�& bpekcO}2xӱ;vV՚6|>|ō;Df~c{;.R:2 @� @� @` 2 qsWn%پ]wW\5"TmযIͯ% n d.qW͋|%bE kL� @� @�P E, zX{XUc+u`ZyRf.\l]kFѱTSB� @� @�G`HsꏗSx8I>l̸<#cC-S$bcl7񪪪8tէ?ri3e8x`&M/[ @� vQJ}+  @@6z16:&OkN� @� @�H ES UB� @� @�4� @� @�J! /:  @� @� @ w @� @� @@)PU' @� @�^@@.@ @� @�($@� @� @� SEH� @� @�BU @� @� zyH  @� @� @R� @� @�R/ O}i  @� @�B@@^ Uu @� @� @@" $@� @� @�RKN @� @�H<] @� @� P y)TI� @� @�4� @� @�J! /:  @� @� @ w @� @� @@)PU' @� @�^@@.@ @� @�($@� @� @� SEH� @� @�BU @� @� zyH  @� @� @R� @� @�R/ O}i  @� @�B@@^ Uu @� @� @@" $@� @� @�RKN @� @�H<] @� @� P y)TI� @� @�4� @� @�J! /:  @� @� @ w @� @� @@)PU' @� @�^@@.@ @� @�($@� @� @� SEH� @� @�BU @� @� zyH  @� @� @R� @� @�R/ O}i  @� @�B@@^ Uu @� @� @@" $@� @� @�RKN @� @�H<] @� @� P y)TI� @� @�4� @� @�J! /:  @� @� @ w @� @� @@)ߎ8:u~̚1clKk:;6?jcKs>6]m3 @� @� v)r/XlYqk=};W<3?X|!%a]wW]GYmǷ?: @� @� <5JL]80?_WWM[jb|o.89_@� @� @�@_ j&):͍Xu"Y_:stXq^&Nl~ |Kص~IX32 @� @� @` ^HeTN,aÊF$mXѶ3fXH}YM/g� @� @�@ lo|2TwIM⧹ǫ5m˳F틲Ɠ뻨f @� @�h( ޞ5_r̿2dHumq7[z^etǓ}S>:'ߧ' @� @� @`` a_$7yle;kc#S_<bǚu'- @� @� @�7yӁl)-V$l-5cIvo:fJ9qd"]  @� @� @@^y= '?{y-Lܴu]_N,|gsYT&2!Ffދ8x`o+C pĝ >aT X}twK'@&Mt#~3|;1NpF{W\l3ӑWk_/[ @� @� @�& oa1btgի=Z, 7eyfc}]c~_B8/ @� @�|fL^F o [?W[.[TtqС!\8@៱o.t!>覀h7F�^ߌ 91n1eÝ۱ ed1;3 ycDuTNo س @� @� @�7٤;鈍ݡ;z,۞ݼ$ [1 Z7w0z$趘>u  @� @� @` O}6?*Gᆦx/W{k="r,(Ə{")<w\>/r/  @� @� 0M@>lMbȊR1&fz_~M/Cr6.n**]5/rĒM:, @� @� @7y+f,x8JVzrQlu(X0m[viµ5QaO5[nN6 @� @� @�Do.gҬgdƈc iU:isƶƅ)V"9zcl`F� @� @�Sn;) s+}6:&O3xwG� @� @�,ЯX @� @� @z; @� @�D@@  @� @�(F� @� @�)#4� @� @�+ / @� @� @@J) @� @� @� l @� @� yJ:B3 @� @� @z; @� @�D@@  @� @�(F� @� @�)#4� @� @�+ / @� @� @@J) @� @� @� l @� @� yJ:B3 @� @� @z; @� @�D@@  @� @�(F� @� @�)#4���(IDAT @� @�+ / @� @� @@J) @� @� @� l @� @� yJ:B3 @� @� @z; @� @�D@@  @� @�(F� @� @�)#4� @� @�+ / @� @� @@J) @� @� @� l @� @� yJ:B3 @� @� @z; @� @�D@@  @� @�(F� @� @�)#4� @� @�+ / @� @� @@J) @� @� @� l @� @� yJ:B3 @� @� @z; @� @�D@@  @� @�(F� @� @�)#4� @� @�+ / @� @� @@J) @� @� @� l @� @� yJ:B3 @� @� @z; @� @�D@@  @� @�(F� @� @�)#4� @� @�+0;gk:6QS{㊹sw,ica� @� @�Ήț?:ñ=qMM<26(ΔN� @� @�,0Xu{6>[/c  @� @� 0|@~x_ǃEY^K 7n7nL� @� @�\` oWԅkv=_XQoqH+ @� @� 0v@|N<^:n5?'˗WmQ{m @� @� h']W_}cGSIk 򨍗^-:e @� @�`< xnk{'ۭW[J� @� @�V`@ vdžv]gv V  @� @� 0Hf�(#o`99ȑ#=(Po @ l'@` �O�ƏAg@䣧fT'Y̩Ax۷  ^f�z*>S1 @X}J`@1AޕJ'6 @� @� ЏQ_9cGthoؿ/(L� @� @�.05=\5gfE~E1{£- @� @� @�iQ:3 y!V>8Mă͙%1}D @� @� 04'|M)W<^?9� @� @�AѰ b%ni$@� @� @@yfݹ6^ٺ&:kg^fW& @� @� `?JQ5D1bbrY!@� @� @`\`UI� @� @�gSQ @� @� 0䃮]0 @� @�de@MM ׹4]3M ѢܸͫvV єtf oGmi8J.1 m(9t''9țǶ ccԩq|޸b bNڲ>vo8^zx詳qr Es3GTۖFS{&G&V끘9*Ɠx;ٺTO̟r64~1w?x=k>yV+tz"j_,Kc{vcn<H�q'>00- u}=^w-|xǗc7FMbbCͳ-fG$>0qmcm8]{yX.ڊc{Ov뙖%KG 晓r5%)jѣc㺏}*|jnLCvL;(@Kp#{VŲ).wǴ~Nm;%pMϣM?x1o?1nV̟;Qo(U 0z}ym~xQ1u{mbat{b7bLknx`΋3sAmIƔy=5XxmP˞N|C;D4'UwUټh36/mK7XeˡVSq[VV揉nY᠖ '^XSp\WP646\U.ZӼ]{Wt9ݽ޵TV@cSu%trp]krutUPۿi<TN]܊!9-͕-jޚɽPsɱ7vr?,_ӵ/sW@@iwhmhgأπ\4/+W;}/>_~=Zt;$?W? <L5K *o:@M6h9Wgޙ[O1Œ d)Dk^h󚪮m^rK'wsUUo5:vSyW;Ƕ탷cphBzB_rww+>5}%Px[[fSsU;Os/| ?$:;-.Fڙ!j^U͛4^vi[yOܜT�_W>?8T-YaKU*r5}+W7lԼjIS]5 }(P@[G,2K= h-֟5U|Vkhy4k~&mϮ^7D>ܷeUNJG;. ygf S,ژ]* V7߿zUvxUo'N]V6XB jj^ySp}x<Uw!پ|gm8PeU-oޘ]w0ϵ7~}sY ЧtUW nQGwEJ^i^NܘY?E+kn ΂^!MKZKH'7.ݧ-ſk<:3okws2-/_̪k5K6P n� >ќDޫπ=S.>_~ jUd�`ccczٿ�,Л߼je`LPuʾ]1L> \UA_waqy[ؓC^}hkHШ@v.NeOKWl7,΂hy+-וS<2 f'wDs]]].s ngכ)R2eVL;K=^/r/}/PٍζiȾmr\Yˇӝ}-ehmh>Qd%Iӻ,T#[cbB[*Wu1w { >ڊπLϐ9�"}.>L'RjreT}MBzuYYՒ{TLt\6 e(]{gՖz̵Wybzw&}V8=s7 ۷ -}~.^ݫYWPjuܖ}\L1'_Gk-qͪʶ'?<_e Gm8mY;1y'xg|5?vT#bdEE<. &uֆ{*J*?{QX oY_DϯWb[6_ϼk?IpzmO:+ܱkz ssj>i_tCD686nϵxrw[+z׆乛/?X9aE\TUɭrG>w6%VP6Ʀ|{LJ!GcQ_@@9v_hɧ@<z[]/OFȋ�s&>O~|O~ʝ$'&@`@ 2n)]&?_(SɃ>䝹gzyg4o(c~g_j_}ѺŸ<K򤊶(Y3by?7 ?|wL˄M gXYtQbhOvyѪMQ*l?E.Yr퐨92**_R;kÈ c[ss21NO]X$<>Km. >8~lMqݔNnN#ǜ\nPw2 V O\5^Lh[X|lfm SZhJkżLa)_= 3zՆ۳nK>-36Ƕ5cw̟m)}je|VI3f[Ƃ&5ep|s/,2~R|U滳{/g\KuZ @$s|䢏'v>_^:?2$$_ν#z\NH�(HΘw䝅m+.`~`afkΟDZœdQlںac'g;-׳hnT#=$_}=^:^'MG/>Yӽ|UJ3=zva1rqe,m߼<_&Ţc뿽+Θ/m;.PcE-ju˒bCq cnCbD2꼰ǞY7ݗH(L3ޞ[8@ʶ1M- ›̥EҶc*vDı rWZu6=&|^iCI6_][ (_[mşGrњ[m, ao>/>}kĽOpRKY}?<z'/{nxK1u<Ix @΂|gw#,KC -Wq$0N~, ܡ 4LsdveQ ypE2MٙH ܶn7\8ҳ[$~N] \^s%1kr.w>wۤ`O6UC֎Kg>*6G1]c̖]E;V{׻-jDvtx#T~4Ͼdʕ7ƴq'p]KOSv[~OV[c/'޸,ܪ_;bhx!lk揄_*~֏M)?%(}}l`<xKu3gI>xT,}">~m~V0-%O^79X";d}qWD;AI|hǟClNfiSmu(I!YFUF@?RFeSKeƐ?<H=ʔz:\ʤʨ2xT&)JkMsߧIw: غ{Wܫ@$:]{Ϥڵnr{ TתY!)B7'\ORB&A.g</\2zU7R0:L}}tŐX<=J:#ev1)ҹׯUP`q|'U ӯ_s#R@#:hǮRĝ;F@Sul򕶍_-y|[q$e$xuo#3<P|DZO*}pF7 }t|."vA�V@�h39;(w#ɟގl&gpO�~tG˔DQ<4.gcq*n  x5wY5+Upo M&hnfX6OLҎM{Νj7#1ӝ[\ײ*M?NN44EjGa_(R>TR<OxzށA:Rzʼfڰo49¾W 6xЈ} fh >mߣtqrG >VR{9>Wdo㛒O?b;zK,?Z OӅScq Y'΍ӧ%&'/^yٓy!fc�VQ-tu</&ԀS\Bɷ׿Q  *Itȿ݋d{1ć\lR3� x5wv7ohj-wv>hԦ~?t^7goZ /GʚW͒jh&Jo1ֺ*Z0zz:ЮWFʭ5fíw-*,oQ9#а}βElh@zT.Of&%ׅ+yM|t jޮ /䭍1u teII~5ҕq;sc[(<b綁C]{*@�<'Z?�?*f+~3+1qb'_pKc ?5vS uI�~ԺYWo+3 |J1E!�8#^ל޹iQ+ugѬaS7_ƭˤ}{XS2#~~,m M-d>O3t?;G'V$jXi՗dTB@m*v>6sz Lvm3voO&₀*!OZ@ե|(ghN~6.-AD/疙2 jx3_i~$+x Vғ.Nәcʌ[%}1mw2070~M:sD7Jh6@�<$:?�?J܇6k~g-^οDq:d=�/ iha@bwSOJٰ3�ܩtzA/zxw+mչ+5g]zx(SE5^Qd(kb_Wŧ麢{_β|\׎oIO bNUYQ곺/JdGu(ҾО& _R:ib|1,׳p~ӪWbPSsYpM`i/_Y)O<t\ dJ~$[i< j+)%ON_7SR١lJƏxb\Mq\̨en#>;@ߍg'^:a �hfC[wPO)? o2 A�d*.Mi;I}VͫɛQRB  �;޳`n)}S=?CU?輗)~C'4"T3xڜ&D$(p _`$.䄲V*bBQ.'Ca.WQ *9|lH FSu-NECj|~+ <. ÓlRul( !cJD4"D"_x4"d$n髡׭/̍}JO ("]5e>=9kOE:'sC\٘N<_7)}wh⇪sBl#FR>CsUYMjCB"W:EbJk' )ʼneH@{є}[ɰ <Q5t*U_R'GU?x^!PՆ@Su0 Xu%an9i<H^su'g0J>6./i!az>/3:shLV4VN䛕rӲ '4񩜎7FT(Ć|aThyK | ,`ԆNJ*~VmS.* a I|rNnzz8PYl/Dg+rS:aXCV fT=6Y=(arrBFUHTHf'? 3\:)e_zX,Z�A �Mhl6݂BmHQfeANf#[ aTA-WzA ppywN,YW<4@N|/iV4RM b6 H ?WF[ ERtho~jGa-(L6[džt|aq\,'" n)zm> |)wn&& ~=_jQAΌuVds +O->5=gH= �^Xq?�?}Ⱦ#ȍ/t8  !QaMGsUokP栎{xq +�;yvbu޼X Ȇk\T䄭$7"3%99wq81NQ9zA2O?x8 Y%h2W2\U^Q#SoظIgL'Y/C.h::>VoPRtKgCt'w\V6c,':xqVN 0L: 2{M O4{V>e翦)?^3aG6}Q2[qF:+ܴ+OmMf)[4I�,݇Νr YwT �M5ms jG1~p�Iu]Lz;35[HNZ]'~PөC=Uw>r@˼V.V[ˋkutKhYZ2mQo#VrsO=ö/l|Vs9-?DTX (s{"mk;k6vV=*}_xkn_/uy.qҷي׋ 'Z~h!11#H �X?�?ڂC ��hs 2,lG%͡5G-H!@KD,~e}Kbz{S7^z09֘ĭ1@Hi � � � � � � � � � �@Sz ����������pD�#\  � � � � � � � � � ^@ _/-z����������8"�.D���������X/ D=@�@�@�@�@�@�@�@�@�@�@"����������KK � � � � � � � � � �@ w A�@�@�@�@�@�@�@�@�@� %Q����������G ;… � � � � � � � � � ��Ғ���������#Bd����������B�ziI@�@�@�@�@�@�@�@�@�@`/r����IENDB`���������������������������������������������������������������������haskell-mode-17.1/inf-haskell.el��������������������������������������������������������������������0000664�0000000�0000000�00000024457�13602233217�0016541�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; inf-haskell.el --- Interaction with an inferior Haskell process -*- lexical-binding: t -*- ;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. ;; Copyright (C) 2017 Vasantha Ganesh Kanniappan <vasanthaganesh.k@tuta.io> ;; Author: Stefan Monnier <monnier@iro.umontreal.ca> ;; Keywords: Haskell ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; A major mode for the buffer that holds the inferior process ;; Todo: ;; - Check out Shim for ideas. ;; - i-h-load-buffer and i-h-send-region. ;;; Code: (require 'comint) (require 'shell) ; For directory tracking. (require 'etags) (require 'compile) (require 'haskell-decl-scan) (require 'haskell-cabal) (require 'haskell-customize) (require 'cl-lib) (require 'haskell-string) ;;;###autoload (defgroup inferior-haskell nil "Settings for REPL interaction via `inferior-haskell-mode'" :link '(custom-manual "(haskell-mode)inferior-haskell-mode") :prefix "inferior-haskell-" :prefix "haskell-" :group 'haskell) (defcustom inferior-haskell-hook nil "The hook that is called after starting inf-haskell." :type 'hook) (defun haskell-program-name-with-args () "Return the command with the arguments to start the repl based on the directory structure." (cl-ecase (haskell-process-type) ('ghci (cond ((eq system-type 'cygwin) `("ghcii.sh" ,@haskell-process-args-ghci)) (t (append (if (listp haskell-process-path-ghci) haskell-process-path-ghci (list haskell-process-path-ghci)) haskell-process-args-ghci)))) ('cabal-repl `(,haskell-process-path-cabal "repl" ,@haskell-process-args-cabal-repl)) ('stack-ghci `(,haskell-process-path-stack "ghci" ,@haskell-process-args-stack-ghci)))) (defconst inferior-haskell-info-xref-re "-- Defined at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)\\(?:-\\([0-9]+\\)\\)?$") (defconst inferior-haskell-module-re "-- Defined in \\(.+\\)$" "Regular expression for matching module names in :info.") (defvar inferior-haskell-multiline-prompt-re "^\\*?[[:upper:]][\\._[:alnum:]]*\\(?: \\*?[[:upper:]][\\._[:alnum:]]*\\)*| " "Regular expression for matching multiline prompt (the one inside :{ ... :} blocks).") (defconst inferior-haskell-error-regexp-alist `(;; Format of error messages used by GHCi. ("^\\(.+?\\):\\([0-9]+\\):\\(\\([0-9]+\\):\\)?\\( \\|\n *\\)\\([Ww]arning\\)?" 1 2 4 ,@(if (fboundp 'compilation-fake-loc) '((6) nil (5 '(face nil font-lock-multiline t))))) ;; Runtime exceptions, from ghci. ("^\\*\\*\\* Exception: \\(.+?\\):(\\([0-9]+\\),\\([0-9]+\\))-(\\([0-9]+\\),\\([0-9]+\\)): .*" 1 ,@(if (fboundp 'compilation-fake-loc) '((2 . 4) (3 . 5)) '(2 3))) ;; GHCi uses two different forms for line/col ranges, depending on ;; whether it's all on the same line or not :-( In Emacs-23, I could use ;; explicitly numbered subgroups to merge the two patterns. ("^\\*\\*\\* Exception: \\(.+?\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\): .*" 1 2 ,(if (fboundp 'compilation-fake-loc) '(3 . 4) 3)) ;; Info messages. Not errors per se. ,@(when (fboundp 'compilation-fake-loc) `(;; Other GHCi patterns used in type errors. ("^[ \t]+at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)$" 1 2 (3 . 4) 0) ;; Foo.hs:318:80: ;; Ambiguous occurrence `Bar' ;; It could refer to either `Bar', defined at Zork.hs:311:5 ;; or `Bar', imported from Bars at Frob.hs:32:0-16 ;; (defined at Location.hs:97:5) ("[ (]defined at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\))?$" 1 2 3 0) ("imported from .* at \\(.+\\):\\([0-9]+\\):\\([0-9]+\\)-\\([0-9]+\\)$" 1 2 (3 . 4) 0) ;; Info xrefs. (,inferior-haskell-info-xref-re 1 2 (3 . 4) 0)))) "Regexps for error messages generated by inferior Haskell processes. The format should be the same as for `compilation-error-regexp-alist'.") (defconst haskell-prompt-regexp ;; Why the backslash in [\\._[:alnum:]]? "^\\*?[[:upper:]][\\._[:alnum:]]*\\(?: \\*?[[:upper:]][\\._[:alnum:]]*\\)*\\( λ\\)?> \\|^λ?> $") ;;; TODO ;;; -> Make font lock work for strings, directories, hyperlinks ;;; -> Make font lock work for key words??? (defvaralias 'inferior-haskell-mode-map 'inf-haskell-map) (defvar inf-haskell-map (let ((map (make-sparse-keymap))) (define-key map "\C-c\C-d" 'comint-kill-subjob) map)) (define-derived-mode inferior-haskell-mode comint-mode "Inf-Haskell" "Major mode for interacting with an inferior Haskell process." :group 'inferior-haskell (setq-local comint-prompt-regexp haskell-prompt-regexp) (setq-local paragraph-start haskell-prompt-regexp) (setq-local comint-input-autoexpand nil) (setq-local comint-prompt-read-only t) ;; Setup directory tracking. (setq-local shell-cd-regexp ":cd") (condition-case nil (shell-dirtrack-mode 1) (error ;The minor mode function may not exist or not accept an arg. (setq-local shell-dirtrackp t) (add-hook 'comint-input-filter-functions 'shell-directory-tracker nil 'local))) ;; Setup `compile' support so you can just use C-x ` and friends. (setq-local compilation-error-regexp-alist inferior-haskell-error-regexp-alist) (setq-local compilation-first-column 0) ;GHCI counts from 0. (if (and (not (boundp 'minor-mode-overriding-map-alist)) (fboundp 'compilation-shell-minor-mode)) ;; If we can't remove compilation-minor-mode bindings, at least try to ;; use compilation-shell-minor-mode, so there are fewer ;; annoying bindings. (compilation-shell-minor-mode 1) ;; Else just use compilation-minor-mode but without its bindings because ;; things like mouse-2 are simply too annoying. (compilation-minor-mode 1) (let ((map (make-sparse-keymap))) (dolist (keys '([menu-bar] [follow-link])) ;; Preserve some of the bindings. (define-key map keys (lookup-key compilation-minor-mode-map keys))) (add-to-list 'minor-mode-overriding-map-alist (cons 'compilation-minor-mode map)))) (add-hook 'inferior-haskell-hook 'inferior-haskell-init)) (defvar inferior-haskell-buffer nil "The buffer in which the inferior process is running.") (defun inferior-haskell-start-process () "Start an inferior haskell process. With universal prefix \\[universal-argument], prompts for a COMMAND, otherwise uses `haskell-program-name-with-args'. It runs the hook `inferior-haskell-hook' after starting the process and setting up the inferior-haskell buffer." (let ((command (haskell-program-name-with-args))) (when inferior-haskell-root-dir (setq default-directory inferior-haskell-root-dir)) (setq inferior-haskell-buffer (apply 'make-comint "haskell" (car command) nil (cdr command))) (with-current-buffer inferior-haskell-buffer (inferior-haskell-mode) (run-hooks 'inferior-haskell-hook)))) (defun inferior-haskell-process () "Restart if not present." (cond ((and (buffer-live-p inferior-haskell-buffer) (comint-check-proc inferior-haskell-buffer)) (get-buffer-process inferior-haskell-buffer)) (t (inferior-haskell-start-process) (inferior-haskell-process)))) ;;;###autoload (defalias 'run-haskell 'switch-to-haskell) ;;;###autoload (defun switch-to-haskell () "Show the inferior-haskell buffer. Start the process if needed." (interactive) (let ((proc (inferior-haskell-process))) (pop-to-buffer-same-window (process-buffer proc)))) (defvar inferior-haskell-result-history nil) (defvar haskell-next-input "" "This is a temporary variable to store the intermediate results while `accecpt-process-output' with `haskell-extract-exp'") (defun haskell-extract-exp (str) (setq haskell-next-input (concat haskell-next-input str)) (if (with-temp-buffer (insert haskell-next-input) (re-search-backward haskell-prompt-regexp nil t 1)) (progn (push (substring haskell-next-input 0 (1- (with-temp-buffer (insert haskell-next-input) (re-search-backward haskell-prompt-regexp nil t 1)))) inferior-haskell-result-history) (setq haskell-next-input "")) "")) (defun inferior-haskell-no-result-return (strg) (let ((proc (inferior-haskell-process))) (with-local-quit (progn (add-to-list 'comint-preoutput-filter-functions (lambda (output) (haskell-extract-exp output))) (process-send-string proc strg) (accept-process-output proc) (sit-for 0.1) (setq comint-preoutput-filter-functions nil))))) (defun inferior-haskell-get-result (inf-expr) "Submit the expression `inf-expr' to ghci and read the result." (let* ((times 5)) (inferior-haskell-no-result-return (concat inf-expr "\n")) (while (and (> times 0) (not (stringp (car inferior-haskell-result-history)))) (setq times (1- times)) (inferior-haskell-no-result-return (concat inf-expr "\n"))) (haskell-string-chomp (car inferior-haskell-result-history)))) (defun inferior-haskell-init () "The first thing run while initalizing inferior-haskell-buffer" (with-local-quit (with-current-buffer inferior-haskell-buffer (process-send-string (inferior-haskell-process) "\n") (accept-process-output (inferior-haskell-process)) (sit-for 0.1)))) (defvar haskell-set+c-p nil "t if `:set +c` else nil") (defun haskell-set+c () "set `:set +c` is not already set" (if (not haskell-set+c-p) (inferior-haskell-get-result ":set +c"))) (provide 'inf-haskell) ;;; inf-haskell.el ends here �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/logo.svg��������������������������������������������������������������������������0000664�0000000�0000000�00000002660�13602233217�0015473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="481.8897pt" height="340.1574pt" viewBox="0 0 481.8897 340.1574" version="1.1"> <defs> <clipPath id="clip1"> <path d="M 0 340.15625 L 481.890625 340.15625 L 481.890625 0 L 0 0 L 0 340.15625 Z M 0 340.15625 "/> </clipPath> </defs> <g id="surface0"> <g clip-path="url(#clip1)" clip-rule="nonzero"> <path style=" stroke:none;fill-rule: nonzero; fill: rgb(40%,40%,40%); fill-opacity: 1;" d="M 0 340.15625 L 113.386719 170.078125 L 0 0 L 85.039062 0 L 198.425781 170.078125 L 85.039062 340.15625 L 0 340.15625 Z M 0 340.15625 "/> <path style=" stroke:none;fill-rule: nonzero; fill: rgb(60%,60%,60%); fill-opacity: 1;" d="M 113.386719 340.15625 L 226.773438 170.078125 L 113.386719 0 L 198.425781 0 L 425.195312 340.15625 L 340.15625 340.15625 L 269.292969 233.859375 L 198.425781 340.15625 L 113.386719 340.15625 Z M 113.386719 340.15625 "/> <path style=" stroke:none;fill-rule: nonzero; fill: rgb(40%,40%,40%); fill-opacity: 1;" d="M 387.402344 240.945312 L 349.609375 184.253906 L 481.890625 184.25 L 481.890625 240.945312 L 387.402344 240.945312 Z M 387.402344 240.945312 "/> <path style=" stroke:none;fill-rule: nonzero; fill: rgb(40%,40%,40%); fill-opacity: 1;" d="M 330.710938 155.90625 L 292.914062 99.214844 L 481.890625 99.210938 L 481.890625 155.90625 L 330.710938 155.90625 Z M 330.710938 155.90625 "/> </g> </g> </svg> ��������������������������������������������������������������������������������haskell-mode-17.1/tests/����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�13602233217�0015150�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-c2hs-tests.el�������������������������������������������������������0000664�0000000�0000000�00000026005�13602233217�0021115�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;; haskell-c2hs-tests.el --- -*- lexical-binding: t; -*- (require 'ert) (require 'haskell-c2hs) (require 'haskell-test-utils) (ert-deftest haskell-c2hs-basic-import-hook () "C2HS import hook" (check-properties '("{# import Foo #}") '(("{#" t haskell-c2hs-hook-pair-face) ("import" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-qualified-import-hook () "C2HS qualified import hook" (check-properties '("{#import qualified Foo #}") '(("{#" t haskell-c2hs-hook-pair-face) ("import" "w" haskell-c2hs-hook-name-face) ("qualified" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-full-context-hook () "C2HS full context hook" (check-properties '("{# context lib = \"libgtk.so\" prefix = \"gtk\" add prefix = \"CGtk\" #}") '(("{#" t haskell-c2hs-hook-pair-face) ("context" "w" haskell-c2hs-hook-name-face) ("lib" "w" haskell-c2hs-hook-name-face) ("prefix" "w" haskell-c2hs-hook-name-face) ("add" "w" haskell-c2hs-hook-name-face) ("prefix" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-type-hook () "C2HS type hook" (check-properties '("{# type gint #}") '(("{#" t haskell-c2hs-hook-pair-face) ("type" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-sizeof-hook () "C2HS sizeof hook" (check-properties '("{# sizeof double #}") '(("{#" t haskell-c2hs-hook-pair-face) ("sizeof" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-enum-hook () "C2HS enum hook" ;; note that this has multiline constructs that do not work reliably at this point :expected-result :failed (check-properties '("{#enum v4l2_quantization as Quantization" " { V4L2_QUANTIZATION_DEFAULT as Default" " , V4L2_QUANTIZATION_FULL_RANGE as FullRange" " , V4L2_QUANTIZATION_LIM_RANGE as LimitedRange" " }" " deriving (Show, Eq, Ord)" " #}") '(("{#" t haskell-c2hs-hook-pair-face) ("enum" "w" haskell-c2hs-hook-name-face) ("as" "w" haskell-c2hs-hook-name-face) ("Quantization" "w" haskell-constructor-face) ("V4L2_QUANTIZATION_DEFAULT" "w" haskell-constructor-face) ("Default" "w" haskell-constructor-face) ("V4L2_QUANTIZATION_FULL_RANGE" "w" haskell-constructor-face) ("FullRange" "w" haskell-constructor-face) ("V4L2_QUANTIZATION_LIM_RANGE" "w" haskell-constructor-face) ("LimitedRange" "w" haskell-constructor-face) ("deriving" "w" haskell-keyword-face) ("Show" "w" haskell-constructor-face) ("Eq" "w" haskell-constructor-face) ("Ord" "w" haskell-constructor-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-enum-define-hook () "C2HS enum define hook" ;; note that this has multiline constructs that do not work reliably at this point :expected-result :failed (check-properties '("{#enum define MMapProtectionFlag" " { PROT_READ as ProtRead" " , PROT_WRITE as ProtWrite" " , PROT_EXEC as ProtExec" " , PROT_NONE as ProtNone" " }" " deriving (Show, Eq, Ord)" " #}" ) '(("{#" t haskell-c2hs-hook-pair-face) ("enum" "w" haskell-c2hs-hook-name-face) ("define" "w" haskell-c2hs-hook-name-face) ("MMapProtectionFlag" "w" haskell-constructor-face) ("PROT_READ" "w" haskell-constructor-face) ("ProtRead" "w" haskell-constructor-face) ("PROT_WRITE" "w" haskell-constructor-face) ("ProtWrite" "w" haskell-constructor-face) ("PROT_EXEC" "w" haskell-constructor-face) ("ProtExec" "w" haskell-constructor-face) ("PROT_NONE" "w" haskell-constructor-face) ("ProtNone" "w" haskell-constructor-face) ("deriving" "w" haskell-keyword-face) ("Show" "w" haskell-constructor-face) ("Eq" "w" haskell-constructor-face) ("Ord" "w" haskell-constructor-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-pure-call-hook () "C2HS pure call hook" (check-properties '("sin :: Float -> Float" "sin = {#call pure sin as \"_sin\"#}") '(("sin" "w" haskell-definition-face) ("::" t haskell-operator-face) ("Float" "w" haskell-type-face) ("->" t haskell-operator-face) ("Float" "w" haskell-type-face) ("sin" "w" haskell-definition-face) ("=" t haskell-operator-face) ("{#" t haskell-c2hs-hook-pair-face) ("call" "w" haskell-c2hs-hook-name-face) ("pure" "w" haskell-c2hs-hook-name-face) ("as" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-unsafe-call-hook () "C2HS unsafe fun hook" (check-properties '("{#fun unsafe sin as ^#}") '(("{#" t haskell-c2hs-hook-pair-face) ("fun" "w" haskell-c2hs-hook-name-face) ("unsafe" "w" haskell-c2hs-hook-name-face) ("as" "w" haskell-c2hs-hook-name-face) ("^" t font-lock-negation-char-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-pure-fun-hook () "C2HS pure call hook" (check-properties '("{#fun pure sin as \"_sin\"#}") '(("{#" t haskell-c2hs-hook-pair-face) ("fun" "w" haskell-c2hs-hook-name-face) ("pure" "w" haskell-c2hs-hook-name-face) ("as" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-unsafe-fun-hook () "C2HS unsafe fun hook" (check-properties '("{#fun unsafe sin as ^#}") '(("{#" t haskell-c2hs-hook-pair-face) ("fun" "w" haskell-c2hs-hook-name-face) ("unsafe" "w" haskell-c2hs-hook-name-face) ("as" "w" haskell-c2hs-hook-name-face) ("^" t font-lock-negation-char-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-get-hook () "C2HS get hook" (check-properties '("visualGetType :: Visual -> IO VisualType" "visualGetType (Visual vis) = liftM cToEnum $ {#get Visual->type#} vis") '(("visualGetType" "w" haskell-definition-face) ("::" t haskell-operator-face) ("Visual" "w" haskell-type-face) ("->" t haskell-operator-face) ("IO" "w" haskell-type-face) ("VisualType" "w" haskell-type-face) ("visualGetType" "w" haskell-definition-face) ("Visual" "w" haskell-constructor-face) ("=" t haskell-operator-face) ("$" t haskell-operator-face) ("{#" t haskell-c2hs-hook-pair-face) ("get" "w" haskell-c2hs-hook-name-face) ("Visual" "w" haskell-constructor-face) ("->" t haskell-operator-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-set-hook () "C2HS set hook" (check-properties '("{#set sockaddr_in.sin_family#} addr_in (cFromEnum AF_NET)") '(("{#" t haskell-c2hs-hook-pair-face) ("set" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face) ("AF_NET" "w_" haskell-constructor-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-pointer-hook-1 () "C2HS pointer hook" (check-properties '("{#pointer *GtkObject as Object foreign newtype#}") '(("{#" t haskell-c2hs-hook-pair-face) ("pointer" "w" haskell-c2hs-hook-name-face) ("*" t haskell-c2hs-hook-name-face) ("GtkObject" "w" haskell-constructor-face) ("as" "w" haskell-c2hs-hook-name-face) ("Object" "w" haskell-constructor-face) ("foreign" "w" haskell-c2hs-hook-name-face) ("newtype" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-pointer-hook-2 () "C2HS pointer hook" (check-properties '("{# pointer point as PointPtr -> Point #}") '(("{#" t haskell-c2hs-hook-pair-face) ("pointer" "w" haskell-c2hs-hook-name-face) ("PointPtr" "w" haskell-constructor-face) ("->" t haskell-operator-face) ("Point" "w" haskell-constructor-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-full-pointer-hook () "C2HS full pointer hook" (check-properties '("{#pointer * foo_t as FooPtr stable -> MkFooPtr nocode#}") '(("{#" t haskell-c2hs-hook-pair-face) ("pointer" "w" haskell-c2hs-hook-name-face) ("*" t haskell-c2hs-hook-name-face) ("as" "w" haskell-c2hs-hook-name-face) ("FooPtr" "w" haskell-constructor-face) ("stable" "w" haskell-c2hs-hook-name-face) ("MkFooPtr" "w" haskell-constructor-face) ("nocode" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-class-hook () "C2HS class hook" (check-properties '("{# class GtkObjectClass => GtkWidgetClass GtkWidget #}") '(("{#" t haskell-c2hs-hook-pair-face) ("class" "w" haskell-c2hs-hook-name-face) ("GtkObjectClass" "w" haskell-type-face) ("=>" t haskell-operator-face) ("GtkWidgetClass" "w" haskell-type-face) ("GtkWidget" "w" haskell-type-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-alignof-hook () "C2HS alignof hook" (check-properties '("gIntAlign :: Int" "gIntAlign = {#alignof gint#}") '(("gIntAlign" "w" haskell-definition-face) ("::" t haskell-operator-face) ("Int" "w" haskell-type-face) ("gIntAlign" "w" haskell-definition-face) ("=" t haskell-operator-face) ("{#" t haskell-c2hs-hook-pair-face) ("alignof" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-offsetof-hook () "C2HS offsetof hook" (check-properties '("{#offsetof struct_t->somefield#}") '(("{#" t haskell-c2hs-hook-pair-face) ("offsetof" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-const-hook () "C2HS const hook" (check-properties '("{#const FOO_BAR #}") '(("{#" t haskell-c2hs-hook-pair-face) ("const" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-typedef-hook () "C2HS typedef hook" (check-properties '("{# typedef size_t CSize #}") '(("{#" t haskell-c2hs-hook-pair-face) ("typedef" "w" haskell-c2hs-hook-name-face) ("CSize" "w" haskell-constructor-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) (ert-deftest haskell-c2hs-nongnu-hook () "C2HS nonGNU hook" (check-properties '("{#nonGNU#}") '(("{#" t haskell-c2hs-hook-pair-face) ("nonGNU" "w" haskell-c2hs-hook-name-face) ("#}" t haskell-c2hs-hook-pair-face)) 'haskell-c2hs-mode)) ;; haskell-c2hs-tests.el ends here ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-cabal-tests.el������������������������������������������������������0000664�0000000�0000000�00000030236�13602233217�0021321�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-cabal-tests.el -*- lexical-binding: t -*- ;;; Code: (require 'ert) (require 'haskell-cabal) (defconst haskell-cabal-test-data-dir (file-name-as-directory (expand-file-name "test-data" (if load-file-name (file-name-directory load-file-name) default-directory)))) (unless (file-directory-p haskell-cabal-test-data-dir) (error "Couldn't find tests/test-data subdir")) (ert-deftest haskell-cabal-enum-targets-1 () "Test enumerating .cabal targets for use by cabal-install." (with-temp-buffer (haskell-cabal-mode) (setq default-directory haskell-cabal-test-data-dir) (should (equal '("lib:Test" "test:test-1" "bench:bench-1" "exe:bin-1") (haskell-cabal-enum-targets))))) (ert-deftest haskell-cabal-enum-targets-2 () "Test enumerating .cabal targets for use by stack." (with-temp-buffer (haskell-cabal-mode) (setq default-directory haskell-cabal-test-data-dir) (should (equal '("Test:lib" "Test:test:test-1" "Test:bench:bench-1" "Test:exe:bin-1") (haskell-cabal-enum-targets 'stack-ghci))))) (ert-deftest haskell-cabal-get-field-1 () (with-temp-buffer (setq default-directory haskell-cabal-test-data-dir) (set-visited-file-name (expand-file-name "Source.hs") t t) (should (equal "Simple" (haskell-cabal-get-field "build-type"))))) (ert-deftest haskell-cabal-compute-checksum-1 () (should (equal "263e67082326a27585639420f4d42c8b" (haskell-cabal-compute-checksum haskell-cabal-test-data-dir)))) (ert-deftest haskell-cabal-compute-next-prev-section-1 () (with-temp-buffer (setq default-directory haskell-cabal-test-data-dir) (insert-file-contents (expand-file-name "Test.cabal")) (haskell-cabal-mode) (goto-char (point-min)) (haskell-cabal-next-section) (haskell-cabal-next-subsection) (haskell-cabal-previous-subsection) (haskell-cabal-previous-section))) (ert-deftest haskell-cabal-period-is-a-word-break () (with-temp-buffer (insert " Executable bin Main-Is: Main Exposed-Modules: Some.Internal.Type ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "Modules:") (skip-chars-forward " ") (should (looking-at-p "Some")) (forward-word) (should (looking-at-p ".Internal")) (forward-word) (should (looking-at-p ".Type")) (backward-word) (should (looking-at-p "Internal")))) (ert-deftest haskell-cabal-subsection-arrange-lines-keep-trailing-commas () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base, bytestring, filepath, directory, text Ghc-Options: -O -Wall ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "Build-Depends:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base, bytestring, directory, filepath, text Ghc-Options: -O -Wall ")))) (ert-deftest haskell-cabal-subsection-arrange-lines-keep-commas-before () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base , bytestring , filepath , directory , text Ghc-Options: -O -Wall ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "Build-Depends:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base , bytestring , directory , filepath , text Ghc-Options: -O -Wall ")))) (ert-deftest haskell-cabal-subsection-arrange-lines-no-commas () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Other-Modules: Some.Module Some.Other.Other.Module Some.Other.Module ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "Other-Modules:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Other-Modules: Some.Module Some.Other.Module Some.Other.Other.Module ")))) (ert-deftest haskell-cabal-subsection-arrange-lines-mixed-styles () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base , bytestring, filepath, directory, text Ghc-Options: -O -Wall ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "Build-Depends:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base , bytestring , directory , filepath , text Ghc-Options: -O -Wall ")))) (ert-deftest haskell-cabal-subsection-arrange-lines-quoted-items () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -fprof-auto \"-with-rtsopts=-N -p -s -h -i0.1\" ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "GHC-Options:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -fprof-auto \"-with-rtsopts=-N -p -s -h -i0.1\" ")))) (ert-deftest haskell-cabal-subsection-arrange-lines-no-commas-quoted-comma () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -Wall -fprof-auto \"foo, bar\" ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "GHC-Options:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -Wall -fprof-auto \"foo, bar\" ")))) (ert-deftest haskell-cabal-subsection-arrange-lines-single-line-quoted-comma () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -Wall,-fprof-auto \"foo, bar\" ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "GHC-Options:") (haskell-cabal-subsection-arrange-lines) (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -Wall, -fprof-auto \"foo, bar\" "))) (ert-deftest haskell-cabal-subsection-arrange-lines-trailing-commas-quoted-comma () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -Wall, -fprof-auto \"foo, bar\" ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "GHC-Options:") (haskell-cabal-subsection-arrange-lines) (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -Wall, -fprof-auto \"foo, bar\" "))) (ert-deftest haskell-cabal-subsection-arrange-lines-commas-before-quoted-comma () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -Wall , -fprof-auto \"foo, bar\" ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "GHC-Options:") (haskell-cabal-subsection-arrange-lines) (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs GHC-Options: -Wall , -fprof-auto \"foo, bar\" "))) (ert-deftest haskell-cabal-subsection-arrange-lines-comma-in-commment () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Other-Modules: Some.Module Some.Other.Other.Module Some.Other.Module -- Foo, bar ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "Other-Modules:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Other-Modules: Some.Module Some.Other.Module Some.Other.Other.Module -- Foo, bar ")))) (ert-deftest haskell-cabal-subsection-arrange-lines-comma-in-commment () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Other-Modules: Some.Module Some.Other.Other.Module Some.Other.Module -- Foo, bar ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "Other-Modules:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Other-Modules: Some.Module Some.Other.Module Some.Other.Other.Module -- Foo, bar ")))) (ert-deftest haskell-cabal-subsection-arrange-lines-dependencies () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: aeson , text , base >= 4.8 && < 5 , base64 , bytestring , base-compat ") (haskell-cabal-mode) (goto-char (point-min)) (search-forward "build-depends:") (haskell-cabal-subsection-arrange-lines) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base >= 4.8 && < 5 , aeson , base-compat , base64 , bytestring , text ")))) (ert-deftest haskell-cabal-add-dependency-01 () ;; cannot add dependency when there is no 'Build-depends' section already :expected-result :failed (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs ") (haskell-cabal-mode) (haskell-cabal-add-build-dependency "bytestring" nil t) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: bytestring ")))) (ert-deftest haskell-cabal-add-dependency-02 () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base ") (haskell-cabal-mode) (haskell-cabal-add-build-dependency "bytestring" nil t) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: bytestring, base ")))) (ert-deftest haskell-cabal-add-dependency-02 () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base ") (haskell-cabal-mode) (haskell-cabal-add-build-dependency "bytestring" nil t) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: bytestring, base ")))) (ert-deftest haskell-cabal-add-dependency-03 () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base, mtl ") (haskell-cabal-mode) (haskell-cabal-add-build-dependency "bytestring" nil t) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: bytestring, base, mtl ")))) (ert-deftest haskell-cabal-add-dependency-04 () (with-temp-buffer (insert " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: base , mtl ") (haskell-cabal-mode) (haskell-cabal-add-build-dependency "bytestring" nil t) (should (string= (buffer-string) " Executable bin-1 Main-Is: TestParsing.hs Build-Depends: bytestring , base , mtl ")))) (provide 'haskell-cabal-tests) ;;; haskell-cabal-tests.el ends here ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-collapse-tests.el���������������������������������������������������0000664�0000000�0000000�00000010334�13602233217�0022056�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-collapse-tests.el --- tests for collapse module -*- lexical-binding: t -*- ;; Copyright © 2017 Vasantha Ganesh K. <vasanthaganesh.k@tuta.io> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. (require 'ert) (require 'haskell-collapse) (setq haskell-code-block-1 "instance FromJSON BlogConfig where parseJSON (Object v) = BlogConfig <$> v .: \"blogname\" <*> v .: \"tagline\" <*> v .: \"author\" <*> v .: \"email\" <*> v .: \"twitter\" <*> v .: \"gitlab\" <*> v .: \"github\" -- A non-Object value is of the wrong type, so fail. parseJSON _ = error \"Can't parse BlogConfig from YAML\" ") (setq haskell-code-block-2 "-------------------------------------------------------------------------------- {-# LANGUAGE OverloadedStrings #-} import Data.Monoid import Hakyll.Web.Sass (sassCompiler) import Hakyll import Control.Applicative import Data.Yaml import Data.Maybe import qualified Data.ByteString.Char8 as BS -------------------------------------------------------------------------------- ") (setq haskell-code-block-3 "archiveCtx posts blogconfig = listField \"posts\" (postCtx blogconfig) (return posts) <> constField \"title\" \"Archive\" <> defaultCTX blogconfig indexCtx posts blogconfig = listField \"posts\" (postCtx blogconfig) (return (take 5 posts)) <> constField \"title\" \"Posts\" <> defaultCTX blogconfig ") (defun test-haskell-collapse-start-end (start end) (let ((start (save-excursion (beginning-of-buffer) (forward-line start) (end-of-line) (point))) (end (save-excursion (beginning-of-buffer) (forward-line end) (end-of-line) (point)))) (cons start end))) (defun test-haskell-indented-block (source lines result) "takes args source (source-code)" (with-temp-buffer (insert source) (beginning-of-buffer) (forward-line lines) (equal (funcall result) (haskell-indented-block)))) (ert-deftest test-haskell-indented-block-1 () (should (test-haskell-indented-block haskell-code-block-1 1 (lambda () (test-haskell-collapse-start-end 1 9))))) (ert-deftest test-haskell-indented-block-2 () (should (test-haskell-indented-block haskell-code-block-1 0 (lambda () (test-haskell-collapse-start-end 0 11))))) (ert-deftest test-haskell-indented-block-3 () (should (test-haskell-indented-block haskell-code-block-1 2 (lambda () (test-haskell-collapse-start-end 1 9))))) (ert-deftest test-haskell-indented-block-4 () (should (test-haskell-indented-block haskell-code-block-2 0 (lambda () nil)))) (ert-deftest test-haskell-indented-block-5 () (should (test-haskell-indented-block haskell-code-block-2 1 (lambda () nil)))) (ert-deftest test-haskell-indented-block-6 () (should (test-haskell-indented-block haskell-code-block-2 3 (lambda () nil)))) (ert-deftest test-haskell-indented-block-7 () (should (test-haskell-indented-block haskell-code-block-3 0 (lambda () (test-haskell-collapse-start-end 0 5))))) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-completions-tests.el������������������������������������������������0000664�0000000�0000000�00000047453�13602233217�0022624�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-completions-tests.el --- Tests for Haskell Completion package -*- lexical-binding: t -*- ;; Copyright © 2015 Athur Fayzrakhmanov. All rights reserved. ;; This file is part of haskell-mode package. ;; You can contact with authors using GitHub issue tracker: ;; https://github.com/haskell/haskell-mode/issues ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This package provides regression tests for haskell-completions package. ;;; Code: (require 'ert) (require 'haskell-mode) (require 'haskell-completions) (ert-deftest haskell-completions-can-grab-prefix-test () "Tests the function `haskell-completions-can-grab-prefix'." (with-temp-buffer (haskell-mode) (should (eql nil (haskell-completions-can-grab-prefix))) (insert " ") (should (eql nil (haskell-completions-can-grab-prefix))) (insert "a") (should (eql t (haskell-completions-can-grab-prefix))) (save-excursion (insert " ") (should (eql nil (haskell-completions-can-grab-prefix))) (insert "bc-") (should (eql t (haskell-completions-can-grab-prefix))) (insert "\n") (should (eql nil (haskell-completions-can-grab-prefix))) (insert "def:#!") (should (eql t (haskell-completions-can-grab-prefix)))) (should (eql t (haskell-completions-can-grab-prefix))) ;; punctuation tests (save-excursion (insert ")")) (should (eql t (haskell-completions-can-grab-prefix))) (save-excursion (insert ",")) (should (eql t (haskell-completions-can-grab-prefix))) (save-excursion (insert "'")) (should (eql t (haskell-completions-can-grab-prefix))) ;; should return nil in the middle of word (save-excursion (insert "bcd")) (should (eql nil (haskell-completions-can-grab-prefix))) ;; region case (push-mark (point-min) t) (activate-mark) (should (eql nil (haskell-completions-can-grab-prefix))))) (ert-deftest haskell-completions-grab-pragma-prefix-nil-cases-test () "Tests the function `haskell-completions-grab-pragma-prefix' within empty pragma comment {-# #-} and outside of it." (with-temp-buffer (haskell-mode) (goto-char (point-min)) (insert "{") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert "-") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert "#") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert " ") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert "#") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert "-") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert "}") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert "\n") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert "main") (should (eql nil (haskell-completions-grab-pragma-prefix))) (insert ":: IO ()") (should (eql nil (haskell-completions-grab-pragma-prefix))))) (ert-deftest haskell-completions-grab-pragma-name-prefix-test () "Tests both `haskell-completions-grab-pragma-prefix' and `haskell-completions-grab-prefix' functions for pragma names completions such as WARNING, LANGUAGE, DEPRECATED and etc." (let ((expected (list 5 8 "LAN" 'haskell-completions-pragma-name-prefix))) (with-temp-buffer (haskell-mode) (goto-char (point-min)) (insert "{-# LAN") (should (equal expected (haskell-completions-grab-pragma-prefix))) ;; minimal prefix length (should (equal expected (haskell-completions-grab-prefix 3))) (should (eql nil (haskell-completions-grab-prefix 4))) (save-excursion (insert " #-}")) ;; should work in case of closed comment, e.g. {-# LAN| #-} (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) ;; pragma function should work in the middle of word (backward-char) (should (not (equal expected (haskell-completions-grab-pragma-prefix)))) ;; but general function should not (should (eql nil (haskell-completions-grab-prefix)))) (with-temp-buffer (haskell-mode) (goto-char (point-min)) (insert "{-#\nLAN") ;; should work for multiline case (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix)))))) (ert-deftest haskell-completions-grab-ghc-options-prefix-test-01 () "Tests both `haskell-completions-grab-pragma-prefix' and `haskell-completions-grab-prefix' functions for GHC options prefixes." (let (expected) (with-temp-buffer (haskell-mode) (goto-char (point-min)) (setq expected (list 5 16 "OPTIONS_GHC" 'haskell-completions-pragma-name-prefix)) (insert "{-# OPTIONS_GHC") (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " --opt1") (setq expected (list 17 23 "--opt1" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " -XOpt-2") (setq expected (list 27 34 "-XOpt-2" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (save-excursion (insert "\n") (insert "\"new-line\"") ;; should handle multiline case (setq expected (list 35 45 "\"new-line\"" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " test") (setq expected (list 46 50 "test" 'haskell-completions-ghc-option-prefix)) ;; minimal prefix length (should (equal expected (haskell-completions-grab-prefix 4))) (should (eql nil (haskell-completions-grab-prefix 5))) (insert " ") (should (eql nil (haskell-completions-grab-pragma-prefix))) (should (eql nil (haskell-completions-grab-prefix))) (insert "#-}")) ;; should work in case of closed comment, e.g. {-# OPTIONS_GHC xyz| #-} (setq expected (list 27 34 "-XOpt-2" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (backward-char) ;; pragma function should work in the middle of word (should (not (eql nil (haskell-completions-grab-pragma-prefix)))) ;; but general function should not (should (eql nil (haskell-completions-grab-prefix)))))) (ert-deftest haskell-completions-grab-ghc-options-prefix-test-02 () "Tests both `haskell-completions-grab-pragma-prefix' and `haskell-completions-grab-prefix' functions for GHC options prefixes. Same tests as above for obsolete OPTIONS pragma." (let (expected) (with-temp-buffer (haskell-mode) (goto-char (point-min)) (insert "{-# OPTIONS") (setq expected (list 5 12 "OPTIONS" 'haskell-completions-pragma-name-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " --opt1") (setq expected (list 13 19 "--opt1" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " -XOpt-2") (setq expected (list 23 30 "-XOpt-2" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (save-excursion (insert "\n") (insert "\"new-line\"") ;; should handle multiline case (setq expected (list 31 41 "\"new-line\"" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " test") ;; minimal prefix length (setq expected (list 42 46 "test" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-prefix 4))) (should (eql nil (haskell-completions-grab-prefix 5))) (insert " ") (should (eql nil (haskell-completions-grab-pragma-prefix))) (should (eql nil (haskell-completions-grab-prefix))) (insert "#-}")) ;; should work in case of closed comment (setq expected (list 23 30 "-XOpt-2" 'haskell-completions-ghc-option-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (backward-char) ;; pragma function should work in the middle of word (should (not (eql nil (haskell-completions-grab-pragma-prefix)))) ;; but general function should not (should (eql nil (haskell-completions-grab-prefix)))))) (ert-deftest haskell-completions-grab-language-extenstion-prefix-test () "Tests both `haskell-completions-grab-pragma-prefix' and `haskell-completions-grab-prefix' functions for language extension prefixes." (let (expected) (with-temp-buffer (haskell-mode) (goto-char (point-min)) (insert "{-# LANGUAGE") (setq expected (list 5 13 "LANGUAGE" 'haskell-completions-pragma-name-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " Rec") (setq expected (list 14 17 "Rec" 'haskell-completions-language-extension-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert ", -XOpt-2") (setq expected (list 22 29 "-XOpt-2" 'haskell-completions-language-extension-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert ",\n") (insert "\"new-line\"") ;; should handle multiline case (setq expected (list 31 41 "\"new-line\"" 'haskell-completions-language-extension-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " -test") ;; minimal prefix length (setq expected (list 42 47 "-test" 'haskell-completions-language-extension-prefix)) (should (equal expected (haskell-completions-grab-prefix 5))) (should (eql nil (haskell-completions-grab-prefix 6))) (save-excursion (insert " #-}")) ;; should work in case of closed comment (setq expected (list 42 47 "-test" 'haskell-completions-language-extension-prefix)) (should (equal expected (haskell-completions-grab-pragma-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (backward-char) ;; pragma function should work in the middle of the word (should (not (eql nil (haskell-completions-grab-pragma-prefix)))) ;; but general function does not (should (eql nil (haskell-completions-grab-prefix)))))) (ert-deftest haskell-completions-grab-identifier-prefix-test () "Tests both `haskell-completions-grab-identifier-prefix' and `haskell-completions-grab-prefix' functions for arbitrary haskell identifiers and module identifiers." (let (expected) (with-temp-buffer (haskell-mode) (should (eql nil (haskell-completions-grab-identifier-prefix))) (should (eql nil (haskell-completions-grab-prefix))) (insert "import") (setq expected (list 1 7 "import" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " Da") (setq expected (list 8 10 "Da" 'haskell-completions-module-name-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) ;; minimal length test (should (equal expected (haskell-completions-grab-prefix 2))) (should (eql nil (haskell-completions-grab-prefix 3))) (insert "ta.") (setq expected (list 8 13 "Data." 'haskell-completions-module-name-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert "Text (pack") (setq expected (list 19 23 "pack" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert ")") ;; should work when point is at punctuation (backward-char) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (forward-char) ;; but should not work after punctuation (should (eql nil (haskell-completions-grab-identifier-prefix))) (should (eql nil (haskell-completions-grab-prefix))) (insert "\n") (insert "import qualified Data.Text as T") (insert "\n\n") ;; should not work at the beginning of a line (should (eql nil (haskell-completions-grab-identifier-prefix))) (should (eql nil (haskell-completions-grab-prefix))) (insert "main") (setq expected (list 58 62 "main" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " :: IO") (setq expected (list 66 68 "IO" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " ()\n") (insert "main") (save-excursion (insert " = putStrLn") (setq expected (list 79 87 "putStrLn" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " (T.") (setq expected (list 89 91 "T." 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert "unpack") (setq expected (list 89 97 "T.unpack" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " (T.pack (\"Hello") (setq expected nil) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " World!\" :: String") (setq expected (list 125 131 "String" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " -- Comment") (setq expected nil) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix)))) ;; test in the middle of line (setq expected (list 72 76 "main" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (backward-char) (setq expected (list 72 75 "mai" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal nil (haskell-completions-grab-prefix)))) ;; qualified imports and "as indentifier" tests (with-temp-buffer (haskell-mode) (insert "import qualified Data.Text") (setq expected (list 18 27 "Data.Text" 'haskell-completions-module-name-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix))) (insert " as T") (setq expected (list 31 32 "T" 'haskell-completions-identifier-prefix)) (should (equal expected (haskell-completions-grab-identifier-prefix))) (should (equal expected (haskell-completions-grab-prefix)))))) (ert-deftest haskell-completions-complete-operators-test () "Tests `haskell-completions-complete-operators' and its effects on `haskell-completions-sync-repl-completion-at-point'." ;; Mock `haskell-completions-sync-complete-repl' (defadvice haskell-completions-sync-complete-repl-mock (around haskell-completions-sync-complete-repl (prefix &optional import)) nil) (ad-activate 'haskell-completions-sync-complete-repl-mock) ;; Mock `haskell-session-maybe' (defadvice haskell-session-maybe-mock (around haskell-session-maybe) t) (ad-activate 'haskell-session-maybe-mock) ;; Mock `haskell-process-cmd' (defadvice haskell-process-cmd-mock (around haskell-process-cmd (P)) nil) (ad-activate 'haskell-process-cmd-mock) ;; Mock `haskell-interactive-process' (defadvice haskell-interactive-process-mock (around haskell-interactive-process) nil) (ad-activate 'haskell-interactive-process-mock) ;;; Tests (unwind-protect (let (expected) (with-temp-buffer (haskell-mode) (insert "import qualified Data.List as L\n\n") (insert "test = L") (let* ((haskell-completions-complete-operators nil)) (setq expected (nth 2 (haskell-completions-sync-repl-completion-at-point))) (should expected)) (let* ((haskell-completions-complete-operators t)) (setq expected (nth 2 (haskell-completions-sync-repl-completion-at-point))) (should expected)) (insert ".") (let* ((haskell-completions-complete-operators nil)) (setq expected (nth 2 (haskell-completions-sync-repl-completion-at-point))) (should-not expected)) (let* ((haskell-completions-complete-operators t)) (setq expected (nth 2 (haskell-completions-sync-repl-completion-at-point))) (should expected)))) (progn ;; Remove mocks (ad-deactivate 'haskell-completions-sync-complete-repl-mock) (ad-deactivate 'haskell-session-maybe-mock) (ad-deactivate 'haskell-process-cmd-mock) (ad-deactivate 'haskell-interactive-process-mock)))) (provide 'haskell-completions-tests) ;;; haskell-completions-tests.el ends here ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-customize-tests.el��������������������������������������������������0000664�0000000�0000000�00000006146�13602233217�0022304�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-customize.el --- Customization settings -*- lexical-binding: t -*- ;; Copyright (c) 2014 Vasantha Ganesh Kanniappan <vasanthaganesh.k@tuta.io> ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'ert) (require 'haskell-customize) (require 'haskell-test-utils) (defvar dir-structure nil) (ert-deftest haskell-process-type-test-1 () (with-temp-dir-structure (("README.md" . "Hello world") ("Main.hs" . "-- Empty file") ("abc.cabal" . "-- Empty File") ("stack.yaml" . "# Empty file") ("src" . (("moduleA.hs" . "-- Empty file") ("moduleB.hs" . "-- Empty file"))) ("tests" . (("test1.hs" . "-- Empty file") ("test2.hs" . "-- Empty file")))) (progn (cd "tests") (should (eq 'stack-ghci (haskell-process-type)))))) (ert-deftest haskell-process-type-test-2 () (with-temp-dir-structure (("README.md" . "Hello world") ("Main.hs" . "-- Empty file") ("stack.yaml" . "# Empty file") ("src" . (("moduleA.hs" . "-- Empty file") ("moduleB.hs" . "-- Empty file"))) ("tests" . (("test1.hs" . "-- Empty file") ("test2.hs" . "-- Empty file")))) (progn (cd "src") (should (eq 'stack-ghci (haskell-process-type)))))) (ert-deftest haskell-process-type-test-3 () (with-temp-dir-structure (("README.md" . "Hello world") ("Main.hs" . "-- Empty file") ("abc.cabal" . "-- Empty file") ("src" . (("moduleA.hs" . "-- Empty file") ("moduleB.hs" . "-- Empty file"))) ("tests" . (("test1.hs" . "-- Empty file") ("test2.hs" . "-- Empty file")))) (progn (should (eq 'cabal-repl (haskell-process-type)))))) (ert-deftest haskell-process-type-test-3 () (with-temp-dir-structure (("README.md" . "Hello world") ("Main.hs" . "-- Empty file") ("src" . (("moduleA.hs" . "-- Empty file") ("moduleB.hs" . "-- Empty file"))) ("tests" . (("test1.hs" . "-- Empty file") ("test2.hs" . "-- Empty file")))) (progn (should (eq 'ghci (haskell-process-type)))))) (ert-deftest haskell-process-type-test-4 () :expected-result :failed (with-temp-dir-structure (("README.md" . "Hello world") ("Main.hs" . "-- Empty file") ("abc.cabal" . "-- Empty file") ("cabal.project" . "-- Empty file") ("src" . (("moduleA.hs" . "-- Empty file") ("moduleB.hs" . "-- Empty file"))) ("tests" . (("test1.hs" . "-- Empty file") ("test2.hs" . "-- Empty file")))) (progn (should (eq 'cabal-new-repl (haskell-process-type)))))) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-decl-scan-tests.el��������������������������������������������������0000664�0000000�0000000�00000013271�13602233217�0022110�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-decl-scan-tests.el -*- lexical-binding: t -*- ;; Copyright © 2016 Chris Gregory. All rights reserved. ;; This file is part of haskell-mode package. ;; You can contact with authors using GitHub issue tracker: ;; https://github.com/haskell/haskell-mode/issues ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This package provides regression tests for haskell-decl-scan package. ;;; Code: (require 'ert) (require 'haskell-decl-scan) (require 'haskell-test-utils) (ert-deftest haskell-ds-line-commented-p-1 () "All lines in this buffer should count as comments" (with-temp-buffer (haskell-mode) (insert-lines "" "--hi" " -- hi\t " "" "{-hi-}" " \t{-hi-} " "-- | hi" "{-| hi -}") (font-lock-fontify-buffer) (goto-char (point-min)) (while (not (eobp)) (should (haskell-ds-line-commented-p)) (forward-line)))) (ert-deftest haskell-ds-comment-p-1 () "All characters in this buffer should count as comments" (with-temp-buffer (haskell-mode) (insert-lines "" "--hi" " -- hi\t " "" "{-hi-}" " \t{-hi-} ") (font-lock-fontify-buffer) (goto-char (point-min)) (while (not (bobp)) (should (haskell-ds-comment-p)) (forward-char)))) (ert-deftest haskell-ds-backward-decl-1 () "Test running haskell-ds-backward-decl" (with-temp-buffer (insert-lines "" "fun :: Int -> Int" "fun = id" "" "f2 :: Int" "f2 = 3" "") (goto-char (point-max)) (should (haskell-ds-backward-decl)) (should (looking-at-p "f2 :: Int")) (should (haskell-ds-backward-decl)) (should (looking-at-p "fun :: Int -> Int")) (should-not (haskell-ds-backward-decl)) (should (bobp)))) (ert-deftest haskell-ds-backward-decl-2-commented () "Test running haskell-ds-backward-decl" (with-temp-buffer (haskell-mode) (insert-lines "" "-- documentation" "fun :: Int -> Int" "" "{- comment -}" "fun = id" "" " -- space comment" "f2 :: Int" "" " {- trailing -} \t" "f2 = 3" "" "" "") (font-lock-fontify-buffer) (goto-char (point-max)) (should (haskell-ds-backward-decl)) (should (looking-at-p "f2 :: Int")) (should (haskell-ds-backward-decl)) (should (looking-at-p "fun :: Int -> Int")) (should-not (haskell-ds-backward-decl)) (should (bobp)))) (ert-deftest haskell-ds-backward-decl-2 () "Test running haskell-ds-backward-decl" (with-temp-buffer (insert-lines "" "" "fun :: Int -> Int" "" "" "fun = id" "" "" "f2 :: Int" "" "" "f2 = 3" "" "" "") (goto-char (point-max)) (should (haskell-ds-backward-decl)) (should (looking-at-p "f2 :: Int")) (should (haskell-ds-backward-decl)) (should (looking-at-p "fun :: Int -> Int")) (should-not (haskell-ds-backward-decl)) (should (= (point-min) (point))))) (ert-deftest haskell-ds-forward-decl-1 () "Test running haskell-ds-forward-decl" (with-temp-buffer (insert-lines "" "fun :: Int -> Int" "fun = id" "" "f2 :: Int" "f2 = 3" "") (goto-char (point-min)) (should (haskell-ds-forward-decl)) (should (looking-at-p "$")) (should (= (point) (save-excursion (goto-line 4) (point)))) (should (haskell-ds-forward-decl)) (should (looking-at-p "f2 :: Int")) (should (= (point-max) (haskell-ds-forward-decl))) (should (eobp)))) (ert-deftest haskell-ds-forward-decl-2 () "Test running haskell-ds-forward-decl" (with-temp-buffer (insert-lines "" "" "fun :: Int -> Int" "" "" "fun = id" "" "" "f2 :: Int" "" "" "f2 = 3" "" "" "") (goto-char (point-min)) (should (haskell-ds-forward-decl)) (should (looking-at-p "$")) (should (= (point) (save-excursion (goto-line 7) (point)))) (should (haskell-ds-forward-decl)) (should (looking-at-p "f2 :: Int")) (should (haskell-ds-forward-decl)) (should (= (point) (save-excursion (goto-line 13) (point)))) (should (= (point-max) (progn (haskell-ds-forward-decl) (point)))) (should (eobp)))) (ert-deftest haskell-ds-forward-decl-2-commented () "Test running haskell-ds-backward-decl" (with-temp-buffer (haskell-mode) (insert-lines "" "-- documentation" "fun :: Int -> Int" "" "{- comment -}" "fun = id" "" " -- space comment" "f2 :: Int" "" " {- trailing -} \t" "f2 = 3" "" "" "") (font-lock-fontify-buffer) (goto-char (point-min)) (should (haskell-ds-forward-decl)) (should (looking-at-p "$")) (should (= (point) (save-excursion (goto-line 7) (point)))) (should (haskell-ds-forward-decl)) (should (looking-at-p "f2 :: Int")) (should (haskell-ds-forward-decl)) (should (= (point) (save-excursion (goto-line 13) (point)))) (should (= (point-max) (progn (haskell-ds-forward-decl) (point)))) (should (eobp)))) (provide 'haskell-decl-scan-tests) ;;; haskell-decl-scan-tests.el ends here ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-doc-tests.el��������������������������������������������������������0000664�0000000�0000000�00000003664�13602233217�0021031�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-doc-tests.el --- Tests for `haskell-docs' package -*- lexical-binding: t -*- ;; Copyright © 2016 Arthur Fayzrakhmanov. All rights reserved. ;; This file is part of haskell-mode package. ;; You can contact with authors using GitHub issue tracker: ;; https://github.com/haskell/haskell-mode/issues ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This package provides regression tests for haskell-docs package. ;;; Code: (require 'ert) (require 'haskell-mode) (require 'haskell-doc) (require 'haskell-test-utils) (require 'haskell-utils) (ert-deftest interactive-prompt-state () (with-temp-buffer (haskell-mode) (haskell-doc-mode) (insert-lines "module A where" "import B") (goto-char (point-min)) (forward-line) (should (string= "import [qualified] modid [as modid] [impspec]" (haskell-doc-mode-print-current-symbol-info))) (haskell-mode-toggle-interactive-prompt-state) (should (eq nil (haskell-doc-mode-print-current-symbol-info))) (haskell-mode-toggle-interactive-prompt-state t) (should (string= "import [qualified] modid [as modid] [impspec]" (haskell-doc-mode-print-current-symbol-info))))) ;;; haskell-doc-tests.el ends here ����������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-exec-tests.el�������������������������������������������������������0000664�0000000�0000000�00000001544�13602233217�0021203�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;; haskell-exec-tests.el --- -*- lexical-binding: t; -*- (require 'ert) (require 'haskell-test-utils) (defvar haskell-example-script "echo") (defun haskell-exec-test-output-argv-and-copy-stdin () (let (line) (while argv (message-stdout "%s" (pop argv))) (while (setq line (read-stdin)) (message-stdout "%s" line)))) (ert-deftest haskell-exec-subst-script () (with-script-path haskell-example-script haskell-exec-test-output-argv-and-copy-stdin (with-temp-buffer (insert "line1\n") (insert "line2\n") (insert "line3-no-newline") (call-process-region (point-min) (point-max) haskell-example-script t t nil "-a" "--arg1" "/zonk" "filename.el") (should (equal "-a\n--arg1\n/zonk\nfilename.el\nline1\nline2\nline3-no-newline\n" (buffer-substring-no-properties (point-min) (point-max))))))) ������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-external.el���������������������������������������������������������0000664�0000000�0000000�00000002664�13602233217�0020745�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;; haskell-check-external.el --- Test if packages depending on haskell-mode install okay -*- lexical-binding: t; -*- (require 'package) (require 'bytecomp) (defun haskell-check-external-batch-and-exit () "Check if packages depending on haskell-mode bytecompile. Haskell Mode should not break packages that depend on it and this function checks if officially released versions still compile." (let ((byte-compile-error-on-warn t) ;; where to install temporary packages (package-user-dir (concat command-line-default-directory "/external/elpa")) ;; use haskell-mode directly from sources, it takes priority ;; over haskell-mode in packages. (package-directory-list (list command-line-default-directory)) ;; packages depending on haskell-mode are in melpa (package-archives (cons '("melpa" . "http://melpa.milkbox.net/packages/") package-archives))) (unwind-protect (progn (make-directory "external") ;; We aren't really able to depend on errors and warnings in ;; bytecompilation as there are many packages that are very ;; inconsistent about following elisp best practices. (package-initialize) (package-refresh-contents) (package-install 'flycheck-haskell) (package-install 'flycheck-stack) (package-install 'ghc) (package-install 'intero)) (delete-directory "external" t)))) ����������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-font-lock-tests.el��������������������������������������������������0000664�0000000�0000000�00000075500�13602233217�0022156�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;; -*- lexical-binding: t -*- (require 'ert) (require 'haskell-test-utils) (require 'haskell-font-lock) (require 'haskell-mode) (ert-deftest haskell-syntactic-test-1 () "Simple keywords fontified" (check-properties '("module Test where") '(("module" "w" haskell-keyword-face) ("Test" "w" haskell-constructor-face) ("where" "w" haskell-keyword-face)))) (ert-deftest haskell-syntactic-test-4 () "Apostrophe as part of a contructor token." :expected-result :failed (check-properties '("T_'ttt_'t_' T Tx T'x T_x T_'_") '(("T_'ttt_'t_'" "w" haskell-constructor-face) ("T" "w" haskell-constructor-face) ("T'x" "w" haskell-constructor-face) ("T_x" "w" haskell-constructor-face) ("T_'_" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-test-5 () "Apostrophe inside a token." :expected-result :failed (check-properties '("_T_'tt't_'t_' xxx'ff _f _'''") '(("_T_'tt't_'t_'" "w" haskell-symbol-face) ("xxx'ff" "w" haskell-symbol-face) ("_f" "w" haskell-symbol-face) ("_'''" "w" haskell-symbol-face)))) (ert-deftest haskell-syntactic-test-character-literal-escapes () (check-properties '("'\\000' '\\x01'") '(("'\\000'" t font-lock-string-face) ("'\\x01'" t font-lock-string-face)))) (ert-deftest haskell-syntactic-test-7 () "Take quotes and double quotes under control." (check-properties '("\"\'\" Cons1" "\'\"\' Cons2") '(("\"\'\"" t font-lock-string-face) ("Cons1" "w" haskell-constructor-face) ("\'\"\'" t font-lock-string-face) ("Cons2" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-test-7b () "Take quotes and double quotes under control." (check-properties ;; do not get fooled '("\"\'\"\'\"\'\"\'\"\'\"\'\"\'\"\'\"\' Cons") '(("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-test-7c () "Tripple backslash in a string that also has a quote." (check-properties ;; the below is: "\"\\\"" and \\\ get marked as punctuation because ;; of detecting -- that is a part of larger non-comment lexeme '(" \"\\\"\\\\\\\"\" Cons") '(("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-test-8 () "Check if gap-rule works." (check-properties '("\"\\ \\\\\\ \\ " " \\\" Cons") '(("\\" "." t) ; 1st is escape ("\\" "." t) ; 2nd is punctuation ("\\" "." t) ; 3rd is escape ("\\" "." t) ; 4th is punctuation ("\\" "." t) ; 5th is escape ("\\" "." t) ; 6th is punctuation ("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-test-9 () "Syntax for hierarchical modules." ; note that quite many things here are not consistent but for now ; this test describes what it is (check-properties '(" A.B.C" " D.E.f" " G.H.>>=" " <=<" ) '(("A" "w" haskell-constructor-face) ("." "." haskell-constructor-face) ("B" "w" haskell-constructor-face) ("." "." haskell-constructor-face) ("C" "w" haskell-constructor-face) ("D" "w" nil) ("." "." nil) ("E" "w" nil) ("." "." nil) ("f" "w" nil) ("G" "w" haskell-operator-face) ("." "." haskell-operator-face) ("H" "w" haskell-operator-face) ("." "." haskell-operator-face) (">>=" "." haskell-operator-face) ("<=<" "." haskell-operator-face)))) (ert-deftest haskell-syntactic-test-18 () "Backtick operators" (check-properties '(" `fmap1`" " ` fmap2 `" " ` {- C1 -} M.fmap3 {- C2 -} `") '(("`" t haskell-operator-face) ("fmap1" t haskell-operator-face) ("`" t haskell-operator-face) ("`" t haskell-operator-face) ("fmap2" t haskell-operator-face) ("`" t haskell-operator-face) ("`" t haskell-operator-face) ("C1" t font-lock-comment-face) ("fmap3" t haskell-operator-face) ("C2" t font-lock-comment-face) ("`" t haskell-operator-face)))) (ert-deftest haskell-syntactic-test-18a-multiline () "Backtick operators multiline" ;; strangely thins works in interactive session :expected-result :failed (check-properties '(" `" " fmap " " `") '(("`" t haskell-operator-face) ("fmap" t haskell-operator-face) ("`" t haskell-operator-face)))) (ert-deftest haskell-syntactic-test-9a () "Syntax for hierarchical modules when on the first line." ;; note that quite many things here are not consistent but for now ;; this test describes what it is. When on the first column ;; font-lock thins we are defining (.) operator. Not good. :expected-result :failed (check-properties '("A1.B.C" "A2.B.c" "A3.B.>>=" "<=<" ) '(("A1" "w" haskell-constructor-face) ("." "." haskell-constructor-face) ("B" "w" haskell-constructor-face) ("." "." haskell-constructor-face) ("C" "w" haskell-constructor-face) ("A2" "w" nil) ("." "." nil) ("B" "w" nil) ("." "." nil) ("C" "w" nil) ("A3" "w" haskell-constructor-face) ("." "." haskell-constructor-face) ("B" "w" haskell-constructor-face) ("." "." haskell-operator-face) ; this is wrong (">>=" "." haskell-operator-face) ("<=<" "." haskell-operator-face)))) (ert-deftest haskell-syntactic-test-10 () "Syntax for comments" (check-properties '(" Cons0 -- Comm1" " --\ Cons2" " ----- Comment3" " {- Comm4 -} -- Comm5" " -- \" Comm6" " Cons7" "{-# pragma1 #-}" "{-# non_pragma2 -}" "{- non_pragma3 #-}" "{-@ liquid_haskell @-}" "{-@ non_liquid_haskell_2 -}" "{- non_liquid_haskell_3 @-}" ) '(("Cons0" "w" haskell-constructor-face) ("Comm1" "w" font-lock-comment-face) ;("Cons2" "w" haskell-constructor-face) -- works in real life, does not work in tests... ("Comment3" "w" font-lock-comment-face) ("Comm4" "w" font-lock-comment-face) ("Comm5" "w" font-lock-comment-face) ("Comm6" "w" font-lock-comment-face) ("Cons7" "w" haskell-constructor-face) ("pragma1" "w" haskell-pragma-face) ("non_pragma2" "w_" font-lock-comment-face) ("non_pragma3" "w_" font-lock-comment-face) ("liquid_haskell" "w_" haskell-liquid-haskell-annotation-face) ("non_liquid_haskell_2" "w_" font-lock-comment-face) ("non_liquid_haskell_3" "w_" font-lock-comment-face)))) (ert-deftest haskell-syntactic-string-vs-comment-escape () "Check string escape vs comment escape" (check-properties ;; "\"" \-- Cons '("\"\\\"\" \\-- Cons") '(("\\--" "." haskell-operator-face) ("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-quasiquote-no-escape () "Check string escape vs comment escape" (check-properties '("[qq| \\|] Cons") '(("qq" "w" nil) ("\\" "." haskell-quasi-quote-face) ("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-quasiquote-three-punctuation () "Check string escape vs comment escape" (check-properties '("[qq| %\\|] Cons") '(("qq" "w" nil) ("%\\" "." haskell-quasi-quote-face) ("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-quasiquote-constructor () "Check string escape vs comment escape" (check-properties '("[Cons1| Cons2 |]") '(("Cons1" "w" haskell-constructor-face) ("Cons2" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-quasiquote-number () "Check string escape vs comment escape" (check-properties '("[11| Cons2 |]") '(("1" "w" nil) ("Cons2" "w" haskell-constructor-face)))) (ert-deftest haskell-haddock-01 () "Syntax for haddock comments" (check-properties '(" -- | Dcom1" ; haddocks " -- $ Dcom2" " -- ^ Dcom3" " -- * Dcom4" " --| Cons5" ; non-haddocks, operators " --$ Cons6" " --^ Cons7" " --* Cons8" " -- | Com5" ; non-haddocks, comments " -- $ Com6" " -- ^ Com7" " -- * Com8" " {-| Dcom10 -}" ; haddocks " {-$ Dcom11 -}" " {-^ Dcom12 -}" " {-* Dcom13 -}" " {- | Dcom14 -}" ; also haddocks " {- $ Dcom15 -}" " {- ^ Dcom16 -}" " {- * Dcom17 -}") '(("Dcom1" "w" font-lock-doc-face) ("Dcom2" "w" font-lock-doc-face) ("Dcom3" "w" font-lock-doc-face) ("Dcom4" "w" font-lock-doc-face) ("Cons5" "w" haskell-constructor-face) ("Cons6" "w" haskell-constructor-face) ("Cons7" "w" haskell-constructor-face) ("Cons8" "w" haskell-constructor-face) ("Com5" "w" font-lock-comment-face) ("Com6" "w" font-lock-comment-face) ("Com7" "w" font-lock-comment-face) ("Com8" "w" font-lock-comment-face) ("Dcom10" "w" font-lock-doc-face) ("Dcom11" "w" font-lock-doc-face) ("Dcom12" "w" font-lock-doc-face) ("Dcom13" "w" font-lock-doc-face) ("Dcom14" "w" font-lock-doc-face) ("Dcom15" "w" font-lock-doc-face) ("Dcom16" "w" font-lock-doc-face) ("Dcom17" "w" font-lock-doc-face) ))) (ert-deftest haskell-haddock-02 () "Syntax for italic and bold in haddock comments" ;; Emacs 23 does not have `add-face-text-property' :expected-result (if (fboundp 'add-face-text-property) :passed :failed) (check-properties '("-- | haddock" "-- /it1/ nonit2 /it3/" "-- /it\\/4/ nonit5" "-- __/boldit1/__" "-- /__boldit2__/" "-- __bold_bold_bold__" "-- __/unfinished") '(("/it1/" t ((:slant italic) font-lock-doc-face)) ("nonit2" t font-lock-doc-face) ("/it3/" t ((:slant italic) font-lock-doc-face)) ("/it\\/4/" t ((:slant italic) font-lock-doc-face)) ("nonit5" t font-lock-doc-face) ("boldit1" t ((:weight bold) (:slant italic) font-lock-doc-face)) ("boldit2" t ((:slant italic) (:weight bold) font-lock-doc-face)) ("__bold_bold_bold__" t ((:weight bold) font-lock-doc-face)) ("unfinished" t font-lock-doc-face)))) (ert-deftest haskell-syntactic-test-11b () "Syntax for haddock comments" ;; Note: all of these are prefixed with space so that ;; top-level definition detection does not kick in. (check-properties '(" 'a''b'" ; ('a','b') " 12'c'" ; (12,'c') " 0x32'd'" ; (0x34,'d') " e56'f'" ; Not in scope: ‘e56'f'’ " 'g''h''" ; lexical error in string/character literal at end of input " 'i'j " ; ('i',45) " 'k''l" ; ('k',l_1627393257) " \"m\"'n'" ; ("m",'n') " 'o'\"p\"" ; ('o',"p") " '\"'\"'\"" ; ('"',"'") " 7e-8'q'" ; (7e-8,'q') " 9.9'r'" ; (9.9,'r') " 's'12e-34" ; ('s',1.2e-33) " 't'56.78" ; ('t',56.78) " ." ) '(("'a'" t font-lock-string-face) ("'b'" t font-lock-string-face) ("12" t nil) ("'c'" t font-lock-string-face) ("0x32" t nil) ("'d'" t font-lock-string-face) ("e56'f'" t nil) ("'g'" t font-lock-string-face) ("'h'" t font-lock-string-face) ("'" t nil) ; ?? stray apostrophe is what?? ("'i'" t font-lock-string-face) ("j" t nil) ("'k'" t font-lock-string-face) ("'l" t nil) ;; apostrophe here should be prefix operator ("\"m\"'n'" t font-lock-string-face) ("'o'\"p\"" t font-lock-string-face) ("'\"'\"'\"" t font-lock-string-face) ("7e-8" t nil) ("'q'" t font-lock-string-face) ("9.9" t nil) ("'r'" t font-lock-string-face) ("'s'" t font-lock-string-face) ("12e-34" t nil) ("'t'" t font-lock-string-face) ("56.78" t nil) ("." t haskell-operator-face) ))) (ert-deftest haskell-syntactic-preprocessor-01 () (check-properties '(" # NoPreproc" "#preproc" "#prep1 \\" " Prep2" "Cons") '(("NoPreproc" t haskell-constructor-face) ("preproc" t font-lock-preprocessor-face) ("prep1" t font-lock-preprocessor-face) ("Prep2" t font-lock-preprocessor-face) ("Cons" t haskell-constructor-face)))) (ert-deftest haskell-syntactic-preprocessor-02 () (check-properties '"#preproc\\\ncont\\" ;; backslash is last char in buffer '(("preproc" t font-lock-preprocessor-face) ("cont" t font-lock-preprocessor-face) ("\\" t font-lock-preprocessor-face)))) (ert-deftest haskell-syntactic-test-quasiquoter-1 () "Basic syntax for QuasiQuote" (check-properties '("v = [quoter| string |] Cons") '(("[" t nil) ("|" t haskell-quasi-quote-face) ("string" t haskell-quasi-quote-face) ("|" t haskell-quasi-quote-face) ("]" t nil) ("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-test-quasiquoter-2 () "Basic syntax for QuasiQuote multiline" (check-properties '("v = [quoter| string" " one more | ]" " finishing line" "|] Cons") '(("[" t nil) ("|" t haskell-quasi-quote-face) ("string" t haskell-quasi-quote-face) ("line" t haskell-quasi-quote-face) ("|" t haskell-quasi-quote-face) ("]" t nil) ("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-syntactic-test-quasiquoter-3 () "QuasiQuote inside quasi quote" (check-properties '("v = [quoter| [inner| string {- -- |] Outside |]") '(("[" t nil) ("|" t haskell-quasi-quote-face) ("inner" t haskell-quasi-quote-face) ("string" t haskell-quasi-quote-face) ("|" t haskell-quasi-quote-face) ("]" t nil) ("Outside" "w" haskell-constructor-face) ))) (ert-deftest haskell-syntactic-test-quasiquoter-4 () "QuasiQuote inside comment" (check-properties '("v = -- [quoter| " " [inner| string {- -- |] Outside1 |] Outside2") '(("quoter" t font-lock-comment-face) ("inner" t nil) ("string" t haskell-quasi-quote-face) ("|" t haskell-quasi-quote-face) ("]" t nil) ("Outside1" "w" haskell-constructor-face) ("Outside2" "w" haskell-constructor-face) ))) (ert-deftest haskell-syntactic-test-quasiquoter-5 () "QuasiQuote should not conflict with TemplateHaskell" (check-properties '("nope = [| Cons |]" "nope = [e| Cons_e |]" "nope = [t| Cons_t |]" "nope = [d| Cons_d |]" "nope = [p| Cons_p |]" "yes = [x| Cons_x |]") '(("Cons" t haskell-constructor-face) ("Cons_e" t haskell-constructor-face) ("Cons_t" t haskell-constructor-face) ("Cons_d" t haskell-constructor-face) ("Cons_p" t haskell-constructor-face) ("Cons_x" t haskell-quasi-quote-face)))) (ert-deftest haskell-syntactic-test-quasiquoter-sql-1 () "Embedded SQL statements" (check-properties '("sql = [sql| SELECT title FROM books; |]") '(("SELECT" t font-lock-keyword-face) ("title" t default) ("FROM" t font-lock-keyword-face) ("books" t default)))) (ert-deftest haskell-syntactic-test-quasiquoter-sql-2 () "Embedded SQL statements" ;; for now we have this problem that connstructor faces are used, ;; org-mode knows how to get around this problem (check-properties '("sql = [sql| SELECT Title FROM Books; |]") '(("Title" t default) ("Books" t default)))) (ert-deftest haskell-syntactic-test-special-not-redefined () "QuasiQuote should not conflict with TemplateHaskell" (check-properties '("nope1, nope2 " "nope3 = nope4 " "nope -> nope" "nope :: nope" "nope <- nope" "nope ` nope") '(("," t nil) ("=" t haskell-operator-face) ("->" t haskell-operator-face) ("::" t haskell-operator-face) ("<-" t haskell-operator-face) ("`" t nil)))) (ert-deftest haskell-syntactic-definition-face-1 () (check-properties '("F +++ G") '(("+++" t haskell-definition-face)))) (ert-deftest haskell-syntactic-definition-face-1a () (check-properties '("F `abc` G") '(("abc" t haskell-definition-face)))) (ert-deftest haskell-syntactic-definition-face-2 () :expected-result :failed (check-properties '("M.F +++ N.G") '(("+++" t haskell-definition-face)))) (ert-deftest haskell-syntactic-definition-face-2a () :expected-result :failed (check-properties '("M.F `abc` N.G") '(("abc" t haskell-definition-face)))) (ert-deftest haskell-syntactic-definition-face-3 () (check-properties '("Q +++ 12.12") '(("+++" t haskell-definition-face)))) (ert-deftest haskell-syntactic-definition-face-4 () (check-properties '("_test'") '(("_test'" t nil)))) (ert-deftest haskell-syntactic-definition-face-5 () (check-properties '("_test' _") '(("_test'" t haskell-definition-face)))) (ert-deftest haskell-literate-bird-1 () (check-properties '("Comment1" "" "> code1 = 1" "> code2 = 1" "" "Comment2" "" "> code3 = 1" "" "Comment3") '(("Comment1" t haskell-literate-comment-face) ("code1" t haskell-definition-face) ("code2" t haskell-definition-face) ("Comment2" t haskell-literate-comment-face) ("code3" t haskell-definition-face) ("Comment3" t haskell-literate-comment-face)) 'literate-haskell-mode)) (ert-deftest haskell-literate-bird-2 () ;; Haskell Report requires empty line before bird code block. So it ;; is a code block, just in error. :expected-result :failed (check-properties '("Comment1" "> code1 = 1" "> code2 = 1" "Comment2" "" "> code3 = 1" "" "Comment3") '(("Comment1" t haskell-literate-comment-face) (">" t font-lock-warning-face) ("code1" t haskell-definition-face) ("code2" t haskell-definition-face) ("Comment2" t haskell-literate-comment-face) ("code3" t haskell-definition-face) ("Comment3" t haskell-literate-comment-face)) 'literate-haskell-mode)) (ert-deftest haskell-literate-latex-1 () (check-properties '("Comment1" "" "\\begin{code}" "code1 = 1" "code2 = 1" "\\end{code}" "" "Comment2" "\\begin{code}" "code3 = 1" "\\end{code}" "Comment3") '(("Comment1" t haskell-literate-comment-face) ("code1" t haskell-definition-face) ("code2" t haskell-definition-face) ("Comment2" t haskell-literate-comment-face) ("code3" t haskell-definition-face) ("Comment3" t haskell-literate-comment-face)) 'literate-haskell-mode)) (ert-deftest haskell-literate-mixed-1 () ;; Although Haskell Report does not advice mixing modes, it is a ;; perfectly valid construct that we should support in syntax ;; highlighting. (check-properties '("Comment1" "" "> code1 = 1" "> code2 = 1" "" "Comment2" "\\begin{code}" "code3 = 1" "\\end{code}" "Comment3") '(("Comment1" t haskell-literate-comment-face) ("code1" t haskell-definition-face) ("code2" t haskell-definition-face) ("Comment2" t haskell-literate-comment-face) ("code3" t haskell-definition-face) ("Comment3" t haskell-literate-comment-face)) 'literate-haskell-mode)) (ert-deftest haskell-type-instance () "Fontify \"instance\" after \"type\"" ;; Note that instance is always fontified, because it is a keyword even ;; without 'type' before it. (check-properties '("type instance Foo Int = Char") '(("type" "w" haskell-keyword-face) ("instance" "w" haskell-keyword-face)))) (ert-deftest haskell-type-family () "Fontify \"family\" after \"type\"" (check-properties '("type family Foo a :: *") '(("type" "w" haskell-keyword-face) ("family" "w" haskell-keyword-face)))) (ert-deftest haskell-data-family () "Fontify \"family\" after \"data\"" (check-properties '("data family Foo a :: *") '(("data" "w" haskell-keyword-face) ("family" "w" haskell-keyword-face)))) (ert-deftest haskell-no-family () "Don't fontify \"family\" when not after \"type\" or \"data\"" (check-properties '("foo family = 10") '(("foo" "w" haskell-definition-face) ("family" "w" nil)))) (ert-deftest haskell-type-role () "Fontify \"role\" after \"type\"" (check-properties '("type role Ptr representational") '(("type" "w" haskell-keyword-face) ("role" "w" haskell-keyword-face) ("Ptr" "w" haskell-type-face)))) (ert-deftest haskell-no-type-role () "Don't fontify \"role\" when not after \"type\"" (check-properties '("foo role = 3") '(("foo" "w" haskell-definition-face) ("role" "w" nil)))) (ert-deftest haskell-forall-in-type () (check-properties '("forall = 23" "zonk :: forall x . x -> x") '(("forall" "w" haskell-definition-face) ("forall" "w" haskell-keyword-face)))) (ert-deftest haskell-unterminated-string-1 () (check-properties '("foo = \"zonk" " Cons") '(("\"" "|" font-lock-warning-face) ("zonk" t font-lock-string-face) ("Cons" "w" haskell-constructor-face)))) (ert-deftest haskell-unterminated-string-2 () (check-properties '"foo = \"zonk" '(("\"" "\"" font-lock-warning-face) ("zonk" t font-lock-string-face)))) (ert-deftest haskell-unterminated-string-3 () (check-properties '"foo = \"zonk\\" '(("\"" "\"" font-lock-warning-face) ("zonk" t font-lock-string-face) ("\\" t font-lock-warning-face)))) (ert-deftest haskell-type-colors-01 () (check-properties "x :: Int -> String" '(("Int" t haskell-type-face) ("String" t haskell-type-face)))) (ert-deftest haskell-type-colors-02 () (check-properties '("x :: (Monad m," " Applicative m)" " => m Int") '(("Monad" t haskell-type-face) ("Applicative" t haskell-type-face) ("Int" t haskell-type-face)))) (ert-deftest haskell-type-colors-03 () (check-properties '("x :: Lens' S A" "y Nothing1 Nothing2 = Nothing3") '(("Lens" t haskell-type-face) ("S" t haskell-type-face) ("A" t haskell-type-face) ("Nothing1" t haskell-constructor-face) ("Nothing2" t haskell-constructor-face) ("Nothing3" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-04 () (check-properties '("x :: Lens' S A" "(++++) Nothing1 Nothing2 = Nothing3") '(("Lens" t haskell-type-face) ("S" t haskell-type-face) ("A" t haskell-type-face) ("Nothing1" t haskell-constructor-face) ("Nothing2" t haskell-constructor-face) ("Nothing3" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-05 () (check-properties '"class (Monad a, Applicative b) => m a Int | a -> b String where" '(("Monad" t haskell-type-face) ("Applicative" t haskell-type-face) ("Int" t haskell-type-face) ("String" t haskell-type-face)))) (ert-deftest haskell-type-colors-06 () (check-properties '"instance (Monad a, Applicative b) => m a Int | a -> b String where" '(("Monad" t haskell-type-face) ("Applicative" t haskell-type-face) ("Int" t haskell-type-face) ("String" t haskell-type-face)))) (ert-deftest haskell-type-colors-07 () :expected-result :failed (check-properties '"data X = X1 String | X2 Int" '(("X" t haskell-type-face) ("X1" t haskell-constructor-face) ("String" t haskell-type-face) ("X2" t haskell-constructor-face) ("Int" t haskell-type-face)))) (ert-deftest haskell-type-colors-08 () ;; simplified version of 07 (check-properties '"data X = X1 String | X2 Int" '(("X" t haskell-type-face)))) (ert-deftest haskell-type-colors-09 () (check-properties '"type X a b = Monad a (Lens b)" '(("X" t haskell-type-face) ("Monad" t haskell-type-face) ("Lens" t haskell-type-face)))) (ert-deftest haskell-type-colors-10 () (check-properties '"type family X a b = Monad a (Lens b)" '(("X" t haskell-type-face) ("Monad" t haskell-type-face) ("Lens" t haskell-type-face)))) (ert-deftest haskell-type-colors-11 () (check-properties '("data X a where" " X1 :: Int1 -> X Int2" " X2 :: String1 -> X String2") '(("X" t haskell-type-face) ("X1" t haskell-constructor-face) ("Int1" t haskell-type-face) ("X" t haskell-type-face) ("Int2" t haskell-type-face) ("X2" t haskell-constructor-face) ("String1" t haskell-type-face) ("X" t haskell-type-face) ("String2" t haskell-type-face)))) (ert-deftest haskell-type-colors-12 () :expected-result :failed (check-properties '"data X = Int1 :+: String2 | String3 :-: Int4" '(("X" t haskell-type-face) ("Int1" t haskell-type-face) (":+:" t haskell-constructor-face) ("String2" t haskell-type-face) ("String3" t haskell-type-face) (":-:" t haskell-constructor-face) ("Int4" t haskell-type-face)))) (ert-deftest haskell-type-colors-13 () (check-properties '"newtype Xa = Xb Int" '(("Xa" t haskell-type-face) ("Xb" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-14 () :expected-result :failed (check-properties '"newtype Xa = Xb Int" '(("Xa" t haskell-type-face) ("Xb" t haskell-constructor-face) ("Int" t haskell-type-face)))) (ert-deftest haskell-type-colors-15 () (check-properties '"newtype Xa = Xb { xbField :: Int }" '(("Xa" t haskell-type-face) ("Xb" t haskell-constructor-face) ("Int" t haskell-type-face)))) (ert-deftest haskell-type-colors-16 () :expected-result :failed (check-properties '"module M ( a, X(..), Y, Z(A,B)) where" '(("M" t haskell-constructor-face) ("X" t haskell-type-face) ("Y" t haskell-type-face) ("Z" t haskell-type-face) ("A" t haskell-constructor-face) ("B" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-17 () (check-properties '"[Just 5 :: Maybe Int | X <- xs]" '(("Just" t haskell-constructor-face) ("Maybe" t haskell-type-face) ("Int" t haskell-type-face) ("X" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-18 () (check-properties '"[Just 5 :: Maybe Int]" '(("Just" t haskell-constructor-face) ("Maybe" t haskell-type-face) ("Int" t haskell-type-face)))) (ert-deftest haskell-type-colors-19 () (check-properties '"(5 :: Int, Just 5 :: Maybe Int) X" '(("Int" t haskell-type-face) ("Just" t haskell-constructor-face) ("Maybe" t haskell-type-face) ("Int" t haskell-type-face) ("X" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-20 () (check-properties '"x { x = 5 :: Int} Nothing" '(("Int" t haskell-type-face) ("Nothing" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-21 () (check-properties '("x = do" " y :: Maybe Int <- return Nothing") '(("Maybe" t haskell-type-face) ("Int" t haskell-type-face) ("Nothing" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-22 () (check-properties '("x = case y :: Int of" " 42 -> Nothing") '(("Int" t haskell-type-face) ("Nothing" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-23 () (check-properties '("x :: Int ->" " String") '(("Int" t haskell-type-face) ("String" t haskell-type-face)))) (ert-deftest haskell-type-colors-24 () (check-properties '("x :: Int ->" "" " -- comment" " {-" " multiline" " -}" "" " String") '(("Int" t haskell-type-face) ("String" t haskell-type-face)))) (ert-deftest haskell-type-colors-25 () (check-properties '("x :: Int" "" " -- comment" " {-" " multiline" " -}" "" " -> String") '(("Int" t haskell-type-face) ("String" t haskell-type-face)))) (ert-deftest haskell-type-colors-26 () (check-properties '("x :: Int" "" " -- comment" " {-" " multiline" " -}" "" "X `abc` Z") '(("Int" t haskell-type-face) ("X" t haskell-constructor-face) ("Z" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-27 () (check-properties '("x" " ::" " Int" " ->" " String") '(("Int" t haskell-type-face) ("String" t haskell-type-face)))) (ert-deftest haskell-type-colors-28 () (check-properties "type instance Typ Int b = Show b" '(("Typ" t haskell-type-face) ("Int" t haskell-type-face) ("Show" t haskell-type-face)))) (ert-deftest haskell-type-colors-29 () :expected-result :failed (check-properties "import qualified X as Y(a,Z(C))" '(("X" t haskell-constructor-face) ("Y" t haskell-constructor-face) ("Z" t haskell-type-face) ("C" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-30 () :expected-result :failed (check-properties "import qualified X as Y hiding(a,Z(C))" '(("X" t haskell-constructor-face) ("Y" t haskell-constructor-face) ("Z" t haskell-type-face) ("C" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-31 () (check-properties ;; open parentheses do not keep type decl open because there might ;; be an unclosed parenthesis stretching to the end of file and ;; that is very costly to check '("x :: (OpenParen" " NotType)") '(("OpenParen" t haskell-type-face) ("NotType" t haskell-constructor-face)))) (ert-deftest haskell-type-colors-32 () (check-properties ;; keywords in comments or strings should not create problems '("flagSpec \"partial-type-signatures\" Opt_WarnPartialTypeSignatures," "{- class -} Cons2" "-- type" " Cons3") '(("Opt_WarnPartialTypeSignatures" t haskell-constructor-face) ("Cons2" t haskell-constructor-face) ("Cons3" t haskell-constructor-face)))) (ert-deftest haskell-pattern-1 () "Fontify the \"pattern\" keyword in contexts related to pattern synonyms." (check-properties '("pattern A = B" "pattern A <- B" "pattern A ← B" "pattern A n <- (subtract 1 -> n) where A n = n + 1" "module Main (pattern A) where" "pattern A :: a -> B" "pattern A :: (C a) => a -> B" "pattern A :: (C a) => a -> B" "pattern A :: (C a) => () => a -> B" "pattern A :: (C a) => () => a -> B" "pattern A :: (C a) => (C a) => a -> B" "pattern A :: (C a) => (C a) => a -> B") '(("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("module" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("where" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face)))) (ert-deftest haskell-pattern-2 () (check-properties '("pattern :: Int" "pattern = 3") '(("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face)))) (ert-deftest haskell-pattern-3 () (check-properties '("foo :: (a -> pattern) -> a -> pattern" "foo pattern x = pattern x" "bar = pattern where pattern = 5") '(("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face) ("pattern" t haskell-keyword-face)))) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-indent-tests.el�����������������������������������������������������0000664�0000000�0000000�00000051636�13602233217�0021547�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;; -*- lexical-binding: t -*- (require 'ert) (require 'haskell-indent) (require 'haskell-mode) (ert-deftest haskell-indent-in-comment-1 () "Document bad behavior. Should not assert." :expected-result :failed ;; Emacs 25 (snapshot) starts debugger on cl-assert ;; even in batch mode. So we do not run this test. (skip-unless (< emacs-major-version 25)) (should (with-temp-buffer (haskell-mode) (haskell-indent-mode) (insert (concat "module Test where\n" "-- {{{ A header\n" "--\n")) (indent-for-tab-command) t))) ;; haskell-indent-put-region-in-literate happens to be in haskell-indent ;; when the function is moved, move the tests also (ert-deftest haskell-indent-put-region-in-literate-1 () (should (equal "> literate" (with-temp-buffer (insert "literate") (literate-haskell-mode) (haskell-indent-put-region-in-literate (point-min) (point-max)) (buffer-substring-no-properties (point-min) (point-max)))))) (ert-deftest haskell-indent-put-region-in-literate-2 () :expected-result (if (< emacs-major-version 24) :failed :passed) (should (equal "literate" (with-temp-buffer (insert "> literate") (literate-haskell-mode) (haskell-indent-put-region-in-literate (point-min) (point-max) -1) (buffer-substring-no-properties (point-min) (point-max)))))) (defsubst string-trim-left (string) "Remove leading whitespace from STRING." (if (string-match "\\`[ \t\n\r]+" string) (replace-match "" t t string) string)) (defun haskell-indent-format-info (info) (if (cdr info) (list (car info) (substring-no-properties (cdr info))) (car info))) (defun haskell-indent-check (source &rest test-cases) "Check if `haskell-indentation-find-indentations' returns expected results. SOURCE should be a string representing Haskell source code. It will be inserted in a brand-new buffer where `haskell-mode' and `haskell-indent-mode' are enabled. Position of point and expected results of `haskell-indentation-find-indentations' are described in TEST-CASES. Every element in TEST-CASES list should have the following structure: (line pos0 pos1 pos2 …) point will be placed in the first column of LINE before testing. POS0, POS1, POS2, … are expressions representing indentation positions. For example: (2 0 7) means that when point is placed at line 2 and column 0, `haskell-indentation-find-indentations' should return value that's equal to (0 7). It's recommended to specify several test-cases per one snippet because it helps increase coverage." (dolist (current test-cases) (cl-destructuring-bind (line . result) current (with-temp-buffer (let ((haskell-indent-offset 2)) (haskell-mode) (haskell-indent-mode 1) (insert source) (newline) (font-lock-fontify-buffer) (goto-char (point-min)) (forward-line (1- line)) (should (equal current (cons (line-number-at-pos) (condition-case condition (reverse (mapcar #'haskell-indent-format-info (haskell-indent-indentation-info))) (error ;; for unknown reason Emacs 24.4 ERT does not ;; catch overrun recursion, so we have to ;; catch it here, and throw it again (signal (car condition) (cdr condition)))))))))))) (defmacro hindent1-test (name source &rest test-cases) "Define ert test using `haskell-indentation-check'. This little macro helps eliminate boilerplate. It automatically expracts prefix from NAME and uses it to name result test. If the prefix (everything before first space) contains asterisk *, this test is allowed to fail. It trims empty lines from the beginning of SOURCE. TEST-CASES don't need to be quoted, the macro quotes them for you." (declare (indent defun)) (let ((split-pos (cl-position ? name))) (cl-destructuring-bind (test-name allow-failure doc-string) (if split-pos (let ((raw-prefix (substring name 0 split-pos))) (list (intern (concat "haskell-indent-check-" (remove ?* raw-prefix))) (cl-find ?* raw-prefix) (substring name (1+ split-pos)))) (list 'haskell-indent-check-fixme nil name)) `(ert-deftest ,test-name () ,doc-string :expected-result ,(if allow-failure :failed :passed) (haskell-indent-check ,(string-trim-left source) ,@(mapcar (lambda (x) (list 'quote x)) test-cases)))))) (hindent1-test "1 Check if '{' on its own line gets properly indented"" function = Record { field = 123 }" (1 0) (2 0 11)) (hindent1-test "2* Handle underscore in identifiers"" function = do (_x) <- return () z" (1 0) (2 2) (3 0 2 4)) (hindent1-test "2u* Handle underscore in identifiers"" function = do (_x) ← return () z" (1 0) (2 2) (3 0 2 4)) (hindent1-test "2a* Handle apostrophe in identifiers"" function = do (_'x') <- return () z" (1 0) (2 2) (3 0 2 4)) (hindent1-test "2au* Handle apostrophe in identifiers"" function = do (_'x') ← return () z" (1 0) (2 2) (3 0 2 4)) (hindent1-test "3* Import statememnt symbol list 1"" import Control.Concurrent ( forkIO, killThread )" (1 0) (2 0 7) (3 9) (4 0 7)) (hindent1-test "4* Import statememnt symbol list 2"" import Control.Concurrent ( forkIO , killThread )" (1 0) (2 0 7) (3 7) (4 0 7)) (hindent1-test "5* List comprehension"" fun = [ x | y , z ]" (1 0) (2 10) (3 0 2)) (hindent1-test "5a* List comprehension"" fun = [ x | y, z ]" (1 0) (2 12) (3 0 6)) (hindent1-test "6* \"let\" in list comprehension"" fun = [ f | x <- xs , y <- ys , let c = 123 , f <- fx x y c ]" (1 0) (2 10) (3 10) (4 10) (5 0 6)) (hindent1-test "6u* \"let\" in list comprehension"" fun = [ f | x ← xs , y ← ys , let c = 123 , f ← fx x y c ]" (1 0) (2 10) (3 10) (4 10) (5 0)) (hindent1-test "6b* \"let\" in do"" fact n = do let g = 7 z <- let x = 5 in return (x + 4)" (1 0) (2 2) (3 2 6 8) (4 7) (5 2 10)) (hindent1-test "7a* \"data\" after \"data\""" data ABC = ABC data DEF = DEF" (1 0) (2 0)) (hindent1-test "7* \"import\" after \"import\""" import ABC import DEF" (1 0) (2 0) (3 0 7)) (hindent1-test "7b* declaration after declaration" " fun1 = undefined fun2 = undefined" (1 0) (2 0)) (hindent1-test "8* Guards in function definition"" resolve (amount, max) number | number > max = (1, number) | number == max = (amount + 1, number)" (1 0) (2 2) (3 0 2) (4 0 2)) (hindent1-test "9* Operator last on line"" fun = x ++" (1 0) (2 6)) (hindent1-test "10 Operator first on line"" fun = x ++ z" (1 0) (2 0 6)) (hindent1-test "11* Guards with commas"" clunky env var1 var2 | Just val1 <- lookup env var1 , Just val2 <- lookup env var2" (1 0) (2 2) (3 2) (4 0 4)) (hindent1-test "11u* Guards with commas"" clunky env var1 var2 | Just val1 ← lookup env var1 , Just val2 ← lookup env var2" (1 0) (2 2) (3 2) (4 0 4)) (hindent1-test "12* \"do\" as expression"" fun = do { putStrLn \"X\"; }" (1 0) (2 9 11) (3 0)) (hindent1-test "13* Don't indent after deriving"" data X = X deriving (Eq, Ord, Show)" (1 0) (2 0 2) (3 0)) (hindent1-test "13b honour = on a separate line in data declaration" " data X a b = X" (1 0) (2 2)) (hindent1-test "14* Line starting with operator inside \"do\" needs to be indented"" fun = do pure X something <*> marg" (1 0) (2 2) (3 0 2) (4 4)) (hindent1-test "15* An \"if..then\" inside a \"do\" block"" fun = do if x then do putStrLn \"True\"" (1 0) (2 2) (3 2) (4 4) (5 2 4)) (hindent1-test "16 Lambda and a \"do\" block"" fun = \\x -> do" (1 0) (2 8)) (hindent1-test "16a* A lambda"" fun = \\x ->" (1 0) (2 2)) (hindent1-test "16u Lambda and a do block"" fun = \\x → do" (1 0) (2 8)) (hindent1-test "16au* A lambda"" fun = \\x →" (1 0) (2 8)) (hindent1-test "17a* A type for a function"" fun :: Int -> Int" (1 0) (2 4) (3 0 4)) (hindent1-test "17au* A type for a function"" fun :: Int → Int" (1 0) (2 4) (3 0 4)) (hindent1-test "17b* A type for a function with context"" fun :: Monad m => Int" (1 0) (2 4) (3 0 4)) (hindent1-test "17bu* A type for a function with context"" fun ∷ Monad m ⇒ Int" (1 0) (2 4) (3 0 4)) (hindent1-test "17c* A type for a function with complicated context"" fun :: (Monad m, MonadBaseControl IO m, MyMonad (A v) m) => MyMonad (A v) m" (1 0) (2 4) (3 0 4)) (hindent1-test "17cu* A type for a function with complicated context"" fun ∷ (Monad m, MonadBaseControl IO m, MyMonad (A v) m) ⇒ MyMonad (A v) m" (1 0) (2 4) (3 0 4)) (hindent1-test "17d* A type for a function with param and a complicated context"" fun :: (Monad m, MonadBaseControl IO m, MyMonad (A v) m) => MyMonad (A v) m -> m (Maybe a)" (1 0) (2 4) (3 4) (4 0 4)) (hindent1-test "17du* A type for a function with param and a complicated context"" fun ∷ (Monad m, MonadBaseControl IO m, MyMonad (A v) m) ⇒ MyMonad (A v) m → m (Maybe a)" (1 0) (2 4) (3 4) (4 0 4)) (hindent1-test "18a* \"if-then-else\" indentation: \"then\""" x = if flag then 1" (1 0) (2 4) (3 4 9)) (hindent1-test "18b* \"if-then-else\" indentation: \"else\""" x = if flag then 1 else 0" (1 0) (2 4) (3 4) (4 0 9)) (hindent1-test "18c* \"do\" and \"if-then-else\" indentation: \"then\""" x = do if flag then 1" (1 0) (2 2) (3 2) (4 2)) (hindent1-test "18d* \"do\" and \"if-then-else\" indentation: \"else\""" x = do if flag then 1 else 0" (1 0) (2 2) (3 2) (4 2)) (hindent1-test "18e* \"do\" and \"if-then-else\" indentation: \"else\""" x = do if flag then do return ()" (1 0) (2 2) (3 2) (4 4) (5 2 4)) (hindent1-test "18f* \"do\" and \"if-then-else\" indentation: \"else\""" x = do if flag then do return () else do return ()" (1 0) (2 2) (3 2) (4 4) (5 2 4) (6 4) (7 0 2 4)) (hindent1-test "19a* \"let\" and \"in\""" x = let y" (1 0) (2 2) (3 2)) (hindent1-test "19b* \"let\" and \"in\"" " x = let y in z" (1 0) (2 4) (3 6)) (hindent1-test "19c* \"let\" in a \"do\""" x = do thing let z = 5" (1 0) (2 2) (3 2) (4 4)) (hindent1-test "20a* \"instance\" declaration"" instance C a where c = undefined" (1 0) (2 2) (3 0 2)) (hindent1-test "20b* \"instance\" declaration"" instance (Monad m) => C m a where c = undefined" (1 0) (2 2) (3 0 2)) (hindent1-test "20bu* \"instance\" declaration"" instance (Monad m) ⇒ C m a where c = undefined" (1 0) (2 2) (3 0 2)) (hindent1-test "21a* fix \"let\" statement in \"do\" block"" main :: IO () main = do let foo = Foo { bar = 0 , baz = 0" (1 0) (2 0) (3 2) (4 6) (5 6) (6 8)) (hindent1-test "21b* fix named fields in \"data\" declaration"" data Foo = Foo { bar :: Int , baz :: Int" (1 0) (2 4) (3 2) (4 11)) (hindent1-test "21c* \"data\" declaration open on next line" " data Foo = Foo { bar :: Int , baz :: Int" (1 0) (2 2) (3 2) (4 4 11)) (hindent1-test "22* should obey layout only outside parentheses" " func = 1234 where foo :: Ivory eff () foo = do return ()" (1 0) (2 2) (3 4) (4 0 4 11) (5 6)) (hindent1-test "23* should not fail when seeing comments" " -- important non-empty line {- -}" ((3 2) 0)) (hindent1-test "24* should parse inline type signatures properly" " foo = do _ :: String <- undefined _ :: String <- undefined return ()" (1 0) (2 2) (3 0 2 4) (4 0 2 4)) (hindent1-test "25a* support scoped type declarations" " foo = do bar :: String -> String <- undefined" (1 0) (2 2) (3 6 9) ;; here it brakes, it would like to put '<-' on same line with 'bar' ;; the culprit is the 'do' keyword (4 4)) (hindent1-test "25b* support scoped type declarations" " foo = let bar :: String -> String = undefined" (1 0) (2 2) (3 6 9) (4 4)) (hindent1-test "26 should parse unindented where-clause properly" " foo = do return () where bar = undefined" (4 4)) (hindent1-test "27* expecting then (GH-884)" " foo = do if True then return () " (4 4)) (hindent1-test "28a names starting with quotes" " f = a (a 'A) (a 'A) " (2 0 4)) (hindent1-test "28b character literal (escape sequence)" " f = '\\\\' " (2 0 4)) (hindent1-test "28c name starting with a quote" " function (Operation 'Init) = do print 'Init " (2 2)) (hindent1-test "29a quasiquote single line" " test = [randomQQ| This is a quasiquote with the word in |] " (2 0 7)) (hindent1-test "29b* quasiquote multiple lines" " test = [randomQQ| This is a quasiquote with the word in |] " (4 0 2)) (hindent1-test "30* parse '[] identifier correctly" " instance Callable '[] " (1 2)) (hindent1-test "31* allow type class declaration without methods" " class Foo a where instance Bar Int " (2 0)) (hindent1-test "32* allow type operators" " data (:.) a b = a :. b " (2 0 2)) (hindent1-test "33* parse #else in CPP" " #ifdef FLAG foo = () #else " (4 0)) (hindent1-test "34 beginning of line inside parentheses" " data T = T { foo :: String , bar :: String } " (5 0)) (hindent1-test "35* baroque construct which causes parse error" " az = Projection { unproject = do case x of _ -> return , maxR = pi } " (6 2)) (hindent1-test "35a* parse a backslash properly" " az = Projection { unproject = \\x -> do case x of _ -> return , maxR = pi } " (6 2)) (hindent1-test "36* yet another parser failure" " tokOpenTag = asum [ do void , return ] " (4 7)) (hindent1-test "37* Indent continuation lines in multiline string literal" " a = \"multiline\\ " (2 4)) (hindent1-test "38* Indent in do block after multiline string literal" " s = do a <- \"multiline\\ \\ line 2\" " (4 0 2 4)) (hindent1-test "39* do not crash after two multiline literals in do block" " servePost = do a <- fun \"line 1\\ \\line 2\" b <- queryT \"comma is important: , \\ \\ line 2 \" " (6 0 2 4)) (hindent1-test "40* parse error in multiline tuple" " a = ( 1 , " (2 4) (3 2)) (hindent1-test "41 open do inside a list" " x = asum [ withX $ do return () ] " (2 13)) (hindent1-test "42 open do inside a list second element" " x = asum [ mzero , withX $ do return () ] " (3 13)) (hindent1-test "43 open do inside a list second element, reset alignment" " x = asum [ mzero , withX $ do return () ] " (3 15)) (hindent1-test "44 expression continues, reset alignment" " function = abc def xyz" (3 0 7)) (hindent1-test "46* case expression with paths on their own lines" " fact n = case n of 0 -> 1 _ -> n * fact (n - 1) " (1 0) (2 2) (3 4) (4 0 2 4 6) (5 0 2 4 6)) (hindent1-test "46b* case expression with guards" " fact n = case n of n | n == 0 -> 1 _ | n > 0 , True == True -> n * fact (n - 1)" (1 0) (2 2) ;; returns (0 2 2 6), to investigate (3 0 2 6) (4 4) (5 0 2 6)) (hindent1-test "47a* multiline strings" " fact n = \"\\ \\a\"" (1 0) ;; we want to offer both a continuation style and the ;; align to left column style (like in lisp) (2 0 9) (3 0 2)) (hindent1-test "47b* multiline strings" " fact n = \"\\ \\a\\ \\x\"" ;; here we want to keep third line like the second one, ;; although the second one wasn't best indented (1 0) (2 0 9) (3 6)) (hindent1-test "48* functional dependencies" " class X a b | a -> b , b -> a where fun :: a -> b" (1 0) (2 12) (3 2) (4 0 2 9)) (hindent1-test "49* data with GADT syntax" " data Term a where Lit :: Int -> Term Int Pair :: Term a -> Term b -> Term (a,b)" (1 0) (2 2) (3 0 2 9) (4 0 2 10)) (hindent1-test "49b* data with GADT syntax and a deriving clause" " data G [a] b where G1 :: c -> G [Int] b deriving (Eq)" (1 0) (2 2) (3 0 2)) (hindent1-test "50* standalone deriving" " data Name = Name String deriving instance Eq Name" (1 0) ;; We accept position 2 here because we have just one ;; look-ahead token so we do not see 'instance' ;; following 'deriving'. (2 0 2)) (hindent1-test "51* standalone deriving" " data family T a data instance T Int = T1 Int | T2 Bool newtype instance T Char = TC Bool" ;; We check that indentation does not bail on 'instance' ;; here, we do not really check if it is working ;; correctly. Needs better test. (1 0) (2 0) (3 0) (4 0 2)) (hindent1-test "52a* module simplest case two lines" " module A.B where" (1 0) (2 0) (3 0)) (hindent1-test "52b* module simplest case one line" " module A.B where" (1 0) (2 0)) (hindent1-test "52c* module with exports" " module A.B ( x , y ) where" (1 0) (2 2) (3 2) (4 2) (5 0) (6 0)) (hindent1-test "53* multiway if" " fun = if | guard1 -> expr1 | guardN -> exprN" (1 0) (2 9) (3 0 11)) (hindent1-test "54* equal after guards on separate line" " foo x | True = X" (1 0) (2 2) (3 2)) ��������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-indentation-tests.el������������������������������������������������0000664�0000000�0000000�00000060432�13602233217�0022574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-indentation-tests.el --- tests for indentation module -*- lexical-binding: t -*- ;; Copyright © 2015 Haskell Mode contributors. All rights reserved. ;; 2016 Arthur Fayzrakhmanov. ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Commentary: ;; These are tests for `haskell-indentation-mode'. It's easy to add new ;; tests, just... (require 'cl-lib) (require 'ert) (require 'haskell-test-utils) (require 'haskell-mode) (require 'haskell-font-lock) (require 'haskell-indentation) (require 'haskell-indent) ;;; Code: (defsubst string-trim-left (string) "Remove leading whitespace from STRING." (if (string-match "\\`[ \t\n\r]+" string) (replace-match "" t t string) string)) (defun haskell-indentation-check (source &rest test-cases) "Check if `haskell-indentation-find-indentations' returns expected results. SOURCE should be a string representing Haskell source code. It will be inserted in a brand-new buffer where `haskell-mode' and `haskell-indent-mode' are enabled. Position of point and expected results of `haskell-indentation-find-indentations' are described in TEST-CASES. Every element in TEST-CASES list should have the following structure: (line pos0 pos1 pos2 …) point will be placed in the first column of LINE before testing. POS0, POS1, POS2, … are expressions representing indentation positions. For example: (2 0 7) means that when point is placed at line 2 and column 0, `haskell-indentation-find-indentations' should return value that's equal to (0 7). It's recommended to specify several test-cases per one snippet because it helps increase coverage." (dolist (current test-cases) (cl-destructuring-bind (line . result) current (with-temp-buffer (haskell-mode) (haskell-indentation-mode 1) (insert source) (newline) (font-lock-fontify-buffer) (goto-char (point-min)) (forward-line (1- line)) (should (equal current (cons (line-number-at-pos) (condition-case condition (haskell-indentation-find-indentations) (error ;; for unknown reason Emacs 24.4 ERT does not ;; catch overrun recursion, so we have to ;; catch it here, and throw it again (signal (car condition) (cdr condition))))))))))) (defmacro hindent-test (name source &rest test-cases) "Define ert test using `haskell-indentation-check'. This little macro helps eliminate boilerplate. It automatically expracts prefix from NAME and uses it to name result test. If the prefix (everything before first space) contains asterisk *, this test is allowed to fail. It trims empty lines from the beginning of SOURCE. TEST-CASES don't need to be quoted, the macro quotes them for you." (declare (indent defun)) (let ((split-pos (cl-position ? name))) (cl-destructuring-bind (test-name allow-failure doc-string) (if split-pos (let ((raw-prefix (substring name 0 split-pos))) (list (intern (concat "haskell-indentation-check-" (remove ?* raw-prefix))) (cl-find ?* raw-prefix) (substring name (1+ split-pos)))) (list 'haskell-indentation-check-fixme nil name)) `(ert-deftest ,test-name () ,doc-string :expected-result ,(if allow-failure :failed :passed) (haskell-indentation-check ,(string-trim-left source) ,@(mapcar (lambda (x) (list 'quote x)) test-cases)))))) (ert-deftest haskell-indentation-turns-off-haskell-indent () (with-temp-buffer (haskell-mode) (haskell-indent-mode) (should haskell-indent-mode) (haskell-indentation-mode) (should haskell-indentation-mode) (should-not haskell-indent-mode) (haskell-indent-mode) (should-not haskell-indentation-mode) (should haskell-indent-mode))) (hindent-test "1 Check if '{' on its own line gets properly indented"" function = Record { field = 123 }" (1 0) (2 2 11)) (hindent-test "2 Handle underscore in identifiers"" function = do (_x) <- return () z" (1 0) (2 2) (3 0 2 4 10)) (hindent-test "2u Handle underscore in identifiers"" function = do (_x) ← return () z" (1 0) (2 2) (3 0 2 4 9)) (hindent-test "2a Handle apostrophe in identifiers"" function = do (_'x') <- return () z" (1 0) (2 2) (3 0 2 4 12)) (hindent-test "2au Handle apostrophe in identifiers"" function = do (_'x') ← return () z" (1 0) (2 2) (3 0 2 4 11)) (hindent-test "3 Import statememnt symbol list 1"" import Control.Concurrent ( forkIO, killThread )" (1 0) (2 0 2 7) (3 9) (4 0 2 7)) (hindent-test "4 Import statememnt symbol list 2"" import Control.Concurrent ( forkIO , killThread )" (1 0) (2 0 2 7) (3 7) (4 0 2 7)) (hindent-test "5 List comprehension"" fun = [ x | y , z ]" (1 0) (2 8 10) (3 0 2 6)) (hindent-test "5a* List comprehension"" fun = [ x | y, z ]" (1 0) (2 12) (3 0 6)) (hindent-test "6a* \"let\" in list comprehension"" fun = [ f | x <- xs , y <- ys , let c = 123 , f <- fx x y c ]" (1 0) (2 10) (3 10) (4 10) (5 0 6)) (hindent-test "6b* \"let\" in list comprehension"" fun = [ f | x <- [1] , y <- [2] , let c, d :: Int c = 123 d = 45 , f <- [x * y * c * d] ]" ;; this one is interesting because the comma betweed c ;; and d does not count as a comma for list ;; comprehension elements (1 0) (2 10) (3 10) (4 16) (5 16) (6 10) (7 0 6)) (hindent-test "6u* \"let\" in list comprehension"" fun = [ f | x ← xs , y ← ys , let c = 123 , f ← fx x y c ]" (1 0) (2 10) (3 10) (4 10) (5 0)) (hindent-test "6bx \"let\" in do"" fact n = do let g = 7 z <- let x = 5 in return (x + 4)" (1 0) (2 2) (3 2 6 8 10) (4 4 7) (5 0 2 4 10)) (hindent-test "7a \"data\" after \"data\""" data ABC = ABC data DEF = DEF" (1 0) (2 0)) (hindent-test "7 \"import\" after \"import\""" import ABC import DEF" (1 0) (2 0) (3 0 2 7)) (hindent-test "7b declaration after declaration" " fun1 = undefined fun2 = undefined" (1 0) (2 0 2 7)) (hindent-test "8 Guards in function definition"" resolve (amount, max) number | number > max = (1, number) | number == max = (amount + 1, number)" (1 0) (2 2) (3 2) (4 0 2 4 20)) (hindent-test "9 Operator last on line"" fun = x ++" (1 0) (2 2 6)) (hindent-test "10 Operator first on line"" fun = x ++ z" (1 0) (2 2 6)) (hindent-test "11 Guards with commas"" clunky env var1 var2 | Just val1 <- lookup env var1 , Just val2 <- lookup env var2" (1 0) (2 2) (3 2) (4 0 2 4 17)) (hindent-test "11u Guards with commas"" clunky env var1 var2 | Just val1 ← lookup env var1 , Just val2 ← lookup env var2" (1 0) (2 2) (3 2) (4 0 2 4 16)) (hindent-test "12 \"do\" as expression"" fun = do { putStrLn \"X\"; }" (1 0) (2 9 11) (3 0 2)) (hindent-test "13a Deriving on new line"" data X = X | Y deriving (Eq, Ord, Show)" (1 0) (2 0 2 7)) (hindent-test "13b Don't indent after deriving"" data X = X deriving (Eq, Ord, Show)" (1 0) (2 0 2 7) (3 0)) (hindent-test "13bb Don't indent after deriving"" data X = X deriving" (1 0) (2 0 2 7) (3 4)) (hindent-test "13c honour = on a separate line in data declaration" " data X a b = X" (1 0) (2 2)) (hindent-test "14* Line starting with operator inside \"do\" needs to be indented"" fun = do pure X something <*> marg" (1 0) (2 2) (3 0 2) (4 4)) (hindent-test "15* An \"if..then\" inside a \"do\" block"" fun = do if x then do putStrLn \"True\"" (1 0) (2 2) (3 2) (4 4) (5 2 4)) (hindent-test "16 Lambda and a \"do\" block"" fun = \\x -> do" (1 0) (2 2)) (hindent-test "16a A lambda"" fun = \\x ->" (1 0) (2 2 8)) (hindent-test "16u Lambda and a do block"" fun = \\x → do" (1 0) (2 2)) (hindent-test "16au A lambda"" fun = \\x →" (1 0) (2 2 8)) (hindent-test "17a A type for a function"" fun :: Int -> Int" (1 0) (2 2 4) (3 0 2 4)) (hindent-test "17au A type for a function"" fun :: Int → Int" (1 0) (2 2 4) (3 0 2 4)) (hindent-test "17b* A type for a function with context"" fun :: Monad m => Int" (1 0) (2 4) (3 0 4)) (hindent-test "17bu* A type for a function with context"" fun ∷ Monad m ⇒ Int" (1 0) (2 4) (3 0 4)) (hindent-test "17c* A type for a function with complicated context"" fun :: (Monad m, MonadBaseControl IO m, MyMonad (A v) m) => MyMonad (A v) m" (1 0) (2 4) (3 0 4)) (hindent-test "17cu* A type for a function with complicated context"" fun ∷ (Monad m, MonadBaseControl IO m, MyMonad (A v) m) ⇒ MyMonad (A v) m" (1 0) (2 4) (3 0 4)) (hindent-test "17d* A type for a function with param and a complicated context"" fun :: (Monad m, MonadBaseControl IO m, MyMonad (A v) m) => MyMonad (A v) m -> m (Maybe a)" (1 0) (2 4) (3 4) (4 0 4)) (hindent-test "17du* A type for a function with param and a complicated context"" fun ∷ (Monad m, MonadBaseControl IO m, MyMonad (A v) m) ⇒ MyMonad (A v) m → m (Maybe a)" (1 0) (2 4) (3 4) (4 0 4)) (hindent-test "18a* \"if-then-else\" indentation: \"then\""" x = if flag then 1" (1 0) (2 4) (3 4 9)) (hindent-test "18b \"if-then-else\" indentation: \"else\""" x = if flag then 1 else 0" (1 0) (2 2 4) (3 2 4) (4 0 2 9)) (hindent-test "18c* \"do\" and \"if-then-else\" indentation: \"then\""" x = do if flag then 1" (1 0) (2 2) (3 2) (4 2)) (hindent-test "18d* \"do\" and \"if-then-else\" indentation: \"else\""" x = do if flag then 1 else 0" (1 0) (2 2) (3 2) (4 2)) (hindent-test "18e* \"do\" and \"if-then-else\" indentation: \"else\""" x = do if flag then do return ()" (1 0) (2 2) (3 2) (4 4) (5 2 4)) (hindent-test "18f* \"do\" and \"if-then-else\" indentation: \"else\""" x = do if flag then do return () else do return ()" (1 0) (2 2) (3 2) (4 4) (5 2 4) (6 4) (7 0 2 4)) (hindent-test "19a \"let\" and \"in\""" x = let y" (1 0) (2 2) (3 0 2 4)) (hindent-test "19b \"let\" and \"in\"" " x = let y in z" (1 0) (2 2 4) (3 2 6)) (hindent-test "19c \"let\" in a \"do\""" x = do thing let z = 5" (1 0) (2 2) (3 0 2 4) (4 4)) (hindent-test "20a \"instance\" declaration"" instance C a where c = undefined" (1 0) (2 2) (3 0 2 4 6)) (hindent-test "20b \"instance\" declaration"" instance (Monad m) => C m a where c = undefined" (1 0) (2 2) (3 0 2 4 6)) (hindent-test "20bu \"instance\" declaration"" instance (Monad m) ⇒ C m a where c = undefined" (1 0) (2 2) (3 0 2 4 6)) (hindent-test "21a fix \"let\" statement in \"do\" block"" main :: IO () main = do let foo = Foo { bar = 0 , baz = 0" (1 0) (2 0 2 8) (3 2) (4 6) (5 6) (6 6 8 14)) (hindent-test "21b fix named fields in \"data\" declaration"" data Foo = Foo { bar :: Int , baz :: Int" (1 0) (2 2) (3 2) (4 2 4 8 11)) (hindent-test "21c \"data\" declaration open on next line" " data Foo = Foo { bar :: Int , baz :: Int" (1 0) (2 2 11) (3 2) (4 2 4 8 11)) (hindent-test "22 should obey layout only outside parentheses" " func = 1234 where foo :: Ivory eff () foo = do return ()" (1 0) (2 2) (3 4) (4 0 4 6 11) (5 6)) (hindent-test "23 should not fail when seeing comments" " -- important non-empty line {- -}" (3 0)) (hindent-test "24 should parse inline type signatures properly" " foo = do _ :: String <- undefined _ :: String <- undefined return ()" (1 0) (2 2) (3 0 2 4 17) (4 0 2 4 17)) (hindent-test "25a* support scoped type declarations" " foo = do bar :: String -> String <- undefined" (1 0) (2 2) (3 4 6 9) ;; here it brakes, it would like to put '<-' on same line with 'bar' ;; the culprit is the 'do' keyword (4 4)) (hindent-test "25b support scoped type declarations" " foo = let bar :: String -> String = undefined" (1 0) (2 2) (3 4 6) (4 4)) (hindent-test "26 should parse unindented where-clause properly" " foo = do return () where bar = undefined" (4 4)) (hindent-test "27* expecting then (GH-884)" " foo = do if True then return () " (4 4)) (hindent-test "28a names starting with quotes" " f = a (a 'A) (a 'A) " (2 0 2 4)) (hindent-test "28g continue expression after value" " f = a a" (3 0 2 7)) (hindent-test "28h continue expression after parentheses" " f = a (a)" (3 0 2 7)) (hindent-test "28b character literal (escape sequence)" " f = '\\\\' " (2 0 2 4)) (hindent-test "28c name starting with a quote" " function (Operation 'Init) = do print 'Init " (2 2)) (hindent-test "29a quasiquote single line" " test = [randomQQ| This is a quasiquote with the word in |]" (2 2)) (hindent-test "29b quasiquote multiple lines" " test = [randomQQ| This is a quasiquote with the word in |]" (4 2)) (hindent-test "29c quasiquote with quotes in it and a string outside" " foo = do let bar = [text|\"some text\"|] button \"Cancel\" $ do " (4 4)) (hindent-test "29d unfinished quasiquote" " foo = [text|some " (2 0 11)) (hindent-test "29e an expression quotation" " foo = [|forever $ do " (2 10)) (hindent-test "30 parse '[] identifier correctly" " instance Callable '[] where " (2 2)) (hindent-test "31* allow type class declaration without methods" " class Foo a where instance Bar Int " (2 0)) (hindent-test "32 allow type operators" " data (:.) a b = a :. b" (2 0 2 14 16)) (hindent-test "32b next line after data" " data X = X | Y" (2 0 2 7 13)) (hindent-test "32c* next line after unfinished data" " data X = X | Y |" (2 2 9)) (hindent-test "33* parse #else in CPP" " #ifdef FLAG foo = () #else " (4 0)) (hindent-test "34 beginning of line inside parentheses" " data T = T { foo :: String , bar :: String } " (5 0 2 7 9)) (hindent-test "35 baroque construct which causes parse error" " az = Projection { unproject = do case x of _ -> return , maxR = pi } " (6 2)) (hindent-test "35a parse a backslash properly" " az = Projection { unproject = \\x -> do case x of _ -> return , maxR = pi } " (6 2)) (hindent-test "36 yet another parser failure" " tokOpenTag = asum [ do void , return ] " (4 7)) (hindent-test "37 Indent continuation lines in multiline string literal" " a = \"multiline\\ " (2 0 4)) (hindent-test "38 Indent in do block after multiline string literal" " s = do a <- \"multiline\\ \\ line 2\" " (4 0 2 4 7)) (hindent-test "39 do not crash after two multiline literals in do block" " servePost = do a <- fun \"line 1\\ \\line 2\" b <- queryT \"comma is important: , \\ \\ line 2 \" " (6 0 2 4 7)) (hindent-test "40 parse error in multiline tuple" " a = ( 1 , " (2 4) (3 6)) (hindent-test "41 open do inside a list" " x = asum [ withX $ do return () ] " (2 13)) (hindent-test "42 open do inside a list second element" " x = asum [ mzero , withX $ do return () ] " (3 13)) (hindent-test "43 open do inside a list second element, reset alignment" " x = asum [ mzero , withX $ do return () ] " (3 17)) (hindent-test "44 expression continues, reset alignment" " function = abc def xyz" (3 0 2 7)) (hindent-test "46 case expression with paths on their own lines" " fact n = case n of 0 -> 1 _ -> n * fact (n - 1) " (1 0) (2 2) (3 4) (4 0 2 4 6 9) (5 0 2 4 6 9)) (hindent-test "46b case expression with guards" " fact n = case n of n | n == 0 -> 1 _ | n > 0 , True == True -> n * fact (n - 1)" (1 0) (2 2 11) (3 0 2 6 9 16) (4 4) (5 0 2 4 6 9 22)) (hindent-test "47a multiline strings" " fact n = \"\\ \\a\"" (1 0) ;; we want to offer both a continuation style and the ;; align to left column style (like in lisp) (2 0 9) (3 0 2 9)) (hindent-test "47b multiline strings" " fact n = \"\\ \\a\\ \\x\"" ;; here we want to keep third line like the second one, ;; although the second one wasn't best indented (1 0) (2 0 9) (3 6)) (hindent-test "48 functional dependencies" " class X a b | a -> b , b -> a where fun :: a -> b" (1 0) (2 2 12) (3 2) (4 0 2 4 6 9)) (hindent-test "49 data with GADT syntax" " data Term a where Lit :: Int -> Term Int Pair :: Term a -> Term b -> Term (a,b)" (1 0) (2 2) (3 0 2 4 9) (4 0 2 4 7 10)) (hindent-test "49b data with GADT syntax and a deriving clause" " data G [a] b where G1 :: c -> G [Int] b deriving (Eq)" (1 0) (2 2) (3 0 2)) (hindent-test "50 standalone deriving" " data Name = Name String deriving instance Eq Name" (1 0) ;; We accept position 2 here because we have just one ;; look-ahead token so we do not see 'instance' ;; following 'deriving'. (2 0 2 10)) (hindent-test "51 standalone deriving" " data family T a data instance T Int = T1 Int | T2 Bool newtype instance T Char = TC Bool" ;; We check that indentation does not bail on 'instance' ;; here, we do not really check if it is working ;; correctly. Needs better test. (1 0) (2 0) (3 0) (4 0 2 24 26)) (hindent-test "52a module simplest case two lines" " module A.B where" (1 0) (2 0) (3 0)) (hindent-test "52b module simplest case one line" " module A.B where" (1 0) (2 0)) (hindent-test "52c module with exports" " module A.B ( x , y ) where" (1 0) (2 2) (3 2) (4 2) (5 0) (6 0)) (hindent-test "53 multiway if" " fun = if | guard1 -> expr1 | guardN -> exprN" (1 0) (2 9) (3 0 2 9 11 21)) (hindent-test "54 equal after guards on separate line" " foo x | True = X" (1 0) (2 2) (3 2)) (hindent-test "55 data constructor on separate line" " data Foo = Bar | Baz" (1 0) (2 2 9)) (hindent-test "55a deriving below aligned data constructors" " data Foo = Bar | Baz deriving (Show)" (1 0) (2 2 9) (3 0 2 9)) (hindent-test "56 module name on next line" " module X" (1 0) (2 2)) (hindent-test "57 module continued" " module X" (1 0) (2 2)) (hindent-test "58 module where same line" " module X where" (1 0) (2 0)) (hindent-test "59 module where same line" " module X where" (1 0) (2 0) (3 0)) (hindent-test "60* must continue indentation after a vertical bar" " data X = X | Y" (1 0) (2 2 9) (3 0 7 9)) (hindent-test "61 unterminated/multiline strings whose line doesn't end in backslash" " func = \"unterminated where" (1 0) (2 2)) (hindent-test "62 foreign import"" import javascript unsafe \"$2[$1]\" js_getProp :: S.JSString -> O.Object -> T.JSVal" (1 0) (2 0 2 7)) (ert-deftest haskell-indentation-ret-indents () (with-temp-switch-to-buffer (haskell-mode) (insert "main = do") (execute-kbd-macro (kbd "<RET>")) (should (equal 2 (- (point) (line-beginning-position)))))) (ert-deftest haskell-indentation-tab-and-backtab () (with-temp-switch-to-buffer (haskell-mode) (insert "main = do\n lala\n ") (execute-kbd-macro (kbd "TAB")) (should (equal 4 (- (point) (line-beginning-position)))) (execute-kbd-macro (kbd "<backtab>")) (should (equal 2 (- (point) (line-beginning-position)))))) (ert-deftest haskell-indentation-altj-comment () :expected-result :failed ;; Emacs 25 (snapshot) somehow passes this test, there is something ;; fishy going on (skip-unless (< emacs-major-version 25)) (with-temp-switch-to-buffer (haskell-mode) (insert "main = do\n return ()\n\n-- comment") (execute-kbd-macro (kbd "M-j")) (should (equal 3 (- (point) (line-beginning-position)))))) ;;; haskell-indentation-tests.el ends here ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-lexeme-tests.el�����������������������������������������������������0000664�0000000�0000000�00000024732�13602233217�0021542�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;; unit tests for haskell-string.el -*- lexical-binding: t -*- (require 'ert) (require 'haskell-lexeme) ;; implementation under test (require 'haskell-mode) (require 'haskell-font-lock) (defun check-lexemes (lines-or-contents lexemes &optional literate) "Checks if tokenization works as expected. LINES is a list of strings that will be inserted to a new buffer. Then LEXEMES is a list of lexemes that should be found in order." (when (get-buffer "*haskell-mode-buffer*") (kill-buffer "*haskell-mode-buffer*")) (save-current-buffer (set-buffer (get-buffer-create "*haskell-mode-buffer*")) (when (fboundp 'jit-lock-debug-mode) ;; to see stack traces from inside font-lock (jit-lock-debug-mode)) ;; Note that all of this should work both in haskell-mode and ;; outside of it. Currently we test only haskell-mode setup. (if literate (literate-haskell-mode) (haskell-mode)) (if (consp lines-or-contents) (dolist (line lines-or-contents) (insert line) (insert "\n")) (insert lines-or-contents)) (font-lock-fontify-buffer) (goto-char (point-min)) (let (current-token (left-lexemes lexemes)) (while (haskell-lexeme-looking-at-token) (setq current-token (match-string-no-properties 0)) ;; it should be in the list of lexemes at all (should (member current-token lexemes)) ;; it should be next in the list (should (equal (car left-lexemes) current-token)) (setq left-lexemes (cdr left-lexemes)) (goto-char (match-end 0))) (should (equal nil left-lexemes))))) (defun check-lexemes-nocheck (lines-or-contents &optional literate) "Checks if tokenization works as expected. LINES is a list of strings that will be inserted to a new buffer." (when (get-buffer "*haskell-mode-buffer*") (kill-buffer "*haskell-mode-buffer*")) (save-current-buffer (set-buffer (get-buffer-create "*haskell-mode-buffer*")) (if (consp lines-or-contents) (dolist (line lines-or-contents) (insert line) (insert "\n")) (insert lines-or-contents)) (when (fboundp 'jit-lock-debug-mode) ;; to see stack traces from inside font-lock (jit-lock-debug-mode)) ;; Note that all of this should work both in haskell-mode and ;; outside of it. Currently we test only haskell-mode setup. (if literate (literate-haskell-mode) (haskell-mode)) (font-lock-fontify-buffer) ;; here we check only if tokenization did not end in exception thrown (goto-char (point-min)) (while (haskell-lexeme-looking-at-token) (goto-char (match-end 0))))) (ert-deftest haskell-lexeme-classify-chars-1 () (should (equal 'varsym (haskell-lexeme-classify-by-first-char ?=))) (should (equal 'conid (haskell-lexeme-classify-by-first-char ?L))) (should (equal 'consym (haskell-lexeme-classify-by-first-char ?:))) (should (equal 'varid (haskell-lexeme-classify-by-first-char ?_))) (should (equal 'varid (haskell-lexeme-classify-by-first-char ?x))) (should (equal 'char (haskell-lexeme-classify-by-first-char ?'))) (should (equal 'string (haskell-lexeme-classify-by-first-char ?\"))) (should (equal 'special (haskell-lexeme-classify-by-first-char ?\;))) (should (equal 'number (haskell-lexeme-classify-by-first-char ?4)))) (ert-deftest haskell-lexeme-basic-tokens-1 () "Get some basic self delimiting tokens right" (check-lexemes '(")(}{][,;;") '(")" "(" "}" "{" "]" "[" "," ";" ";"))) (ert-deftest haskell-lexeme-qid-1 () "Indentifiers" (check-lexemes '("head,at_first,safeHead;Data") '("head" "," "at_first" "," "safeHead" ";" "Data"))) (ert-deftest haskell-lexeme-qid-2 () "Operators (symbols)" (check-lexemes '(">>=,---->,<-;::::") '(">>=" "," "---->" "," "<-" ";" "::::"))) (ert-deftest haskell-lexeme-qid-3 () "Qualified Indentifiers" (check-lexemes '("Data.List.head,Modu.at_first,Zonk.safeHead;Data.Data") '("Data.List.head" "," "Modu.at_first" "," "Zonk.safeHead" ";" "Data.Data"))) (ert-deftest haskell-lexeme-qid-4 () "Qualified Operators (symbols)" (check-lexemes '("Monad.>>=,Comment.---->,Func.<-;Cons.::::;Category..") '("Monad.>>=" "," "Comment.---->" "," "Func.<-" ";" "Cons.::::" ";" "Category.."))) (ert-deftest haskell-lexeme-unicode-ids-1 () "Unicode ids" (check-lexemes '("Żółw.head,Data.żółw,Артур.Артур ") '("Żółw.head" "," "Data.żółw" "," "Артур.Артур"))) (ert-deftest haskell-lexeme-unicode-ids-2 () "Unicode ids, unicode as last character in line" ;;:expected-result :failed (check-lexemes '("Żółw.head,Data.żółw,Артур.Артур") '("Żółw.head" "," "Data.żółw" "," "Артур.Артур"))) (ert-deftest haskell-lexeme-unicode-syms-1 () "Unicode symbols" (check-lexemes '("∷∷,.→,Control.Monad.★★") '("∷∷" "," ".→" "," "Control.Monad.★★"))) (ert-deftest haskell-lexeme-spaces () (check-lexemes '("fun::C.Monad a -> ()" "fun=do { xyz <- abc <*> def; xyz }") '("fun" "::" "C.Monad" "a" "->" "(" ")" "fun" "=" "do" "{" "xyz" "<-" "abc" "<*>" "def" ";" "xyz" "}"))) (ert-deftest haskell-lexeme-japanese-is-treated-as-lowercase () (check-lexemes '("てすと3 ∷ IO ()" "てすと3 = do" " putStrLn $ show 人間虫 where" " 人間虫 = x123") '("てすと3" "∷" "IO" "(" ")" "てすと3" "=" "do" "putStrLn" "$" "show" "人間虫" "where" "人間虫" "=" "x123"))) (ert-deftest haskell-lexeme-modifier-letters () (check-lexemes '("xᵦ xᵦxᵦ xxx###") '("xᵦ" "xᵦxᵦ" "xxx###"))) (ert-deftest haskell-lexeme-char-literal-1 () (check-lexemes '("'\\ENQ'") '("'\\ENQ'"))) (ert-deftest haskell-lexeme-char-literal-2 () (check-lexemes '("'\\''") '("'\\''"))) (ert-deftest haskell-lexeme-char-literal-3 () (check-lexemes '("'\"'") '("'\"'"))) (ert-deftest haskell-lexeme-char-literal-4 () (check-lexemes '("'D'") '("'D'"))) (ert-deftest haskell-lexeme-char-literal-5 () (check-lexemes '("':'") '("':'"))) (ert-deftest haskell-lexeme-char-literal-6 () (check-lexemes '("(':')") '("(" "':'" ")"))) (ert-deftest haskell-lexeme-string-literal-1 () (check-lexemes '("\"\\ \\\"") '("\"\\ \\\""))) (ert-deftest haskell-lexeme-string-literal-1a () (check-lexemes '("\"\\ \n \\\"") '("\"\\ \n \\\""))) (ert-deftest haskell-lexeme-string-literal-2 () (check-lexemes '("\"\"") '("\"\""))) (ert-deftest haskell-lexeme-string-literal-3 () (check-lexemes '("\"foobar\"") '("\"foobar\""))) (ert-deftest haskell-lexeme-string-literal-4 () (check-lexemes '("\"\\^Z\"") '("\"\\^Z\""))) (ert-deftest haskell-lexeme-string-literal-5 () (check-lexemes '("\"\\\\\"") '("\"\\\\\""))) (ert-deftest haskell-lexeme-string-literal-6 () (check-lexemes '("\"\\ENQ\"") '("\"\\ENQ\""))) (ert-deftest haskell-lexeme-string-literal-7 () (check-lexemes '("\"\\\\\"") '("\"\\\\\""))) (ert-deftest haskell-lexeme-string-literal-8 () (check-lexemes '("foo = \"zonk" " Cons") '("foo" "=" "\"zonk" "Cons"))) (ert-deftest haskell-lexeme-line-comment-1 () (check-lexemes '(" -- x " " --%% cons" " -- cons" ) '("-- x " "--%%" "cons" "-- cons" ))) (ert-deftest haskell-lexeme-template-haskell-1 () (check-lexemes '(" 'C ''C 'x ''x 0x12'x'xx") '("'" "C" "''" "C" "'" "x" "''" "x" "0x12" "'x'" "xx"))) (ert-deftest haskell-lexeme-decimal-numbers-1 () (check-lexemes '("123+345-123412") '("123" "+" "345" "-" "123412"))) (ert-deftest haskell-lexeme-octal-hexadecimal-numbers-1 () (check-lexemes '("0o123+0xaf345-0O121 0X234523fff") '("0o123" "+" "0xaf345" "-" "0O121" "0X234523fff"))) (ert-deftest haskell-lexeme-float-numbers-1 () (check-lexemes '("0.12 34.22.33 1e+23 1e23 1e+33 455.33E1456.4") '("0.12" "34.22" "." "33" "1e+23" "1e23" "1e+33" "455.33E1456" "." "4"))) (ert-deftest haskell-lexeme-quasi-quote-1 () (check-lexemes '("[xml| <xml /> |]") '("[xml| <xml /> |]"))) (ert-deftest haskell-lexeme-quasi-quote-2 () (check-lexemes '("[xml| <xml /> |] |]") '("[xml| <xml /> |]" "|" "]"))) (ert-deftest haskell-lexeme-quasi-quote-3 () (check-lexemes "[xml| <xml /> |" '("[xml| <xml /> |"))) (ert-deftest haskell-lexeme-quasi-quote-4 () (check-lexemes "[xml| <xml />" '("[xml| <xml />"))) (ert-deftest haskell-lexeme-literate-1 () (check-lexemes '("no code" "\\begin{code}" "code code" "\\end{code}" "no code no code") '("no code" "\\begin{code}" "code" "code" "\\end{code}" "no code no code") 'literate)) (ert-deftest haskell-lexeme-literate-2 () (check-lexemes '("no code" "> code code" "no code") '("no code" "code" "code" "no code") 'literate)) (ert-deftest haskell-lexeme-big-01-quasi-literal () (check-lexemes-nocheck (concat "x = " "[th|" (make-string (* 10 1000 1000) ? ) "|]"))) (ert-deftest haskell-lexeme-big-02-string () (check-lexemes-nocheck (concat "x = " "\"" (make-string (* 10 1000 1000) ? ) "\""))) (ert-deftest haskell-lexeme-big-03-string-with-escapes () (check-lexemes-nocheck (concat "x = " "\"" (let ((result "\\x01\\&,..\\NUL")) (dotimes (i 10) (setq result (concat result result))) result) "\""))) (ert-deftest haskell-lexeme-big-04-long-id () (check-lexemes-nocheck (concat "x = " (make-string 1000000 ?x)))) (ert-deftest haskell-lexeme-big-05-long-sym() (check-lexemes-nocheck (concat "x = " (make-string 1000000 ?+)))) (ert-deftest haskell-lexeme-big-06-long-module-name() (check-lexemes-nocheck (concat "x = " (make-string 10000000 ?M) ".x"))) (ert-deftest haskell-lexeme-big-07-many-modules-id() (check-lexemes-nocheck (concat "x = " (let ((result "M.")) (dotimes (i 20) (setq result (concat result result))) result) "x"))) (ert-deftest haskell-lexeme-big-08-many-modules-sym() (check-lexemes-nocheck (concat "x = " (let ((result "M.")) (dotimes (i 20) (setq result (concat result result))) result) "++"))) (ert-deftest haskell-lexeme-big-09-backticks-long-id() (check-lexemes-nocheck (concat "x = `" (let ((result "xx")) (dotimes (i 20) (setq result (concat result result))) result) "id`"))) ��������������������������������������haskell-mode-17.1/tests/haskell-load-tests.el�������������������������������������������������������0000664�0000000�0000000�00000006641�13602233217�0021201�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-load-tests.el -*- lexical-binding: t -*- ;;; Code: (require 'cl-lib) (require 'ert) (require 'haskell-test-utils) (require 'haskell-load) (defun insert-errors () (insert "import Control.Applicativ\nimport Data.Mayb\nimport Data.String") (goto-char 1) (let ((applicativ (progn (search-forward "Control.Applicativ") (make-overlay (match-beginning 0) (match-end 0))))) (overlay-put applicativ 'haskell-check t) (overlay-put applicativ 'haskell-msg-type 'error) (overlay-put applicativ 'haskell-msg "Could not find module ‘Control.Applicativ’\n Perhaps you meant Control.Applicative (from base-4.8.1.0)\n Use -v to see a list of the files searched for.")) (let ((mayb (progn (search-forward "Data.Mayb") (make-overlay (match-beginning 0) (match-end 0))))) (overlay-put mayb 'haskell-check t) (overlay-put mayb 'haskell-msg-type 'error) (overlay-put mayb 'haskell-msg "Could not find module ‘Data.Mayb’\n Perhaps you meant\n Data.Maybe (from base-4.8.1.0)\n Data.Map (from containers-0.5.6.2@conta_LKCPrTJwOTOLk4OU37YmeN)\n Use -v to see a list of the files searched for.")) (goto-char 1)) (ert-deftest goto-first-error-before () (with-temp-switch-to-buffer (insert-errors) (haskell-goto-first-error) (should (looking-at-p "Control.Applicativ")))) (ert-deftest goto-first-error-after () (with-temp-switch-to-buffer (insert-errors) (search-forward "Data.String") (haskell-goto-first-error) (should (looking-at-p "Control.Applicativ")))) (ert-deftest goto-first-error-between () (with-temp-switch-to-buffer (insert-errors) (search-forward "import Data.Mayb") (haskell-goto-first-error) (should (looking-at-p "Control.Applicativ")))) (ert-deftest goto-next-error-before () (with-temp-switch-to-buffer (insert-errors) (haskell-goto-next-error) (should (looking-at-p "Control.Applicativ")))) (ert-deftest goto-next-error-between () (with-temp-switch-to-buffer (insert-errors) (search-forward "import" nil nil 2) (haskell-goto-next-error) (should (looking-at-p "Data.Mayb")))) (ert-deftest goto-next-error-after () (with-temp-switch-to-buffer (insert-errors) (search-forward "import" nil nil 3) (haskell-goto-next-error) (should (looking-at-p " Data.String")))) (ert-deftest goto-prev-error-before () (with-temp-switch-to-buffer (insert-errors) (haskell-goto-prev-error) (should (looking-at-p "import Control.Applicativ")))) (ert-deftest goto-prev-error-between () (with-temp-switch-to-buffer (insert-errors) (search-forward "import" nil nil 2) (haskell-goto-prev-error) (should (looking-at-p "Control.Applicativ")))) (ert-deftest goto-prev-error-after () (with-temp-switch-to-buffer (insert-errors) (search-forward "import Data.String") (haskell-goto-prev-error) (should (looking-at-p "Data.Mayb")))) (ert-deftest do-cabal-no-process () "Ensure that haskell-process-do-cabal can call cabal directly. Redefine `shell-command' to just capture the command it's asked to execute, and make sure it matches what we expected." (let (shell-call) (cl-letf (((symbol-function 'shell-command) (lambda (command &optional input-buffer output-buffer) (setq shell-call command)))) (haskell-process-do-cabal "help") (should (equal shell-call "cabal help"))))) �����������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-mode-tests.el�������������������������������������������������������0000664�0000000�0000000�00000054605�13602233217�0021211�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-mode-tests.el --- -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'ert) (require 'haskell-mode) (require 'haskell-test-utils) (ert-deftest haskell-mode-ident-at-point-empty () (should (with-temp-buffer (haskell-mode) (eq nil (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-pos-at-point-empty () (should (with-temp-buffer (haskell-mode) (eq nil (haskell-ident-pos-at-point))))) (ert-deftest haskell-mode-spanable-pos-at-point-empty-spanable () (should (with-temp-buffer (haskell-mode) (eq nil (haskell-spanable-pos-at-point))))) (ert-deftest haskell-mode-ident-at-point-aftercolons () (should (with-temp-buffer (haskell-mode) (insert "foo ::") (string= "::" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-pos-at-point-aftercolons () (should (with-temp-buffer (haskell-mode) (insert "foo ::") (not (eq nil (haskell-ident-pos-at-point)))))) (ert-deftest haskell-mode-ident-at-point-beforetype () (should (with-temp-buffer (haskell-mode) (insert "foo ::") (save-excursion (insert " bar -> baz")) (string= "::" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-pos-at-point-beforetype () (should (with-temp-buffer (haskell-mode) (insert "foo ::") (save-excursion (insert " bar -> baz")) (not (eq nil (haskell-ident-pos-at-point)))))) (ert-deftest haskell-mode-spanable-pos-at-point-beforetype () (should (with-temp-buffer (haskell-mode) (insert "foo ::") (save-excursion (insert " bar -> baz")) (not (eq nil (haskell-spanable-pos-at-point)))))) (ert-deftest haskell-mode-ident-at-point-single () (should (with-temp-buffer (haskell-mode) (insert "a") (string= "a" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-constructor () (should (with-temp-buffer (haskell-mode) (insert "Hello123") (string= "Hello123" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-in-string () (should (with-temp-buffer (haskell-mode) (insert "\"Hello\"") (goto-char (1- (point-max))) (eq nil (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-in-commas () (should (with-temp-buffer (haskell-mode) (insert ",Hello,") (goto-char (1- (point-max))) (string= "Hello" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-var () (should (with-temp-buffer (haskell-mode) (insert "hello") (string= "hello" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-prime () (should (with-temp-buffer (haskell-mode) (insert "f'") (string= "f'" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-prime2 () (should (with-temp-buffer (haskell-mode) (insert "f5oo'") (string= "f5oo'" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-prime3 () (should (with-temp-buffer (haskell-mode) (insert "f'oo'") (string= "f'oo'" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-prime4 () (should (with-temp-buffer (haskell-mode) (insert "f'oo'") (goto-char (point-min)) (string= "f'oo'" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-prime5 () (should (with-temp-buffer (haskell-mode) (insert "f'o6o'") (goto-char (+ 1 (point-min))) (string= "f'o6o'" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-prime6 () (should (with-temp-buffer (haskell-mode) (insert "f'oo'") (goto-char (+ 2 (point-min))) (string= "f'oo'" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-underscore () (should (with-temp-buffer (haskell-mode) (insert "f_oo_") (goto-char (+ 2 (point-min))) (string= "f_oo_" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-underscore2 () (should (with-temp-buffer (haskell-mode) (insert "_oo_") (goto-char (point-min)) (string= "_oo_" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-underscore3 () (should (with-temp-buffer (haskell-mode) (insert "o3o_") (string= "o3o_" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-unicode () (should (with-temp-buffer (haskell-mode) (insert "åöèą5ċōïá") (string= "åöèą5ċōïá" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-at-point-unicode2 () (should (with-temp-buffer (haskell-mode) (insert "Äöèąċōïá") (string= "Äöèąċōïá" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-pos-at-point-unicode () (should (with-temp-buffer (haskell-mode) (insert "åöèą5ċōïá") (equal (cons (point-min) (point-max)) (haskell-ident-pos-at-point))))) (ert-deftest haskell-mode-ident-pos-at-point-unicode2 () (should (with-temp-buffer (haskell-mode) (insert "Äöèąċōïá") (equal (cons (point-min) (point-max)) (haskell-ident-pos-at-point))))) (ert-deftest haskell-mode-spanable-pos-at-point-unicode () (should (with-temp-buffer (haskell-mode) (insert "åöèą5ċōïá") (equal (cons (point-min) (point-max)) (haskell-spanable-pos-at-point))))) (ert-deftest haskell-mode-spanable-pos-at-point-unicode2 () (should (with-temp-buffer (haskell-mode) (insert "Äöèąċōïá") (equal (cons (point-min) (point-max)) (haskell-spanable-pos-at-point))))) (ert-deftest haskell-mode-ident-at-point-in-backticks () (should (with-temp-buffer (haskell-mode) (insert "`foo`") (backward-char 2) (string= "foo" (haskell-ident-at-point))))) (ert-deftest haskell-mode-ident-pos-at-point-in-backticks () (should (with-temp-buffer (haskell-mode) (insert "`foo`") (backward-char 2) (equal (cons (1+ (point-min)) (1- (point-max))) (haskell-ident-pos-at-point))))) (ert-deftest haskell-mode-spanable-pos-at-point-in-backticks () (should (with-temp-buffer (haskell-mode) (insert "`foo`") (backward-char 2) (equal (cons (point-min) (point-max)) (haskell-spanable-pos-at-point))))) (ert-deftest haskell-mode-ident-at-point-operators () "Test `haskell-ident-at-point' for all operator cases." (with-temp-buffer (haskell-mode) ;; point at the end of unqualified operator (insert ">>") (should (string= ">>" (haskell-ident-at-point))) ;; point in the middle of unqualified operator (save-excursion (insert "=") (insert "\n")) (should (string= ">>=" (haskell-ident-at-point))) (forward-line) ;; point at the end of qualified operator (insert "Control.Monad.>>=") (should (string= "Control.Monad.>>=" (haskell-ident-at-point))) ;; point at the beginning of qualified operator (goto-char (line-beginning-position)) (should (string= "Control.Monad.>>=" (haskell-ident-at-point))) ;; point in the middle of qualified part of operator (forward-char) (should (string= "Control.Monad.>>=" (haskell-ident-at-point))) ;; point atfer `.` dot in qualified part of operator (search-forward ".") (should (string= "Control.Monad.>>=" (haskell-ident-at-point))) ;; point at `.` dot in qualified part (backward-char) (should (string= "Control.Monad.>>=" (haskell-ident-at-point))) (goto-char (line-end-position)) (insert "\n") ;; Overloaded `.` dot tests. ;; point at operator's `.` dot preceded by delimiting `.` dot (insert "Data.Aeson.") (save-excursion (insert ".:")) (should (string= "Data.Aeson..:" (haskell-ident-at-point))) (forward-char) (should (string= "Data.Aeson..:" (haskell-ident-at-point))) ;; surrounding parentheses (goto-char (line-beginning-position)) (save-excursion (insert "(")) (should (eq nil (haskell-ident-at-point))) (goto-char (line-end-position)) (insert ")") (should (eq nil (haskell-ident-at-point))) (backward-char 2) (should (string= "Data.Aeson..:" (haskell-ident-at-point))))) (defun check-fill (expected initial) "Check using ERT if `fill-paragraph' over `initial' gives `expected' result. Cursor fill be positioned at '@' character or at the beginning of the buffer. `fill-column' will be set to 10 so that it is easy to spot issues." (should (equal expected (with-temp-buffer (haskell-mode) (setq fill-column 10) (dolist (line initial) (insert line) (insert "\n")) (goto-char (point-min)) (skip-chars-forward "^@") (if (eobp) (goto-char (point-min)) (delete-char 1)) (fill-paragraph nil) (split-string (buffer-substring-no-properties (point-min) (1- (point-max))) "\n"))))) (ert-deftest fill-comment-1 () (check-fill '("{- a -}") '("{- @a -}"))) (ert-deftest fill-comment-2 () (check-fill '("{- a b c d e" " f g h i j" " k -}") '("{- @a b c d e f g h i j k -}"))) (ert-deftest fill-comment-3 () (check-fill '("{-" "a" "-}") '("{-" "@a" "-}"))) (ert-deftest fill-comment-4 () (check-fill '("{-" "a b c d e" "f g h i-}") '("{-" "@a" "b" "c" "d e f g h i-}"))) (ert-deftest fill-comment-5 () (check-fill '(" {-" " a b c d e" " f g h i" " -}") '(" {-" " @a b c d e f g h i" " -}"))) (ert-deftest fill-comment-6 () (check-fill '(" -- a b c" " -- d e f" " -- g h i" " -- j k l" " -- m n o" " -- p q r" " -- s t u" " -- v") '(" -- @a b c d e f g h i j k l m n o p q r s t u v"))) (ert-deftest fill-comment-7 () (check-fill '(" -- a b" " -- c d" " -- e f" " -- g h" " -- i j") '(" -- @a b c d e f g h i j "))) (ert-deftest fill-comment-8 () "Note: first letter of second line should be in the same column as first letter in the first line. Also should respect 10 column fill." :expected-result :failed (check-fill '(" {- a b" " c d" " e f" " g h" " i j" " -}") '(" {- @a b c d e f g h i j" " -}"))) (ert-deftest fill-comment-9 () "Note: first letter in the second line position should be kept as defined, just the content should move properly. Also should respect 10 column fill." :expected-result :failed (check-fill '(" {- a b" " c d e" " f g h" " i j" " -}") '(" {- @a" " b c d e f g h i j" " -}"))) (ert-deftest fill-comment-10 () "Note: first letter in the second line position should be kept as defined, just the content should move properly. Following lines should take position from second line. Also should respect 10 column fill." :expected-result :failed (check-fill '(" {- a b" " c d e" " f g h" " i j" " -}") '(" {- @a" " b c d e" " f g h" " i j" " -}"))) (ert-deftest fill-comment-11 () "Note: first letter in the second line position should be kept as defined, just the content should move properly. Also should respect 10 column fill." (check-fill '(" -- a b" " -- c d e" " -- f g h" " -- i j") '(" -- @a" " -- b c d e f g h i j"))) (ert-deftest fill-comment-12 () "Note: first letter in the second line position should be kept as defined, just the content should move properly. Following lines should take position from second line. Also should respect 10 column fill." (check-fill '(" -- a b" " -- c d e" " -- f g h" " -- i j") '(" -- @a" " -- b c d e" "--f g h" " -- i j"))) (ert-deftest fill-comment-haddock-1 () (check-fill '("-- | a b c" "-- d") '("-- @| a b c d"))) (ert-deftest fill-comment-haddock-2 () (check-fill '("-- | a b c" "-- d e") '("-- @| a b c d" "-- e"))) (ert-deftest insert-scc-feasible () "insert an SCC where it's possible to do so" (should (with-temp-buffer (insert "hello world") (goto-char 6) (haskell-mode-toggle-scc-at-point) (string= "hello {-# SCC \"\" #-} world" (buffer-substring 1 (point-max)))))) (ert-deftest insert-scc-infeasible () "insert an SCC where it's not possible to do so" (should-error (with-temp-buffer (insert "hello world") (goto-char 2) (haskell-mode-toggle-scc-at-point) (string= "hello world" (buffer-substring 1 (point-max)))))) (ert-deftest remove-scc () "insert an SCC where it's possible to do so" (should (with-temp-buffer (insert "hello {-# SCC \"\" #-} world") (goto-char 10) (haskell-mode-toggle-scc-at-point) (string= "hello world" (buffer-substring 1 (point-max)))))) (ert-deftest forward-sexp-function-1 () "Check if `forward-sexp-function' behaves properly on end of sexp." (should (with-temp-buffer (haskell-mode) (insert "(foo) bar") (goto-char 5) (condition-case err (progn (forward-sexp) nil) (scan-error (equal (cddr err) (list 5 6))))))) (ert-deftest forward-sexp-function-2 () "Check if `forward-sexp-function' behaves properly on beginning of sexp." (should (with-temp-buffer (haskell-mode) (insert "(foo) bar") (goto-char 1) (forward-sexp) (eq (point) 6)))) (ert-deftest haskell-forward-sexp-1 () "Check if `haskell-forward-sexp' properly moves over sexps." (should (with-temp-buffer (insert "foo = bar . baz") (goto-char 1) (haskell-forward-sexp 4) (eq (point) 12)))) (ert-deftest haskell-forward-sexp-2 () "Check if `haskell-forward-sexp' properly moves over sexps." (should (with-temp-buffer (insert "foo = bar . baz") (goto-char 1) (haskell-forward-sexp 1) (eq (point) 4)))) (ert-deftest haskell-forward-sexp-3 () "Check if `haskell-forward-sexp' properly moves over sexps." (should (with-temp-buffer (insert "(a b) c = d . e") (goto-char 1) (haskell-forward-sexp 5) (eq (point) 14)))) (ert-deftest haskell-forward-sexp-4 () "Check if `haskell-forward-sexp' properly moves over sexps." (should (with-temp-buffer (insert "(a b) c = d . e") (goto-char 1) (haskell-forward-sexp 1) (eq (point) 6)))) (ert-deftest backward-sexp () "Check if `forward-sexp-function' behaves properly on beginning of sexp." (should (with-temp-buffer (haskell-mode) (insert "(foo) bar") (goto-char 2) (condition-case err (progn (backward-sexp) nil) (scan-error (equal (cddr err) (list 1 1))))))) (ert-deftest haskell-backward-sexp () "Check if `haskell-forward-sexp' with negatives arg properly moves over sexps." (should (with-temp-buffer (insert "a (b c) = d . e") (goto-char 15) (haskell-forward-sexp -4) (eq (point) 3)))) (ert-deftest haskell-guess-module-name () "Check if `haskell-guess-module-name'." (should (equal nil (haskell-guess-module-name-from-file-name "nonmodule.hs"))) (should (equal "Mod" (haskell-guess-module-name-from-file-name "Mod.hs"))) (should (equal "Żółw" (haskell-guess-module-name-from-file-name "Żółw.hs"))) (should (equal "Mod" (haskell-guess-module-name-from-file-name "żółw/Mod.hs"))) (should (equal "Module" (haskell-guess-module-name-from-file-name "Juicy-pixels/Module.lhs"))) (should (equal "Mod.Mod.Mod" (haskell-guess-module-name-from-file-name "src/Mod/Mod/Mod.hs"))) (should (equal "Żółw1.Żółw2.Żółw3" (haskell-guess-module-name-from-file-name "Żółw1/Żółw2/Żółw3.lhs"))) (should (equal "Mod'X.Mod" (haskell-guess-module-name-from-file-name "c:/Mod'X/Mod.lhs"))) (should (equal "Mod" (haskell-guess-module-name-from-file-name "Mod.xx/Mod.hs")))) (defun haskell-generate-tags-test-helper () (with-current-buffer (find-file-noselect "TAGS-test-format") (erase-buffer) (dolist (arg (sort argv #'string<)) (insert arg "\n")) (save-buffer) (kill-buffer))) (ert-deftest haskell-generate-tags () ;; this test is special for Unix because under Windows the ;; invocation is different :expected-result (if (equal system-type 'windows-nt) :failed :passed) (with-temp-dir-structure (("xxx.cabal" . "") ("T1.hs" . "i1 :: Int") ("src" . (("T2.hs" . "i2 :: Int"))) (".git" . (("Tx.hs" . "should_not_see_me :: Int")))) (with-script-path haskell-hasktags-path haskell-generate-tags-test-helper (haskell-mode-generate-tags) (with-current-buffer (find-file-noselect "TAGS-test-format") (should (equal "-e\n-x\n./T1.hs\n./src/T2.hs\n" (buffer-substring (point-min) (point-max)))))))) (defun haskell-stylish-haskell-add-first-line () (message-stdout "-- HEADER") (let (line) (while (setq line (read-stdin)) (message-stdout line)))) (defun haskell-stylish-haskell-no-change () (let (line) (while (setq line (read-stdin)) (message-stdout line)))) (defun haskell-stylish-haskell-bad-exit-code () (when noninteractive (kill-emacs 34))) (defun haskell-stylish-haskell-error-message () (message-stderr "Something wrong")) (ert-deftest haskell-stylish-on-save-add-first-line () (with-temp-dir-structure (("T.hs" . "main :: IO ()\n")) (with-script-path haskell-mode-stylish-haskell-path haskell-stylish-haskell-add-first-line (let ((haskell-stylish-on-save t)) (with-current-buffer (find-file-noselect "T.hs") (goto-char (point-max)) (save-excursion (insert "main = return ()\n")) (save-buffer) ;; should have header added (goto-char (point-min)) (should (looking-at-p "-- HEADER"))))))) (ert-deftest haskell-stylish-on-save-keep-point () ;; Looks like insert-file-contents under Windows does not keep the ;; point as it should. :expected-result (if (equal system-type 'windows-nt) :failed :passed) (with-temp-dir-structure (("T.hs" . "main :: IO ()\n")) (with-script-path haskell-mode-stylish-haskell-path haskell-stylish-haskell-add-first-line (let ((haskell-stylish-on-save t)) (with-current-buffer (find-file-noselect "T.hs") (goto-char (point-max)) (save-excursion (insert "main = return ()\n")) (save-buffer) ;; should keep pointer in place (should (looking-at-p "main = return"))))))) (ert-deftest haskell-stylish-on-save-no-change () (with-temp-dir-structure (("T.hs" . "main :: IO ()")) (with-script-path haskell-mode-stylish-haskell-path haskell-stylish-haskell-no-change (let ((haskell-stylish-on-save t)) (with-current-buffer (find-file-noselect "T.hs") (insert "main = return ()\n") (save-buffer) (goto-char (point-min)) (should (looking-at-p "main = return"))))))) (ert-deftest haskell-stylish-on-save-bad-exit-code () (with-temp-dir-structure (("T.hs" . "main :: IO ()")) (with-script-path haskell-mode-stylish-haskell-path haskell-stylish-haskell-bad-exit-code (let ((haskell-stylish-on-save t)) (with-current-buffer (find-file-noselect "T.hs") (insert "main = return ()\n") (save-buffer) (goto-char (point-min)) (should (looking-at-p "main = return ()"))))))) (ert-deftest haskell-stylish-on-save-error-message () (with-temp-dir-structure (("T.hs" . "main :: IO ()")) (with-script-path haskell-mode-stylish-haskell-path haskell-stylish-haskell-error-message (let ((haskell-stylish-on-save t)) (with-current-buffer (find-file-noselect "T.hs") (insert "main = return ()\n") (save-buffer) (goto-char (point-min)) (should (looking-at-p "main = return ()"))))))) (provide 'haskell-mode-tests) ���������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-process-tests.el����������������������������������������������������0000664�0000000�0000000�00000010576�13602233217�0021742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-process-tests.el -*- lexical-binding: t -*- ;;; Code: (require 'ert) (require 'cl-lib) (require 'haskell-process) (ert-deftest haskell-process-wrapper-command-function-identity () "No wrapper, return directly the command." (should (equal '("ghci") (progn (custom-set-variables '(haskell-process-wrapper-function #'identity)) (apply haskell-process-wrapper-function (list '("ghci"))))))) (ert-deftest haskell-process-wrapper-function-non-identity () "Wrapper as a string, return the wrapping command as a string." (should (equal '("nix-shell" "default.nix" "--command" "cabal\\ run") (progn (custom-set-variables '(haskell-process-wrapper-function (lambda (argv) (append '("nix-shell" "default.nix" "--command") (list (shell-quote-argument argv)))))) (apply haskell-process-wrapper-function (list "cabal run")))))) (ert-deftest test-haskell-process--compute-process-log-and-command-ghci () (should (equal '("Starting inferior GHCi process ghci ..." "dumses1" nil "ghci" "-ferror-spans") (let ((haskell-process-path-ghci "ghci") (haskell-process-args-ghci '("-ferror-spans"))) (custom-set-variables '(haskell-process-wrapper-function #'identity)) (cl-letf (((symbol-function 'haskell-session-name) (lambda (session) "dumses1"))) (haskell-process-compute-process-log-and-command "dummy-session" 'ghci)))))) (ert-deftest test-haskell-process--with-wrapper-compute-process-log-and-command-ghci () (should (equal '("Starting inferior GHCi process ghci ..." "dumses1" nil "nix-shell" "default.nix" "--command" "ghci\\ -ferror-spans") (let ((haskell-process-path-ghci "ghci") (haskell-process-args-ghci '("-ferror-spans"))) (custom-set-variables '(haskell-process-wrapper-function (lambda (argv) (append (list "nix-shell" "default.nix" "--command" ) (list (shell-quote-argument (mapconcat 'identity argv " "))))))) (cl-letf (((symbol-function 'haskell-session-name) (lambda (session) "dumses1"))) (haskell-process-compute-process-log-and-command "dummy-session" 'ghci)))))) (ert-deftest test-haskell-process--compute-process-log-and-command-cabal-repl () (should (equal '("Starting inferior `cabal repl' process using cabal ..." "dumses2" nil "cabal" "repl" "--ghc-option=-ferror-spans" "dumdum-session") (let ((haskell-process-path-cabal "cabal") (haskell-process-args-cabal-repl '("--ghc-option=-ferror-spans"))) (custom-set-variables '(haskell-process-wrapper-function #'identity)) (cl-letf (((symbol-function 'haskell-session-name) (lambda (session) "dumses2")) ((symbol-function 'haskell-session-target) (lambda (session) "dumdum-session"))) (haskell-process-compute-process-log-and-command "dummy-session2" 'cabal-repl)))))) (ert-deftest test-haskell-process--with-wrapper-compute-process-log-and-command-cabal-repl () (should (equal '("Starting inferior `cabal repl' process using cabal ..." "dumses2" nil "nix-shell" "default.nix" "--command" "cabal\\ repl\\ --ghc-option\\=-ferror-spans\\ dumdum-session") (let ((haskell-process-path-cabal "cabal") (haskell-process-args-cabal-repl '("--ghc-option=-ferror-spans"))) (custom-set-variables '(haskell-process-wrapper-function (lambda (argv) (append (list "nix-shell" "default.nix" "--command" ) (list (shell-quote-argument (mapconcat 'identity argv " "))))))) (cl-letf (((symbol-function 'haskell-session-name) (lambda (session) "dumses2")) ((symbol-function 'haskell-session-target) (lambda (session) "dumdum-session"))) (haskell-process-compute-process-log-and-command "dummy-session2" 'cabal-repl)))))) ;;; haskell-process-tests.el ends here ����������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-sort-imports-tests.el�����������������������������������������������0000664�0000000�0000000�00000007224�13602233217�0022742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-sort-imports-tests.el --- Unit tests for haskell-sort-imports -*- lexical-binding: t -*- ;; Copyright (c) 2014 Chris Done. All rights reserved. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. ;;; Code: (require 'ert) (require 'haskell-sort-imports) (ert-deftest empty-buffer () (should (with-temp-buffer (haskell-sort-imports) t))) (ert-deftest single-line () (should (with-temp-buffer (insert "import A\n") (goto-char (point-min)) (haskell-sort-imports) (string= (buffer-string) "import A\n")))) (ert-deftest two-idem () (should (with-temp-buffer (insert "import A import B ") (goto-char (point-min)) (haskell-sort-imports) (string= (buffer-string) "import A import B "))) (should (with-temp-buffer (insert "import qualified A import B ") (goto-char (point-min)) (haskell-sort-imports) (string= (buffer-string) "import qualified A import B "))) (should (with-temp-buffer (insert "import qualified \"mtl\" A import B ") (goto-char (point-min)) (haskell-sort-imports) (string= (buffer-string) "import qualified \"mtl\" A import B ")))) (ert-deftest two-rev () (should (with-temp-buffer (insert "import B import A ") (goto-char (point-min)) (haskell-sort-imports) (string= (buffer-string) "import A import B ")))) (ert-deftest file-structure () (should (with-temp-buffer (insert "module A where import B import A ") (goto-char (point-min)) (forward-line) (haskell-sort-imports) (string= (buffer-string) "module A where import A import B "))) (should (with-temp-buffer (insert "module C where import B import A ") (goto-char (point-min)) (forward-line 2) (haskell-sort-imports) (string= (buffer-string) "module C where import A import B ")))) (ert-deftest bos-270 () (should (with-temp-buffer (insert "import Data.Aeson.Encode (encode) import Data.Aeson.Types import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json') import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L ") (goto-char (point-min)) (haskell-sort-imports) (string= (buffer-string) "import Data.Aeson.Encode (encode) import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json') import Data.Aeson.Types import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L ")))) (provide 'haskell-sort-imports-tests) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-string-tests.el�����������������������������������������������������0000664�0000000�0000000�00000013040�13602233217�0021557�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;; unit tests for haskell-string.el -*- lexical-binding: t -*- (require 'ert) (require 'haskell-string) ;; implementation under test (ert-deftest haskell-string-take () (should (string= (haskell-string-take "" 0) "")) (should (string= (haskell-string-take "" 1) "")) (should (string= (haskell-string-take "" 2) "")) (should (string= (haskell-string-take "x" 0) "")) (should (string= (haskell-string-take "x" 1) "x")) (should (string= (haskell-string-take "x" 2) "x")) (should (string= (haskell-string-take "x" 3) "x")) (should (string= (haskell-string-take "xy" 0) "")) (should (string= (haskell-string-take "xy" 1) "x")) (should (string= (haskell-string-take "xy" 2) "xy")) (should (string= (haskell-string-take "xy" 3) "xy")) (should (string= (haskell-string-take "xyz" 0) "")) (should (string= (haskell-string-take "xyz" 1) "x")) (should (string= (haskell-string-take "xyz" 2) "xy")) (should (string= (haskell-string-take "xyz" 3) "xyz")) (should (string= (haskell-string-take "xyz" 4) "xyz"))) (ert-deftest haskell-string-ellipsize () (should (string= (haskell-string-ellipsize "" 0) "")) (should (string= (haskell-string-ellipsize "" 1) "")) (should (string= (haskell-string-ellipsize "" 2) "")) (should (string= (haskell-string-ellipsize "x" 0) "")) (should (string= (haskell-string-ellipsize "x" 1) "x")) (should (string= (haskell-string-ellipsize "x" 2) "x")) (should (string= (haskell-string-ellipsize "x" 3) "x")) (should (string= (haskell-string-ellipsize "xy" 0) "")) (should (string= (haskell-string-ellipsize "xy" 1) "…")) (should (string= (haskell-string-ellipsize "xy" 2) "xy")) (should (string= (haskell-string-ellipsize "xy" 3) "xy")) (should (string= (haskell-string-ellipsize "xyz" 0) "")) (should (string= (haskell-string-ellipsize "xyz" 1) "…")) (should (string= (haskell-string-ellipsize "xyz" 2) "x…")) (should (string= (haskell-string-ellipsize "xyz" 3) "xyz")) (should (string= (haskell-string-ellipsize "xyz" 4) "xyz"))) (ert-deftest haskell-string-literal-encode-empty () (should (string= (haskell-string-literal-encode "") "\"\"")) (should (string= (haskell-string-literal-encode "" t) ""))) (ert-deftest haskell-string-literal-decode-empty () (dolist (s0 (list "\"\"" "\"\\&\"" "\"\\&\\&\\&\"" "\"\\ \\\"" "\"\\ \\\\ \\\"" "\"\\&\\ \\\"" "\"\\ \\\\&\\ \\\"")) (should (string= "" (haskell-string-literal-decode s0))) (should (string= "" (haskell-string-literal-decode (substring s0 1 -1) t))))) (ert-deftest haskell-string-literal-decode-backslash () "Test some edge cases involving backslashes." (dolist (cs (list (cons "\\\\" "\\") (cons "\\x10" "\x10") (cons "\\\\x10" "\\x10") (cons "\\ \\x10" "x10") (cons "\\ \\ \\x30" " 0") (cons "\\SO\\&H" "\x0eH") (cons "\\SOH\\&" "\x01") (cons "\\n" "\n") (cons "\\'" "'") (cons "\\\"" "\"") (cons "\\SOH" "\x01") (cons "\\1114111" "\x10ffff") (cons "\\o4177777" "\x10ffff") (cons "\\x10ffff" "\x10ffff") (cons "\\^@" "\x00") (cons "\\^A" "\x01") (cons "\\^Z" "\x1A") (cons "\\^[" "\x1B") (cons "\\^\\" "\x1C") (cons "\\^]" "\x1D") (cons "\\^^" "\x1E") (cons "\\^_" "\x1F"))) (should (string= (cdr cs) (haskell-string-literal-decode (concat "\"" (car cs) "\"")))) (should (string= (cdr cs) (haskell-string-literal-decode (car cs) t))))) (defun haskell-string-random (n) "Generate random N characters long string." (let ((a ())) (apply #'string (dotimes (_ n a) (setq a (cons (random 1024) a)))))) (ert-deftest haskell-string-literal-decode-encode () "Test whether decode+encode is the identity function." (random "c7430a4") ;; some edge cases (dolist (s0 (list "\x0e\x48" ;; '\SO' 'H' "\x01" ;; '\SOH' "\x00df\x30" ;; '\223' '0' "'" "\'" "\"" "\x0e&H" "\\" " \\ \\" "\\\\\"" (string 40 945 8322 946 8323 8743 947 178 949 178 41) "x" "xy" "\\x123" "\\ \\x123" " " " " "")) (should (string= s0 (haskell-string-literal-decode (haskell-string-literal-encode s0)))) (should (string= s0 (haskell-string-literal-decode (haskell-string-literal-encode s0 t) t)))) ;; randomized testing (dotimes (_ 50) (dotimes (n 15) (let* ((s0 (haskell-string-random (+ 1 n))) (s1 (haskell-string-literal-decode (haskell-string-literal-encode s0))) (s2 (haskell-string-literal-decode (haskell-string-literal-encode s0 t) t))) (should (string= s0 s1)) (should (string= s0 s2)))))) (ert-deftest haskell-string-test-trim () (should (equal "saf \t sdsaf" (haskell-string-trim "\r\n saf \t sdsaf \t\v\n \f"))) (should (haskell-string-only-spaces-p "\r\n \t \t\v\n \f")) (should-not (haskell-string-only-spaces-p "\r\n \t x \t\v\n \f"))) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-test-utils-tests.el�������������������������������������������������0000664�0000000�0000000�00000002604�13602233217�0022372�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-test-utils.el --- Utilities for Haskell Mode tests. -*- lexical-binding: t -*- ;; Copyright © 2017 Vasantha Ganesh Kanniappan <vasanthaganesh.k@tuta.io> ;; This file is part of haskell-mode package. ;; You can contact with authors using GitHub issue tracker: ;; https://github.com/haskell/haskell-mode/issues ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This file provides tests for `haskell-test-utils.el' (require 'haskell-test-utils) (ert-deftest haskell-with-temp-dir-structure-test () (setq cur-haskell-dir default-directory) (with-temp-dir-structure (("a.hs" . "-- Empty file") ("abc" . (("b.hs" . "-- Empty file")))) (cd "abc")) (should (eq default-directory cur-haskell-dir))) ����������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-test-utils.el�������������������������������������������������������0000664�0000000�0000000�00000027033�13602233217�0021235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-test-utils.el --- Utilities for Haskell Mode tests. -*- lexical-binding: t -*- ;; Copyright © 2016 Arthur Fayzrakhmanov. All rights reserved. ;; This file is part of haskell-mode package. ;; You can contact with authors using GitHub issue tracker: ;; https://github.com/haskell/haskell-mode/issues ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This package provides utilities for `haskell-mode' tests. ;;; Code: (require 'cl-lib) (defun insert-lines (&rest lines) "Insert all LINES in current buffer." (let ((ls lines) (line "")) (while ls (setq line (car ls)) (setq ls (cdr ls)) (when ls (insert line) (insert "\n"))) (insert line))) (defmacro with-temp-switch-to-buffer (&rest body) "Create a temporary buffer and evalute BODY there. Uses `switch-to-buffer' and evaluates BODY in temp buffer like `progn'. Seems that `execute-kbd-macro' is not able to correctly execute keybindings without this." (declare (indent 0) (debug t)) (let ((temp-buffer (make-symbol "temp-buffer"))) `(let ((,temp-buffer (generate-new-buffer " *temp*"))) ;; FIXME: kill-buffer can change current-buffer in some odd cases. (unwind-protect (progn (switch-to-buffer ,temp-buffer) ,@body) (and (buffer-name ,temp-buffer) (kill-buffer ,temp-buffer)))))) (defun check-syntax-and-face-match-range (beg end syntax face) "Check if all charaters between positions BEG and END have syntax set to SYNTAX and face set to FACE. If SYNTAX or FACE are set to t then any syntex respective face is not checked." (let (all-syntaxes all-faces (syntax-classes "-.w_()'\"$\\/<>@!|") (text (buffer-substring-no-properties beg end))) (while (< beg end) (cl-pushnew (char-to-string (aref syntax-classes (syntax-class (syntax-after beg)))) all-syntaxes :test #'equal) (cl-pushnew (get-text-property beg 'face) all-faces :test #'equal) (setq beg (1+ beg))) (unless (eq syntax t) (should (equal (list text (mapconcat #'identity (sort (mapcar (lambda (syn) (char-to-string syn)) syntax) #'string<) "")) (list text (mapconcat #'identity (sort all-syntaxes #'string<) ""))))) (unless (eq face t) (should (equal (list text (list face)) (list text all-faces)))))) (defun check-face-match-range (face n) (let ((beg (match-beginning n)) (end (match-end n))) (while (< beg end) (should (eq face (get-text-property beg 'face))) (setq beg (1+ beg))))) (defmacro with-haskell-test-buffer (mode &rest body) "Run BODY in the context of a new buffer set to `haskell-mode'. Buffer is named *haskell-mode-buffer*. It is not deleted after a test as this aids interactive debugging." (declare (indent 1) (debug t)) `(progn ;; we want to create buffer from scratch so that there are no ;; leftover state from the previous test (when (get-buffer "*haskell-test-buffer*") (kill-buffer "*haskell-test-buffer*")) (save-current-buffer (set-buffer (get-buffer-create "*haskell-test-buffer*")) (funcall ,mode) ,@body))) (defun check-properties (lines-or-contents props &optional mode) "Check if syntax properties and font-lock properties as set properly. LINES is a list of strings that will be inserted to a new buffer. Then PROPS is a list of tripples of (string syntax face). String is searched for in the buffer and then is checked if all of its characters have syntax and face. See `check-syntax-and-face-match-range`." (with-haskell-test-buffer (or mode #'haskell-mode) (if (consp lines-or-contents) (dolist (line lines-or-contents) (let ((pos (point))) (insert line "\n") (save-excursion ;; For some reason font-lock-fontify-region moves the ;; point. I do not think it is guaranteed it should not, ;; but then it might be our fault. Investigate later. (font-lock-fontify-region pos (point))))) (insert lines-or-contents) (font-lock-fontify-buffer)) (goto-char (point-min)) (dolist (prop props) (cl-destructuring-bind (string syntax face) prop (let ((case-fold-search nil)) (search-forward string)) (check-syntax-and-face-match-range (match-beginning 0) (match-end 0) syntax face))))) (defun message-stderr (&rest args) "Output a message to stderr in batch mode. ARGS are formatted according to `format'. A newline is automatically appended." (apply #'message args)) (defun message-stdout (&rest args) "Output a message to stdout in batch mode. ARGS are formatted according to `format'. A newline is automatically appended." (princ (apply #'format args)) (terpri)) (defun read-stdin () "Read a line from stdin in batch mode. A line is read and returned. End of input is signalled by nil. Newlines are stripped. Last line is returned even if there is no final newline." (condition-case nil (read-from-minibuffer "") (error nil))) (defmacro with-script-path-unix (cmdvar func &rest body) "Temporarily substitute a command line executable. Creates a temporary executable script and sets CMDVAR to point to the script. When the script is run it spawns another Emacs instance and executes function FUNC. Substitution is in effect throughout BODY. In FUNC variable `argv' is a list of all arguments that the script received when invoked. If the FUNC returns a number then it will be used as exit code for `kill-emacs' function, otherwise 0 will be used." (declare (indent 2) (debug t)) `(let ((,cmdvar (make-temp-file "haskell-mode-tests-script"))) (with-current-buffer (find-file-noselect ,cmdvar) (insert "#!/bin/sh\n") (insert "\":\"; exec \"" invocation-directory invocation-name "\" -Q --batch -l \"$0\" -- \"$@\"\n") (insert "(setq debug-on-error t)\n") (insert "(pop argv)\n") (insert "(setq load-path '" (format "%S" load-path) ")\n") (insert "(load \"" (symbol-file ',func) "\" nil t)\n") (insert "(let ((return-value (" (symbol-name ',func) ")))\n") (insert " (if (numberp return-value)\n") (insert " (kill-emacs return-value)\n") (insert " (kill-emacs 0)))\n") (basic-save-buffer) (kill-buffer)) (set-file-modes ,cmdvar (string-to-number "700" 8)) (unwind-protect (progn ,@body) (delete-file ,cmdvar)))) (defmacro with-script-path-windows (cmdvar func &rest body) "Temporarily substitute a command line executable. Creates a temporary executable script and sets CMDVAR to point to the script. When the script is run it spawns another Emacs instance and executes function FUNC. Substitution is in effect throughout BODY. In FUNC variable `argv' is a list of all arguments that the script received when invoked. If the FUNC returns a number then it will be used as exit code for `kill-emacs' function, otherwise 0 will be used." (declare (indent 2) (debug t)) `(let* ((,cmdvar (make-temp-file "haskell-mode-tests-script" nil ".bat")) (el (concat (file-name-sans-extension ,cmdvar) ".el"))) (with-current-buffer (find-file-noselect ,cmdvar) (insert "@\"" invocation-directory invocation-name "\" -Q --batch -l \"%~dpn0.el\" -- %*\n") (basic-save-buffer) (kill-buffer)) (with-current-buffer (find-file-noselect el) (insert "(setq debug-on-error t)\n") (insert "(pop argv)\n") (insert "(setq load-path '" (format "%S" load-path) ")\n") (insert "(load \"" (symbol-file ',func) "\" nil t)\n") (insert "(let ((return-value (" (symbol-name ',func) ")))\n") (insert " (if (numberp return-value)\n") (insert " (kill-emacs return-value)\n") (insert " (kill-emacs 0)))\n") (basic-save-buffer) (kill-buffer)) (unwind-protect (progn ,@body) (delete-file ,cmdvar) (delete-file el)))) (if (equal system-type 'windows-nt) (defalias 'with-script-path 'with-script-path-windows) (defalias 'with-script-path 'with-script-path-unix)) (defun create-directory-structure (entries) (dolist (entry entries) (cond ((stringp (cdr entry)) (with-current-buffer (find-file-noselect (car entry)) (insert (cdr entry)) (basic-save-buffer) (kill-buffer))) ((bufferp (cdr entry)) (with-current-buffer (find-file-noselect (car entry)) (insert (with-current-buffer (cdr entry) (buffer-substring-no-properties (point-min) (point-max)))) (basic-save-buffer) (kill-buffer))) (t (make-directory (car entry)) (let ((default-directory (file-name-as-directory (concat default-directory (car entry))))) (create-directory-structure (cdr entry))))))) (defmacro with-temp-dir-structure (entries &rest body) "Create a temporary directory structure. ENTRIES is an alist with file or directory names as keys. If associated value is a string or buffer then a file is created, if value is an association list then a directory is created recursively. Throughout BODY `default-directory' is set to the root of the hierarchy created. Whole hierarchy is removed after BODY finishes and value of `default-directory' is restored." (declare (indent 2) (debug t)) `(let ((tmpdir (make-temp-name "haskell-mode-test-dir"))) (make-directory tmpdir) (unwind-protect (let ((default-directory (file-name-as-directory (concat default-directory tmpdir)))) (create-directory-structure ',entries) ,@body) (delete-directory tmpdir t)))) (defun haskell-bypass-confirmation (function &rest args) "Call FUNCTION with ARGS, bypassing all prompts. This includes both `y-or-n-p' and `yes-or-no-p'. from `https://emacs.stackexchange.com/questions/19077/how-to-programmatically-answer-yes-to-those-commands-that-prompt-for-a-decisio'" (haskell-with-advice ((#'y-or-n-p :override (lambda (prompt) t)) (#'yes-or-no-p :override (lambda (prompt) t))) (apply function args))) (defmacro haskell-with-advice (adlist &rest body) "Execute BODY with temporary advice in ADLIST. Each element of ADLIST should be a list of the form (SYMBOL WHERE FUNCTION [PROPS]) suitable for passing to `advice-add'. The BODY is wrapped in an `unwind-protect' form, so the advice will be removed even in the event of an error or nonlocal exit." (declare (debug ((&rest (&rest form)) body)) (indent 1)) `(progn ,@(mapcar (lambda (adform) (cons 'advice-add adform)) adlist) (unwind-protect (progn ,@body) ,@(mapcar (lambda (adform) `(advice-remove ,(car adform) ,(nth 2 adform))) adlist)))) (defun haskell-unconditional-kill-buffer (buffer) "Buffer names are passed" (when (buffer-live-p (get-buffer buffer)) (haskell-bypass-confirmation #'kill-buffer buffer))) (provide 'haskell-test-utils) ;;; haskell-test-utils.el ends here �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/haskell-utils-tests.el������������������������������������������������������0000664�0000000�0000000�00000023451�13602233217�0021420�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; haskell-utils-tests.el --- Tests for Haskell utilities package -*- lexical-binding: t -*- ;; Copyright © 2016 Arthur Fayzrakhmanov. All rights reserved. ;; This file is part of haskell-mode package. ;; You can contact with authors using GitHub issue tracker: ;; https://github.com/haskell/haskell-mode/issues ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This package provides regression tests for haskell-utils package. ;;; Code: (require 'ert) (require 'haskell-test-utils) (require 'haskell-utils) (ert-deftest simple-import-parse () (should (equal "A.B.C" (with-temp-buffer (insert-lines "import A.B.C") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest qualified-import-parse () (should (equal "A.B.C" (with-temp-buffer (insert-lines "import qualified A.B.C") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest qualified-as-import-parse () (should (equal "AAA.Bc.Cx" (with-temp-buffer (insert-lines "import qualified AAA.Bc.Cx as Something") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest international-characters-import-parse () (should (equal "Żółć" (with-temp-buffer (insert-lines "import Żółć") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest commented-out-import-parse () (should (equal nil (with-temp-buffer (insert-lines "-- import Nothing") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest non-import-import-parse () (should (equal nil (with-temp-buffer (insert-lines "something import Nothing") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest many-spaces-import-parse () (should (equal "M" (with-temp-buffer (insert-lines "\t import\t qualified \t\tM\tas G") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest using-underscores-import-parse () (should (equal "Module_1.S_3_3_" (with-temp-buffer (insert-lines "import Module_1.S_3_3_") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest slightly-malformed-import-parse () (should (equal "q.Module...qwerqwe..." (with-temp-buffer (insert-lines "import q.Module...qwerqwe...") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest package-import-parse () (should (equal "B" (with-temp-buffer (insert-lines "import \"package-1.2.3\" B") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest safe-haskell-import-parse () (should (equal "B" (with-temp-buffer (insert-lines "import safe B") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest full-import-parse () (should (equal "Data.Char.Unicode_v_7" (with-temp-buffer (insert-lines "import safe qualified \"unicode-7.0\" Data.Char.Unicode_v_7 as U (func)") (goto-char (point-min)) (forward-line 0) (haskell-utils-parse-import-statement-at-point))))) (ert-deftest type-at-command-composition () "Test `haskell-utils-compose-type-at-command'. Test only position conversion to line and column numbers, do not test last string compontent, it is used in `:type-at` command to provide user friendly output only and could be any string, even empty one. Very likely the way how its composed for multilne strings will change in future." (with-temp-buffer (insert-lines "module A where" "" "int :: Int" "int = 369" "" "act =" " do print int" " return int") (goto-char (point-min)) (let (test-a-points test-b-points test-a-result test-b-result) ;; go to third line, e.g. `int` definition (forward-line 3) (setq test-a-points (point)) ;; go to at the end of `int` definition, i.e. point stands at whitespace (forward-char 3) (setq test-a-points `(,test-a-points . ,(point))) (goto-char (line-beginning-position)) ;; go to do-block line (forward-line 3) ;; go to `do` keyword beginning (forward-char 2) (setq test-b-points (point)) ;; go to the end of do-block (goto-char (point-max)) (setq test-b-points `(,test-b-points . ,(point))) (setq test-a-result (haskell-utils-compose-type-at-command test-a-points)) (setq test-b-result (haskell-utils-compose-type-at-command test-b-points)) (should (string-prefix-p ":type-at nil 4 1 4 4" test-a-result)) (should (string-prefix-p ":type-at nil 7 3 8 16" test-b-result))))) (ert-deftest parse-repl-response () "Test `haskell-utils-repl-response-error-status' function." (let* ((t1-str "unknown command ':type-at'\nuse :? for help.") (t2-str "\n<interactive>:3:5: Not in scope: ‘x’") (t3-str "Couldn't guess that module name. Does it exist?") (t4-str "Hello World!") (t5-str " ") (t6-str "") (t7-str "\n\n\n\n") (r1 (haskell-utils-repl-response-error-status t1-str)) (r2 (haskell-utils-repl-response-error-status t2-str)) (r3 (haskell-utils-repl-response-error-status t3-str)) (r4 (haskell-utils-repl-response-error-status t4-str)) (r5 (haskell-utils-repl-response-error-status t5-str)) (r6 (haskell-utils-repl-response-error-status t6-str)) (r7 (haskell-utils-repl-response-error-status t7-str))) (should (equal r1 'unknown-command)) (should (equal r2 'interactive-error)) (should (equal r3 'option-missing)) (should (equal r4 'no-error)) (should (equal r5 'no-error)) (should (equal r6 'no-error)) (should (equal r7 'no-error)))) (ert-deftest reduce-strign () "Test `haskell-utils-reduce-strign' command. Whitespace sequences at beginning of lines should be replaced with single whitespace, all newline characters should be removed." (should (string-equal "" (haskell-utils-reduce-string "\n"))) (should (string-equal "" (haskell-utils-reduce-string "\r\n"))) (should (string-equal " " (haskell-utils-reduce-string " \n"))) (should (string-equal "TestTest" (haskell-utils-reduce-string "Test\nTest"))) (should (string-equal "Test Test" (haskell-utils-reduce-string "Test\n Test"))) (should (string-equal " Test Test" (haskell-utils-reduce-string " Test\r\n Test"))) (should (string-equal " TestTest" (haskell-utils-reduce-string " Test\r\nTest"))) (should (string-equal " TestTest Test test" (haskell-utils-reduce-string " Test\r\nTest\n Test test")))) (ert-deftest post-command-hooks () "Test commands related `haskell-utils-async-post-command-flag'. Tests flag updates and `post-command-hook' cleanup." (with-temp-switch-to-buffer ;; set some random value to flag to test that it will be reseted (setq haskell-utils-async-post-command-flag "non nil") (haskell-utils-async-watch-changes) ;; now flag should be empty (should (null haskell-utils-async-post-command-flag)) ;; execute some commands (save-excursion (insert "Hello World!")) (execute-kbd-macro (kbd "SPC")) ;; now flag should not be empty (should (not (null haskell-utils-async-post-command-flag))) ;; check that hook was installed (should (cl-member #'haskell-utils-async-update-post-command-flag post-command-hook :test #'equal)) ;; check that flag was cleaned up (haskell-utils-async-stop-watching-changes (current-buffer)) (should (null haskell-utils-async-post-command-flag)) ;; check that hook was removed (should (not (cl-member #'haskell-utils-async-update-post-command-flag post-command-hook :test #'equal))))) ;;; haskell-utils-tests.el ends here �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/inferior-haskell-tests.el���������������������������������������������������0000664�0000000�0000000�00000003435�13602233217�0022075�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; inferior-haskell-tests.el --- tests for collapse module -*- lexical-binding: t -*- 1;4803;0c ;; Copyright © 2017 Vasantha Ganesh K. <vasanthaganesh.k@tuta.io> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 <http://www.gnu.org/licenses/>. (require 'ert) (require 'inf-haskell) (require 'haskell-string) (require 'haskell-test-utils) (ert-deftest test-run-haskell () (haskell-unconditional-kill-buffer "*haskell*") (run-haskell) (let* ((times 5) (ans nil)) (setq ans (inferior-haskell-get-result "1 + 1")) (while (and (> times 0) (not (equal ans "2"))) (setq times (1- times)) (setq ans (inferior-haskell-get-result "1 + 1"))) (should (equal ans "2")))) (ert-deftest test-inferior-haskell-buffer () "Check if the inferior haskell buffer has been started" (haskell-unconditional-kill-buffer "*haskell*") (run-haskell) (should (buffer-live-p inferior-haskell-buffer))) (ert-deftest test-inferior-haskell-root-dir () "Check if the root dir of the loaded file/project is not nil This way we test is the file is loaded or not" (haskell-unconditional-kill-buffer "*haskell*") (run-haskell) (should (file-directory-p inferior-haskell-root-dir))) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/interactive-haskell-mode-tests.el�������������������������������������������0000664�0000000�0000000�00000004201�13602233217�0023507�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; interactive-haskell-mode-tests.el --- Tests for Haskell Interactive Mode -*- lexical-binding: t -*- ;; Copyright © 2016 Athur Fayzrakhmanov. All rights reserved. ;; This file is part of haskell-mode package. ;; You can contact the authors using GitHub issue tracker: ;; https://github.com/haskell/haskell-mode/issues ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;; This package provides regression tests for the package ;; haskell-interactive-mode. ;;; Code: (require 'ert) (require 'haskell-interactive-mode) (defun should-match (str) (should (eq 0 (string-match-p haskell-interactive-mode-error-regexp str)))) (ert-deftest haskell-interactive-error-regexp-test () "Tests the regexp `haskell-interactive-mode-error-regexp'" (should (eq 0 (string-match-p haskell-interactive-mode-error-regexp "/home/user/Test.hs:24:30:"))) (should (eq 0 (string-match-p haskell-interactive-mode-error-regexp "Test.hs:5:18:"))) (should (eq 0 (string-match-p haskell-interactive-mode-error-regexp "Test.hs:7:6: Not in scope: type constructor or class ‘Ty’"))) (should (eq 0 (string-match-p haskell-interactive-mode-error-regexp "Test.hs:9:5: Not in scope: ‘c’"))) (should (eq nil (string-match-p haskell-interactive-mode-error-regexp ;; leading space " Test.hs:8:9:"))) ) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/test-data/������������������������������������������������������������������0000775�0000000�0000000�00000000000�13602233217�0017036�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/tests/test-data/Test.cabal��������������������������������������������������������0000664�0000000�0000000�00000004057�13602233217�0020747�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Name: Test Version: 2999.18.0.1 Stability: Beta Synopsis: Testing haskell-mode Description: { This is test .cabal file } Build-Type: Simple Tested-With: GHC == 7.10.2 Cabal-Version: >= 1.14 Extra-Source-Files: TODO.md Changelog.md README.md FAQ.md utils/AttributeGenerator.hs Source-Repository head Type: git Location: git://github.com/haskell-mode Flag some-flag Description: This is a flag Default: False Library Default-Language: Haskell2010 Build-Depends: base == 4.*, containers, process, directory, Exposed-Modules: Some.Module Other-Modules: Some.Other.Module Ghc-Options: -Wall Test-Suite test-1 { Default-Language: Haskell2010 Type: exitcode-stdio-1.0 Build-Depends: base, containers, fgl, fgl-arbitrary == 0.2.*, filepath, text, QuickCheck >= 2.3 && < 2.9 hs-Source-Dirs: tests Main-Is: RunTests.hs Other-Modules: Some.Module Ghc-Options: -O -Wall } Benchmark bench-1 { Default-Language: Haskell2010 Type: exitcode-stdio-1.0 Build-Depends: base, deepseq, text, criterion >= 0.5 && < 1.2 hs-Source-Dirs: utils Main-Is: Benchmark.hs } Executable bin-1 Default-Language: Haskell2010 hs-Source-Dirs: utils Main-Is: TestParsing.hs Build-Depends: base, bytestring, directory, filepath, text Ghc-Options: -O -Wall ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������haskell-mode-17.1/w3m-haddock.el��������������������������������������������������������������������0000664�0000000�0000000�00000015037�13602233217�0016437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������;;; w3m-haddock.el --- Make browsing haddocks with w3m-mode better -*- lexical-binding: t -*- ;; Copyright (C) 2014 Chris Done ;; Author: Chris Done <chrisdone@gmail.com> ;; This file is not part of GNU Emacs. ;; This file 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, or (at your option) ;; any later version. ;; This file 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 GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, ;; Boston, MA 02110-1301, USA. ;;; Commentary: ;;; Code: (require 'cl-lib) (require 'haskell-mode) (require 'haskell-font-lock) (declare-function w3m-buffer-title "ext:w3m") (declare-function w3m-browse-url "ext:w3m") (defvar w3m-current-url) (add-hook 'w3m-display-hook 'w3m-haddock-display) ;;;###autoload (defface w3m-haddock-heading-face '((((class color)) :inherit highlight)) "Face for quarantines." :group 'haskell) (defcustom haskell-w3m-haddock-dirs '("~/.cabal/share/doc/") "The path to your cabal documentation dir. It should contain directories of package-name-x.x. You can rebind this if you're using hsenv by adding it to your .dir-locals.el in your project root. E.g. ((haskell-mode . ((haskell-w3m-haddock-dirs . (\"/home/chris/Projects/foobar/.hsenv/cabal/share/doc\"))))) " :group 'haskell :type 'list) (defvar w3m-haddock-entry-regex "^\\(\\(data\\|type\\) \\|[a-z].* :: \\)" "Regex to match entry headings.") (defun haskell-w3m-open-haddock () "Open a haddock page in w3m." (interactive) (let* ((entries (cl-remove-if (lambda (s) (string= s "")) (apply 'append (mapcar (lambda (dir) (split-string (shell-command-to-string (concat "ls -1 " dir)) "\n")) haskell-w3m-haddock-dirs)))) (package-dir (ido-completing-read "Package: " entries))) (cond ((member package-dir entries) (unless (cl-loop for dir in haskell-w3m-haddock-dirs when (w3m-haddock-find-index dir package-dir) do (progn (w3m-browse-url (w3m-haddock-find-index dir package-dir) t) (cl-return t))) (w3m-browse-url (concat "http://hackage.haskell.org/package/" package-dir) t))) (t (w3m-browse-url (concat "http://hackage.haskell.org/package/" package-dir) t))))) (defun w3m-haddock-find-index (dir package) (let ((html-index (concat dir "/" package "/html/index.html")) (index (concat dir "/" package "/index.html"))) (cond ((file-exists-p html-index) html-index) ((file-exists-p index) index)))) (defun w3m-haddock-page-p () "Haddock general page?" (save-excursion (goto-char (point-max)) (forward-line -2) (looking-at "[ ]*Produced by Haddock"))) (defun w3m-haddock-source-p () "Haddock source page?" (save-excursion (goto-char (point-min)) (or (looking-at "Location: https?://hackage.haskell.org/package/.*/docs/src/") (looking-at "Location: file://.*cabal/share/doc/.*/html/src/") (looking-at "Location: .*src/.*.html$")))) (defun w3m-haddock-p () "Any haddock page?" (or (w3m-haddock-page-p) (w3m-haddock-source-p))) (defun w3m-haddock-find-tag () "Find a tag by jumping to the \"All\" index and doing a search-forward." (interactive) (when (w3m-haddock-p) (let ((ident (haskell-ident-at-point))) (when ident (w3m-browse-url (replace-regexp-in-string "docs/.*" "docs/doc-index-All.html" w3m-current-url)) (search-forward ident))))) (defun w3m-haddock-display (_url) "To be run by w3m's display hook. This takes a normal w3m buffer containing hadddock documentation and reformats it to be more usable and look like a dedicated documentation page." (when (w3m-haddock-page-p) (save-excursion (goto-char (point-min)) (let ((inhibit-read-only t)) (delete-region (point) (line-end-position)) (w3m-haddock-next-heading) ;; Start formatting entries (while (looking-at w3m-haddock-entry-regex) (when (w3m-haddock-valid-heading) (w3m-haddock-format-heading)) (w3m-haddock-next-heading)))) (rename-buffer (concat "*haddock: " (w3m-buffer-title (current-buffer)) "*"))) (when (w3m-haddock-source-p) (font-lock-mode -1) (let ((n (line-number-at-pos))) (save-excursion (goto-char (point-min)) (forward-line 1) (let ((text (buffer-substring (point) (point-max))) (inhibit-read-only t)) (delete-region (point) (point-max)) (insert (haskell-fontify-as-mode text 'haskell-mode)))) (goto-char (point-min)) (forward-line (1- n))))) (defun w3m-haddock-format-heading () "Format a haddock entry." (let ((o (make-overlay (line-beginning-position) (1- (save-excursion (w3m-haddock-header-end)))))) (overlay-put o 'face 'w3m-haddock-heading-face)) (let ((end (save-excursion (w3m-haddock-next-heading) (when (w3m-haddock-valid-heading) (point))))) (when end (save-excursion (w3m-haddock-header-end) (indent-rigidly (point) end 4))))) (defun w3m-haddock-next-heading () "Go to the next heading, or end of the buffer." (forward-line 1) (or (search-forward-regexp w3m-haddock-entry-regex nil t 1) (goto-char (point-max))) (goto-char (line-beginning-position))) (defun w3m-haddock-valid-heading () "Is this a valid heading?" (not (get-text-property (point) 'face))) (defun w3m-haddock-header-end () "Go to the end of the header." (search-forward-regexp "\n[ \n]")) (provide 'w3m-haddock) ;;; w3m-haddock.el ends here �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������