prinseq-lite-0.20.4/0000775000076700007670000000000012240000123014367 5ustar rschmiedrschmiedprinseq-lite-0.20.4/COPYING0000644000076700007670000010451312240000123015424 0ustar rschmiedrschmied 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 . prinseq-lite-0.20.4/prinseq-graphs-noPCA.pl0000644000076700007670000036317012240000123020635 0ustar rschmiedrschmied#!/usr/bin/perl #=============================================================================== # Author: Robert SCHMIEDER, Computational Science Research Center @ SDSU, CA # # File: prinseq-graphs # Date: 2012-12-22 # Version: 0.6 graphs # # Usage: # prinseq-graphs [options] # # Try 'prinseq-graphs-noPCA -h' for more information. # # Purpose: PRINSEQ will help you to preprocess your genomic or metagenomic # sequence data in FASTA or FASTQ format. The graphs version allows # users of the lite version to generate graphs similar to the web # version. # # Bugs: Please use http://sourceforge.net/tracker/?group_id=315449 # #=============================================================================== use strict; use warnings; use Getopt::Long; use Pod::Usage; use File::Temp qw(tempfile); #for output files use Fcntl qw(:flock SEEK_END); #for log file use Cwd; use JSON; use Cairo; #use Statistics::PCA; use MIME::Base64; use File::Basename; use Data::Dumper; ### $| = 1; # Do not buffer output my $PI = 4 * atan2(1, 1); my $LOG62 = log(62); my $DINUCODDS_VIR = [ [qw(1.086940308 0.98976932 1.034167044 0.880024041 1.070421277 0.990687084 0.890945575 1.069957074 0.92465631 0.803973303)], [qw(1.101064857 0.986812783 1.038299155 0.896162618 1.081652847 0.976365237 0.867445186 1.06727283 0.94688543 0.768007295)], [qw(1.071548411 0.912204166 1.196914981 0.80628184 1.294201511 1.148517794 0.269295791 1.033948026 0.895951033 0.623192149)], [qw(1.090253719 0.907428629 1.203991784 0.786359294 1.281499107 1.145421568 0.235974709 1.033437274 0.899580091 0.631699771)], [qw(1.075864745 1.003413074 1.01872902 0.897841689 0.980373171 1.05854979 0.934262259 1.052477953 0.88145851 0.889239724)], [qw(1.101890467 1.030028291 1.019912674 0.84191395 1.0015174 1.069546264 0.900151602 0.996269395 0.889195343 0.904039022)], [qw(1.152417359 0.855028574 0.91164793 1.017415486 1.114163672 1.128353311 0.846355573 0.916745489 1.206820475 0.811014651)], [qw(1.142454218 0.8635465 0.923406967 1.026242747 1.134445058 1.131747833 0.79793368 0.920767641 1.179468556 0.799770057)], [qw(1.124462747 0.873556143 0.945627041 1.013755408 1.159866153 1.096259526 0.757315047 0.972924919 1.105562567 0.772731886)], [qw(1.143826972 0.866968779 0.995740249 0.945859278 1.109590621 1.089305083 0.76048874 0.971561388 1.157101408 0.792923027)], [qw(1.131900141 0.82776996 0.996204924 0.999433455 1.024692372 1.071176333 0.921026216 1.088936699 1.054010776 0.773498892)], [qw(1.042180476 0.930180412 1.019242897 0.98909997 1.006666828 1.046708539 0.959492164 1.011183418 1.055168776 0.937433818)], [qw(1.086515695 0.985345815 0.930914307 0.969581792 1.043010232 1.087463712 0.939482285 0.990551965 0.954752469 0.893972874)], [qw(1.096657826 0.950117614 0.936195529 0.965619788 1.114975275 1.077011195 0.843153131 0.989128406 1.043790912 0.840634731)], [qw(1.158030995 0.935307365 0.874812261 1.056236525 1.117171274 0.937484692 1.057442372 0.970079538 1.174848738 0.725071711)], [qw(1.15591506 0.93000227 0.883538923 1.0567652 1.095730954 0.944489906 1.074229471 0.983993745 1.156051409 0.726688465)], [qw(1.205726473 0.924439339 1.049457756 0.805718412 0.975472778 1.07581991 0.726992211 1.075025787 0.8704929 0.726672843)], [qw(1.188544681 0.95239611 1.049066985 0.790031334 1.038632598 1.056749787 0.665197397 1.057566244 0.862429061 0.708982398)], [qw(1.063631482 0.925593715 1.014869316 0.944904401 1.119690731 1.325971834 0.273781451 0.943347677 1.06438014 0.920825904)], [qw(1.077560287 0.911888545 1.044147857 0.927758054 1.058535939 1.296838544 0.421514996 0.945722451 1.128317986 0.926419928)], [qw(1.163753415 0.989905668 0.893599328 0.955641844 1.176047687 0.941559156 0.950641089 0.959741692 1.100815282 0.72491925)], [qw(1.139253929 0.946297517 0.922096125 1.024801537 1.205206793 0.968818717 0.915801342 0.971626058 1.107569276 0.627623404)] ]; my $DINUCODDS_MIC = [ [qw(1.13127323 0.853587195 0.911041047 1.104520778 1.065586428 1.021434164 0.999734139 1.063684014 1.078035184 0.733596552)], [qw(1.173267344 0.840539337 0.919534602 1.068050141 1.062394214 1.051999071 0.96770576 1.035511729 1.095600433 0.72328141)], [qw(1.172939786 0.84567902 0.911836259 1.106288994 1.05351787 1.026143368 1.002308358 1.066319771 1.094918797 0.710733535)], [qw(1.073527689 0.850290918 0.978455025 1.080882178 1.111174765 1.010754115 0.895668707 1.072980666 1.079304608 0.754057386)], [qw(1.08807747 0.837444678 0.95824965 1.097310298 1.118897971 1.030863881 0.886827263 1.072349394 1.07406322 0.733440096)], [qw(1.071685485 0.861055813 0.966566865 1.090268118 1.112945761 1.012538936 0.909535491 1.063745603 1.071156598 0.755770377)], [qw(1.142698587 0.867936867 1.000612099 0.977934257 1.111801746 1.018318601 0.788556794 0.987763594 1.184649653 0.784776176)], [qw(1.134560074 0.876651844 0.998190253 0.995723123 1.128448077 1.014172324 0.781776188 0.971020602 1.182411449 0.786449476)], [qw(1.180029632 0.787899325 1.01316945 0.932268406 1.077837263 1.211699678 0.612128817 1.033036699 1.157314398 0.74940288)], [qw(1.160925546 0.788308899 1.003702496 0.965371236 1.076051693 1.188304271 0.641536444 1.070331188 1.124067192 0.740126813)], [qw(1.173873006 0.790118011 1.014718833 0.937979878 1.07453725 1.207167373 0.622279064 1.046150047 1.145627707 0.742212886)], [qw(1.128383111 0.870541389 0.987269741 0.98353238 1.115643879 1.040107028 0.774505865 1.010896432 1.164757274 0.775254395)], [qw(1.15297511 0.853883985 0.956393231 1.000027661 1.139915472 1.01355294 0.838843622 1.015553125 1.216219741 0.70447264)], [qw(1.148264236 0.852123859 0.974568293 0.985455546 1.13192373 1.015879393 0.828987111 1.016820786 1.216647853 0.71634006)], [qw(1.12933788 0.831777975 1.005434367 0.991081409 1.126146895 1.07421504 0.69343913 1.054032466 1.14809591 0.728541157)], [qw(1.124157235 0.828112691 1.022348424 0.983822386 1.143028487 1.081830005 0.672594435 1.05685982 1.149537403 0.684432106)], [qw(1.128029586 0.841853305 1.00983936 0.967179139 1.122524003 1.094555807 0.659238308 1.061578854 1.1243601 0.740148171)], [qw(1.093521636 0.855071052 0.929160818 1.203773691 1.178257185 0.881341255 1.078305505 1.051988532 1.169143967 0.555057308)], [qw(1.073737278 0.877396537 0.968017446 1.124155374 1.166244435 0.909044208 0.999147578 1.071098934 1.120156138 0.607444953)], [qw(1.092150184 0.863407008 0.927040387 1.185387013 1.171670826 0.882276859 1.083058605 1.048379554 1.168635365 0.580337997)] ]; my $DATA_VIR = [ [2,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [3,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [42,2,'Human (nasal)',[127/255, 127/255, 255/255,1]], [43,2,'Human (nasal)',[127/255, 127/255, 255/255,1]], [45,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [49,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [52,3,'Human (sputum)',[127/255, 127/255, 255/255,1]], [54,3,'Human (sputum)',[127/255, 127/255, 255/255,1]], [55,4,'Human (sputum, CF)',[127/255, 127/255, 255/255,1]], [57,4,'Human (sputum, CF)',[127/255, 127/255, 255/255,1]], [88,5,'Freshwater (Hot spring)',[127/255, 127/255, 255/255,1]], [89,5,'Freshwater (Hot spring)',[127/255, 127/255, 255/255,1]], [98,6,'Freshwater (Antartic lake)',[127/255, 127/255, 255/255,1]], [99,6,'Freshwater (Antartic lake)',[127/255, 127/255, 255/255,1]], [100,7,'Freshwater (reclaimed)',[127/255, 127/255, 255/255,1]], [102,7,'Freshwater (reclaimed)',[127/255, 127/255, 255/255,1]], [153,8,'Mouse (brain tissue)',[127/255, 127/255, 255/255,1]], [154,8,'Mouse (brain tissue)',[127/255, 127/255, 255/255,1]], [202,9,'Fish (gut)',[127/255, 127/255, 255/255,1]], [206,9,'Fish (gut)',[127/255, 127/255, 255/255,1]], [209,10,'Mosquito',[127/255, 127/255, 255/255,1]], [211,10,'Mosquito',[127/255, 127/255, 255/255,1]], ['U',0,'User input',[255/255, 127/255, 127/255,1]] ]; my $DATA_MIC = [ [17,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [20,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [22,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [63,2,'Mouse (fecal)',[127/255, 127/255, 255/255,1]], [65,2,'Mouse (fecal)',[127/255, 127/255, 255/255,1]], [68,2,'Mouse (fecal)',[127/255, 127/255, 255/255,1]], [93,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [95,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [109,4,'Marine (open ocean)',[127/255, 127/255, 255/255,1]], [110,4,'Marine (open ocean)',[127/255, 127/255, 255/255,1]], [111,4,'Marine (open ocean)',[127/255, 127/255, 255/255,1]], [120,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [124,5,'Marine (estuary)',[127/255, 127/255, 255/255,1]], [125,5,'Marine (estuary)',[127/255, 127/255, 255/255,1]], [134,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [146,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [148,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [201,6,'Fish (gut)',[127/255, 127/255, 255/255,1]], [203,7,'Fish (slime)',[127/255, 127/255, 255/255,1]], [205,6,'Fish (gut)',[127/255, 127/255, 255/255,1]], ['U',0,'User input',[255/255, 127/255, 127/255,1]] ]; my $BASE64_BASES = {A => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAAzVJREFUeNrsnMFxo0AQRWe7fJcyMBnYGawyMIe9a0JQJtbefDPOAB33 JmdgZyBlsIpgl9lCLkwJA/N7uhu0XTXlkstI8Oh+agbG355+/XDC8VaNu8htf1ZjI73DJPx59wCg EN4phDQkNAsWGqCkIeUM7zFrSL7OBDS+VyObMyQrZWsSUlZnACfw5dwgcZ/5BZPfTEHyEwCvColL 2O24q/uuWUDKJ1TGKpCCsB8Sn4Dl1CGlbvxEBD51SCIlR4lL4VYAUnKB08SzSCSbUkFKLWxRgdMM sii5wK1BOlksuRSQVoCwA9wjIPDVVCAhWVTWw1SZc0MK8lxHblvUP7fA569TCJyMZFET0qEa75ay iRtSrDwDlLfG663CPohAQoRdtF4jXrrlFjgZKbU2lN/VeLFSclyQlkAzt6s95BiziVXgXJByFz/7 WH7x+6OFbOKCFCvL0wUffeUqFYFzQELu7/eVFAKJTeCkmEVDIARXvWqXHAoJEXbwzZ4BZJ/AM21I iLCLESV50swmMlxqzZ6pnCqkDBD2a0dvlErguRYkiSw6x16zZyKlDy4FwDbjARE4AYBihf1Se0YS EnRSaSJZpNozxUAKaRv7QNYR/KZSEXgMpI1CFjUhifdMMZBypUzgAB0lcIoAFDv72J6ijY0tuL1P DckrZ5GrQSM90yYlpMxh9/cfq/GHaSBPq4xeVUBCWWQt/kMaEKNWFQyFJPVAlmRsuCF5N7/wnJCW TvaBLKkYLHC60iwadWzEWbtzFXgfpNUMhT06CeiKS23wMVKPsNdXAKlX4HTlWTToWG8SQdoxXK3H zA7E3r0JAr/vmqXogoSu3w87vFeA9AwK3I8pN+Rr/6gAKAQ669m5qoA6hJ0r7mxsoE/Hda4qoA6i CzDttaJI0TMRc6mFKdqDIqS9w2YtLy4LowTC1o4tdzYR83VaaQASu8Dpwh/ERuzta+441H0am8Cp 1TwuJp5FSQROTB32yRgk9Om4TwI/Q8oc9g9XCmcv2LKJmIRtERL6LfexqoAYSo3r9nUKgb+D7+HP kFBhW8wi1p6JHL4KujQMCRX4v1UFARJyu2infBky5KIXPYn+rwADAOL8qKxS08x7AAAAAElFTkSu QmCC', C => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAA7BJREFUeNrsnM1xqzAQxxUNDfBKwCWQCt7g+7vgEkgJ5pRDTnYJpgRz eXeYVBBKCCU8SvAzM6sZxuMPaXclQaydYYKTGPBv/7tagdYvp9NJTO3Px6dwZPl5S2A/hdf3rD9v 1eT1nvuC/r7/vvr7SLizDGAUEzgmNr5nN3mt9ksAWNu6cNuQYoCyhX0bpmANoK4K9tlMWrrw0euH 8/YPPkTsQKkxnIv9nNKSZ79BQb5sy3kNkjnnfMMFzsFiUHNDVZVk9FyDTMguBowvGDS8QTpejDpz tARAZT4gNRr1zZyswYCSrk84Azuahp58MkAqoR9NkjkG0m7BgG5V76yQcgtD/B6mFqvz9nJlW8Pf uacdha6zI0P6B6YLbGH6UGv+b3tRbnCNpgdwDpuSOEr9cU61AXXUBOX9YlJWolOVS4MwyxnUs2L6 cAr2G1MhzAKJKu8K1DMw55UKYFHVlFMhYe//KKuZPH7v+CXxGCyQsNZbBjTNUzURUoyFlFEmhhAK g3BjVDUVWEg5MV90DgvEy3vgppZi66ScGAKurTJMDxXAvXuPPMLGqUYy7T1A6mBLHxSlRg6MMPLT hOTLWnBuNVELKS9GD5I2ttDzCalkSOJaiTsmKKkVP8wks4qE4xHNKyRKhd0HSCHcyCPb4LDC9g4p DqFmL9yGZ4EUkrbhBDeYBSWJoKQAKViAFCAFSLOERKl1kqCkoKSgJFMl9QGSPUijpQHSE6rppypJ tU5Y7Qig3IL1vZ5ydNJ403BcdzSuZBt71Rp4ncxJSbFHSNmN36melxMAK6iQhgWrSWf9wu6KylBL byiQCo+hliIcqlTmFFLmaZSjOKfCQFIrNLDmuqUrIULqsHO3muhVl+UAxSl3F3lIDQlSHhMZ9XAQ w9tKqOlAUs2/lBA4OAgz6jlIkDjUlFsEpTqOqGsXeiokqppUfmqYQy+BY1Lz3sPPJg0O1DPkDXSL 5xV1fjEAanVKHZM7kxtG72ObCjN4L9eAoLUQ36SVqwNFcdQ/GWzTUL6V+7aTn5zhqh0dpl/DUYLE ueZm6lshhHDbEd4Lg8WnmAcBG7H8dZFGqQMDSfWa9QsG1NmGpOS6XiAoVC+vJMb164JCr8TWe9SH kwOAqmcO6I1SEEvGON/MEI5KC5QWL9bH3KOaVjNSVQXXQ15XLi14TrW0+1r03kIKYGtrlRYvdM0h dUPlvMI5WQeTyIFXW/Cqeu5VMIPpheUuTZdfobifjDTTXvxYcz5YXsBxtrD+vwADADoA0kx0ZQr1 AAAAAElFTkSuQmCC', G => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAA6lJREFUeNrsnN2RqjAUgANjA9wS3CefsQQsAUtgS8AStAQsQUuQEuR5 nzYlSAkumTnZy/UKJpyTEANn5syqs0L8cn4hIbjf70zI19eaWZS40aT1Pm80Uvhe1ei59b6Ez8hl tbr+vl5YhpLCa8xx4h54RqCZhCQsI9OwEkYEr2700OgRXqMlNARn3+gN/kbMrrTPXzS6dA2SHFzO 3BBhyd8wrtEhJTAYV+A8Sg7ji8eCJGbpQmHWhkWM7wrJwxqkCODk7L3kpDvmBWJW3sF6+qyfQRY0 YknvDqgNKjUByRdAUgqVYK4DKQJ/9gWQ/E0FJSQl6gNExIVdo9tGgw5dw/8cDJw/fhXIA8UGN8cW ZA9ybPVaQ4vEjHDSapgI/qzBDRXjEBUgAeaj0U8EIAl5Dcepidwux7hbQTRTG3ApTmyRa6LOP+3q M0OFLybIk1fwQ0pmRjhMQEVgTdkQSHsCQBti6+mzVE5gTVqQMmS6l4BqZkckKGymi3UhYQa8tQio 7Xo7gisaSpASZHrdWXCxvrqLI61JqcFNkW52HLmSPmrG0yOA5ezfGw2dxaSI8t9s+GXXjcFMppOp bj21WgWhoHMyX90tSRCAuAOAZEws4XecdS6LPJOFik9qmq0rsqE6UEic1VyCxExBWiJcrRoh5Y8C CeNqJfNUKCFVU4GEaUP4DGm2JDQkb63oEVKEyGz1lCCxGZJaMemKiKL2PpJeuiDNme0NLck7SNFU INUzJLOQ2AzptSxnSLO7kaTyyGdQVJC8drmQsJOPpwJpDt4KkDCXYBPisYmbCgFSuSl3qxHuFk3B krDWlE0FEiZ4p1OBdEZmuHgKkDjSmrIpQMJaU2Yg0zkJCXtPfz8FSDUSVOwTqL4rk9gtCvnI2Y6s 6e6DRLEg6zRSfBLnvNqAJOST4BwXyxZVMOLtZq8gcUazMOtkIUaJrHozUYKo3C2hWm6cgwtQu5/c qV2Y6h1VINUMv4C8nfUuoBnyOALOHSzU6GWaQOOBLntmZue2XDLMe4rYpHWVwcbu8XK1uv4uTNXZ zb1j/z+thkJS1xtj3Tu4W+bxYq22JWEgyZ1APoPaPhbSQ9YCSFC+rbYVE//xLC4OXTAhQR08ASTi 7bqr1AkJDr59YziiUP7zarIplt6cu8zUcTjKu8Gp1idxsCjXg/qB/d1yrzxO6pVuJcyQS6VCBWEh GNpiBYYfoSiLz/0IYM6gg/rO9qbAwOJzJmVrgd0l3pdEGFXGbUP6EWAA2LwDwtC8jpAAAAAASUVO RK5CYII=', T => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAALRJREFUeNrs09ENQDAUQFHEXlhAYgJWMJnEBLqBUWxQFkCC/si5yftq mzYnaR5jzM4KXXu++J9CNc311YYi022QIEGCBAkSJEiCBCll5c16k+DO4Zj+4dnxmPXj92xvkZYE SPWLs2uiN/lukCBBggQJkiBBggQJEiRIggQJEiRIkCBBEiRIkCBBggRJkCBBggQJEiRICCBBggQJ EiRIggQJEiRIkCAJEiRIkCBBggRJ1+0CDAAzsw5U48snWgAAAABJRU5ErkJggg==', N => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAACXBIWXMAAAsTAAALEwEAmpwYAAAK T2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AU kSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXX Pues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgAB eNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAt AGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3 AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dX Lh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+ 5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk 5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd 0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA 4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzA BhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/ph CJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5 h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+ Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhM WE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQ AkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+Io UspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdp r+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZ D5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61Mb U2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY /R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllir SKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79u p+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6Vh lWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1 mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lO k06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7Ry FDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3I veRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+B Z7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/ 0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5p DoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5q PNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIs OpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5 hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQ rAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9 rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1d T1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aX Dm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7 vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3S PVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKa RptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO 32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21 e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfV P1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i /suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8 IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADq YAAAOpgAABdvkl/FRgAAAh1JREFUeNrsmk1xwzAQRr8RgYRBwqBhkDJoGbQMagZ1GbgMVAYNA5dB wsBm4CBwL9Wx0Uwk7593Z3z0SHmRn3fXi3me8d8FoAUw33kdQB/9PXu9xWCeZ4QFN9zBSCwJ6Qig cUj5aAFsHdLt2Fh47ALBGi8AHh2ScYlTQXrQLPFAuJZaiVNC2gCIDikfTxolHhjWjA4pH7s/Pzmk TDQA9g7JUCYeGNdWI/HAvH50SEYkHgTs4V26xIOQfUSHlI8jgGeHlI9OagEsCdIOQtspQdh+REo8 CPzjokNSKPGlIJ0qnKatdUgdgJ/CArhdw+NW+qZ6A888ASmkM4DPCifSvLhbANdCib9ahzRV+JHs mThFCvCtXeJUeVLpaWKVOBWkAcCH1kycMuPuAIwF97PNE1BCqiHxlkPi1LVbX1iysHyK4ihwm8Lc iXwojAPSUOE0dNYhJbdctEics5/UVAC9tQ6pB/BVKPFoHVINiZPME3BDmirUZdE6pPSmKimAF58n kPIhoKlw/946pDPKupiLZuKSPim1FSR+sA6pRgG8sQ4JKO9iYg2QAAGNfw2QBpR3Mc1DSrnT6JCW l7h5SKkAPjmk5QvgVUAaIGAeQDqklImPDkl47qQFUo+yLuYqILFKXBOkCUzTJZogpUz84pAESlwj pDPKZzHNQ0q509Uh5SXeOKR8RBB1MTVDIpO4dkgDCLqY2iGl3Gl0SMwS/x0AsYSfWCRqIfIAAAAA SUVORK5CYII=' }; my $MMCHART_B2 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGCAYAAAACEPQxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAABdJREFUeNpiYGBg+M/w//9/BmwEQIABANxBD/HRDNRSAAAAAElFTkSu QmCC'; my $FREQCHART_L = 'iVBORw0KGgoAAAANSUhEUgAAAC8AAABvCAIAAADzHQ6XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAABWNJREFUeNrkm91V7DoMhTOsaQBKgBKgBCjhUgKUAI/wBiUwJUAJUAKU ACVACed+K/tcYxz5J5nYk3uOHmYFxokVWdrakj17v1rJ6+trdkw3y0x3d3dd172/v5vfPj8/d/8J Iytq488U0+bw8PDq6oqLh4cHhn1+fta1jXQytWGB+ErLhB5cPz4+xp6z11WWr68vPvf39/WJnT4+ PmKD17W10dwoYX57c3Oji9vbW2xTXRvpgYVknoQ2fFZfKSkhC6ETFzE7tdDm+PiY6V9eXrh+enri 8/T0NDq6RkxxwZ/EczneSJNuIVgsbVa62rmsVqsfeHN5eanV3aU4W8n5cTqWNobx9ST0G2AbPZzD c+HcsJk2ht8ACYTiSy8Y7J9eUmG5hQRYbMQUy+SMhDasnUyVyL1NV4rgRCcs1E6btBdDUPiqnTYX FxeA5q8dyZxYXMJ5W2jDmrqcHHMsTO7GxFDD0OauF/cI1i4bR4yRPylTmixTMOHIvPlMafMjM1xf X/tgAOqcnZ2JSsaEMcwkVoVab29vJhlVqOozwUQ7n0sHb8br8lqZmsMzPnZivuEYgWc6MKXJ2mev AeAe9pKwTZrzOkHdo14Yr9ceYvEP24gQDUODmbK2cRY1bYOX8BDZj1kwtpmSQy8+7oXbPnvhTiwc u9n3UKcut6uK80UVXfb1Qm0wTGDzrNP49ojFlJZGz9EKmEFu4w1Dr3rh/pI0aeJNwIt5lCtfhsZb LhYvixev/XC9v78fwpdPM2rLtzbALgqJW+2YpRMLXO+cUayDKrWxLWwsFnZl0aWdbYAEcjiuE7Q2 wLdsJprZb9QDMyXRGKtYT8VytdkFql6H7/eCThR1akVJSp5lkqyt6nAWSyxO2YQFwq+zkF/Cixnj orU0T4k/EFYiBjwCCOY/6dxZwot5DmN4jskwDW38cY6mcH+WVGT5TbZHbLB0k4mqvZtm6X6z02Tp 6gltNptVL6TCfJ5ynUsfjtXCTDhyCS/WyzCGV0cnKhOmcK+dwmJEzovBHRNN+02WFysDuofElt5g okGe4s7semf9Rh7p8nGpNtOYaJYXi5lrjBh7Uc0wYx0e8GIfb0bU4QvixScnJ2ZQtGGiYZ4ys08a bCr2i83dSnyiavNxnN80I4QGL06AaRte/O3FQStJfkOWAUIc06jtxSkm6naOF8FE23BQ3zZL3Z/a Rubixd8xFcNiJ/gybjQkUxTwDrWHA3wydHR0RJ4i0eb3fMWtxmIx7MmdkSAqE+PPz89HYPGwI6ee VAKLy89ICNZLc3jA0AqxONh4jnUY1XfWFGlt1sHSDtsU2/eLWUEVOiN6FGrN8wbq0GJ/uVuiqSPb OIuatsEYSr0BBRvdoc0eJSrxm2EETeTFJYzO2SN77micbbY/KeVe2px4ijbcg7XH7s7Pv3c3rUcx bw4Pz1GoR6GiGpDI7pZV4cWTexRVbDO5R1Gllz6tR1G3XzyhR1GrgpnWo6h74mWz2ciHUAVQb0aN F8yLcVgdxtstL86wrWl5akj8Rp/3U0CN1SZ7dli4qmSpMWa2Cb2YzMBiDelIYg+GBaLSUDCy1gcH B8MymTF+qOIfZtmQr3yzezCFvNhkZyleLJQbuwdTyItdoGB+LOebKorFk6lWmhf7NNc8gWIzinpn h3EdmAmq+AEYPf/rVwVjgzzLi0VLsp2X3xHu++kE1MnyYh9s8jXDltrMy4vn6ZjMtZG+1y1JlqXN KrBzAOSNO/vrYO7GRymi/eI/pwv5Z3rx36pNEXduUCst63cwJb+7a6RNYU95zqyZ3Wz7n/3uTgDY tXHhEu7cYqX++t/dbY83vyOr2WnHEu78rwADABaBbeIZChwYAAAAAElFTkSuQmCC'; my $CSS_STYLE = ' html, body, div, span, p, img { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; } html, body { font-family: Arial, Verdana; color: #40454b; font-size: 12px; text-align: center; } img { padding: 0px; margin: 0px; border: none; } .info-panel { margin-top: 10px; margin-bottom: 10px; width: 740px; text-align: left; } .info-header { padding-top: 20px; padding-top: 10px; } .info-header-title { color: #126499; text-decoration: none; font-family: sans-serif; font-weight: bold; font-size: 16px; vertical-align: baseline; margin-right: 20px; margin-bottom: 25px; margin-top: 15px; } .info-content { padding: 2px; font-family: "lucida grande",sans-serif,arial; margin-top: 15px; margin-bottom: 15px; } .info-table-type { min-width: 70px; padding: 4px; vertical-align: top; } .info-table-value { font-weight: bold; padding-top: 4px; padding-left: 10px; padding-right: 10px; vertical-align: top; } hr { background-color: #E0E0E0; border: medium none; color: #E0E0E0; height: 1px; outline: medium none; } .sequencetext { font-family: courier, "courier new"; font-weight: normal; } '; my $VERSION = '0.6'; my $WHAT = 'graphs-noPCA'; my $man = 0; my $help = 0; my %params = ('help' => \$help, 'h' => \$help, 'man' => \$man); GetOptions( \%params, 'help|h', 'man', 'verbose', 'version' => sub { print "PRINSEQ-$WHAT $VERSION\n"; exit; }, 'i=s', 'o=s', 'png_all', 'html_all', 'log:s', 'web:s' ) or pod2usage(2); pod2usage(1) if $help; pod2usage(-exitstatus => 0, -verbose => 2) if $man; =head1 NAME PRINSEQ - PReprocessing and INformation of SEQuence data =head1 VERSION PRINSEQ-graphs 0.6 =head1 SYNOPSIS perl prinseq-graphs.pl [-h] [-help] [-version] [-man] [-verbose] [-i input_graph_data_file] [-png_all] [-html_all] [-log file] =head1 DESCRIPTION PRINSEQ will help you to preprocess your genomic or metagenomic sequence data in FASTA (and QUAL) or FASTQ format. The graphs version allows users of the lite version to generate graphs similar to the web version. =head1 OPTIONS =over 8 =item B<-help> | B<-h> Print the help message; ignore other arguments. =item B<-man> Print the full documentation; ignore other arguments. =item B<-version> Print program version; ignore other arguments. =item B<-verbose> Prints status and info messages during processing. =item B<***** INPUT OPTIONS *****> =item B<-i> Input file containing the graph data generated by the lite version. =item B<***** OUTPUT OPTIONS *****> =item B<-o> By default, the output files are created in the same directory as the input file with an additional "_prinseq_graphs_XXXX" in their name (where XXXX is replaced by random characters to prevent overwriting previous files). To change the output filename and location, specify the filename using this option. The file extension will be added automatically. =item B<-png_all> Use this option to generate PNG files with the graphs. =item B<-html_all> Use this option to generate a HTML file with the graphs and tables. =item B<-log> Log file to keep track of parameters, errors, etc. The log file name is optional. If no file name is given, the log file name will be "inputname.log". If the log file already exists, new content will be added to the file. =back =head1 AUTHOR Robert SCHMIEDER, C<< >> =head1 BUGS If you find a bug please email me at C<< >> or use http://sourceforge.net/tracker/?group_id=315449 so that I can make PRINSEQ better. =head1 COPYRIGHT Copyright (C) 2011-2012 Robert SCHMIEDER =head1 LICENSE 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 . =cut # ################################################################################ ## DATA AND PARAMETER CHECKING ################################################################################ # my ($file1,$command,@dataread); #Check if input file exists and check if file format is correct if(exists $params{i}) { $command .= ' -i '.$params{i}; $file1 = $params{i}; if($params{i} eq 'stdin') { my $format = &checkInputFormat(); unless($format eq 'gd') { &printError('input data for -i is in '.uc($format).' format not in graph data format'); } } elsif(-e $params{i}) { #check for file format my $format = &checkFileFormat($file1); unless($format eq 'gd') { &printError('input file for -i is in '.uc($format).' format not in graph data format'); } } else { &printError("could not find input file \"".$params{i}."\""); } } else { &printError("you did not specify an input file containing the graph data"); } #check output file name prefix if(exists $params{o}) { $command .= ' -o '.$params{o}; } #check for output format unless(exists $params{png_all} || exists $params{html_all}) { &printError("No output format specified. Use -png_all and/or -html_all to generate graphs."); } if(exists $params{png_all}) { $command .= ' -png_all'; } if(exists $params{html_all}) { $command .= ' -html_all'; } if(exists $params{web}) { $command .= ' -web'.($params{web} ? ' '.$params{web} : ''); } #add remaining to log command if(exists $params{log}) { $command .= ' -log'.($params{log} ? ' '.$params{log} : ''); unless($params{log}) { $params{log} = join("__",$file1||'nonamegiven').'.log'; } $params{log} = cwd().'/'.$params{log} unless($params{log} =~ /^\//); &printLog("Executing PRINSEQ with command: \"perl prinseq-".$WHAT.".pl".$command."\""); } # ################################################################################ ## DATA PROCESSING ################################################################################ # my $filename = $file1; while($filename =~ /[\w\d]+\.[\w\d]+$/) { $filename =~ s/\.[\w\d]+$//; last if($filename =~ /\/[^\.]+$/); } if(exists $params{png_all}) { my $graphs = &generateGraphs($params{i},$params{o}); if(exists $params{web} && $params{web} ne 'nozip') { #png files if(scalar(@$graphs)) { system("zip -j -r ".dirname($params{o})."/png_graphs.zip ".dirname($params{o}).' -i \*.png') == 0 or &printError("Cannot generate graphs ZIP file"); } } } if(exists $params{html_all}) { &generateHtml($params{i},$params{o}); } &printWeb("STATUS: done"); ## ################################################################################# ### MISC FUNCTIONS ################################################################################# ## sub printError { my $msg = shift; print STDERR "\nERROR: ".$msg.".\n\nTry \'perl prinseq-".$WHAT.".pl -h\' for more information.\nExit program.\n"; &printLog("ERROR: ".$msg.". Exit program.\n"); exit(0); } sub printWarning { my $msg = shift; print STDERR "WARNING: ".$msg.".\n"; &printLog("WARNING: ".$msg.".\n"); } sub printWeb { my $msg = shift; if(exists $params{web}) { print STDERR "\n".&getTime()."$msg\n"; } } sub getTime { return sprintf("[%02d/%02d/%04d %02d:%02d:%02d] ",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); } sub printLog { my $msg = shift; if(exists $params{log}) { my $time = sprintf("%02d/%02d/%04d %02d:%02d:%02d",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); open(FH, ">>", $params{log}) or die "ERROR: Can't open file ".$params{log}.": $! \n"; flock(FH, LOCK_EX) or die "ERROR: Cannot lock file ".$params{log}.": $! \n"; print FH "[prinseq-".$WHAT."-$VERSION] [$time] $msg\n"; flock(FH, LOCK_UN) or die "ERROR: cannot unlock ".$params{log}.": $! \n"; close(FH); } } sub addCommas { my $num = shift; return unless(defined $num); return $num if($num < 1000); $num = scalar reverse $num; $num =~ s/(\d{3})/$1\,/g; $num =~ s/\,$//; $num = scalar reverse $num; return $num; } sub checkFileFormat { my $file = shift; my ($format,$count,$id,$fasta,$fastq,$qual,$gd,$aa); $count = 3; $fasta = $fastq = $qual = $gd = $aa = 0; $format = 'unknown'; open(FILE,"perl -p -e 's/\r/\n/g;s/\n\n/\n/g' < $file |") or die "ERROR: Could not open file $file: $! \n"; while () { # chomp(); # next unless(length($_)); if($count-- == 0) { last; } elsif(!$fasta && /^\>\S+\s*/) { $fasta = 1; $qual = 1; } elsif($fasta == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/))) { $fasta = 2; } elsif($qual == 1 && /^\s*\d+/) { $qual = 2; } elsif(!$fastq && /^\@(\S+)\s*/) { $id = $1; $fastq = 1; } elsif($fastq == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/))) { $fastq = 2; } elsif($fastq == 2 && /^\+(\S*)\s*/) { $fastq = 3 if($id eq $1 || /^\+\s*$/); } elsif(!$gd && /^\{\"numseqs\"\:/) { $gd = 1; } } close(FILE); if($fasta == 2) { $format = 'fasta'; } elsif($qual == 2) { $format = 'qual'; } elsif($fastq == 3) { $format = 'fastq'; } elsif($gd == 1) { $format = 'gd'; } return $format; } sub checkInputFormat { my ($format,$count,$id,$fasta,$fastq,$qual,$gd,$aa); $count = 3; $fasta = $fastq = $qual = $gd = $aa = 0; $format = 'unknown'; while () { push(@dataread,$_); # chomp(); # next unless(length($_)); if($count-- == 0) { last; } elsif(!$fasta && /^\>\S+\s*/) { $fasta = 1; $qual = 1; } elsif($fasta == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/))) { $fasta = 2; } elsif($qual == 1 && /^\s*\d+/) { $qual = 2; } elsif(!$fastq && /^\@(\S+)\s*/) { $id = $1; $fastq = 1; } elsif($fastq == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/))) { $fastq = 2; } elsif($fastq == 2 && /^\+(\S*)\s*/) { $fastq = 3 if($id eq $1 || /^\+\s*$/); } elsif(!$gd && /^\{\"numseqs\"\:/) { $gd = 1; } } if($fasta == 2) { $format = 'fasta'; } elsif($qual == 2) { $format = 'qual'; } elsif($fastq == 3) { $format = 'fastq'; } elsif($gd == 1) { $format = 'gd'; } return $format; } sub readGdFile { my $file = shift; my $data; open(DATA,"<$file") or &printError("Could not open file $file: $!"); while() { next if(/^\#/); chomp(); if(length($_)) { $data = from_json($_); } } close(DATA); return $data; } sub getFileName { my $ext = shift; my ($file,$fh); if(exists $params{o}) { $file = $params{o}.$ext; open(OUT,">$file") or &printError('cannot open output file'); close(OUT); } else { $fh = File::Temp->new( TEMPLATE => $filename.'_prinseq_graphs_XXXX', SUFFIX => $ext, UNLINK => 0); $file = $fh->filename; $fh->close(); } return $file; } sub generateGraphs { my ($in,$out) = @_; my ($file,$data,$surface,@graphs); $data = &readGdFile($in); #length plot if(exists $data->{counts}->{length}) { $file = &getFileName('_ld.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{length},1),$data->{stats}->{length},'Length Distribution','Read Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{counts2} && exists $data->{counts2}->{length}) { $file = &getFileName('_ld-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{length},1),$data->{stats2}->{length},'Length Distribution','Read Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } #tail plot if(exists $data->{tail}) { $file = &getFileName('_td5.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{tail5},1),undef,'Poly-A/T Tail Distribution (> 4bp)','5\' Tail Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); $file = &getFileName('_td3.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{tail3},1),undef,'Poly-A/T Tail Distribution (> 4bp)','3\' Tail Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{tail2}) { $file = &getFileName('_td5-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{tail5},1),undef,'Poly-A/T Tail Distribution (> 4bp)','5\' Tail Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); $file = &getFileName('_td3-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{tail3},1),undef,'Poly-A/T Tail Distribution (> 4bp)','3\' Tail Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } #Ns plot if(exists $data->{counts}->{ns}) { $file = &getFileName('_ns.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{ns},1),undef,'Percentage of N\'s (> 0%)','Percentage of N\'s per Read (1-100%)','# Sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{counts2} && exists $data->{counts2}->{ns}) { $file = &getFileName('_ns-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{ns},1),undef,'Percentage of N\'s (> 0%)','Percentage of N\'s per Read (1-100%)','# Sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } #GC content plot if(exists $data->{counts}->{gc}) { $file = &getFileName('_gc.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{gc},0),$data->{stats}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences',$file,1); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{counts2} && exists $data->{counts2}->{gc}) { $file = &getFileName('_gc-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{gc},0),$data->{stats2}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences',$file,1); $surface->write_to_png($file); push(@graphs,$file); } #Sequence complexity plot - dust if(exists $data->{compldust}) { $file = &getFileName('_cd.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{compldust},0),undef,'Sequence complexity distribution','Mean sequence complexity (DUST scores)','Number of sequences',$file,1); $surface->write_to_png($file); push(@graphs,$file); } #Sequence complexity plot - entropy if(exists $data->{complentropy}) { $file = &getFileName('_ce.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{complentropy},0),undef,'Sequence complexity distribution','Mean sequence complexity (Entropy values)','Number of sequences',$file,1); $surface->write_to_png($file); push(@graphs,$file); } #Dinucleotide odd ratio PCA plot - microbial/viral #Odds ratio plot if(exists $data->{dinucodds}) { my @new = map {$data->{dinucodds}->{$_}} sort keys %{$data->{dinucodds}}; # $file = &getFileName('_pm.png'); # $surface = &createPCAPlot(&convertToPCAValues(\@new,'m'),'PCA','1st Principal Component Score','2nd Principal Component Score',$file); # $surface->write_to_png($file); # push(@graphs,$file); # $file = &getFileName('_pv.png'); # $surface = &createPCAPlot(&convertToPCAValues(\@new,'v'),'PCA','1st Principal Component Score','2nd Principal Component Score',$file); # $surface->write_to_png($file); # push(@graphs,$file); $file = &getFileName('_or.png'); $surface = &createOddsRatioPlot($data->{dinucodds},'Odds ratios','Dinucleotide','Odds ratio',$file); $surface->write_to_png($file); push(@graphs,$file); } #Qual plot if(exists $data->{quals}) { $file = &getFileName('_qd.png'); $surface = &createBoxPlot(&convertToBoxValues($data->{quals},4),'Base Quality Distribution','Read position in %','Quality score',$file); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{quals2}) { $file = &getFileName('_qd-2.png'); $surface = &createBoxPlot(&convertToBoxValues($data->{quals2},4),'Base Quality Distribution','Read position in %','Quality score',$file); $surface->write_to_png($file); push(@graphs,$file); } #Qualbin plot if(exists $data->{qualsbin}) { $file = &getFileName('_qd2.png'); $surface = &createBoxPlot(&convertToBoxValues($data->{qualsbin},4),'Base Quality Distribution','Read position in bp','Quality score',$file,0,'bp',$data->{binval}); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{qualsbin2}) { $file = &getFileName('_qd2-2.png'); $surface = &createBoxPlot(&convertToBoxValues($data->{qualsbin2},4),'Base Quality Distribution','Read position in bp','Quality score',$file,0,'bp',$data->{binval}); $surface->write_to_png($file); push(@graphs,$file); } #Qualmean plot if(exists $data->{qualsmean}) { $file = &getFileName('_qd3.png'); $surface = &createBarPlot(&convertToBarValues($data->{qualsmean},5,1),'Sequence Quality Distribution','Mean of quality scores per sequence','Number of sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{qualsmean2}) { $file = &getFileName('_qd3-2.png'); $surface = &createBarPlot(&convertToBarValues($data->{qualsmean2},5,1),'Sequence Quality Distribution','Mean of quality scores per sequence','Number of sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } #Sequence duplicate plots if(exists $data->{dubscounts}) { $file = &getFileName('_df.png'); $surface = &createStackBarPlot(&convertOdToStackBinMatrix($data->{dubscounts},5,1,100),'Sequence duplication level','Number of duplicates','Number of sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{dubslength}) { $file = &getFileName('_dl.png'); $surface = &createStackBarPlot(&convertOdToStackBinMatrix($data->{dubslength},5,1),'Sequence duplication level','Read Length in bp','Number of duplicates',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{dubscounts}) { my %dubsmax; my $count = 1; foreach my $n (sort {$b <=> $a} keys %{$data->{dubscounts}}) { foreach my $s (keys %{$data->{dubscounts}->{$n}}) { foreach my $i (1..$data->{dubscounts}->{$n}->{$s}) { $dubsmax{$count++}->{$s} = $n; last unless($count <= 100); } last unless($count <= 100); } last unless($count <= 100); } $file = &getFileName('_dm.png'); $surface = &createStackBarPlot(&convertOdToStackBinMatrix(\%dubsmax,5,1,100),'Sequence duplication level','Sequence','Number of duplicates',$file,0); $surface->write_to_png($file); push(@graphs,$file); } return \@graphs; } sub convertOdToBinMatrix { my ($data,$min,$max,$nonice) = @_; my ($num,$ymax,$xmax,$xmin,$step,%vals,$tmp,@matrix,$bin,$tmpbin); #make nice xmax value if(defined $max) { $xmax = $max; } else { $xmax = (sort {$b <=> $a} keys %$data)[0]; } $bin = &getBinVal($xmax); $xmax = $bin*100; $xmin = (defined $min ? $min : 0); #get data to bin and find y axis max value $ymax = 0; $tmp = 0; $tmpbin = $bin; foreach my $i ($xmin..$xmax) { if(exists $data->{$i}) { $tmp += $data->{$i}; } if(--$tmpbin <= 0) { $tmpbin = $bin; $ymax = &max($ymax,$tmp); push(@matrix,$tmp); $tmp = 0; } } #make nice ymax value unless($nonice) { $ymax = sprintf("%d",($ymax/4)+1)*4 if($ymax % 4); # $step = ($ymax <= 10 ? 10 : ($ymax < 40 ? 40 : ($ymax < 100 ? 100 : ($ymax < 1000 ? 100 : 100)))); # $ymax = sprintf("%d",($ymax/$step)+1)*$step if($ymax % $step); } return (\@matrix,$xmax,$ymax); } sub getBinVal { my $val = shift; my $step; if(!$val || $val <= 100) { return 1; } elsif($val < 10000) { return int($val/100)+($val % 100 ? 1 : 0); } elsif($val < 100000) { return 1000; } else { $step = 1000000; my $xmax = ($val % $step ? sprintf("%d",($val/$step+1))*$step : $val); return ($xmax/100); } } sub max { my ($a,$b) = @_; return ($a < $b ? $b : $a); } sub min { my ($a,$b) = @_; return ($a > $b ? $b : $a); } sub createAnnotBarPlot { my ($matrix,$xmax,$ymax,$annot,$title,$xlab,$ylab,$file,$zero,$add) = @_; my $bin = 1; if($xmax > 100) { $bin = $xmax / 100; $xmax = 100; } my @barcol = (127/255, 127/255, 255/255, 1); #b2b2ff my @meancol = (255/255, 127/255, 127/255, 1); #ffb2b2 my @stdcol = (178/255, 178/255, 255/255, 0.8); #7f7fff my @std1col = (0, 0, 0, 0.04); #ff7f7f my @std2col = (0, 0, 0, 0.03); #ff7f7f my @linecol = (0, 0, 0, 0.4); my @helplinecol = (1, 1, 1, 0.9); my @background = (0.95, 0.95, 0.95, 1); my @tickcol = (0, 0, 0, 0.8); my @labelcol = (0, 0, 0, 1); #create new image my $size = 6; my $offset = 20; my $left = 40; my $bottom = 15; my $top = 20; my $height = 200; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+($xmax+$zero)*$size,$bottom+$top+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+2*200+20); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); $cr->save; #set up work space $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, ($xmax+$zero)*$size-1, $height); $cr->set_source_rgba(@background); $cr->fill; #draw ticks #x-axis $cr->set_source_rgba(@tickcol); foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%5) == 0 && $i > 1 && $i < $xmax) { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+3); } else { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+1); } } $cr->stroke; #y-axis $cr->move_to($left+$offset, $top+$offset); $cr->line_to($left+$offset-3, $top+$offset); $cr->move_to($left+$offset, $top+$offset+$height-1); $cr->line_to($left+$offset-3, $top+$offset+$height-1); $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol); foreach my $j (1..3) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(@tickcol); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%10) == 0 && $i > 1 && $i < $xmax) { $extents = $cr->text_extents($i*$bin); $cr->move_to($left+$offset+int($size/2+1)+$size*$i-($zero ? 0 : $size)-$extents->{width}/2-1-($i == 1 ? 1 : 0), $top+$offset+$height+$fontheight+2); $cr->show_text($i*$bin); } } #y-axis $extents = $cr->text_extents(&addCommas($ymax)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2); $cr->show_text(&addCommas($ymax)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2+$height); $cr->show_text(0); $cr->save; #labels $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #axis labels $cr->set_source_rgba(@labelcol); $extents = $cr->text_extents($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->move_to($left+$offset+($xmax+$zero)*$size/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab.($bin>1 ? ' (per bin)' : '')); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2),$offset+10); $cr->show_text($ylab.($bin>1 ? ' (per bin)' : '')); $cr->restore; #draw annotations if($annot) { $cr->set_antialias('none'); my ($std1l,$std2l,$std1r,$std2r); #std boxes $std1l = int($annot->{mean})-int($annot->{std}); $std2l = int($annot->{mean})-2*int($annot->{std}); $std1r = int($annot->{mean})+int($annot->{std}); $std2r = int($annot->{mean})+2*int($annot->{std}); unless($std1l == $std1r) { if($std1l < 0) { $std1l = 0; } else { $std1l = int($std1l/$bin); } if($std2l < 0) { $std2l = 0; } else { $std2l = int($std2l/$bin); } if($std1r/$bin > 100) { $std1r = 100; } else { $std1r = int($std1r/$bin); } if($std2r/$bin > 100) { $std2r = 100; } else { $std2r = int($std2r/$bin); } $cr->rectangle($left+$offset+$std2l*$size+2, $top+$offset, ($std2r-$std2l)*$size, $height); $cr->set_source_rgba(@std2col); $cr->fill; $cr->rectangle($left+$offset+$std1l*$size+2, $top+$offset, ($std1r-$std1l)*$size, $height); $cr->set_source_rgba(@std1col); $cr->fill; #mean line $cr->set_source_rgba(@meancol); $cr->move_to($left+$offset+int(int($annot->{mean})/$bin)*$size+2, $top+$offset-5); $cr->line_to($left+$offset+int(int($annot->{mean})/$bin)*$size+2, $top+$offset+$height); $cr->stroke; #std lines $cr->set_source_rgba(@stdcol); if($std1l > 0) { $cr->move_to($left+$offset+$std1l*$size+2, $top+$offset-5); $cr->line_to($left+$offset+$std1l*$size+2, $top+$offset+$height); } if($std2l > 0) { $cr->move_to($left+$offset+$std2l*$size+2, $top+$offset-5); $cr->line_to($left+$offset+$std2l*$size+2, $top+$offset+$height); } if($std1r < 100) { $cr->move_to($left+$offset+$std1r*$size+2, $top+$offset-5); $cr->line_to($left+$offset+$std1r*$size+2, $top+$offset+$height); } if($std2r < 100) { $cr->move_to($left+$offset+$std2r*$size+2, $top+$offset-5); $cr->line_to($left+$offset+$std2r*$size+2, $top+$offset+$height); } $cr->stroke; #labels $cr->set_antialias('default'); $cr->set_source_rgba(@tickcol); $extents = $cr->text_extents('M'); $cr->move_to($left+$offset+int(int($annot->{mean})/$bin)*$size+2-$extents->{width}/2, $top+$offset-10); $cr->show_text('M'); if($std1l > 0) { $extents = $cr->text_extents('1SD'); $cr->move_to($left+$offset+$std1l*$size-$extents->{width}/2+2, $top+$offset-10); $cr->show_text('1SD'); } if($std2l > 0) { $extents = $cr->text_extents('2SD'); $cr->move_to($left+$offset+$std2l*$size-$extents->{width}/2+3, $top+$offset-10); $cr->show_text('2SD'); } if($std1r < 100) { $extents = $cr->text_extents('1SD'); $cr->move_to($left+$offset+$std1r*$size-$extents->{width}/2+2, $top+$offset-10); $cr->show_text('1SD'); } if($std2r < 100) { $extents = $cr->text_extents('2SD'); $cr->move_to($left+$offset+$std2r*$size-$extents->{width}/2+3, $top+$offset-10); $cr->show_text('2SD'); } } } #draw boxes $cr->set_antialias('none'); $cr->set_source_rgba(@barcol); foreach my $pos (0..$xmax-($zero ? 0 : 1)) { next unless($matrix->[$pos]); my $tmp = $matrix->[$pos] / $ymax; #unique if($tmp) { $cr->rectangle($left+$offset+$pos*$size, $top+$offset+$height, $size-1, -$tmp*$height); $cr->fill; } } #write image $cr->show_page; return $surface; } #sub convertToPCAValues { # my ($new,$type) = @_; # # my @data = ($type eq 'v' ? @$DINUCODDS_VIR : @$DINUCODDS_MIC); # # push(@data,$new); # # my $pca = Statistics::PCA->new; # $pca->load_data({format => 'table', data => \@data}); # $pca->pca(); # # my @variances = $pca->results('proportion'); # my @list = $pca->results('transformed'); # # my ($xmin,$xmax,$ymin,$ymax); # $xmax = $ymax = -100; # $xmin = $ymin = 100; # # #get min/max values for PC1 # foreach my $v (@{$list[0]}) { # $xmax = &max($xmax,$v); # $xmin = &min($xmin,$v); # } # #get min/max values for PC2 # foreach my $v (@{$list[1]}) { # $ymax = &max($ymax,$v); # $ymin = &min($ymin,$v); # } # # return ([$list[0],$list[1]],sprintf("%d",$variances[0]*100),sprintf("%d",$variances[1]*100),$xmin,$xmax,$ymin,$ymax,$type); #} sub createPCAPlot { my ($data,$var1,$var2,$xmin,$xmax,$ymin,$ymax,$type,$title,$xlab,$ylab,$file) = @_; my @linecol = (0, 0, 0, 0.4); my @helplinecol1 = (1,1,1, 0.9); my @helplinecol2 = (1,1,1, 0.5); #create new image my $size = 5; my $offset = 20; my $left = 25; my $bottom = 15; my $top = ($type eq 'v' ? 35 : 20); my $height = 500; my $space = 10; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+$height+2*$space,$top+$bottom+$offset*2+$height+2*$space); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+$height+2*$space,$top+$bottom+$offset*2+$height+2*$space); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans-serif', 'normal', 'normal'); $cr->save; #set up work space my ($dx, $dy); $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, $height+2*$space, $height+2*$space); $cr->set_source_rgba(0.95, 0.95, 0.95, 1); $cr->fill; #get infos my $num = scalar(@{$data->[0]})-1; my $xrange = ($xmax-$xmin); my $yrange = ($ymax-$ymin); my $data_info = ($type eq 'v' ? $DATA_VIR : $DATA_MIC); #draw ticks #x-axis $cr->set_source_rgba(0, 0, 0, 0.8); $cr->move_to($left+$offset+$space, $top+$offset+$height+2*$space); $cr->line_to($left+$offset+$space, $top+$offset+$height+2*$space+3); $cr->move_to($left+$offset+$space+$height, $top+$offset+$height+2*$space); $cr->line_to($left+$offset+$space+$height, $top+$offset+$height+2*$space+3); $cr->move_to($left+$offset+$space+int(abs($xmin)/$xrange*$height), $top+$offset+$height+2*$space); $cr->line_to($left+$offset+$space+int(abs($xmin)/$xrange*$height), $top+$offset+$height+2*$space+3); $cr->stroke; #y-axis $cr->move_to($left+$offset, $top+$offset+$space); $cr->line_to($left+$offset-3, $top+$offset+$space); $cr->move_to($left+$offset, $top+$offset+$height+$space); $cr->line_to($left+$offset-3, $top+$offset+$height+$space); $cr->move_to($left+$offset, $top+$offset+$space+int(abs($ymax)/$yrange*$height)); $cr->line_to($left+$offset-3, $top+$offset+$space+int(abs($ymax)/$yrange*$height)); $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol1); $cr->move_to($left+$offset+$space+int(abs($xmin)/$xrange*$height), $top+$offset); $cr->line_to($left+$offset+$space+int(abs($xmin)/$xrange*$height), $top+$offset+$height+2*$space); $cr->stroke; $cr->move_to($left+$offset, $top+$offset+$space+int(abs($ymax)/$yrange*$height)); $cr->line_to($left+$offset+2*$space+$height, $top+$offset+$space+int(abs($ymax)/$yrange*$height)); $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(0, 0, 0, 0.8); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis $extents = $cr->text_extents(sprintf("%.2f",$xmin)); $cr->move_to($left+$offset+$space-$extents->{width}/2-1, $top+$offset+$height+2*$space+$fontheight+2); $cr->show_text(sprintf("%.2f",$xmin)); $extents = $cr->text_extents(sprintf("%.2f",$xmax)); $cr->move_to($left+$offset+$space+$height-$extents->{width}/2-1, $top+$offset+$height+2*$space+$fontheight+2); $cr->show_text(sprintf("%.2f",$xmax)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset+$space+int(abs($xmin)/$xrange*$height)-$extents->{width}/2, $top+$offset+$height+2*$space+$fontheight+2); $cr->show_text(0); #y-axis $extents = $cr->text_extents(sprintf("%.2f",$ymax)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$space+$fontheight/2-2); $cr->show_text(sprintf("%.2f",$ymax)); $extents = $cr->text_extents(sprintf("%.2f",$ymin)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$height+$space+$fontheight/2-2); $cr->show_text(sprintf("%.2f",$ymin)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$space+int(abs($ymax)/$yrange*$height)+$fontheight/2-2); $cr->show_text(0); $cr->save; #labels $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #add type $cr->set_source_rgba(0, 0, 0, 0.5); $extents = $cr->text_extents(uc($type)); $cr->arc($offset/2+$extents->{width}/2, $offset-5, 10, 0, 2*$PI); $cr->fill; $cr->set_source_rgba(1, 1, 1, 1); $cr->move_to($offset/2-($type eq 'm' ? 1 : 0), $offset); $cr->show_text(uc($type)); #axis labels $cr->set_source_rgba(0, 0, 0, 1); $extents = $cr->text_extents($xlab.' ('.$var1.'%)'); $cr->move_to($left+$offset+$height/2-$extents->{width}/2+$space, $top+$offset+$height+$fontheight+15+2*$space); $cr->show_text($xlab.' ('.$var1.'%)'); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab.' ('.$var2.'%)'); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2)+$space,$offset); $cr->show_text($ylab.' ('.$var2.'%)'); $cr->restore; #draw dots $cr->set_antialias('default'); $cr->set_font_size (10); foreach my $i (0..$num) { $cr->set_source_rgba(@{$data_info->[$i]->[3]}); $cr->arc(($left+$offset+$space+int(($data->[0]->[$i]+abs($xmin))/$xrange*$height)), ($space+$top+$offset+int(($data->[1]->[$i]+abs($ymin))/$yrange*$height)), $size, 0, 2*$PI); $cr->fill; } $cr->set_source_rgba(0, 0, 0, 1); foreach my $i (0..$num) { $extents = $cr->text_extents($data_info->[$i]->[1]); $cr->move_to(($left+$offset+$space+int(($data->[0]->[$i]+abs($xmin))/$xrange*$height))+$size+1, ($space+$top+$offset+int(($data->[1]->[$i]+abs($ymin))/$yrange*$height))+$size*2); $cr->show_text($data_info->[$i]->[1]); } #draw legend my %labels; foreach my $i (0..$num) { $labels{$data_info->[$i]->[1]} = $data_info->[$i]->[2]; } $cr->set_font_size(10); $fontheight = $font_extents->{height}; $cr->set_source_rgba(0, 0, 0, 1); my $x = $left+$offset+$space; my $y = int($offset/2); foreach my $n (sort {$a <=> $b} keys %labels) { if($x+$cr->text_extents($n.' - '.$labels{$n})->{width}+15 >= $left+$offset+$space+$height) { $x = $left+$offset+$space; $y += $fontheight; } $cr->move_to($x,$y); $cr->show_text($n.' - '.$labels{$n}); $x += $cr->text_extents($n.' - '.$labels{$n})->{width}+15; } #write image $cr->show_page; return $surface; } sub createOddsRatioPlot { my ($data,$title,$xlab,$ylab,$file) = @_; my @yvalues = (0.5,0.78,1.00,1.23,1.5); my @linecol = (0, 0, 0, 0.4); my @helplinecol1 = (1,1,1, 0.9); my @helplinecol2 = (1,1,1, 0.5); #create new image my $size = 40; my $offset = 20; my $left = 35; my $right = 90; my $bottom = 20; my $top = 0; my $height = 100; my $width = $size*10; my $space = 20; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+$width+$right,$top+$bottom+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+$width+$right,$top+$bottom+$offset*2+$height); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); $cr->save; #set up work space my ($dx, $dy); $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, $width, $height); $cr->set_source_rgba(0.95, 0.95, 0.95, 1); $cr->fill; #right side marks $cr->set_source_rgba(255/255, 127/255, 127/255, 0.6); $cr->rectangle($left+$offset+$width+8, $top+$offset, 3, 0.77/2*$height); $cr->fill; $cr->rectangle($left+$offset+$width+8, $top+$offset+$height-0.78/2*$height, 3, 0.78/2*$height); $cr->fill; #get infos my $num = scalar(keys %$data)-1; #draw ticks #x-axis $cr->set_source_rgba(0, 0, 0, 0.8); foreach my $i (0..$num) { $cr->move_to($left+$offset+$size/2+$i*$size, $top+$offset+$height); $cr->line_to($left+$offset+$size/2+$i*$size, $top+$offset+$height+3); } $cr->stroke; #y-axis foreach my $i (@yvalues) { $cr->move_to($left+$offset, $top+$offset+$height-$i/2*$height); $cr->line_to($left+$offset-3, $top+$offset+$height-$i/2*$height); } $cr->stroke; #helplines #x-axis $cr->set_source_rgba(@helplinecol1); foreach my $i (0..$num) { $cr->move_to($left+$offset+$size/2+$i*$size, $top+$offset); $cr->line_to($left+$offset+$size/2+$i*$size, $top+$offset+$height); } $cr->stroke; #yaxis foreach my $i (@yvalues) { $cr->set_source_rgba(0, 0, 0, ($i == 0.5 || $i == 1.00 || $i == 1.50 ? 0.1 : 0.3)); $cr->move_to($left+$offset, $top+$offset+$height-$i/2*$height); $cr->line_to($left+$offset+$width, $top+$offset+$height-$i/2*$height); $cr->stroke; } $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(0, 0, 0, 0.8); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis my $xcur = 0; foreach my $dn (map {join("/",(m/../g ))} sort keys %$data) { $extents = $cr->text_extents($dn); $cr->move_to($left+$offset+$size/2-$extents->{width}/2-1+$size*$xcur++, $top+$offset+$height+$fontheight+2); $cr->show_text($dn); } #y-axis foreach my $i (@yvalues) { $cr->set_source_rgba(0, 0, 0, ($i == 0.5 || $i == 1.00 || $i == 1.50 ? 0.5 : 0.8)); $extents = $cr->text_extents(sprintf("%.2f",$i)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$height-$i/2*$height+$fontheight/2-2); $cr->show_text(sprintf("%.2f",$i)); } #label on right side $cr->set_source_rgba(0, 0, 0, 1); $extents = $cr->text_extents('Over-represented'); $cr->move_to($left+$offset+$width+15, $top+$offset+$height-1.6/2*$height+$fontheight/2-2); $cr->show_text('Over-represented'); $extents = $cr->text_extents('Under-represented'); $cr->move_to($left+$offset+$width+15, $top+$offset+$height-0.4/2*$height+$fontheight/2-2); $cr->show_text('Under-represented'); $cr->save; #labels $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #axis labels #x-axis $cr->set_source_rgba(0, 0, 0, 1); $extents = $cr->text_extents($xlab); $cr->move_to($left+$offset+$width/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab); #y-axis $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2),$offset); $cr->show_text($ylab); $cr->restore; #draw dots $cr->set_antialias('default'); $xcur = 0; foreach my $dn (sort keys %$data) { if($data->{$dn} > 1.23 || $data->{$dn} < 0.78) { $cr->set_source_rgba(255/255, 127/255, 127/255, 1); } else { $cr->set_source_rgba(127/255, 127/255, 255/255, 1); } $cr->arc($left+$offset+$size/2+$size*$xcur++, $top+$offset+$height-$data->{$dn}/2*$height, 5, 0, 2*$PI); $cr->fill; } #write image $cr->show_page; return $surface; } sub convertToBoxValues { my ($data,$niceval) = @_; my ($xmax,$ymax,@matrix); $xmax = $ymax = 0; foreach my $i (sort {$a <=> $b} keys %$data) { $xmax++; push(@matrix,[$i,$data->{$i}->{min},$data->{$i}->{p25},$data->{$i}->{median},$data->{$i}->{p75},$data->{$i}->{max}]); $ymax = &max($ymax,$data->{$i}->{max}); } if($niceval) { $ymax = sprintf("%d",($ymax/$niceval)+1)*$niceval if($ymax % $niceval); } return (\@matrix,$xmax,$ymax); } sub createBoxPlot { my ($matrix,$xmax,$ymax,$title,$xlab,$ylab,$file,$zero,$add,$bin) = @_; $bin = ($bin ? $bin : 1); $zero = 0 unless($zero); $add = '' unless(defined $add); if($xmax != 100) { $xmax = 100; } $ymax = 1 unless($ymax); # die Dumper $matrix; my @col0 = (178/255, 178/255, 255/255); #b2b2ff my @col1 = (255/255, 178/255, 178/255); #ffb2b2 my @col3 = (127/255, 127/255, 255/255); #7f7fff my @col4 = (255/255, 127/255, 127/255); #ff7f7f my @linecol = (0, 0, 0, 0.4); my @linecol0 = (@col3, 1); my @linecol1 = (@col4, 1); my @boxcol = (@col3, 1); my @whiscol = (@col0, 0.9); my @medcol = (0,0,0, 0.5); my @helplinecol1 = (1,1,1, 0.9); my @helplinecol2 = (1,1,1, 0.5); #create new image my $size = 6; my $offset = 20; my $left = 25; my $bottom = 25; my $top = 5; my $height = 300; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+2*200+20); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); # $cr->set_font_size (30); $cr->save; #set up work space $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, ($xmax+$zero)*$size-1, $height); $cr->set_source_rgba(0.95, 0.95, 0.95, 1); $cr->fill; #draw legend $cr->set_font_size(10); # $font_extents = $cr->font_extents; my $x = $left+$offset+$size*50; foreach my $v ([\@whiscol,'Min/Max value'],[\@boxcol,'25th to 75th percentile'],[\@medcol,'Median']) { $cr->set_antialias('none'); $cr->set_source_rgba(@{$v->[0]}); $cr->rectangle($x, $top+5, 10, 10); $cr->fill; $x += 15; $cr->set_antialias('default'); $cr->move_to($x,$top+5+9); $cr->set_source_rgba(0, 0, 0, 0.8); $cr->show_text($v->[1]); $x += $cr->text_extents($v->[1])->{width}+15; } $cr->set_antialias('none'); #draw ticks #x-axis $cr->set_source_rgba(0, 0, 0, 0.8); # $cr->move_to($left+$offset+int($size/2+1), $top+$offset+$height); # $cr->line_to($left+$offset+int($size/2+1), $top+$offset+$height+3); # $cr->move_to($left+$offset+int($size/2+1), $top+$offset+$height+$space); # $cr->line_to($left+$offset+int($size/2+1), $top+$offset+$height+$space-3); foreach my $i (1..9) { $cr->move_to($left+$offset+int($size/2)+$size*10*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*10*$i-($zero ? 0 : $size)-1, $top+$offset+$height+3); # $cr->move_to($left+$offset+int($size/2)+$size*10*$i-($zero ? 0 : $size)-1, $top+$offset); # $cr->line_to($left+$offset+int($size/2)+$size*10*$i-($zero ? 0 : $size)-1, $top+$offset-3); } $cr->stroke; #y-axis foreach my $j (0..4) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset-3, $top+$offset+$height*$j/4-($j ? 1 : 0)); # $cr->move_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); # $cr->line_to($left+$offset+($xmax+$zero)*$size+3, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol1); foreach my $j (1..3) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(0, 0, 0, 0.8); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis # $extents = $cr->text_extents(1); # $cr->move_to($left+$offset+int($size/2+1)-$extents->{width}, $top+$offset+$height+$fontheight+2); # $cr->show_text(1); foreach my $i (1..9) { $extents = $cr->text_extents($i*10*$bin); $cr->move_to($left+$offset+int($size/2+1)+$size*10*$i-($zero ? 0 : $size)-$extents->{width}/2-1-($i == 1 ? 1 : 0), $top+$offset+$height+$fontheight+2); $cr->show_text($i*10*$bin); } #y-axis foreach my $j (0..4) { $extents = $cr->text_extents(&addCommas($ymax*$j/4)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2+$height*(4-$j)/4); $cr->show_text(&addCommas($ymax*$j/4)); } $cr->save; #axis labels $cr->set_source_rgba(0, 0, 0, 1); $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; $extents = $cr->text_extents($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->move_to($left+$offset+($xmax+$zero)*$size/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2),$offset); $cr->show_text($ylab); $cr->restore; #draw boxes my $factor = $height/$ymax; $cr->set_antialias('none'); foreach my $v (@$matrix) { #wiskers $cr->set_source_rgba(@whiscol); if($v->[1] != $v->[2]) { $cr->move_to($left+$offset+$size*$v->[0]+1, $top+$offset+$height-$v->[1]*$factor-1); $cr->line_to($left+$offset+$size*$v->[0]+$size-2, $top+$offset+$height-$v->[1]*$factor-1); $cr->stroke; } if($v->[4] != $v->[5]) { $cr->move_to($left+$offset+$size*$v->[0]+1, $top+$offset+$height-$v->[5]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+$size-2, $top+$offset+$height-$v->[5]*$factor); $cr->stroke; } $cr->save; $cr->set_dash(1,4,3); if($v->[1] != $v->[2]) { $cr->move_to($left+$offset+$size*$v->[0]+int($size/2)-1, $top+$offset+$height-$v->[2]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+int($size/2)-1, $top+$offset+$height-$v->[1]*$factor); $cr->stroke; } if($v->[4] != $v->[5]) { $cr->move_to($left+$offset+$size*$v->[0]+int($size/2)-1, $top+$offset+$height-$v->[5]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+int($size/2)-1, $top+$offset+$height-$v->[4]*$factor-1); $cr->stroke; } $cr->restore; #box if(($v->[2] != $v->[3]) || ($v->[4] != $v->[3])) { $cr->set_source_rgba(@whiscol); $cr->rectangle($left+$offset+$size*$v->[0], $top+$offset+$height-$v->[2]*$factor, $size-1, -($v->[4]-$v->[2])*$factor); $cr->fill; $cr->stroke; $cr->set_source_rgba(@boxcol); $cr->rectangle($left+$offset+$size*$v->[0], $top+$offset+$height-$v->[2]*$factor, $size-2, -($v->[4]-$v->[2])*$factor); $cr->stroke; } else { $cr->set_source_rgba(@boxcol); $cr->move_to($left+$offset+$size*$v->[0], $top+$offset+$height-$v->[3]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+$size-1, $top+$offset+$height-$v->[3]*$factor); $cr->stroke; } #median $cr->set_source_rgba(@medcol); $cr->move_to($left+$offset+$size*$v->[0]+1, $top+$offset+$height-$v->[3]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+$size-2, $top+$offset+$height-$v->[3]*$factor); $cr->stroke; } #write image $cr->show_page; return $surface; } sub convertToBarValues { my ($data,$niceval,$start,$max) = @_; my ($xmax,$ymax,@matrix,$tmp); $xmax = $ymax = 0; #get xmax value if($max) { $xmax = $max; } else { foreach my $q (keys %$data) { $xmax = &max($xmax,$q); } } if($niceval) { $xmax = sprintf("%d",($xmax/$niceval)+1)*$niceval if($xmax % $niceval); } #get matrix values foreach my $q ($start..$xmax) { $tmp = (exists $data->{$q} ? $data->{$q} : 0); $ymax = &max($ymax,$tmp); push(@matrix,$tmp); } $ymax = sprintf("%d",($ymax/4)+1)*4 if($ymax % 4); return (\@matrix,$xmax,$ymax); } sub createBarPlot { my ($matrix,$xmax,$ymax,$title,$xlab,$ylab,$file,$zero) = @_; my @col0 = (178/255, 178/255, 255/255); #b2b2ff my @col1 = (255/255, 178/255, 178/255); #ffb2b2 my @col3 = (127/255, 127/255, 255/255); #7f7fff my @col4 = (255/255, 127/255, 127/255); #ff7f7f my @linecol = (0, 0, 0, 0.4); my @linecol0 = (@col3, 1); my @linecol1 = (@col4, 1); my @barcol0 = (@col3, 1); my @barcol1 = (@col4, 1); my @helplinecol1 = (1,1,1, 0.9); my @helplinecol2 = (1,1,1, 0.5); #create new image my $size = ($xmax <= 50 ? 10 : ($xmax <= 100 ? 6 : 3)); my $offset = 20; my $left = 25; my $bottom = 15; my $top = 0; my $height = 200; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+2*200+20); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); # $cr->set_font_size (30); $cr->save; #set up work space my ($dx, $dy); $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, ($xmax+$zero)*$size-1, $height); $cr->set_source_rgba(0.95, 0.95, 0.95, 1); $cr->fill; #draw ticks #x-axis $cr->set_source_rgba(0, 0, 0, 0.8); foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%5) == 0 && $i > 1 && $i < $xmax) { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+3); } else { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+1); } } $cr->stroke; #y-axis $cr->move_to($left+$offset, $top+$offset); $cr->line_to($left+$offset-3, $top+$offset); $cr->move_to($left+$offset, $top+$offset+$height-1); $cr->line_to($left+$offset-3, $top+$offset+$height-1); $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol1); foreach my $j (1..3) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(0, 0, 0, 0.8); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%5) == 0 && $i > 1 && $i < $xmax) { $extents = $cr->text_extents($i); $cr->move_to($left+$offset+int($size/2+1)+$size*$i-($zero ? 0 : $size)-$extents->{width}/2-1-($i == 1 ? 1 : 0), $top+$offset+$height+$fontheight+2); $cr->show_text($i); } } #y-axis $extents = $cr->text_extents(&addCommas($ymax)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2); $cr->show_text(&addCommas($ymax)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2+$height); $cr->show_text(0); $cr->save; #labels $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #axis labels $cr->set_source_rgba(0, 0, 0, 1); $extents = $cr->text_extents($xlab); $cr->move_to($left+$offset+($xmax+$zero)*$size/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2),$offset); $cr->show_text($ylab); $cr->restore; #draw boxes $cr->set_antialias('none'); foreach my $pos (0..$xmax-($zero ? 0 : 1)) { next unless($matrix->[$pos+($zero ? 0 : 1)]); my $tmp = $matrix->[$pos+($zero ? 0 : 1)] / $ymax; #unique if($tmp) { $cr->set_source_rgba(@barcol0); $cr->rectangle($left+$offset+($pos+($zero ? 0 : 1))*$size, $top+$offset+$height, $size-1, -$tmp*$height); $cr->fill; } } #write image $cr->show_page; return $surface; } sub convertOdToStackBinMatrix { my ($data,$stacks,$min,$max,$nonice) = @_; my ($num,$ymax,$xmax,$xmin,$step,%vals,%sums,$sum,@matrix,$bin,$tmpbin); #make nice xmax value if(defined $max) { $xmax = $max; } else { $xmax = (sort {$b <=> $a} keys %$data)[0]; } $bin = &getBinVal($xmax); $xmax = $bin*100; $xmin = (defined $min ? $min : 0); #get data to bin and find y axis max value $ymax = 0; foreach my $s (0..$stacks-1) { $sums{$s} = 0; } $sum = 0; $tmpbin = $bin; foreach my $i ($xmin..$xmax) { foreach my $s (0..$stacks-1) { next unless(exists $data->{$i}->{$s}); $sums{$s} += $data->{$i}->{$s}; $sum += $data->{$i}->{$s}; } if(--$tmpbin <= 0) { $tmpbin = $bin; $ymax = &max($ymax,$sum); $sum = 0; foreach my $s (0..$stacks-1) { push(@{$matrix[$s]},$sums{$s}); $sums{$s} = 0; } } } #make nice ymax value unless($nonice) { $ymax = sprintf("%d",($ymax/4)+1)*4 if($ymax % 4); # $step = ($ymax <= 10 ? 10 : ($ymax < 40 ? 40 : ($ymax < 100 ? 100 : ($ymax < 1000 ? 100 : 100)))); # $ymax = sprintf("%d",($ymax/$step)+1)*$step if($ymax % $step); } return (\@matrix,$xmax,$ymax,$stacks); } sub createStackBarPlot { my ($matrix,$xmax,$ymax,$stacks,$title,$xlab,$ylab,$file,$zero,$add) = @_; my $bin = 1; if($xmax > 100) { $bin = $xmax / 100; $xmax = 100; } my @legend = ('Exact dupl.','5\' dupl.','3\' dupl.','Rev. compl. exact dupl.','Rev. compl. 5\'/3\' dupl.'); my @cols = ([69/255, 114/255, 167/255, 1], [137/255, 1165/255, 78/255, 1], [170/255, 70/255, 67/255, 1], [147/255, 169/255, 207/255, 1], [51/255, 102/255, 102/255, 1]); my @barcol = (127/255, 127/255, 255/255, 1); #b2b2ff my @meancol = (255/255, 127/255, 127/255, 1); #ffb2b2 my @stdcol = (178/255, 178/255, 255/255, 0.8); #7f7fff my @std1col = (0, 0, 0, 0.02); #ff7f7f my @std2col = (0, 0, 0, 0.02); #ff7f7f my @linecol = (0, 0, 0, 0.4); my @helplinecol = (1, 1, 1, 0.9); my @background = (0.95, 0.95, 0.95, 1); my @tickcol = (0, 0, 0, 0.8); my @labelcol = (0, 0, 0, 1); #create new image my $size = 6; my $offset = 20; my $left = 40; my $bottom = 15; my $top = 20; my $height = 200; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+($xmax+$zero)*$size,$bottom+$top+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+2*200+20); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); $cr->save; #set up work space $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, ($xmax+$zero)*$size-1, $height); $cr->set_source_rgba(@background); $cr->fill; #draw legend $cr->set_font_size(10); # $font_extents = $cr->font_extents; my $x = $left+$offset+$size*100-5; foreach my $i (reverse (0..scalar(@legend)-1)) { $cr->set_antialias('default'); $x -= $cr->text_extents($legend[$i])->{width}; $cr->move_to($x,$top+5+9); $cr->set_source_rgba(@tickcol); $cr->show_text($legend[$i]); $x -= 15; $cr->set_antialias('none'); $cr->set_source_rgba(@{$cols[$i]}); $cr->rectangle($x, $top+5, 10, 10); $cr->fill; $x -= 15; } #draw ticks $cr->set_antialias('none'); #x-axis $cr->set_source_rgba(@tickcol); foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%5) == 0 && $i > 1 && $i < $xmax) { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+3); } else { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+1); } } $cr->stroke; #y-axis $cr->move_to($left+$offset, $top+$offset); $cr->line_to($left+$offset-3, $top+$offset); $cr->move_to($left+$offset, $top+$offset+$height-1); $cr->line_to($left+$offset-3, $top+$offset+$height-1); $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol); foreach my $j (1..3) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(@tickcol); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%10) == 0 && $i > 1 && $i < $xmax) { $extents = $cr->text_extents($i*$bin); $cr->move_to($left+$offset+int($size/2+1)+$size*$i-($zero ? 0 : $size)-$extents->{width}/2-1-($i == 1 ? 1 : 0), $top+$offset+$height+$fontheight+2); $cr->show_text($i*$bin); } } #y-axis $extents = $cr->text_extents(&addCommas($ymax)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2); $cr->show_text(&addCommas($ymax)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2+$height); $cr->show_text(0); $cr->save; #labels $cr->set_font_size(14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #axis labels $cr->set_source_rgba(@labelcol); $extents = $cr->text_extents($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->move_to($left+$offset+($xmax+$zero)*$size/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab.($bin>1 ? ' (per bin)' : '')); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2+($bin>1 ? 12 : 0)),$offset+10); $cr->show_text($ylab.($bin>1 ? ' (per bin)' : '')); $cr->restore; #draw boxes $cr->set_antialias('none'); foreach my $pos (0..$xmax-($zero ? 0 : 1)) { my $tmp = 0; foreach my $s (0..$stacks-1) { next unless($matrix->[$s]->[$pos]); my $cur = $matrix->[$s]->[$pos] / $ymax; $cr->set_source_rgba(@{$cols[$s]}); if($cur) { $cr->rectangle($left+$offset+$pos*$size, $top+$offset+$height-$tmp*$height, $size-1, -$cur*$height); $cr->fill; } $tmp += $cur; } } #write image $cr->show_page; return $surface; } sub header { return ' PRINSEQ-'.$WHAT.' Report
'; } sub footer { return '
'; } sub generateHtml { my ($in,$out) = @_; my ($file,$data,$surface,$html,$png); $data = &readGdFile($in); my $time = sprintf("%02d/%02d/%04d %02d:%02d:%02d",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); $html .= &header(); $html .= '

PRINSEQ-'.$WHAT.' v'.$VERSION.' HTML Report   

[Generated: '.$time.']

'; $html .= '
'; #input info if(exists $data->{numseqs}) { $html .= '
Input Information
'; $html .= '
'; if(exists $data->{pairedend} && $data->{pairedend}) { my $singletons1 = ($data->{numseqs}||0)-($data->{pairs}||0); my $singletons2 = ($data->{numseqs2}||0)-($data->{pairs}||0); $html .= ''; } else { $html .= ''; } $html .= '
Input file(s):'.($data->{filename1} ? &convertIntToString($data->{filename1}) : '-').($data->{filename2} ? ' and '.&convertIntToString($data->{filename2}) : '').'
Input format(s):'.($data->{format1} ? uc($data->{format1}) : '-').($data->{format2} ? ' and '.uc($data->{format2}) : '').'
# Sequences (file 1):'.&addCommas($data->{numseqs}||'-').'
Total bases (file 1):'.&addCommas($data->{numbases}||'-').'
# Sequences (file 2):'.&addCommas($data->{numseqs2}||'-').'
Total bases (file 2):'.&addCommas($data->{numbases2}||'-').'
# Pairs:'.&addCommas($data->{pairs}||'-').($data->{pairs} ? '  ('.sprintf("%.2f",(100*(2*$data->{pairs})/(($data->{numseqs}||0)+($data->{numseqs2}||0)))).'% of sequences)' : '').'
# Singletons (file 1):'.&addCommas($singletons1).($singletons1 ? '  ('.sprintf("%.2f",(100*$singletons1/$data->{numseqs})).'%)' : '').'
# Singletons (file 2):'.&addCommas($singletons2).($singletons2 ? '  ('.sprintf("%.2f",(100*$singletons2/$data->{numseqs2})).'%)' : '').'
# Sequences:'.&addCommas($data->{numseqs}||'-').'
Total bases:'.&addCommas($data->{numbases}||'-').'

'; } #length plot if(exists $data->{counts}->{length} && keys %{$data->{counts}->{length}}) { $html .= '
Length Distribution
'; if(exists $data->{pairedend} && $data->{pairedend}) { $html .= '
File 1
Mean sequence length: '.(exists $data->{stats}->{length}->{mean} ? sprintf("%.2f",$data->{stats}->{length}->{mean}) : '-').' ± '.(exists $data->{stats}->{length}->{std} ? sprintf("%.2f",$data->{stats}->{length}->{std}) : '-').' bp
Minimum length: '.(exists $data->{stats}->{length}->{min} ? &addCommas($data->{stats}->{length}->{min}) : '-').' bp
Maximum length:'.(exists $data->{stats}->{length}->{max} ? &addCommas($data->{stats}->{length}->{max}) : '-').' bp
Length range:'.(exists $data->{stats}->{length}->{range} ? &addCommas($data->{stats}->{length}->{range}) : '-').' bp
Mode length: '.(exists $data->{stats}->{length}->{mode} ? &addCommas($data->{stats}->{length}->{mode}) : '-').' bp with '.(exists $data->{stats}->{length}->{modeval} ? &addCommas($data->{stats}->{length}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{length},1),$data->{stats}->{length},'Length Distribution','Read Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; $html .= '

File 2
Mean sequence length: '.(exists $data->{stats2}->{length}->{mean} ? sprintf("%.2f",$data->{stats2}->{length}->{mean}) : '-').' ± '.(exists $data->{stats2}->{length}->{std} ? sprintf("%.2f",$data->{stats2}->{length}->{std}) : '-').' bp
Minimum length: '.(exists $data->{stats2}->{length}->{min} ? &addCommas($data->{stats2}->{length}->{min}) : '-').' bp
Maximum length:'.(exists $data->{stats2}->{length}->{max} ? &addCommas($data->{stats2}->{length}->{max}) : '-').' bp
Length range:'.(exists $data->{stats2}->{length}->{range} ? &addCommas($data->{stats2}->{length}->{range}) : '-').' bp
Mode length: '.(exists $data->{stats2}->{length}->{mode} ? &addCommas($data->{stats2}->{length}->{mode}) : '-').' bp with '.(exists $data->{stats2}->{length}->{modeval} ? &addCommas($data->{stats2}->{length}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{length},1),$data->{stats2}->{length},'Length Distribution','Read Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; } else { $html .= '
Mean sequence length: '.(exists $data->{stats}->{length}->{mean} ? sprintf("%.2f",$data->{stats}->{length}->{mean}) : '-').' ± '.(exists $data->{stats}->{length}->{std} ? sprintf("%.2f",$data->{stats}->{length}->{std}) : '-').' bp
Minimum length: '.(exists $data->{stats}->{length}->{min} ? &addCommas($data->{stats}->{length}->{min}) : '-').' bp
Maximum length:'.(exists $data->{stats}->{length}->{max} ? &addCommas($data->{stats}->{length}->{max}) : '-').' bp
Length range:'.(exists $data->{stats}->{length}->{range} ? &addCommas($data->{stats}->{length}->{range}) : '-').' bp
Mode length: '.(exists $data->{stats}->{length}->{mode} ? &addCommas($data->{stats}->{length}->{mode}) : '-').' bp with '.(exists $data->{stats}->{length}->{modeval} ? &addCommas($data->{stats}->{length}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{length},1),$data->{stats}->{length},'Length Distribution','Read Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; } $html .= '
'; } #GC content if(exists $data->{counts}->{gc} && keys %{$data->{counts}->{gc}}) { $html .= '
GC Content Distribution
'; if(exists $data->{pairedend} && $data->{pairedend}) { $html .= '
File 1
Mean GC content: '.(exists $data->{stats}->{gc}->{mean} ? sprintf("%.2f",$data->{stats}->{gc}->{mean}) : '-').' ± '.(exists $data->{stats}->{gc}->{std} ? sprintf("%.2f",$data->{stats}->{gc}->{std}) : '-').' %
Minimum GC content: '.(exists $data->{stats}->{gc}->{min} ? $data->{stats}->{gc}->{min} : '-').' %
Maximum GC content: '.(exists $data->{stats}->{gc}->{max} ? $data->{stats}->{gc}->{max} : '-').' %
GC content range: '.(exists $data->{stats}->{gc}->{range} ? $data->{stats}->{gc}->{range} : '-').' %
Mode GC content: '.(exists $data->{stats}->{gc}->{mode} ? $data->{stats}->{gc}->{mode} : '-').' % with '.(exists $data->{stats}->{gc}->{modeval} ? &addCommas($data->{stats}->{gc}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{gc},0),$data->{stats}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; $html .= '

File 2
Mean GC content: '.(exists $data->{stats2}->{gc}->{mean} ? sprintf("%.2f",$data->{stats2}->{gc}->{mean}) : '-').' ± '.(exists $data->{stats2}->{gc}->{std} ? sprintf("%.2f",$data->{stats2}->{gc}->{std}) : '-').' %
Minimum GC content: '.(exists $data->{stats2}->{gc}->{min} ? $data->{stats2}->{gc}->{min} : '-').' %
Maximum GC content: '.(exists $data->{stats2}->{gc}->{max} ? $data->{stats2}->{gc}->{max} : '-').' %
GC content range: '.(exists $data->{stats2}->{gc}->{range} ? $data->{stats2}->{gc}->{range} : '-').' %
Mode GC content: '.(exists $data->{stats2}->{gc}->{mode} ? $data->{stats2}->{gc}->{mode} : '-').' % with '.(exists $data->{stats2}->{gc}->{modeval} ? &addCommas($data->{stats2}->{gc}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{gc},0),$data->{stats2}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; } else { $html .= '
Mean GC content: '.(exists $data->{stats}->{gc}->{mean} ? sprintf("%.2f",$data->{stats}->{gc}->{mean}) : '-').' ± '.(exists $data->{stats}->{gc}->{std} ? sprintf("%.2f",$data->{stats}->{gc}->{std}) : '-').' %
Minimum GC content: '.(exists $data->{stats}->{gc}->{min} ? $data->{stats}->{gc}->{min} : '-').' %
Maximum GC content: '.(exists $data->{stats}->{gc}->{max} ? $data->{stats}->{gc}->{max} : '-').' %
GC content range: '.(exists $data->{stats}->{gc}->{range} ? $data->{stats}->{gc}->{range} : '-').' %
Mode GC content: '.(exists $data->{stats}->{gc}->{mode} ? $data->{stats}->{gc}->{mode} : '-').' % with '.(exists $data->{stats}->{gc}->{modeval} ? &addCommas($data->{stats}->{gc}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{gc},0),$data->{stats}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; } $html .= '
'; } #Base quality if(exists $data->{quals} || exists $data->{qualsmean} || exists $data->{qualsbin}) { $html .= '
Base Quality Distribution
'; if(exists $data->{pairedend} && $data->{pairedend}) { $html .= 'File 1
'; } } if(exists $data->{quals} && keys %{$data->{quals}}) { $surface = &createBoxPlot(&convertToBoxValues($data->{quals},4),'Base Quality Distribution','Read position in %','Quality score',''); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); } if(exists $data->{qualsbin} && keys %{$data->{qualsbin}}) { $surface = &createBoxPlot(&convertToBoxValues($data->{qualsbin},4),'Base Quality Distribution','Read position in bp','Quality score','',0,'bp',$data->{binval}); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{quals}); $html .= &insert_image($png); } if(exists $data->{qualsmean} && keys %{$data->{qualsmean}}) { $surface = &createBarPlot(&convertToBarValues($data->{qualsmean},5,1),'Sequence Quality Distribution','Mean of quality scores per sequence','Number of sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{qualsbin}); $html .= &insert_image($png); } if(exists $data->{pairedend} && $data->{pairedend}) { if(exists $data->{quals} || exists $data->{qualsmean} || exists $data->{qualsbin}) { $html .= '


File 2
'; } if(exists $data->{quals2} && keys %{$data->{quals2}}) { $surface = &createBoxPlot(&convertToBoxValues($data->{quals2},4),'Base Quality Distribution','Read position in %','Quality score',''); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); } if(exists $data->{qualsbin2} && keys %{$data->{qualsbin2}}) { $surface = &createBoxPlot(&convertToBoxValues($data->{qualsbin2},4),'Base Quality Distribution','Read position in bp','Quality score','',0,'bp',$data->{binval}); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{quals2}); $html .= &insert_image($png); } if(exists $data->{qualsmean2} && keys %{$data->{qualsmean2}}) { $surface = &createBarPlot(&convertToBarValues($data->{qualsmean2},5,1),'Sequence Quality Distribution','Mean of quality scores per sequence','Number of sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{qualsbin2}); $html .= &insert_image($png); } } if(exists $data->{quals} || exists $data->{qualsmean} || exists $data->{qualsbin}) { $html .= '

'; } #Ns if((exists $data->{counts}->{ns} && keys %{$data->{counts}->{ns}}) || (exists $data->{counts2} && exists $data->{counts2}->{ns} && keys %{$data->{counts2}->{ns}})) { $html .= '
Occurence of N
'; if(exists $data->{pairedend} && $data->{pairedend}) { $html .= 'File 1
'; } } if(exists $data->{counts}->{ns} && keys %{$data->{counts}->{ns}}) { my $nscount = 0; foreach my $n (values %{$data->{counts}->{ns}}) { $nscount += $n; } $html .= '
Sequences with N: '.($nscount ? &addCommas($nscount).'  ('.sprintf("%.2f",100/$data->{numseqs}*$nscount).' %)' : 0).'
Max percentage of Ns per sequence: '.(exists $data->{stats}->{ns}->{max} ? $data->{stats}->{ns}->{max} : 0).' %
'; if($nscount) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{ns},1),undef,'Percentage of N\'s (> 0%)','Percentage of N\'s per Read (1-100%)','# Sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } } if(exists $data->{pairedend} && $data->{pairedend} && exists $data->{counts2}->{ns} && keys %{$data->{counts2}->{ns}}) { $html .= '


File 2
'; my $nscount = 0; foreach my $n (values %{$data->{counts2}->{ns}}) { $nscount += $n; } $html .= '
Sequences with N: '.($nscount ? &addCommas($nscount).'  ('.sprintf("%.2f",100/$data->{numseqs2}*$nscount).' %)' : 0).'
Max percentage of Ns per sequence: '.(exists $data->{stats2}->{ns}->{max} ? $data->{stats2}->{ns}->{max} : 0).' %
'; if($nscount) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{ns},1),undef,'Percentage of N\'s (> 0%)','Percentage of N\'s per Read (1-100%)','# Sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } } if((exists $data->{counts}->{ns} && keys %{$data->{counts}->{ns}}) || (exists $data->{counts2} && exists $data->{counts2}->{ns} && keys %{$data->{counts2}->{ns}})) { $html .= '

'; } #tails if(exists $data->{tail} || exists $data->{tail2}) { $html .= '
Poly-A/T Tails
'; } if(exists $data->{tail}) { my $tail5count = 0; foreach my $n (values %{$data->{counts}->{tail5}}) { $tail5count += $n; } my $tail3count = 0; foreach my $n (values %{$data->{counts}->{tail3}}) { $tail3count += $n; } if(exists $data->{pairedend} && $data->{pairedend}) { $html .= 'File 1
'; } $html .= '
5\'-end 3\'-end
Sequences with tail:'.($tail5count ? &addCommas($tail5count).'  ('.sprintf("%.2f",100/$data->{numseqs}*$tail5count).' %)' : 0).' '.($tail3count ? &addCommas($tail3count).'  ('.sprintf("%.2f",100/$data->{numseqs}*$tail3count).' %)' : 0).'
Maximum tail length: '.(exists $data->{stats}->{tail5}->{max} ? $data->{stats}->{tail5}->{max} : 0).' '.(exists $data->{stats}->{tail3}->{max} ? $data->{stats}->{tail3}->{max} : 0).'
'; if($tail5count) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{tail5},1),undef,'Poly-A/T Tail Distribution (> 4bp)','5\' Tail Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); if($tail3count) { $html .= '
'; } } if($tail3count) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{tail3},1),undef,'Poly-A/T Tail Distribution (> 4bp)','3\' Tail Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } } if(exists $data->{pairedend} && $data->{pairedend} && exists $data->{tail2}) { my $tail5count = 0; foreach my $n (values %{$data->{counts2}->{tail5}}) { $tail5count += $n; } my $tail3count = 0; foreach my $n (values %{$data->{counts2}->{tail3}}) { $tail3count += $n; } $html .= '


File 2
'; $html .= '
5\'-end 3\'-end
Sequences with tail:'.($tail5count ? &addCommas($tail5count).'  ('.sprintf("%.2f",100/$data->{numseqs2}*$tail5count).' %)' : 0).' '.($tail3count ? &addCommas($tail3count).'  ('.sprintf("%.2f",100/$data->{numseqs2}*$tail3count).' %)' : 0).'
Maximum tail length: '.(exists $data->{stats2}->{tail5}->{max} ? $data->{stats2}->{tail5}->{max} : 0).' '.(exists $data->{stats2}->{tail3}->{max} ? $data->{stats2}->{tail3}->{max} : 0).'
'; if($tail5count) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{tail5},1),undef,'Poly-A/T Tail Distribution (> 4bp)','5\' Tail Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); if($tail3count) { $html .= '
'; } } if($tail3count) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{tail3},1),undef,'Poly-A/T Tail Distribution (> 4bp)','3\' Tail Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } } if(exists $data->{tail} || exists $data->{tail2}) { $html .= '

'; } #tag sequence check if(exists $data->{freqs} || exists $data->{freqs2}) { $html .= '
Tag Sequence Check
'; } if(exists $data->{freqs}) { my $tagmidseq; if(exists $data->{tagmidseq}) { $tagmidseq = $data->{tagmidseq}; $tagmidseq =~ s/\,/\
/g; } if(exists $data->{pairedend} && $data->{pairedend}) { $html .= 'File 1
'; } $html .= '
5\'-end3\'-end
Probability of tag sequence:'.(exists $data->{tagprob}->{5} ? $data->{tagprob}->{5}.' %' : '-').''.(exists $data->{tagprob}->{3} ? $data->{tagprob}->{3}.' %' : '-').'
GSMIDs or RLMIDs:'.(exists $data->{tagmidnum} ? ($data->{tagmidnum} == 0 ? 'none' : ($tagmidseq ? $tagmidseq : $data->{tagmidnum})) : '-').' 

'; $html .= ''; foreach my $pos (sort {$a <=> $b} keys %{$data->{freqs}->{5}}) { $html .= ''; } $html .= ''; foreach my $pos (sort {$a <=> $b} keys %{$data->{freqs}->{3}}) { $html .= ''; } $html .= ''; $html .= ''; foreach my $num (1,0,0,0,5,0,0,0,0,10,0,0,0,0,15,0,0,0,0,20,0,20,0,0,0,0,15,0,0,0,0,10,0,0,0,0,5,0,0,0,1) { $html .= ''; } $html .= ''; $html .= '
'.&insert_image($FREQCHART_L,undef,undef,1).''; foreach my $base (qw(A C G T N)) { if($data->{freqs}->{5}->{$pos}->{$base}) { $html .= &insert_image($BASE64_BASES->{$base},$data->{freqs}->{5}->{$pos}->{$base},14,1).'
'; #''.$base.'
'; } } $html .= &insert_image($MMCHART_B2,6,16,1).'
 ... '; foreach my $base (qw(A C G T N)) { if($data->{freqs}->{3}->{$pos}->{$base}) { $html .= &insert_image($BASE64_BASES->{$base},$data->{freqs}->{3}->{$pos}->{$base},14,1).'
'; } } $html .= &insert_image($MMCHART_B2,6,16,1).'
 '.($num ? $num : '').' 
 Position from Sequence Ends
'; } if(exists $data->{pairedend} && $data->{pairedend} && exists $data->{freqs2}) { $html .= '


File 2
'; $html .= '
5\'-end3\'-end
Probability of tag sequence:'.(exists $data->{tagprob2}->{5} ? $data->{tagprob2}->{5}.' %' : '-').''.(exists $data->{tagprob2}->{3} ? $data->{tagprob2}->{3}.' %' : '-').'

'; $html .= ''; foreach my $pos (sort {$a <=> $b} keys %{$data->{freqs2}->{5}}) { $html .= ''; } $html .= ''; foreach my $pos (sort {$a <=> $b} keys %{$data->{freqs2}->{3}}) { $html .= ''; } $html .= ''; $html .= ''; foreach my $num (1,0,0,0,5,0,0,0,0,10,0,0,0,0,15,0,0,0,0,20,0,20,0,0,0,0,15,0,0,0,0,10,0,0,0,0,5,0,0,0,1) { $html .= ''; } $html .= ''; $html .= '
'.&insert_image($FREQCHART_L,undef,undef,1).''; foreach my $base (qw(A C G T N)) { if($data->{freqs2}->{5}->{$pos}->{$base}) { $html .= &insert_image($BASE64_BASES->{$base},$data->{freqs2}->{5}->{$pos}->{$base},14,1).'
'; #''.$base.'
'; } } $html .= &insert_image($MMCHART_B2,6,16,1).'
 ... '; foreach my $base (qw(A C G T N)) { if($data->{freqs2}->{3}->{$pos}->{$base}) { $html .= &insert_image($BASE64_BASES->{$base},$data->{freqs2}->{3}->{$pos}->{$base},14,1).'
'; } } $html .= &insert_image($MMCHART_B2,6,16,1).'
 '.($num ? $num : '').' 
 Position from Sequence Ends
'; } if(exists $data->{freqs} || exists $data->{freqs2}) { $html .= '

'; } #Sequence duplicates if(exists $data->{dubslength} || exists $data->{dubscounts}) { $html .= '
Sequence Duplication
'; } my %dubs; if(exists $data->{dubscounts} && keys %{$data->{dubscounts}}) { my $exactonly = $data->{exactonly}||0; foreach my $n (keys %{$data->{dubscounts}}) { foreach my $s (keys %{$data->{dubscounts}->{$n}}) { $dubs{$s}->{count} += $data->{dubscounts}->{$n}->{$s} * $n; $dubs{$s}->{max} = $n unless(exists $dubs{$s}->{max} && $dubs{$s}->{max} > $n); $dubs{all} += $data->{dubscounts}->{$n}->{$s} * $n; } } $html .= '
'; unless($exactonly) { $html .= ''; } $html .= '
# Sequences Max duplicates
Exact duplicates:'.(exists $dubs{0}->{count} ? &addCommas($dubs{0}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{0}->{count}).' %)' : 0).''.($dubs{0}->{max}||0).'
Exact duplicates with reverse complements:'.(exists $dubs{3}->{count} ? &addCommas($dubs{3}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{3}->{count}).' %)' : 0).' '.($dubs{3}->{max}||0).'
5\' duplicates'.(exists $dubs{1}->{count} ? &addCommas($dubs{1}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{1}->{count}).' %)' : 0).' '.($dubs{1}->{max}||0).'
3\' duplicates'.(exists $dubs{2}->{count} ? &addCommas($dubs{2}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{2}->{count}).' %)' : 0).' '.($dubs{2}->{max}||0).'
5\'/3\' duplicates with reverse complements'.(exists $dubs{4}->{count} ? &addCommas($dubs{4}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{4}->{count}).' %)' : 0).' '.($dubs{4}->{max}||0).'
Total:'.(exists $dubs{all} ? &addCommas($dubs{all}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{all}).' %)' : 0).'-
'; } if(exists $dubs{all} && $dubs{all}) { if(exists $data->{dubslength} && keys %{$data->{dubslength}}) { $surface = &createStackBarPlot(&convertOdToStackBinMatrix($data->{dubslength},5,1),'Sequence duplication level','Read Length in bp','Number of duplicates','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } if(exists $data->{dubscounts} && keys %{$data->{dubscounts}}) { $surface = &createStackBarPlot(&convertOdToStackBinMatrix($data->{dubscounts},5,1,100),'Sequence duplication level','Number of duplicates','Number of sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{dubslength}); $html .= &insert_image($png); my %dubsmax; my $count = 1; foreach my $n (sort {$b <=> $a} keys %{$data->{dubscounts}}) { foreach my $s (keys %{$data->{dubscounts}->{$n}}) { foreach my $i (1..$data->{dubscounts}->{$n}->{$s}) { $dubsmax{$count++}->{$s} = $n; last unless($count <= 100); } last unless($count <= 100); } last unless($count <= 100); } $surface = &createStackBarPlot(&convertOdToStackBinMatrix(\%dubsmax,5,1,100),'Sequence duplication level','Sequence','Number of duplicates','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{dubslength}); $html .= &insert_image($png); } } if(exists $data->{dubslength} || exists $data->{dubscounts}) { $html .= '

'; } #Sequence complexity if(exists $data->{compldust} || exists $data->{complentropy}) { $html .= '
Sequence Complexity
'; if(exists $data->{complvals}) { my $complseq; foreach my $d (keys %{$data->{complvals}}) { foreach my $m ('minseq','maxseq') { $complseq = $data->{complvals}->{$d}->{$m}; $complseq = substr($complseq,0,797).'...' if(length($complseq) > 800); $complseq =~ s/(.{60})/$1\
/g; $data->{complvals}->{$d}->{$m} = $complseq; } } } $html .= '
ValueSequence
Minimum DUST score:'.(exists $data->{complvals}->{dust}->{minval} ? $data->{complvals}->{dust}->{minval} : '-').''.(exists $data->{complvals}->{dust}->{minseq} ? $data->{complvals}->{dust}->{minseq} : '').'
Maximum DUST score:'.(exists $data->{complvals}->{dust}->{maxval} ? $data->{complvals}->{dust}->{maxval} : '').''.(exists $data->{complvals}->{dust}->{maxseq} ? $data->{complvals}->{dust}->{maxseq} : '').'
Minimum Entropy value:'.(exists $data->{complvals}->{entropy}->{minval} ? $data->{complvals}->{entropy}->{minval} : '').''.(exists $data->{complvals}->{entropy}->{minseq} ? $data->{complvals}->{entropy}->{minseq} : '').'
Maximum Entropy value:'.(exists $data->{complvals}->{entropy}->{maxval} ? $data->{complvals}->{entropy}->{maxval} : '').''.(exists $data->{complvals}->{entropy}->{maxseq} ? $data->{complvals}->{entropy}->{maxseq} : '').'

'; } if(exists $data->{compldust}) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{compldust},0),undef,'Sequence complexity distribution','Mean sequence complexity (DUST scores)','Number of sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); } if(exists $data->{complentropy}) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{complentropy},0),undef,'Sequence complexity distribution','Mean sequence complexity (Entropy values)','Number of sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{compldust}); $html .= &insert_image($png); } if(exists $data->{compldust} || exists $data->{complentropy}) { $html .= '

'; } #Dinucleotide odd ratio PCA - microbial/viral if(exists $data->{dinucodds} && keys %{$data->{dinucodds}}) { $html .= '
Dinucleotide Odds Ratios
'; $html .= '
'; foreach my $d (map {join("/",(m/../g ))} sort keys %{$data->{dinucodds}}) { $html .= ''; } $html .= ''; foreach my $d (map {sprintf("%.4f",$data->{dinucodds}->{$_})} sort keys %{$data->{dinucodds}}) { $html .= ''; } $html .= '
 '.$d.'
Odds ratio'.$d.'

'; my @new = map {$data->{dinucodds}->{$_}} sort keys %{$data->{dinucodds}}; $surface = &createOddsRatioPlot($data->{dinucodds},'Odds ratios','Dinucleotide','Odds ratio',''); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); #$surface = &createPCAPlot(&convertToPCAValues(\@new,'m'),'PCA','1st Principal Component Score','2nd Principal Component Score',''); #$png = ''; #$surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); #$html .= '

'; #$html .= &insert_image($png); #$surface = &createPCAPlot(&convertToPCAValues(\@new,'v'),'PCA','1st Principal Component Score','2nd Principal Component Score',''); #$png = ''; #$surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); #$html .= '

'; #$html .= &insert_image($png); $html .= '
'; } $html .= '
'; $html .= &footer(); #write html to file $file = &getFileName('.html'); open(FH, ">$file") or &printError("Can't open file ".$file.": $!"); print FH $html; close(FH); &printLog("Done with HTML data"); } sub insert_image { my ($data, $height, $width, $noencode) = @_; my $content .= ''."\n"; return $content; } sub inline_image { return "data:image/png;base64,".MIME::Base64::encode_base64($_[0]); } sub convertIntToString { my $int = shift; $int =~ s/(.{2})/chr(hex($1))/eg; return $int; } prinseq-lite-0.20.4/prinseq-graphs.pl0000644000076700007670000036345112240000123017701 0ustar rschmiedrschmied#!/usr/bin/perl #=============================================================================== # Author: Robert SCHMIEDER, Computational Science Research Center @ SDSU, CA # # File: prinseq-graphs # Date: 2012-12-22 # Version: 0.6 graphs # # Usage: # prinseq-graphs [options] # # Try 'prinseq-graphs -h' for more information. # # Purpose: PRINSEQ will help you to preprocess your genomic or metagenomic # sequence data in FASTA or FASTQ format. The graphs version allows # users of the lite version to generate graphs similar to the web # version. # # Bugs: Please use http://sourceforge.net/tracker/?group_id=315449 # #=============================================================================== use strict; use warnings; use Getopt::Long; use Pod::Usage; use File::Temp qw(tempfile); #for output files use Fcntl qw(:flock SEEK_END); #for log file use Cwd; use JSON; use Cairo; use Statistics::PCA; use MIME::Base64; use File::Basename; use Data::Dumper; ### $| = 1; # Do not buffer output my $PI = 4 * atan2(1, 1); my $LOG62 = log(62); my $DINUCODDS_VIR = [ [qw(1.086940308 0.98976932 1.034167044 0.880024041 1.070421277 0.990687084 0.890945575 1.069957074 0.92465631 0.803973303)], [qw(1.101064857 0.986812783 1.038299155 0.896162618 1.081652847 0.976365237 0.867445186 1.06727283 0.94688543 0.768007295)], [qw(1.071548411 0.912204166 1.196914981 0.80628184 1.294201511 1.148517794 0.269295791 1.033948026 0.895951033 0.623192149)], [qw(1.090253719 0.907428629 1.203991784 0.786359294 1.281499107 1.145421568 0.235974709 1.033437274 0.899580091 0.631699771)], [qw(1.075864745 1.003413074 1.01872902 0.897841689 0.980373171 1.05854979 0.934262259 1.052477953 0.88145851 0.889239724)], [qw(1.101890467 1.030028291 1.019912674 0.84191395 1.0015174 1.069546264 0.900151602 0.996269395 0.889195343 0.904039022)], [qw(1.152417359 0.855028574 0.91164793 1.017415486 1.114163672 1.128353311 0.846355573 0.916745489 1.206820475 0.811014651)], [qw(1.142454218 0.8635465 0.923406967 1.026242747 1.134445058 1.131747833 0.79793368 0.920767641 1.179468556 0.799770057)], [qw(1.124462747 0.873556143 0.945627041 1.013755408 1.159866153 1.096259526 0.757315047 0.972924919 1.105562567 0.772731886)], [qw(1.143826972 0.866968779 0.995740249 0.945859278 1.109590621 1.089305083 0.76048874 0.971561388 1.157101408 0.792923027)], [qw(1.131900141 0.82776996 0.996204924 0.999433455 1.024692372 1.071176333 0.921026216 1.088936699 1.054010776 0.773498892)], [qw(1.042180476 0.930180412 1.019242897 0.98909997 1.006666828 1.046708539 0.959492164 1.011183418 1.055168776 0.937433818)], [qw(1.086515695 0.985345815 0.930914307 0.969581792 1.043010232 1.087463712 0.939482285 0.990551965 0.954752469 0.893972874)], [qw(1.096657826 0.950117614 0.936195529 0.965619788 1.114975275 1.077011195 0.843153131 0.989128406 1.043790912 0.840634731)], [qw(1.158030995 0.935307365 0.874812261 1.056236525 1.117171274 0.937484692 1.057442372 0.970079538 1.174848738 0.725071711)], [qw(1.15591506 0.93000227 0.883538923 1.0567652 1.095730954 0.944489906 1.074229471 0.983993745 1.156051409 0.726688465)], [qw(1.205726473 0.924439339 1.049457756 0.805718412 0.975472778 1.07581991 0.726992211 1.075025787 0.8704929 0.726672843)], [qw(1.188544681 0.95239611 1.049066985 0.790031334 1.038632598 1.056749787 0.665197397 1.057566244 0.862429061 0.708982398)], [qw(1.063631482 0.925593715 1.014869316 0.944904401 1.119690731 1.325971834 0.273781451 0.943347677 1.06438014 0.920825904)], [qw(1.077560287 0.911888545 1.044147857 0.927758054 1.058535939 1.296838544 0.421514996 0.945722451 1.128317986 0.926419928)], [qw(1.163753415 0.989905668 0.893599328 0.955641844 1.176047687 0.941559156 0.950641089 0.959741692 1.100815282 0.72491925)], [qw(1.139253929 0.946297517 0.922096125 1.024801537 1.205206793 0.968818717 0.915801342 0.971626058 1.107569276 0.627623404)] ]; my $DINUCODDS_MIC = [ [qw(1.13127323 0.853587195 0.911041047 1.104520778 1.065586428 1.021434164 0.999734139 1.063684014 1.078035184 0.733596552)], [qw(1.173267344 0.840539337 0.919534602 1.068050141 1.062394214 1.051999071 0.96770576 1.035511729 1.095600433 0.72328141)], [qw(1.172939786 0.84567902 0.911836259 1.106288994 1.05351787 1.026143368 1.002308358 1.066319771 1.094918797 0.710733535)], [qw(1.073527689 0.850290918 0.978455025 1.080882178 1.111174765 1.010754115 0.895668707 1.072980666 1.079304608 0.754057386)], [qw(1.08807747 0.837444678 0.95824965 1.097310298 1.118897971 1.030863881 0.886827263 1.072349394 1.07406322 0.733440096)], [qw(1.071685485 0.861055813 0.966566865 1.090268118 1.112945761 1.012538936 0.909535491 1.063745603 1.071156598 0.755770377)], [qw(1.142698587 0.867936867 1.000612099 0.977934257 1.111801746 1.018318601 0.788556794 0.987763594 1.184649653 0.784776176)], [qw(1.134560074 0.876651844 0.998190253 0.995723123 1.128448077 1.014172324 0.781776188 0.971020602 1.182411449 0.786449476)], [qw(1.180029632 0.787899325 1.01316945 0.932268406 1.077837263 1.211699678 0.612128817 1.033036699 1.157314398 0.74940288)], [qw(1.160925546 0.788308899 1.003702496 0.965371236 1.076051693 1.188304271 0.641536444 1.070331188 1.124067192 0.740126813)], [qw(1.173873006 0.790118011 1.014718833 0.937979878 1.07453725 1.207167373 0.622279064 1.046150047 1.145627707 0.742212886)], [qw(1.128383111 0.870541389 0.987269741 0.98353238 1.115643879 1.040107028 0.774505865 1.010896432 1.164757274 0.775254395)], [qw(1.15297511 0.853883985 0.956393231 1.000027661 1.139915472 1.01355294 0.838843622 1.015553125 1.216219741 0.70447264)], [qw(1.148264236 0.852123859 0.974568293 0.985455546 1.13192373 1.015879393 0.828987111 1.016820786 1.216647853 0.71634006)], [qw(1.12933788 0.831777975 1.005434367 0.991081409 1.126146895 1.07421504 0.69343913 1.054032466 1.14809591 0.728541157)], [qw(1.124157235 0.828112691 1.022348424 0.983822386 1.143028487 1.081830005 0.672594435 1.05685982 1.149537403 0.684432106)], [qw(1.128029586 0.841853305 1.00983936 0.967179139 1.122524003 1.094555807 0.659238308 1.061578854 1.1243601 0.740148171)], [qw(1.093521636 0.855071052 0.929160818 1.203773691 1.178257185 0.881341255 1.078305505 1.051988532 1.169143967 0.555057308)], [qw(1.073737278 0.877396537 0.968017446 1.124155374 1.166244435 0.909044208 0.999147578 1.071098934 1.120156138 0.607444953)], [qw(1.092150184 0.863407008 0.927040387 1.185387013 1.171670826 0.882276859 1.083058605 1.048379554 1.168635365 0.580337997)] ]; my $DATA_VIR = [ [2,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [3,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [42,2,'Human (nasal)',[127/255, 127/255, 255/255,1]], [43,2,'Human (nasal)',[127/255, 127/255, 255/255,1]], [45,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [49,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [52,3,'Human (sputum)',[127/255, 127/255, 255/255,1]], [54,3,'Human (sputum)',[127/255, 127/255, 255/255,1]], [55,4,'Human (sputum, CF)',[127/255, 127/255, 255/255,1]], [57,4,'Human (sputum, CF)',[127/255, 127/255, 255/255,1]], [88,5,'Freshwater (Hot spring)',[127/255, 127/255, 255/255,1]], [89,5,'Freshwater (Hot spring)',[127/255, 127/255, 255/255,1]], [98,6,'Freshwater (Antartic lake)',[127/255, 127/255, 255/255,1]], [99,6,'Freshwater (Antartic lake)',[127/255, 127/255, 255/255,1]], [100,7,'Freshwater (reclaimed)',[127/255, 127/255, 255/255,1]], [102,7,'Freshwater (reclaimed)',[127/255, 127/255, 255/255,1]], [153,8,'Mouse (brain tissue)',[127/255, 127/255, 255/255,1]], [154,8,'Mouse (brain tissue)',[127/255, 127/255, 255/255,1]], [202,9,'Fish (gut)',[127/255, 127/255, 255/255,1]], [206,9,'Fish (gut)',[127/255, 127/255, 255/255,1]], [209,10,'Mosquito',[127/255, 127/255, 255/255,1]], [211,10,'Mosquito',[127/255, 127/255, 255/255,1]], ['U',0,'User input',[255/255, 127/255, 127/255,1]] ]; my $DATA_MIC = [ [17,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [20,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [22,1,'Human (fecal)',[127/255, 127/255, 255/255,1]], [63,2,'Mouse (fecal)',[127/255, 127/255, 255/255,1]], [65,2,'Mouse (fecal)',[127/255, 127/255, 255/255,1]], [68,2,'Mouse (fecal)',[127/255, 127/255, 255/255,1]], [93,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [95,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [109,4,'Marine (open ocean)',[127/255, 127/255, 255/255,1]], [110,4,'Marine (open ocean)',[127/255, 127/255, 255/255,1]], [111,4,'Marine (open ocean)',[127/255, 127/255, 255/255,1]], [120,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [124,5,'Marine (estuary)',[127/255, 127/255, 255/255,1]], [125,5,'Marine (estuary)',[127/255, 127/255, 255/255,1]], [134,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [146,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [148,3,'Marine (coastal)',[127/255, 127/255, 255/255,1]], [201,6,'Fish (gut)',[127/255, 127/255, 255/255,1]], [203,7,'Fish (slime)',[127/255, 127/255, 255/255,1]], [205,6,'Fish (gut)',[127/255, 127/255, 255/255,1]], ['U',0,'User input',[255/255, 127/255, 127/255,1]] ]; my $BASE64_BASES = {A => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAAzVJREFUeNrsnMFxo0AQRWe7fJcyMBnYGawyMIe9a0JQJtbefDPOAB33 JmdgZyBlsIpgl9lCLkwJA/N7uhu0XTXlkstI8Oh+agbG355+/XDC8VaNu8htf1ZjI73DJPx59wCg EN4phDQkNAsWGqCkIeUM7zFrSL7OBDS+VyObMyQrZWsSUlZnACfw5dwgcZ/5BZPfTEHyEwCvColL 2O24q/uuWUDKJ1TGKpCCsB8Sn4Dl1CGlbvxEBD51SCIlR4lL4VYAUnKB08SzSCSbUkFKLWxRgdMM sii5wK1BOlksuRSQVoCwA9wjIPDVVCAhWVTWw1SZc0MK8lxHblvUP7fA569TCJyMZFET0qEa75ay iRtSrDwDlLfG663CPohAQoRdtF4jXrrlFjgZKbU2lN/VeLFSclyQlkAzt6s95BiziVXgXJByFz/7 WH7x+6OFbOKCFCvL0wUffeUqFYFzQELu7/eVFAKJTeCkmEVDIARXvWqXHAoJEXbwzZ4BZJ/AM21I iLCLESV50swmMlxqzZ6pnCqkDBD2a0dvlErguRYkiSw6x16zZyKlDy4FwDbjARE4AYBihf1Se0YS EnRSaSJZpNozxUAKaRv7QNYR/KZSEXgMpI1CFjUhifdMMZBypUzgAB0lcIoAFDv72J6ijY0tuL1P DckrZ5GrQSM90yYlpMxh9/cfq/GHaSBPq4xeVUBCWWQt/kMaEKNWFQyFJPVAlmRsuCF5N7/wnJCW TvaBLKkYLHC60iwadWzEWbtzFXgfpNUMhT06CeiKS23wMVKPsNdXAKlX4HTlWTToWG8SQdoxXK3H zA7E3r0JAr/vmqXogoSu3w87vFeA9AwK3I8pN+Rr/6gAKAQ669m5qoA6hJ0r7mxsoE/Hda4qoA6i CzDttaJI0TMRc6mFKdqDIqS9w2YtLy4LowTC1o4tdzYR83VaaQASu8Dpwh/ERuzta+441H0am8Cp 1TwuJp5FSQROTB32yRgk9Om4TwI/Q8oc9g9XCmcv2LKJmIRtERL6LfexqoAYSo3r9nUKgb+D7+HP kFBhW8wi1p6JHL4KujQMCRX4v1UFARJyu2infBky5KIXPYn+rwADAOL8qKxS08x7AAAAAElFTkSu QmCC', C => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAA7BJREFUeNrsnM1xqzAQxxUNDfBKwCWQCt7g+7vgEkgJ5pRDTnYJpgRz eXeYVBBKCCU8SvAzM6sZxuMPaXclQaydYYKTGPBv/7tagdYvp9NJTO3Px6dwZPl5S2A/hdf3rD9v 1eT1nvuC/r7/vvr7SLizDGAUEzgmNr5nN3mt9ksAWNu6cNuQYoCyhX0bpmANoK4K9tlMWrrw0euH 8/YPPkTsQKkxnIv9nNKSZ79BQb5sy3kNkjnnfMMFzsFiUHNDVZVk9FyDTMguBowvGDS8QTpejDpz tARAZT4gNRr1zZyswYCSrk84Azuahp58MkAqoR9NkjkG0m7BgG5V76yQcgtD/B6mFqvz9nJlW8Pf uacdha6zI0P6B6YLbGH6UGv+b3tRbnCNpgdwDpuSOEr9cU61AXXUBOX9YlJWolOVS4MwyxnUs2L6 cAr2G1MhzAKJKu8K1DMw55UKYFHVlFMhYe//KKuZPH7v+CXxGCyQsNZbBjTNUzURUoyFlFEmhhAK g3BjVDUVWEg5MV90DgvEy3vgppZi66ScGAKurTJMDxXAvXuPPMLGqUYy7T1A6mBLHxSlRg6MMPLT hOTLWnBuNVELKS9GD5I2ttDzCalkSOJaiTsmKKkVP8wks4qE4xHNKyRKhd0HSCHcyCPb4LDC9g4p DqFmL9yGZ4EUkrbhBDeYBSWJoKQAKViAFCAFSLOERKl1kqCkoKSgJFMl9QGSPUijpQHSE6rppypJ tU5Y7Qig3IL1vZ5ydNJ403BcdzSuZBt71Rp4ncxJSbFHSNmN36melxMAK6iQhgWrSWf9wu6KylBL byiQCo+hliIcqlTmFFLmaZSjOKfCQFIrNLDmuqUrIULqsHO3muhVl+UAxSl3F3lIDQlSHhMZ9XAQ w9tKqOlAUs2/lBA4OAgz6jlIkDjUlFsEpTqOqGsXeiokqppUfmqYQy+BY1Lz3sPPJg0O1DPkDXSL 5xV1fjEAanVKHZM7kxtG72ObCjN4L9eAoLUQ36SVqwNFcdQ/GWzTUL6V+7aTn5zhqh0dpl/DUYLE ueZm6lshhHDbEd4Lg8WnmAcBG7H8dZFGqQMDSfWa9QsG1NmGpOS6XiAoVC+vJMb164JCr8TWe9SH kwOAqmcO6I1SEEvGON/MEI5KC5QWL9bH3KOaVjNSVQXXQ15XLi14TrW0+1r03kIKYGtrlRYvdM0h dUPlvMI5WQeTyIFXW/Cqeu5VMIPpheUuTZdfobifjDTTXvxYcz5YXsBxtrD+vwADADoA0kx0ZQr1 AAAAAElFTkSuQmCC', G => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAA6lJREFUeNrsnN2RqjAUgANjA9wS3CefsQQsAUtgS8AStAQsQUuQEuR5 nzYlSAkumTnZy/UKJpyTEANn5syqs0L8cn4hIbjf70zI19eaWZS40aT1Pm80Uvhe1ei59b6Ez8hl tbr+vl5YhpLCa8xx4h54RqCZhCQsI9OwEkYEr2700OgRXqMlNARn3+gN/kbMrrTPXzS6dA2SHFzO 3BBhyd8wrtEhJTAYV+A8Sg7ji8eCJGbpQmHWhkWM7wrJwxqkCODk7L3kpDvmBWJW3sF6+qyfQRY0 YknvDqgNKjUByRdAUgqVYK4DKQJ/9gWQ/E0FJSQl6gNExIVdo9tGgw5dw/8cDJw/fhXIA8UGN8cW ZA9ybPVaQ4vEjHDSapgI/qzBDRXjEBUgAeaj0U8EIAl5Dcepidwux7hbQTRTG3ApTmyRa6LOP+3q M0OFLybIk1fwQ0pmRjhMQEVgTdkQSHsCQBti6+mzVE5gTVqQMmS6l4BqZkckKGymi3UhYQa8tQio 7Xo7gisaSpASZHrdWXCxvrqLI61JqcFNkW52HLmSPmrG0yOA5ezfGw2dxaSI8t9s+GXXjcFMppOp bj21WgWhoHMyX90tSRCAuAOAZEws4XecdS6LPJOFik9qmq0rsqE6UEic1VyCxExBWiJcrRoh5Y8C CeNqJfNUKCFVU4GEaUP4DGm2JDQkb63oEVKEyGz1lCCxGZJaMemKiKL2PpJeuiDNme0NLck7SNFU INUzJLOQ2AzptSxnSLO7kaTyyGdQVJC8drmQsJOPpwJpDt4KkDCXYBPisYmbCgFSuSl3qxHuFk3B krDWlE0FEiZ4p1OBdEZmuHgKkDjSmrIpQMJaU2Yg0zkJCXtPfz8FSDUSVOwTqL4rk9gtCvnI2Y6s 6e6DRLEg6zRSfBLnvNqAJOST4BwXyxZVMOLtZq8gcUazMOtkIUaJrHozUYKo3C2hWm6cgwtQu5/c qV2Y6h1VINUMv4C8nfUuoBnyOALOHSzU6GWaQOOBLntmZue2XDLMe4rYpHWVwcbu8XK1uv4uTNXZ zb1j/z+thkJS1xtj3Tu4W+bxYq22JWEgyZ1APoPaPhbSQ9YCSFC+rbYVE//xLC4OXTAhQR08ASTi 7bqr1AkJDr59YziiUP7zarIplt6cu8zUcTjKu8Gp1idxsCjXg/qB/d1yrzxO6pVuJcyQS6VCBWEh GNpiBYYfoSiLz/0IYM6gg/rO9qbAwOJzJmVrgd0l3pdEGFXGbUP6EWAA2LwDwtC8jpAAAAAASUVO RK5CYII=', T => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAALRJREFUeNrs09ENQDAUQFHEXlhAYgJWMJnEBLqBUWxQFkCC/si5yftq mzYnaR5jzM4KXXu++J9CNc311YYi022QIEGCBAkSJEiCBCll5c16k+DO4Zj+4dnxmPXj92xvkZYE SPWLs2uiN/lukCBBggQJkiBBggQJEiRIggQJEiRIkCBBEiRIkCBBggRJkCBBggQJEiRICCBBggQJ EiRIggQJEiRIkCAJEiRIkCBBggRJ1+0CDAAzsw5U48snWgAAAABJRU5ErkJggg==', N => 'iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAACXBIWXMAAAsTAAALEwEAmpwYAAAK T2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AU kSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXX Pues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgAB eNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAt AGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3 AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dX Lh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+ 5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk 5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd 0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA 4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzA BhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/ph CJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5 h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+ Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhM WE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQ AkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+Io UspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdp r+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZ D5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61Mb U2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY /R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllir SKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79u p+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6Vh lWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1 mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lO k06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7Ry FDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3I veRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+B Z7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/ 0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5p DoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5q PNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIs OpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5 hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQ rAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9 rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1d T1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aX Dm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7 vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3S PVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKa RptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO 32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21 e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfV P1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i /suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8 IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADq YAAAOpgAABdvkl/FRgAAAh1JREFUeNrsmk1xwzAQRr8RgYRBwqBhkDJoGbQMagZ1GbgMVAYNA5dB wsBm4CBwL9Wx0Uwk7593Z3z0SHmRn3fXi3me8d8FoAUw33kdQB/9PXu9xWCeZ4QFN9zBSCwJ6Qig cUj5aAFsHdLt2Fh47ALBGi8AHh2ScYlTQXrQLPFAuJZaiVNC2gCIDikfTxolHhjWjA4pH7s/Pzmk TDQA9g7JUCYeGNdWI/HAvH50SEYkHgTs4V26xIOQfUSHlI8jgGeHlI9OagEsCdIOQtspQdh+REo8 CPzjokNSKPGlIJ0qnKatdUgdgJ/CArhdw+NW+qZ6A888ASmkM4DPCifSvLhbANdCib9ahzRV+JHs mThFCvCtXeJUeVLpaWKVOBWkAcCH1kycMuPuAIwF97PNE1BCqiHxlkPi1LVbX1iysHyK4ihwm8Lc iXwojAPSUOE0dNYhJbdctEics5/UVAC9tQ6pB/BVKPFoHVINiZPME3BDmirUZdE6pPSmKimAF58n kPIhoKlw/946pDPKupiLZuKSPim1FSR+sA6pRgG8sQ4JKO9iYg2QAAGNfw2QBpR3Mc1DSrnT6JCW l7h5SKkAPjmk5QvgVUAaIGAeQDqklImPDkl47qQFUo+yLuYqILFKXBOkCUzTJZogpUz84pAESlwj pDPKZzHNQ0q509Uh5SXeOKR8RBB1MTVDIpO4dkgDCLqY2iGl3Gl0SMwS/x0AsYSfWCRqIfIAAAAA SUVORK5CYII=' }; my $MMCHART_B2 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAAGCAYAAAACEPQxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAAABdJREFUeNpiYGBg+M/w//9/BmwEQIABANxBD/HRDNRSAAAAAElFTkSu QmCC'; my $FREQCHART_L = 'iVBORw0KGgoAAAANSUhEUgAAAC8AAABvCAIAAADzHQ6XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ bWFnZVJlYWR5ccllPAAABWNJREFUeNrkm91V7DoMhTOsaQBKgBKgBCjhUgKUAI/wBiUwJUAJUAKU ACVACed+K/tcYxz5J5nYk3uOHmYFxokVWdrakj17v1rJ6+trdkw3y0x3d3dd172/v5vfPj8/d/8J Iytq488U0+bw8PDq6oqLh4cHhn1+fta1jXQytWGB+ErLhB5cPz4+xp6z11WWr68vPvf39/WJnT4+ PmKD17W10dwoYX57c3Oji9vbW2xTXRvpgYVknoQ2fFZfKSkhC6ETFzE7tdDm+PiY6V9eXrh+enri 8/T0NDq6RkxxwZ/EczneSJNuIVgsbVa62rmsVqsfeHN5eanV3aU4W8n5cTqWNobx9ST0G2AbPZzD c+HcsJk2ht8ACYTiSy8Y7J9eUmG5hQRYbMQUy+SMhDasnUyVyL1NV4rgRCcs1E6btBdDUPiqnTYX FxeA5q8dyZxYXMJ5W2jDmrqcHHMsTO7GxFDD0OauF/cI1i4bR4yRPylTmixTMOHIvPlMafMjM1xf X/tgAOqcnZ2JSsaEMcwkVoVab29vJhlVqOozwUQ7n0sHb8br8lqZmsMzPnZivuEYgWc6MKXJ2mev AeAe9pKwTZrzOkHdo14Yr9ceYvEP24gQDUODmbK2cRY1bYOX8BDZj1kwtpmSQy8+7oXbPnvhTiwc u9n3UKcut6uK80UVXfb1Qm0wTGDzrNP49ojFlJZGz9EKmEFu4w1Dr3rh/pI0aeJNwIt5lCtfhsZb LhYvixev/XC9v78fwpdPM2rLtzbALgqJW+2YpRMLXO+cUayDKrWxLWwsFnZl0aWdbYAEcjiuE7Q2 wLdsJprZb9QDMyXRGKtYT8VytdkFql6H7/eCThR1akVJSp5lkqyt6nAWSyxO2YQFwq+zkF/Cixnj orU0T4k/EFYiBjwCCOY/6dxZwot5DmN4jskwDW38cY6mcH+WVGT5TbZHbLB0k4mqvZtm6X6z02Tp 6gltNptVL6TCfJ5ynUsfjtXCTDhyCS/WyzCGV0cnKhOmcK+dwmJEzovBHRNN+02WFysDuofElt5g okGe4s7semf9Rh7p8nGpNtOYaJYXi5lrjBh7Uc0wYx0e8GIfb0bU4QvixScnJ2ZQtGGiYZ4ys08a bCr2i83dSnyiavNxnN80I4QGL06AaRte/O3FQStJfkOWAUIc06jtxSkm6naOF8FE23BQ3zZL3Z/a Rubixd8xFcNiJ/gybjQkUxTwDrWHA3wydHR0RJ4i0eb3fMWtxmIx7MmdkSAqE+PPz89HYPGwI6ee VAKLy89ICNZLc3jA0AqxONh4jnUY1XfWFGlt1sHSDtsU2/eLWUEVOiN6FGrN8wbq0GJ/uVuiqSPb OIuatsEYSr0BBRvdoc0eJSrxm2EETeTFJYzO2SN77micbbY/KeVe2px4ijbcg7XH7s7Pv3c3rUcx bw4Pz1GoR6GiGpDI7pZV4cWTexRVbDO5R1Gllz6tR1G3XzyhR1GrgpnWo6h74mWz2ciHUAVQb0aN F8yLcVgdxtstL86wrWl5akj8Rp/3U0CN1SZ7dli4qmSpMWa2Cb2YzMBiDelIYg+GBaLSUDCy1gcH B8MymTF+qOIfZtmQr3yzezCFvNhkZyleLJQbuwdTyItdoGB+LOebKorFk6lWmhf7NNc8gWIzinpn h3EdmAmq+AEYPf/rVwVjgzzLi0VLsp2X3xHu++kE1MnyYh9s8jXDltrMy4vn6ZjMtZG+1y1JlqXN KrBzAOSNO/vrYO7GRymi/eI/pwv5Z3rx36pNEXduUCst63cwJb+7a6RNYU95zqyZ3Wz7n/3uTgDY tXHhEu7cYqX++t/dbY83vyOr2WnHEu78rwADABaBbeIZChwYAAAAAElFTkSuQmCC'; my $CSS_STYLE = ' html, body, div, span, p, img { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; } html, body { font-family: Arial, Verdana; color: #40454b; font-size: 12px; text-align: center; } img { padding: 0px; margin: 0px; border: none; } .info-panel { margin-top: 10px; margin-bottom: 10px; width: 740px; text-align: left; } .info-header { padding-top: 20px; padding-top: 10px; } .info-header-title { color: #126499; text-decoration: none; font-family: sans-serif; font-weight: bold; font-size: 16px; vertical-align: baseline; margin-right: 20px; margin-bottom: 25px; margin-top: 15px; } .info-content { padding: 2px; font-family: "lucida grande",sans-serif,arial; margin-top: 15px; margin-bottom: 15px; } .info-table-type { min-width: 70px; padding: 4px; vertical-align: top; } .info-table-value { font-weight: bold; padding-top: 4px; padding-left: 10px; padding-right: 10px; vertical-align: top; } hr { background-color: #E0E0E0; border: medium none; color: #E0E0E0; height: 1px; outline: medium none; } .sequencetext { font-family: courier, "courier new"; font-weight: normal; } '; my $VERSION = '0.6'; my $WHAT = 'graphs'; my $man = 0; my $help = 0; my %params = ('help' => \$help, 'h' => \$help, 'man' => \$man); GetOptions( \%params, 'help|h', 'man', 'verbose', 'version' => sub { print "PRINSEQ-$WHAT $VERSION\n"; exit; }, 'i=s', 'o=s', 'png_all', 'html_all', 'log:s', 'web:s' ) or pod2usage(2); pod2usage(1) if $help; pod2usage(-exitstatus => 0, -verbose => 2) if $man; =head1 NAME PRINSEQ - PReprocessing and INformation of SEQuence data =head1 VERSION PRINSEQ-graphs 0.6 =head1 SYNOPSIS perl prinseq-graphs.pl [-h] [-help] [-version] [-man] [-verbose] [-i input_graph_data_file] [-png_all] [-html_all] [-log file] =head1 DESCRIPTION PRINSEQ will help you to preprocess your genomic or metagenomic sequence data in FASTA (and QUAL) or FASTQ format. The graphs version allows users of the lite version to generate graphs similar to the web version. =head1 OPTIONS =over 8 =item B<-help> | B<-h> Print the help message; ignore other arguments. =item B<-man> Print the full documentation; ignore other arguments. =item B<-version> Print program version; ignore other arguments. =item B<-verbose> Prints status and info messages during processing. =item B<***** INPUT OPTIONS *****> =item B<-i> Input file containing the graph data generated by the lite version. =item B<***** OUTPUT OPTIONS *****> =item B<-o> By default, the output files are created in the same directory as the input file with an additional "_prinseq_graphs_XXXX" in their name (where XXXX is replaced by random characters to prevent overwriting previous files). To change the output filename and location, specify the filename using this option. The file extension will be added automatically. =item B<-png_all> Use this option to generate PNG files with the graphs. =item B<-html_all> Use this option to generate a HTML file with the graphs and tables. =item B<-log> Log file to keep track of parameters, errors, etc. The log file name is optional. If no file name is given, the log file name will be "inputname.log". If the log file already exists, new content will be added to the file. =back =head1 AUTHOR Robert SCHMIEDER, C<< >> =head1 BUGS If you find a bug please email me at C<< >> or use http://sourceforge.net/tracker/?group_id=315449 so that I can make PRINSEQ better. =head1 COPYRIGHT Copyright (C) 2011-2012 Robert SCHMIEDER =head1 LICENSE 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 . =cut # ################################################################################ ## DATA AND PARAMETER CHECKING ################################################################################ # my ($file1,$command,@dataread); #Check if input file exists and check if file format is correct if(exists $params{i}) { $command .= ' -i '.$params{i}; $file1 = $params{i}; if($params{i} eq 'stdin') { my $format = &checkInputFormat(); unless($format eq 'gd') { &printError('input data for -i is in '.uc($format).' format not in graph data format'); } } elsif(-e $params{i}) { #check for file format my $format = &checkFileFormat($file1); unless($format eq 'gd') { &printError('input file for -i is in '.uc($format).' format not in graph data format'); } } else { &printError("could not find input file \"".$params{i}."\""); } } else { &printError("you did not specify an input file containing the graph data"); } #check output file name prefix if(exists $params{o}) { $command .= ' -o '.$params{o}; } #check for output format unless(exists $params{png_all} || exists $params{html_all}) { &printError("No output format specified. Use -png_all and/or -html_all to generate graphs."); } if(exists $params{png_all}) { $command .= ' -png_all'; } if(exists $params{html_all}) { $command .= ' -html_all'; } if(exists $params{web}) { $command .= ' -web'.($params{web} ? ' '.$params{web} : ''); } #add remaining to log command if(exists $params{log}) { $command .= ' -log'.($params{log} ? ' '.$params{log} : ''); unless($params{log}) { $params{log} = join("__",$file1||'nonamegiven').'.log'; } $params{log} = cwd().'/'.$params{log} unless($params{log} =~ /^\//); &printLog("Executing PRINSEQ with command: \"perl prinseq-".$WHAT.".pl".$command."\""); } # ################################################################################ ## DATA PROCESSING ################################################################################ # my $filename = $file1; while($filename =~ /[\w\d]+\.[\w\d]+$/) { $filename =~ s/\.[\w\d]+$//; last if($filename =~ /\/[^\.]+$/); } if(exists $params{png_all}) { my $graphs = &generateGraphs($params{i},$params{o}); if(exists $params{web} && $params{web} ne 'nozip') { #png files if(scalar(@$graphs)) { system("zip -j -r ".dirname($params{o})."/png_graphs.zip ".dirname($params{o}).' -i \*.png') == 0 or &printError("Cannot generate graphs ZIP file"); } } } if(exists $params{html_all}) { &generateHtml($params{i},$params{o}); } &printWeb("STATUS: done"); ## ################################################################################# ### MISC FUNCTIONS ################################################################################# ## sub printError { my $msg = shift; print STDERR "\nERROR: ".$msg.".\n\nTry \'perl prinseq-".$WHAT.".pl -h\' for more information.\nExit program.\n"; &printLog("ERROR: ".$msg.". Exit program.\n"); exit(0); } sub printWarning { my $msg = shift; print STDERR "WARNING: ".$msg.".\n"; &printLog("WARNING: ".$msg.".\n"); } sub printWeb { my $msg = shift; if(exists $params{web}) { print STDERR "\n".&getTime()."$msg\n"; } } sub getTime { return sprintf("[%02d/%02d/%04d %02d:%02d:%02d] ",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); } sub printLog { my $msg = shift; if(exists $params{log}) { my $time = sprintf("%02d/%02d/%04d %02d:%02d:%02d",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); open(FH, ">>", $params{log}) or die "ERROR: Can't open file ".$params{log}.": $! \n"; flock(FH, LOCK_EX) or die "ERROR: Cannot lock file ".$params{log}.": $! \n"; print FH "[prinseq-".$WHAT."-$VERSION] [$time] $msg\n"; flock(FH, LOCK_UN) or die "ERROR: cannot unlock ".$params{log}.": $! \n"; close(FH); } } sub addCommas { my $num = shift; return unless(defined $num); return $num if($num < 1000); $num = scalar reverse $num; $num =~ s/(\d{3})/$1\,/g; $num =~ s/\,$//; $num = scalar reverse $num; return $num; } sub checkFileFormat { my $file = shift; my ($format,$count,$id,$fasta,$fastq,$qual,$gd,$aa); $count = 3; $fasta = $fastq = $qual = $gd = $aa = 0; $format = 'unknown'; open(FILE,"perl -p -e 's/\r/\n/g;s/\n\n/\n/g' < $file |") or die "ERROR: Could not open file $file: $! \n"; while () { # chomp(); # next unless(length($_)); if($count-- == 0) { last; } elsif(!$fasta && /^\>\S+\s*/) { $fasta = 1; $qual = 1; } elsif($fasta == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/))) { $fasta = 2; } elsif($qual == 1 && /^\s*\d+/) { $qual = 2; } elsif(!$fastq && /^\@(\S+)\s*/) { $id = $1; $fastq = 1; } elsif($fastq == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/))) { $fastq = 2; } elsif($fastq == 2 && /^\+(\S*)\s*/) { $fastq = 3 if($id eq $1 || /^\+\s*$/); } elsif(!$gd && /^\{\"numseqs\"\:/) { $gd = 1; } } close(FILE); if($fasta == 2) { $format = 'fasta'; } elsif($qual == 2) { $format = 'qual'; } elsif($fastq == 3) { $format = 'fastq'; } elsif($gd == 1) { $format = 'gd'; } return $format; } sub checkInputFormat { my ($format,$count,$id,$fasta,$fastq,$qual,$gd,$aa); $count = 3; $fasta = $fastq = $qual = $gd = $aa = 0; $format = 'unknown'; while () { push(@dataread,$_); # chomp(); # next unless(length($_)); if($count-- == 0) { last; } elsif(!$fasta && /^\>\S+\s*/) { $fasta = 1; $qual = 1; } elsif($fasta == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/))) { $fasta = 2; } elsif($qual == 1 && /^\s*\d+/) { $qual = 2; } elsif(!$fastq && /^\@(\S+)\s*/) { $id = $1; $fastq = 1; } elsif($fastq == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/))) { $fastq = 2; } elsif($fastq == 2 && /^\+(\S*)\s*/) { $fastq = 3 if($id eq $1 || /^\+\s*$/); } elsif(!$gd && /^\{\"numseqs\"\:/) { $gd = 1; } } if($fasta == 2) { $format = 'fasta'; } elsif($qual == 2) { $format = 'qual'; } elsif($fastq == 3) { $format = 'fastq'; } elsif($gd == 1) { $format = 'gd'; } return $format; } sub readGdFile { my $file = shift; my $data; open(DATA,"<$file") or &printError("Could not open file $file: $!"); while() { next if(/^\#/); chomp(); if(length($_)) { $data = from_json($_); } } close(DATA); return $data; } sub getFileName { my $ext = shift; my ($file,$fh); if(exists $params{o}) { $file = $params{o}.$ext; open(OUT,">$file") or &printError('cannot open output file'); close(OUT); } else { $fh = File::Temp->new( TEMPLATE => $filename.'_prinseq_graphs_XXXX', SUFFIX => $ext, UNLINK => 0); $file = $fh->filename; $fh->close(); } return $file; } sub generateGraphs { my ($in,$out) = @_; my ($file,$data,$surface,@graphs); $data = &readGdFile($in); #length plot if(exists $data->{counts}->{length}) { $file = &getFileName('_ld.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{length},1),$data->{stats}->{length},'Length Distribution','Read Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{counts2} && exists $data->{counts2}->{length}) { $file = &getFileName('_ld-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{length},1),$data->{stats2}->{length},'Length Distribution','Read Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } #tail plot if(exists $data->{tail}) { $file = &getFileName('_td5.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{tail5},1),undef,'Poly-A/T Tail Distribution (> 4bp)','5\' Tail Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); $file = &getFileName('_td3.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{tail3},1),undef,'Poly-A/T Tail Distribution (> 4bp)','3\' Tail Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{tail2}) { $file = &getFileName('_td5-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{tail5},1),undef,'Poly-A/T Tail Distribution (> 4bp)','5\' Tail Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); $file = &getFileName('_td3-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{tail3},1),undef,'Poly-A/T Tail Distribution (> 4bp)','3\' Tail Length in bp','# Sequences',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } #Ns plot if(exists $data->{counts}->{ns}) { $file = &getFileName('_ns.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{ns},1),undef,'Percentage of N\'s (> 0%)','Percentage of N\'s per Read (1-100%)','# Sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{counts2} && exists $data->{counts2}->{ns}) { $file = &getFileName('_ns-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{ns},1),undef,'Percentage of N\'s (> 0%)','Percentage of N\'s per Read (1-100%)','# Sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } #GC content plot if(exists $data->{counts}->{gc}) { $file = &getFileName('_gc.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{gc},0),$data->{stats}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences',$file,1); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{counts2} && exists $data->{counts2}->{gc}) { $file = &getFileName('_gc-2.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{gc},0),$data->{stats2}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences',$file,1); $surface->write_to_png($file); push(@graphs,$file); } #Sequence complexity plot - dust if(exists $data->{compldust}) { $file = &getFileName('_cd.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{compldust},0),undef,'Sequence complexity distribution','Mean sequence complexity (DUST scores)','Number of sequences',$file,1); $surface->write_to_png($file); push(@graphs,$file); } #Sequence complexity plot - entropy if(exists $data->{complentropy}) { $file = &getFileName('_ce.png'); $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{complentropy},0),undef,'Sequence complexity distribution','Mean sequence complexity (Entropy values)','Number of sequences',$file,1); $surface->write_to_png($file); push(@graphs,$file); } #Dinucleotide odd ratio PCA plot - microbial/viral #Odds ratio plot if(exists $data->{dinucodds}) { my @new = map {$data->{dinucodds}->{$_}} sort keys %{$data->{dinucodds}}; $file = &getFileName('_pm.png'); $surface = &createPCAPlot(&convertToPCAValues(\@new,'m'),'PCA','1st Principal Component Score','2nd Principal Component Score',$file); $surface->write_to_png($file); push(@graphs,$file); $file = &getFileName('_pv.png'); $surface = &createPCAPlot(&convertToPCAValues(\@new,'v'),'PCA','1st Principal Component Score','2nd Principal Component Score',$file); $surface->write_to_png($file); push(@graphs,$file); $file = &getFileName('_or.png'); $surface = &createOddsRatioPlot($data->{dinucodds},'Odds ratios','Dinucleotide','Odds ratio',$file); $surface->write_to_png($file); push(@graphs,$file); } #Qual plot if(exists $data->{quals}) { $file = &getFileName('_qd.png'); $surface = &createBoxPlot(&convertToBoxValues($data->{quals},4),'Base Quality Distribution','Read position in %','Quality score',$file); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{quals2}) { $file = &getFileName('_qd-2.png'); $surface = &createBoxPlot(&convertToBoxValues($data->{quals2},4),'Base Quality Distribution','Read position in %','Quality score',$file); $surface->write_to_png($file); push(@graphs,$file); } #Qualbin plot if(exists $data->{qualsbin}) { $file = &getFileName('_qd2.png'); $surface = &createBoxPlot(&convertToBoxValues($data->{qualsbin},4),'Base Quality Distribution','Read position in bp','Quality score',$file,0,'bp',$data->{binval}); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{qualsbin2}) { $file = &getFileName('_qd2-2.png'); $surface = &createBoxPlot(&convertToBoxValues($data->{qualsbin2},4),'Base Quality Distribution','Read position in bp','Quality score',$file,0,'bp',$data->{binval}); $surface->write_to_png($file); push(@graphs,$file); } #Qualmean plot if(exists $data->{qualsmean}) { $file = &getFileName('_qd3.png'); $surface = &createBarPlot(&convertToBarValues($data->{qualsmean},5,1),'Sequence Quality Distribution','Mean of quality scores per sequence','Number of sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{qualsmean2}) { $file = &getFileName('_qd3-2.png'); $surface = &createBarPlot(&convertToBarValues($data->{qualsmean2},5,1),'Sequence Quality Distribution','Mean of quality scores per sequence','Number of sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } #Sequence duplicate plots if(exists $data->{dubscounts}) { $file = &getFileName('_df.png'); $surface = &createStackBarPlot(&convertOdToStackBinMatrix($data->{dubscounts},5,1,100),'Sequence duplication level','Number of duplicates','Number of sequences',$file,0); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{dubslength}) { $file = &getFileName('_dl.png'); $surface = &createStackBarPlot(&convertOdToStackBinMatrix($data->{dubslength},5,1),'Sequence duplication level','Read Length in bp','Number of duplicates',$file,0,' bp'); $surface->write_to_png($file); push(@graphs,$file); } if(exists $data->{dubscounts}) { my %dubsmax; my $count = 1; foreach my $n (sort {$b <=> $a} keys %{$data->{dubscounts}}) { foreach my $s (keys %{$data->{dubscounts}->{$n}}) { foreach my $i (1..$data->{dubscounts}->{$n}->{$s}) { $dubsmax{$count++}->{$s} = $n; last unless($count <= 100); } last unless($count <= 100); } last unless($count <= 100); } $file = &getFileName('_dm.png'); $surface = &createStackBarPlot(&convertOdToStackBinMatrix(\%dubsmax,5,1,100),'Sequence duplication level','Sequence','Number of duplicates',$file,0); $surface->write_to_png($file); push(@graphs,$file); } return \@graphs; } sub convertOdToBinMatrix { my ($data,$min,$max,$nonice) = @_; my ($num,$ymax,$xmax,$xmin,$step,%vals,$tmp,@matrix,$bin,$tmpbin); #make nice xmax value if(defined $max) { $xmax = $max; } else { $xmax = (sort {$b <=> $a} keys %$data)[0]; } $bin = &getBinVal($xmax); $xmax = $bin*100; $xmin = (defined $min ? $min : 0); #get data to bin and find y axis max value $ymax = 0; $tmp = 0; $tmpbin = $bin; foreach my $i ($xmin..$xmax) { if(exists $data->{$i}) { $tmp += $data->{$i}; } if(--$tmpbin <= 0) { $tmpbin = $bin; $ymax = &max($ymax,$tmp); push(@matrix,$tmp); $tmp = 0; } } #make nice ymax value unless($nonice) { $ymax = sprintf("%d",($ymax/4)+1)*4 if($ymax % 4); # $step = ($ymax <= 10 ? 10 : ($ymax < 40 ? 40 : ($ymax < 100 ? 100 : ($ymax < 1000 ? 100 : 100)))); # $ymax = sprintf("%d",($ymax/$step)+1)*$step if($ymax % $step); } return (\@matrix,$xmax,$ymax); } sub getBinVal { my $val = shift; my $step; if(!$val || $val <= 100) { return 1; } elsif($val < 10000) { return int($val/100)+($val % 100 ? 1 : 0); } elsif($val < 100000) { return 1000; } else { $step = 1000000; my $xmax = ($val % $step ? sprintf("%d",($val/$step+1))*$step : $val); return ($xmax/100); } } sub max { my ($a,$b) = @_; return ($a < $b ? $b : $a); } sub min { my ($a,$b) = @_; return ($a > $b ? $b : $a); } sub createAnnotBarPlot { my ($matrix,$xmax,$ymax,$annot,$title,$xlab,$ylab,$file,$zero,$add) = @_; my $bin = 1; if($xmax > 100) { $bin = $xmax / 100; $xmax = 100; } my @barcol = (127/255, 127/255, 255/255, 1); #b2b2ff my @meancol = (255/255, 127/255, 127/255, 1); #ffb2b2 my @stdcol = (178/255, 178/255, 255/255, 0.8); #7f7fff my @std1col = (0, 0, 0, 0.04); #ff7f7f my @std2col = (0, 0, 0, 0.03); #ff7f7f my @linecol = (0, 0, 0, 0.4); my @helplinecol = (1, 1, 1, 0.9); my @background = (0.95, 0.95, 0.95, 1); my @tickcol = (0, 0, 0, 0.8); my @labelcol = (0, 0, 0, 1); #create new image my $size = 6; my $offset = 20; my $left = 40; my $bottom = 15; my $top = 20; my $height = 200; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+($xmax+$zero)*$size,$bottom+$top+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+2*200+20); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); $cr->save; #set up work space $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, ($xmax+$zero)*$size-1, $height); $cr->set_source_rgba(@background); $cr->fill; #draw ticks #x-axis $cr->set_source_rgba(@tickcol); foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%5) == 0 && $i > 1 && $i < $xmax) { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+3); } else { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+1); } } $cr->stroke; #y-axis $cr->move_to($left+$offset, $top+$offset); $cr->line_to($left+$offset-3, $top+$offset); $cr->move_to($left+$offset, $top+$offset+$height-1); $cr->line_to($left+$offset-3, $top+$offset+$height-1); $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol); foreach my $j (1..3) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(@tickcol); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%10) == 0 && $i > 1 && $i < $xmax) { $extents = $cr->text_extents($i*$bin); $cr->move_to($left+$offset+int($size/2+1)+$size*$i-($zero ? 0 : $size)-$extents->{width}/2-1-($i == 1 ? 1 : 0), $top+$offset+$height+$fontheight+2); $cr->show_text($i*$bin); } } #y-axis $extents = $cr->text_extents(&addCommas($ymax)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2); $cr->show_text(&addCommas($ymax)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2+$height); $cr->show_text(0); $cr->save; #labels $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #axis labels $cr->set_source_rgba(@labelcol); $extents = $cr->text_extents($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->move_to($left+$offset+($xmax+$zero)*$size/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab.($bin>1 ? ' (per bin)' : '')); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2),$offset+10); $cr->show_text($ylab.($bin>1 ? ' (per bin)' : '')); $cr->restore; #draw annotations if($annot) { $cr->set_antialias('none'); my ($std1l,$std2l,$std1r,$std2r); #std boxes $std1l = int($annot->{mean})-int($annot->{std}); $std2l = int($annot->{mean})-2*int($annot->{std}); $std1r = int($annot->{mean})+int($annot->{std}); $std2r = int($annot->{mean})+2*int($annot->{std}); unless($std1l == $std1r) { if($std1l < 0) { $std1l = 0; } else { $std1l = int($std1l/$bin); } if($std2l < 0) { $std2l = 0; } else { $std2l = int($std2l/$bin); } if($std1r/$bin > 100) { $std1r = 100; } else { $std1r = int($std1r/$bin); } if($std2r/$bin > 100) { $std2r = 100; } else { $std2r = int($std2r/$bin); } $cr->rectangle($left+$offset+$std2l*$size+2, $top+$offset, ($std2r-$std2l)*$size, $height); $cr->set_source_rgba(@std2col); $cr->fill; $cr->rectangle($left+$offset+$std1l*$size+2, $top+$offset, ($std1r-$std1l)*$size, $height); $cr->set_source_rgba(@std1col); $cr->fill; #mean line $cr->set_source_rgba(@meancol); $cr->move_to($left+$offset+int(int($annot->{mean})/$bin)*$size+2, $top+$offset-5); $cr->line_to($left+$offset+int(int($annot->{mean})/$bin)*$size+2, $top+$offset+$height); $cr->stroke; #std lines $cr->set_source_rgba(@stdcol); if($std1l > 0) { $cr->move_to($left+$offset+$std1l*$size+2, $top+$offset-5); $cr->line_to($left+$offset+$std1l*$size+2, $top+$offset+$height); } if($std2l > 0) { $cr->move_to($left+$offset+$std2l*$size+2, $top+$offset-5); $cr->line_to($left+$offset+$std2l*$size+2, $top+$offset+$height); } if($std1r < 100) { $cr->move_to($left+$offset+$std1r*$size+2, $top+$offset-5); $cr->line_to($left+$offset+$std1r*$size+2, $top+$offset+$height); } if($std2r < 100) { $cr->move_to($left+$offset+$std2r*$size+2, $top+$offset-5); $cr->line_to($left+$offset+$std2r*$size+2, $top+$offset+$height); } $cr->stroke; #labels $cr->set_antialias('default'); $cr->set_source_rgba(@tickcol); $extents = $cr->text_extents('M'); $cr->move_to($left+$offset+int(int($annot->{mean})/$bin)*$size+2-$extents->{width}/2, $top+$offset-10); $cr->show_text('M'); if($std1l > 0) { $extents = $cr->text_extents('1SD'); $cr->move_to($left+$offset+$std1l*$size-$extents->{width}/2+2, $top+$offset-10); $cr->show_text('1SD'); } if($std2l > 0) { $extents = $cr->text_extents('2SD'); $cr->move_to($left+$offset+$std2l*$size-$extents->{width}/2+3, $top+$offset-10); $cr->show_text('2SD'); } if($std1r < 100) { $extents = $cr->text_extents('1SD'); $cr->move_to($left+$offset+$std1r*$size-$extents->{width}/2+2, $top+$offset-10); $cr->show_text('1SD'); } if($std2r < 100) { $extents = $cr->text_extents('2SD'); $cr->move_to($left+$offset+$std2r*$size-$extents->{width}/2+3, $top+$offset-10); $cr->show_text('2SD'); } } } #draw boxes $cr->set_antialias('none'); $cr->set_source_rgba(@barcol); foreach my $pos (0..$xmax-($zero ? 0 : 1)) { next unless($matrix->[$pos]); my $tmp = $matrix->[$pos] / $ymax; #unique if($tmp) { $cr->rectangle($left+$offset+$pos*$size, $top+$offset+$height, $size-1, -$tmp*$height); $cr->fill; } } #write image $cr->show_page; return $surface; } sub convertToPCAValues { my ($new,$type) = @_; my @data = ($type eq 'v' ? @$DINUCODDS_VIR : @$DINUCODDS_MIC); push(@data,$new); my $pca = Statistics::PCA->new; #suppress output from PCA module my $output = ''; open(TOOUTPUT, '>', \$output) or &printError("Can't open TOOUTPUT: $!"); select TOOUTPUT; $pca->load_data({format => 'table', data => \@data}); $pca->pca(); my @variances = $pca->results('proportion'); my @list = $pca->results('transformed'); #end suppress output from PCA module select STDOUT; close(TOOUTPUT); my ($xmin,$xmax,$ymin,$ymax); $xmax = $ymax = -100; $xmin = $ymin = 100; #get min/max values for PC1 foreach my $v (@{$list[0]}) { $xmax = &max($xmax,$v); $xmin = &min($xmin,$v); } #get min/max values for PC2 foreach my $v (@{$list[1]}) { $ymax = &max($ymax,$v); $ymin = &min($ymin,$v); } return ([$list[0],$list[1]],sprintf("%d",$variances[0]*100),sprintf("%d",$variances[1]*100),$xmin,$xmax,$ymin,$ymax,$type); } sub createPCAPlot { my ($data,$var1,$var2,$xmin,$xmax,$ymin,$ymax,$type,$title,$xlab,$ylab,$file) = @_; my @linecol = (0, 0, 0, 0.4); my @helplinecol1 = (1,1,1, 0.9); my @helplinecol2 = (1,1,1, 0.5); #create new image my $size = 5; my $offset = 20; my $left = 25; my $bottom = 15; my $top = ($type eq 'v' ? 35 : 20); my $height = 500; my $space = 10; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+$height+2*$space,$top+$bottom+$offset*2+$height+2*$space); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+$height+2*$space,$top+$bottom+$offset*2+$height+2*$space); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face('sans-serif', 'normal', 'normal'); $cr->save; #set up work space my ($dx, $dy); $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, $height+2*$space, $height+2*$space); $cr->set_source_rgba(0.95, 0.95, 0.95, 1); $cr->fill; #get infos my $num = scalar(@{$data->[0]})-1; my $xrange = ($xmax-$xmin); my $yrange = ($ymax-$ymin); my $data_info = ($type eq 'v' ? $DATA_VIR : $DATA_MIC); #draw ticks #x-axis $cr->set_source_rgba(0, 0, 0, 0.8); $cr->move_to($left+$offset+$space, $top+$offset+$height+2*$space); $cr->line_to($left+$offset+$space, $top+$offset+$height+2*$space+3); $cr->move_to($left+$offset+$space+$height, $top+$offset+$height+2*$space); $cr->line_to($left+$offset+$space+$height, $top+$offset+$height+2*$space+3); $cr->move_to($left+$offset+$space+int(abs($xmin)/$xrange*$height), $top+$offset+$height+2*$space); $cr->line_to($left+$offset+$space+int(abs($xmin)/$xrange*$height), $top+$offset+$height+2*$space+3); $cr->stroke; #y-axis $cr->move_to($left+$offset, $top+$offset+$space); $cr->line_to($left+$offset-3, $top+$offset+$space); $cr->move_to($left+$offset, $top+$offset+$height+$space); $cr->line_to($left+$offset-3, $top+$offset+$height+$space); $cr->move_to($left+$offset, $top+$offset+$space+int(abs($ymax)/$yrange*$height)); $cr->line_to($left+$offset-3, $top+$offset+$space+int(abs($ymax)/$yrange*$height)); $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol1); $cr->move_to($left+$offset+$space+int(abs($xmin)/$xrange*$height), $top+$offset); $cr->line_to($left+$offset+$space+int(abs($xmin)/$xrange*$height), $top+$offset+$height+2*$space); $cr->stroke; $cr->move_to($left+$offset, $top+$offset+$space+int(abs($ymax)/$yrange*$height)); $cr->line_to($left+$offset+2*$space+$height, $top+$offset+$space+int(abs($ymax)/$yrange*$height)); $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(0, 0, 0, 0.8); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis $extents = $cr->text_extents(sprintf("%.2f",$xmin)); $cr->move_to($left+$offset+$space-$extents->{width}/2-1, $top+$offset+$height+2*$space+$fontheight+2); $cr->show_text(sprintf("%.2f",$xmin)); $extents = $cr->text_extents(sprintf("%.2f",$xmax)); $cr->move_to($left+$offset+$space+$height-$extents->{width}/2-1, $top+$offset+$height+2*$space+$fontheight+2); $cr->show_text(sprintf("%.2f",$xmax)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset+$space+int(abs($xmin)/$xrange*$height)-$extents->{width}/2, $top+$offset+$height+2*$space+$fontheight+2); $cr->show_text(0); #y-axis $extents = $cr->text_extents(sprintf("%.2f",$ymax)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$space+$fontheight/2-2); $cr->show_text(sprintf("%.2f",$ymax)); $extents = $cr->text_extents(sprintf("%.2f",$ymin)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$height+$space+$fontheight/2-2); $cr->show_text(sprintf("%.2f",$ymin)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$space+int(abs($ymax)/$yrange*$height)+$fontheight/2-2); $cr->show_text(0); $cr->save; #labels $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #add type $cr->set_source_rgba(0, 0, 0, 0.5); $extents = $cr->text_extents(uc($type)); $cr->arc($offset/2+$extents->{width}/2, $offset-5, 10, 0, 2*$PI); $cr->fill; $cr->set_source_rgba(1, 1, 1, 1); $cr->move_to($offset/2-($type eq 'm' ? 1 : 0), $offset); $cr->show_text(uc($type)); #axis labels $cr->set_source_rgba(0, 0, 0, 1); $extents = $cr->text_extents($xlab.' ('.$var1.'%)'); $cr->move_to($left+$offset+$height/2-$extents->{width}/2+$space, $top+$offset+$height+$fontheight+15+2*$space); $cr->show_text($xlab.' ('.$var1.'%)'); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab.' ('.$var2.'%)'); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2)+$space,$offset); $cr->show_text($ylab.' ('.$var2.'%)'); $cr->restore; #draw dots $cr->set_antialias('default'); $cr->set_font_size (10); foreach my $i (0..$num) { $cr->set_source_rgba(@{$data_info->[$i]->[3]}); $cr->arc(($left+$offset+$space+int(($data->[0]->[$i]+abs($xmin))/$xrange*$height)), ($space+$top+$offset+int(($data->[1]->[$i]+abs($ymin))/$yrange*$height)), $size, 0, 2*$PI); $cr->fill; } $cr->set_source_rgba(0, 0, 0, 1); foreach my $i (0..$num) { $extents = $cr->text_extents($data_info->[$i]->[1]); $cr->move_to(($left+$offset+$space+int(($data->[0]->[$i]+abs($xmin))/$xrange*$height))+$size+1, ($space+$top+$offset+int(($data->[1]->[$i]+abs($ymin))/$yrange*$height))+$size*2); $cr->show_text($data_info->[$i]->[1]); } #draw legend my %labels; foreach my $i (0..$num) { $labels{$data_info->[$i]->[1]} = $data_info->[$i]->[2]; } $cr->set_font_size(10); $fontheight = $font_extents->{height}; $cr->set_source_rgba(0, 0, 0, 1); my $x = $left+$offset+$space; my $y = int($offset/2); foreach my $n (sort {$a <=> $b} keys %labels) { if($x+$cr->text_extents($n.' - '.$labels{$n})->{width}+15 >= $left+$offset+$space+$height) { $x = $left+$offset+$space; $y += $fontheight; } $cr->move_to($x,$y); $cr->show_text($n.' - '.$labels{$n}); $x += $cr->text_extents($n.' - '.$labels{$n})->{width}+15; } #write image $cr->show_page; return $surface; } sub createOddsRatioPlot { my ($data,$title,$xlab,$ylab,$file) = @_; my @yvalues = (0.5,0.78,1.00,1.23,1.5); my @linecol = (0, 0, 0, 0.4); my @helplinecol1 = (1,1,1, 0.9); my @helplinecol2 = (1,1,1, 0.5); #create new image my $size = 40; my $offset = 20; my $left = 35; my $right = 90; my $bottom = 20; my $top = 0; my $height = 100; my $width = $size*10; my $space = 20; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+$width+$right,$top+$bottom+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+$width+$right,$top+$bottom+$offset*2+$height); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); $cr->save; #set up work space my ($dx, $dy); $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, $width, $height); $cr->set_source_rgba(0.95, 0.95, 0.95, 1); $cr->fill; #right side marks $cr->set_source_rgba(255/255, 127/255, 127/255, 0.6); $cr->rectangle($left+$offset+$width+8, $top+$offset, 3, 0.77/2*$height); $cr->fill; $cr->rectangle($left+$offset+$width+8, $top+$offset+$height-0.78/2*$height, 3, 0.78/2*$height); $cr->fill; #get infos my $num = scalar(keys %$data)-1; #draw ticks #x-axis $cr->set_source_rgba(0, 0, 0, 0.8); foreach my $i (0..$num) { $cr->move_to($left+$offset+$size/2+$i*$size, $top+$offset+$height); $cr->line_to($left+$offset+$size/2+$i*$size, $top+$offset+$height+3); } $cr->stroke; #y-axis foreach my $i (@yvalues) { $cr->move_to($left+$offset, $top+$offset+$height-$i/2*$height); $cr->line_to($left+$offset-3, $top+$offset+$height-$i/2*$height); } $cr->stroke; #helplines #x-axis $cr->set_source_rgba(@helplinecol1); foreach my $i (0..$num) { $cr->move_to($left+$offset+$size/2+$i*$size, $top+$offset); $cr->line_to($left+$offset+$size/2+$i*$size, $top+$offset+$height); } $cr->stroke; #yaxis foreach my $i (@yvalues) { $cr->set_source_rgba(0, 0, 0, ($i == 0.5 || $i == 1.00 || $i == 1.50 ? 0.1 : 0.3)); $cr->move_to($left+$offset, $top+$offset+$height-$i/2*$height); $cr->line_to($left+$offset+$width, $top+$offset+$height-$i/2*$height); $cr->stroke; } $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(0, 0, 0, 0.8); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis my $xcur = 0; foreach my $dn (map {join("/",(m/../g ))} sort keys %$data) { $extents = $cr->text_extents($dn); $cr->move_to($left+$offset+$size/2-$extents->{width}/2-1+$size*$xcur++, $top+$offset+$height+$fontheight+2); $cr->show_text($dn); } #y-axis foreach my $i (@yvalues) { $cr->set_source_rgba(0, 0, 0, ($i == 0.5 || $i == 1.00 || $i == 1.50 ? 0.5 : 0.8)); $extents = $cr->text_extents(sprintf("%.2f",$i)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$height-$i/2*$height+$fontheight/2-2); $cr->show_text(sprintf("%.2f",$i)); } #label on right side $cr->set_source_rgba(0, 0, 0, 1); $extents = $cr->text_extents('Over-represented'); $cr->move_to($left+$offset+$width+15, $top+$offset+$height-1.6/2*$height+$fontheight/2-2); $cr->show_text('Over-represented'); $extents = $cr->text_extents('Under-represented'); $cr->move_to($left+$offset+$width+15, $top+$offset+$height-0.4/2*$height+$fontheight/2-2); $cr->show_text('Under-represented'); $cr->save; #labels $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #axis labels #x-axis $cr->set_source_rgba(0, 0, 0, 1); $extents = $cr->text_extents($xlab); $cr->move_to($left+$offset+$width/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab); #y-axis $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2),$offset); $cr->show_text($ylab); $cr->restore; #draw dots $cr->set_antialias('default'); $xcur = 0; foreach my $dn (sort keys %$data) { if($data->{$dn} > 1.23 || $data->{$dn} < 0.78) { $cr->set_source_rgba(255/255, 127/255, 127/255, 1); } else { $cr->set_source_rgba(127/255, 127/255, 255/255, 1); } $cr->arc($left+$offset+$size/2+$size*$xcur++, $top+$offset+$height-$data->{$dn}/2*$height, 5, 0, 2*$PI); $cr->fill; } #write image $cr->show_page; return $surface; } sub convertToBoxValues { my ($data,$niceval) = @_; my ($xmax,$ymax,@matrix); $xmax = $ymax = 0; foreach my $i (sort {$a <=> $b} keys %$data) { $xmax++; push(@matrix,[$i,$data->{$i}->{min},$data->{$i}->{p25},$data->{$i}->{median},$data->{$i}->{p75},$data->{$i}->{max}]); $ymax = &max($ymax,$data->{$i}->{max}); } if($niceval) { $ymax = sprintf("%d",($ymax/$niceval)+1)*$niceval if($ymax % $niceval); } return (\@matrix,$xmax,$ymax); } sub createBoxPlot { my ($matrix,$xmax,$ymax,$title,$xlab,$ylab,$file,$zero,$add,$bin) = @_; $bin = ($bin ? $bin : 1); $zero = 0 unless($zero); $add = '' unless(defined $add); if($xmax != 100) { $xmax = 100; } $ymax = 1 unless($ymax); # die Dumper $matrix; my @col0 = (178/255, 178/255, 255/255); #b2b2ff my @col1 = (255/255, 178/255, 178/255); #ffb2b2 my @col3 = (127/255, 127/255, 255/255); #7f7fff my @col4 = (255/255, 127/255, 127/255); #ff7f7f my @linecol = (0, 0, 0, 0.4); my @linecol0 = (@col3, 1); my @linecol1 = (@col4, 1); my @boxcol = (@col3, 1); my @whiscol = (@col0, 0.9); my @medcol = (0,0,0, 0.5); my @helplinecol1 = (1,1,1, 0.9); my @helplinecol2 = (1,1,1, 0.5); #create new image my $size = 6; my $offset = 20; my $left = 25; my $bottom = 25; my $top = 5; my $height = 300; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+2*200+20); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); # $cr->set_font_size (30); $cr->save; #set up work space $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, ($xmax+$zero)*$size-1, $height); $cr->set_source_rgba(0.95, 0.95, 0.95, 1); $cr->fill; #draw legend $cr->set_font_size(10); # $font_extents = $cr->font_extents; my $x = $left+$offset+$size*50; foreach my $v ([\@whiscol,'Min/Max value'],[\@boxcol,'25th to 75th percentile'],[\@medcol,'Median']) { $cr->set_antialias('none'); $cr->set_source_rgba(@{$v->[0]}); $cr->rectangle($x, $top+5, 10, 10); $cr->fill; $x += 15; $cr->set_antialias('default'); $cr->move_to($x,$top+5+9); $cr->set_source_rgba(0, 0, 0, 0.8); $cr->show_text($v->[1]); $x += $cr->text_extents($v->[1])->{width}+15; } $cr->set_antialias('none'); #draw ticks #x-axis $cr->set_source_rgba(0, 0, 0, 0.8); # $cr->move_to($left+$offset+int($size/2+1), $top+$offset+$height); # $cr->line_to($left+$offset+int($size/2+1), $top+$offset+$height+3); # $cr->move_to($left+$offset+int($size/2+1), $top+$offset+$height+$space); # $cr->line_to($left+$offset+int($size/2+1), $top+$offset+$height+$space-3); foreach my $i (1..9) { $cr->move_to($left+$offset+int($size/2)+$size*10*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*10*$i-($zero ? 0 : $size)-1, $top+$offset+$height+3); # $cr->move_to($left+$offset+int($size/2)+$size*10*$i-($zero ? 0 : $size)-1, $top+$offset); # $cr->line_to($left+$offset+int($size/2)+$size*10*$i-($zero ? 0 : $size)-1, $top+$offset-3); } $cr->stroke; #y-axis foreach my $j (0..4) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset-3, $top+$offset+$height*$j/4-($j ? 1 : 0)); # $cr->move_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); # $cr->line_to($left+$offset+($xmax+$zero)*$size+3, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol1); foreach my $j (1..3) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(0, 0, 0, 0.8); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis # $extents = $cr->text_extents(1); # $cr->move_to($left+$offset+int($size/2+1)-$extents->{width}, $top+$offset+$height+$fontheight+2); # $cr->show_text(1); foreach my $i (1..9) { $extents = $cr->text_extents($i*10*$bin); $cr->move_to($left+$offset+int($size/2+1)+$size*10*$i-($zero ? 0 : $size)-$extents->{width}/2-1-($i == 1 ? 1 : 0), $top+$offset+$height+$fontheight+2); $cr->show_text($i*10*$bin); } #y-axis foreach my $j (0..4) { $extents = $cr->text_extents(&addCommas($ymax*$j/4)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2+$height*(4-$j)/4); $cr->show_text(&addCommas($ymax*$j/4)); } $cr->save; #axis labels $cr->set_source_rgba(0, 0, 0, 1); $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; $extents = $cr->text_extents($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->move_to($left+$offset+($xmax+$zero)*$size/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2),$offset); $cr->show_text($ylab); $cr->restore; #draw boxes my $factor = $height/$ymax; $cr->set_antialias('none'); foreach my $v (@$matrix) { #wiskers $cr->set_source_rgba(@whiscol); if($v->[1] != $v->[2]) { $cr->move_to($left+$offset+$size*$v->[0]+1, $top+$offset+$height-$v->[1]*$factor-1); $cr->line_to($left+$offset+$size*$v->[0]+$size-2, $top+$offset+$height-$v->[1]*$factor-1); $cr->stroke; } if($v->[4] != $v->[5]) { $cr->move_to($left+$offset+$size*$v->[0]+1, $top+$offset+$height-$v->[5]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+$size-2, $top+$offset+$height-$v->[5]*$factor); $cr->stroke; } $cr->save; $cr->set_dash(1,4,3); if($v->[1] != $v->[2]) { $cr->move_to($left+$offset+$size*$v->[0]+int($size/2)-1, $top+$offset+$height-$v->[2]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+int($size/2)-1, $top+$offset+$height-$v->[1]*$factor); $cr->stroke; } if($v->[4] != $v->[5]) { $cr->move_to($left+$offset+$size*$v->[0]+int($size/2)-1, $top+$offset+$height-$v->[5]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+int($size/2)-1, $top+$offset+$height-$v->[4]*$factor-1); $cr->stroke; } $cr->restore; #box if(($v->[2] != $v->[3]) || ($v->[4] != $v->[3])) { $cr->set_source_rgba(@whiscol); $cr->rectangle($left+$offset+$size*$v->[0], $top+$offset+$height-$v->[2]*$factor, $size-1, -($v->[4]-$v->[2])*$factor); $cr->fill; $cr->stroke; $cr->set_source_rgba(@boxcol); $cr->rectangle($left+$offset+$size*$v->[0], $top+$offset+$height-$v->[2]*$factor, $size-2, -($v->[4]-$v->[2])*$factor); $cr->stroke; } else { $cr->set_source_rgba(@boxcol); $cr->move_to($left+$offset+$size*$v->[0], $top+$offset+$height-$v->[3]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+$size-1, $top+$offset+$height-$v->[3]*$factor); $cr->stroke; } #median $cr->set_source_rgba(@medcol); $cr->move_to($left+$offset+$size*$v->[0]+1, $top+$offset+$height-$v->[3]*$factor); $cr->line_to($left+$offset+$size*$v->[0]+$size-2, $top+$offset+$height-$v->[3]*$factor); $cr->stroke; } #write image $cr->show_page; return $surface; } sub convertToBarValues { my ($data,$niceval,$start,$max) = @_; my ($xmax,$ymax,@matrix,$tmp); $xmax = $ymax = 0; #get xmax value if($max) { $xmax = $max; } else { foreach my $q (keys %$data) { $xmax = &max($xmax,$q); } } if($niceval) { $xmax = sprintf("%d",($xmax/$niceval)+1)*$niceval if($xmax % $niceval); } #get matrix values foreach my $q ($start..$xmax) { $tmp = (exists $data->{$q} ? $data->{$q} : 0); $ymax = &max($ymax,$tmp); push(@matrix,$tmp); } $ymax = sprintf("%d",($ymax/4)+1)*4 if($ymax % 4); return (\@matrix,$xmax,$ymax); } sub createBarPlot { my ($matrix,$xmax,$ymax,$title,$xlab,$ylab,$file,$zero) = @_; my @col0 = (178/255, 178/255, 255/255); #b2b2ff my @col1 = (255/255, 178/255, 178/255); #ffb2b2 my @col3 = (127/255, 127/255, 255/255); #7f7fff my @col4 = (255/255, 127/255, 127/255); #ff7f7f my @linecol = (0, 0, 0, 0.4); my @linecol0 = (@col3, 1); my @linecol1 = (@col4, 1); my @barcol0 = (@col3, 1); my @barcol1 = (@col4, 1); my @helplinecol1 = (1,1,1, 0.9); my @helplinecol2 = (1,1,1, 0.5); #create new image my $size = ($xmax <= 50 ? 10 : ($xmax <= 100 ? 6 : 3)); my $offset = 20; my $left = 25; my $bottom = 15; my $top = 0; my $height = 200; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+2*200+20); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); # $cr->set_font_size (30); $cr->save; #set up work space my ($dx, $dy); $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, ($xmax+$zero)*$size-1, $height); $cr->set_source_rgba(0.95, 0.95, 0.95, 1); $cr->fill; #draw ticks #x-axis $cr->set_source_rgba(0, 0, 0, 0.8); foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%5) == 0 && $i > 1 && $i < $xmax) { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+3); } else { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+1); } } $cr->stroke; #y-axis $cr->move_to($left+$offset, $top+$offset); $cr->line_to($left+$offset-3, $top+$offset); $cr->move_to($left+$offset, $top+$offset+$height-1); $cr->line_to($left+$offset-3, $top+$offset+$height-1); $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol1); foreach my $j (1..3) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(0, 0, 0, 0.8); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%5) == 0 && $i > 1 && $i < $xmax) { $extents = $cr->text_extents($i); $cr->move_to($left+$offset+int($size/2+1)+$size*$i-($zero ? 0 : $size)-$extents->{width}/2-1-($i == 1 ? 1 : 0), $top+$offset+$height+$fontheight+2); $cr->show_text($i); } } #y-axis $extents = $cr->text_extents(&addCommas($ymax)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2); $cr->show_text(&addCommas($ymax)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2+$height); $cr->show_text(0); $cr->save; #labels $cr->set_font_size (14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #axis labels $cr->set_source_rgba(0, 0, 0, 1); $extents = $cr->text_extents($xlab); $cr->move_to($left+$offset+($xmax+$zero)*$size/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2),$offset); $cr->show_text($ylab); $cr->restore; #draw boxes $cr->set_antialias('none'); foreach my $pos (0..$xmax-($zero ? 0 : 1)) { next unless($matrix->[$pos+($zero ? 0 : 1)]); my $tmp = $matrix->[$pos+($zero ? 0 : 1)] / $ymax; #unique if($tmp) { $cr->set_source_rgba(@barcol0); $cr->rectangle($left+$offset+($pos+($zero ? 0 : 1))*$size, $top+$offset+$height, $size-1, -$tmp*$height); $cr->fill; } } #write image $cr->show_page; return $surface; } sub convertOdToStackBinMatrix { my ($data,$stacks,$min,$max,$nonice) = @_; my ($num,$ymax,$xmax,$xmin,$step,%vals,%sums,$sum,@matrix,$bin,$tmpbin); #make nice xmax value if(defined $max) { $xmax = $max; } else { $xmax = (sort {$b <=> $a} keys %$data)[0]; } $bin = &getBinVal($xmax); $xmax = $bin*100; $xmin = (defined $min ? $min : 0); #get data to bin and find y axis max value $ymax = 0; foreach my $s (0..$stacks-1) { $sums{$s} = 0; } $sum = 0; $tmpbin = $bin; foreach my $i ($xmin..$xmax) { foreach my $s (0..$stacks-1) { next unless(exists $data->{$i}->{$s}); $sums{$s} += $data->{$i}->{$s}; $sum += $data->{$i}->{$s}; } if(--$tmpbin <= 0) { $tmpbin = $bin; $ymax = &max($ymax,$sum); $sum = 0; foreach my $s (0..$stacks-1) { push(@{$matrix[$s]},$sums{$s}); $sums{$s} = 0; } } } #make nice ymax value unless($nonice) { $ymax = sprintf("%d",($ymax/4)+1)*4 if($ymax % 4); # $step = ($ymax <= 10 ? 10 : ($ymax < 40 ? 40 : ($ymax < 100 ? 100 : ($ymax < 1000 ? 100 : 100)))); # $ymax = sprintf("%d",($ymax/$step)+1)*$step if($ymax % $step); } return (\@matrix,$xmax,$ymax,$stacks); } sub createStackBarPlot { my ($matrix,$xmax,$ymax,$stacks,$title,$xlab,$ylab,$file,$zero,$add) = @_; my $bin = 1; if($xmax > 100) { $bin = $xmax / 100; $xmax = 100; } my @legend = ('Exact dupl.','5\' dupl.','3\' dupl.','Rev. compl. exact dupl.','Rev. compl. 5\'/3\' dupl.'); my @cols = ([69/255, 114/255, 167/255, 1], [137/255, 1165/255, 78/255, 1], [170/255, 70/255, 67/255, 1], [147/255, 169/255, 207/255, 1], [51/255, 102/255, 102/255, 1]); my @barcol = (127/255, 127/255, 255/255, 1); #b2b2ff my @meancol = (255/255, 127/255, 127/255, 1); #ffb2b2 my @stdcol = (178/255, 178/255, 255/255, 0.8); #7f7fff my @std1col = (0, 0, 0, 0.02); #ff7f7f my @std2col = (0, 0, 0, 0.02); #ff7f7f my @linecol = (0, 0, 0, 0.4); my @helplinecol = (1, 1, 1, 0.9); my @background = (0.95, 0.95, 0.95, 1); my @tickcol = (0, 0, 0, 0.8); my @labelcol = (0, 0, 0, 1); #create new image my $size = 6; my $offset = 20; my $left = 40; my $bottom = 15; my $top = 20; my $height = 200; my $surface = Cairo::ImageSurface->create('argb32', $left+$offset*2+($xmax+$zero)*$size,$bottom+$top+$offset*2+$height); #format, width, height my $cr = Cairo::Context->create($surface); my ($font_extents,$extents,$fontheight,$fontdescent); #background $cr->rectangle(0, 0, $left+$offset*2+($xmax+$zero)*$size,$bottom+$offset*2+2*200+20); $cr->set_source_rgba(1, 1, 1, 1); $cr->fill; #fonts $cr->select_font_face ('sans', 'normal', 'normal'); $cr->save; #set up work space $cr->set_antialias('none'); $cr->set_line_width(1); #background for plot $cr->rectangle($left+$offset, $top+$offset, ($xmax+$zero)*$size-1, $height); $cr->set_source_rgba(@background); $cr->fill; #draw legend $cr->set_font_size(10); # $font_extents = $cr->font_extents; my $x = $left+$offset+$size*100-5; foreach my $i (reverse (0..scalar(@legend)-1)) { $cr->set_antialias('default'); $x -= $cr->text_extents($legend[$i])->{width}; $cr->move_to($x,$top+5+9); $cr->set_source_rgba(@tickcol); $cr->show_text($legend[$i]); $x -= 15; $cr->set_antialias('none'); $cr->set_source_rgba(@{$cols[$i]}); $cr->rectangle($x, $top+5, 10, 10); $cr->fill; $x -= 15; } #draw ticks $cr->set_antialias('none'); #x-axis $cr->set_source_rgba(@tickcol); foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%5) == 0 && $i > 1 && $i < $xmax) { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+3); } else { $cr->move_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height); $cr->line_to($left+$offset+int($size/2)+$size*$i-($zero ? 0 : $size)-1, $top+$offset+$height+1); } } $cr->stroke; #y-axis $cr->move_to($left+$offset, $top+$offset); $cr->line_to($left+$offset-3, $top+$offset); $cr->move_to($left+$offset, $top+$offset+$height-1); $cr->line_to($left+$offset-3, $top+$offset+$height-1); $cr->stroke; #helplines $cr->set_source_rgba(@helplinecol); foreach my $j (1..3) { $cr->move_to($left+$offset, $top+$offset+$height*$j/4-($j ? 1 : 0)); $cr->line_to($left+$offset+($xmax+$zero)*$size, $top+$offset+$height*$j/4-($j ? 1 : 0)); } $cr->stroke; $cr->set_antialias('default'); #tick labels $cr->set_source_rgba(@tickcol); $cr->set_font_size(10); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #x-axis foreach my $i (($zero ? 0 : 1)..$xmax) { if(($i%10) == 0 && $i > 1 && $i < $xmax) { $extents = $cr->text_extents($i*$bin); $cr->move_to($left+$offset+int($size/2+1)+$size*$i-($zero ? 0 : $size)-$extents->{width}/2-1-($i == 1 ? 1 : 0), $top+$offset+$height+$fontheight+2); $cr->show_text($i*$bin); } } #y-axis $extents = $cr->text_extents(&addCommas($ymax)); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2); $cr->show_text(&addCommas($ymax)); $extents = $cr->text_extents(0); $cr->move_to($left+$offset-5-$extents->{width}, $top+$offset+$fontheight/2-2+$height); $cr->show_text(0); $cr->save; #labels $cr->set_font_size(14); $font_extents = $cr->font_extents; $fontheight = $font_extents->{height}; #axis labels $cr->set_source_rgba(@labelcol); $extents = $cr->text_extents($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->move_to($left+$offset+($xmax+$zero)*$size/2-$extents->{width}/2, $top+$offset+$height+$fontheight+15); $cr->show_text($xlab.($bin>1 ? ' (Bin size: '.$bin.($add ? $add.')' : '') : '')); $cr->rotate($PI * 3 / 2); $extents = $cr->text_extents($ylab.($bin>1 ? ' (per bin)' : '')); $cr->move_to(-($top+$offset+$height/2+$extents->{width}/2+($bin>1 ? 12 : 0)),$offset+10); $cr->show_text($ylab.($bin>1 ? ' (per bin)' : '')); $cr->restore; #draw boxes $cr->set_antialias('none'); foreach my $pos (0..$xmax-($zero ? 0 : 1)) { my $tmp = 0; foreach my $s (0..$stacks-1) { next unless($matrix->[$s]->[$pos]); my $cur = $matrix->[$s]->[$pos] / $ymax; $cr->set_source_rgba(@{$cols[$s]}); if($cur) { $cr->rectangle($left+$offset+$pos*$size, $top+$offset+$height-$tmp*$height, $size-1, -$cur*$height); $cr->fill; } $tmp += $cur; } } #write image $cr->show_page; return $surface; } sub header { return ' PRINSEQ-'.$WHAT.' Report
'; } sub footer { return '
'; } sub generateHtml { my ($in,$out) = @_; my ($file,$data,$surface,$html,$png); $data = &readGdFile($in); my $time = sprintf("%02d/%02d/%04d %02d:%02d:%02d",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); $html .= &header(); $html .= '

PRINSEQ-'.$WHAT.' v'.$VERSION.' HTML Report   

[Generated: '.$time.']

'; $html .= '
'; #input info if(exists $data->{numseqs}) { $html .= '
Input Information
'; $html .= '
'; if(exists $data->{pairedend} && $data->{pairedend}) { my $singletons1 = ($data->{numseqs}||0)-($data->{pairs}||0); my $singletons2 = ($data->{numseqs2}||0)-($data->{pairs}||0); $html .= ''; } else { $html .= ''; } $html .= '
Input file(s):'.($data->{filename1} ? &convertIntToString($data->{filename1}) : '-').($data->{filename2} ? ' and '.&convertIntToString($data->{filename2}) : '').'
Input format(s):'.($data->{format1} ? uc($data->{format1}) : '-').($data->{format2} ? ' and '.uc($data->{format2}) : '').'
# Sequences (file 1):'.&addCommas($data->{numseqs}||'-').'
Total bases (file 1):'.&addCommas($data->{numbases}||'-').'
# Sequences (file 2):'.&addCommas($data->{numseqs2}||'-').'
Total bases (file 2):'.&addCommas($data->{numbases2}||'-').'
# Pairs:'.&addCommas($data->{pairs}||'-').($data->{pairs} ? '  ('.sprintf("%.2f",(100*(2*$data->{pairs})/(($data->{numseqs}||0)+($data->{numseqs2}||0)))).'% of sequences)' : '').'
# Singletons (file 1):'.&addCommas($singletons1).($singletons1 ? '  ('.sprintf("%.2f",(100*$singletons1/$data->{numseqs})).'%)' : '').'
# Singletons (file 2):'.&addCommas($singletons2).($singletons2 ? '  ('.sprintf("%.2f",(100*$singletons2/$data->{numseqs2})).'%)' : '').'
# Sequences:'.&addCommas($data->{numseqs}||'-').'
Total bases:'.&addCommas($data->{numbases}||'-').'

'; } #length plot if(exists $data->{counts}->{length} && keys %{$data->{counts}->{length}}) { $html .= '
Length Distribution
'; if(exists $data->{pairedend} && $data->{pairedend}) { $html .= '
File 1
Mean sequence length: '.(exists $data->{stats}->{length}->{mean} ? sprintf("%.2f",$data->{stats}->{length}->{mean}) : '-').' ± '.(exists $data->{stats}->{length}->{std} ? sprintf("%.2f",$data->{stats}->{length}->{std}) : '-').' bp
Minimum length: '.(exists $data->{stats}->{length}->{min} ? &addCommas($data->{stats}->{length}->{min}) : '-').' bp
Maximum length:'.(exists $data->{stats}->{length}->{max} ? &addCommas($data->{stats}->{length}->{max}) : '-').' bp
Length range:'.(exists $data->{stats}->{length}->{range} ? &addCommas($data->{stats}->{length}->{range}) : '-').' bp
Mode length: '.(exists $data->{stats}->{length}->{mode} ? &addCommas($data->{stats}->{length}->{mode}) : '-').' bp with '.(exists $data->{stats}->{length}->{modeval} ? &addCommas($data->{stats}->{length}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{length},1),$data->{stats}->{length},'Length Distribution','Read Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; $html .= '

File 2
Mean sequence length: '.(exists $data->{stats2}->{length}->{mean} ? sprintf("%.2f",$data->{stats2}->{length}->{mean}) : '-').' ± '.(exists $data->{stats2}->{length}->{std} ? sprintf("%.2f",$data->{stats2}->{length}->{std}) : '-').' bp
Minimum length: '.(exists $data->{stats2}->{length}->{min} ? &addCommas($data->{stats2}->{length}->{min}) : '-').' bp
Maximum length:'.(exists $data->{stats2}->{length}->{max} ? &addCommas($data->{stats2}->{length}->{max}) : '-').' bp
Length range:'.(exists $data->{stats2}->{length}->{range} ? &addCommas($data->{stats2}->{length}->{range}) : '-').' bp
Mode length: '.(exists $data->{stats2}->{length}->{mode} ? &addCommas($data->{stats2}->{length}->{mode}) : '-').' bp with '.(exists $data->{stats2}->{length}->{modeval} ? &addCommas($data->{stats2}->{length}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{length},1),$data->{stats2}->{length},'Length Distribution','Read Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; } else { $html .= '
Mean sequence length: '.(exists $data->{stats}->{length}->{mean} ? sprintf("%.2f",$data->{stats}->{length}->{mean}) : '-').' ± '.(exists $data->{stats}->{length}->{std} ? sprintf("%.2f",$data->{stats}->{length}->{std}) : '-').' bp
Minimum length: '.(exists $data->{stats}->{length}->{min} ? &addCommas($data->{stats}->{length}->{min}) : '-').' bp
Maximum length:'.(exists $data->{stats}->{length}->{max} ? &addCommas($data->{stats}->{length}->{max}) : '-').' bp
Length range:'.(exists $data->{stats}->{length}->{range} ? &addCommas($data->{stats}->{length}->{range}) : '-').' bp
Mode length: '.(exists $data->{stats}->{length}->{mode} ? &addCommas($data->{stats}->{length}->{mode}) : '-').' bp with '.(exists $data->{stats}->{length}->{modeval} ? &addCommas($data->{stats}->{length}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{length},1),$data->{stats}->{length},'Length Distribution','Read Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; } $html .= '
'; } #GC content if(exists $data->{counts}->{gc} && keys %{$data->{counts}->{gc}}) { $html .= '
GC Content Distribution
'; if(exists $data->{pairedend} && $data->{pairedend}) { $html .= '
File 1
Mean GC content: '.(exists $data->{stats}->{gc}->{mean} ? sprintf("%.2f",$data->{stats}->{gc}->{mean}) : '-').' ± '.(exists $data->{stats}->{gc}->{std} ? sprintf("%.2f",$data->{stats}->{gc}->{std}) : '-').' %
Minimum GC content: '.(exists $data->{stats}->{gc}->{min} ? $data->{stats}->{gc}->{min} : '-').' %
Maximum GC content: '.(exists $data->{stats}->{gc}->{max} ? $data->{stats}->{gc}->{max} : '-').' %
GC content range: '.(exists $data->{stats}->{gc}->{range} ? $data->{stats}->{gc}->{range} : '-').' %
Mode GC content: '.(exists $data->{stats}->{gc}->{mode} ? $data->{stats}->{gc}->{mode} : '-').' % with '.(exists $data->{stats}->{gc}->{modeval} ? &addCommas($data->{stats}->{gc}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{gc},0),$data->{stats}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; $html .= '

File 2
Mean GC content: '.(exists $data->{stats2}->{gc}->{mean} ? sprintf("%.2f",$data->{stats2}->{gc}->{mean}) : '-').' ± '.(exists $data->{stats2}->{gc}->{std} ? sprintf("%.2f",$data->{stats2}->{gc}->{std}) : '-').' %
Minimum GC content: '.(exists $data->{stats2}->{gc}->{min} ? $data->{stats2}->{gc}->{min} : '-').' %
Maximum GC content: '.(exists $data->{stats2}->{gc}->{max} ? $data->{stats2}->{gc}->{max} : '-').' %
GC content range: '.(exists $data->{stats2}->{gc}->{range} ? $data->{stats2}->{gc}->{range} : '-').' %
Mode GC content: '.(exists $data->{stats2}->{gc}->{mode} ? $data->{stats2}->{gc}->{mode} : '-').' % with '.(exists $data->{stats2}->{gc}->{modeval} ? &addCommas($data->{stats2}->{gc}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{gc},0),$data->{stats2}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; } else { $html .= '
Mean GC content: '.(exists $data->{stats}->{gc}->{mean} ? sprintf("%.2f",$data->{stats}->{gc}->{mean}) : '-').' ± '.(exists $data->{stats}->{gc}->{std} ? sprintf("%.2f",$data->{stats}->{gc}->{std}) : '-').' %
Minimum GC content: '.(exists $data->{stats}->{gc}->{min} ? $data->{stats}->{gc}->{min} : '-').' %
Maximum GC content: '.(exists $data->{stats}->{gc}->{max} ? $data->{stats}->{gc}->{max} : '-').' %
GC content range: '.(exists $data->{stats}->{gc}->{range} ? $data->{stats}->{gc}->{range} : '-').' %
Mode GC content: '.(exists $data->{stats}->{gc}->{mode} ? $data->{stats}->{gc}->{mode} : '-').' % with '.(exists $data->{stats}->{gc}->{modeval} ? &addCommas($data->{stats}->{gc}->{modeval}) : '-').' sequences

'; $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{gc},0),$data->{stats}->{gc},'GC Content Distribution','GC Content (0-100%)','Number of Sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $html .= '
'; } $html .= '
'; } #Base quality if(exists $data->{quals} || exists $data->{qualsmean} || exists $data->{qualsbin}) { $html .= '
Base Quality Distribution
'; if(exists $data->{pairedend} && $data->{pairedend}) { $html .= 'File 1
'; } } if(exists $data->{quals} && keys %{$data->{quals}}) { $surface = &createBoxPlot(&convertToBoxValues($data->{quals},4),'Base Quality Distribution','Read position in %','Quality score',''); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); } if(exists $data->{qualsbin} && keys %{$data->{qualsbin}}) { $surface = &createBoxPlot(&convertToBoxValues($data->{qualsbin},4),'Base Quality Distribution','Read position in bp','Quality score','',0,'bp',$data->{binval}); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{quals}); $html .= &insert_image($png); } if(exists $data->{qualsmean} && keys %{$data->{qualsmean}}) { $surface = &createBarPlot(&convertToBarValues($data->{qualsmean},5,1),'Sequence Quality Distribution','Mean of quality scores per sequence','Number of sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{qualsbin}); $html .= &insert_image($png); } if(exists $data->{pairedend} && $data->{pairedend}) { if(exists $data->{quals} || exists $data->{qualsmean} || exists $data->{qualsbin}) { $html .= '


File 2
'; } if(exists $data->{quals2} && keys %{$data->{quals2}}) { $surface = &createBoxPlot(&convertToBoxValues($data->{quals2},4),'Base Quality Distribution','Read position in %','Quality score',''); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); } if(exists $data->{qualsbin2} && keys %{$data->{qualsbin2}}) { $surface = &createBoxPlot(&convertToBoxValues($data->{qualsbin2},4),'Base Quality Distribution','Read position in bp','Quality score','',0,'bp',$data->{binval}); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{quals2}); $html .= &insert_image($png); } if(exists $data->{qualsmean2} && keys %{$data->{qualsmean2}}) { $surface = &createBarPlot(&convertToBarValues($data->{qualsmean2},5,1),'Sequence Quality Distribution','Mean of quality scores per sequence','Number of sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{qualsbin2}); $html .= &insert_image($png); } } if(exists $data->{quals} || exists $data->{qualsmean} || exists $data->{qualsbin}) { $html .= '

'; } #Ns if((exists $data->{counts}->{ns} && keys %{$data->{counts}->{ns}}) || (exists $data->{counts2} && exists $data->{counts2}->{ns} && keys %{$data->{counts2}->{ns}})) { $html .= '
Occurence of N
'; if(exists $data->{pairedend} && $data->{pairedend}) { $html .= 'File 1
'; } } if(exists $data->{counts}->{ns} && keys %{$data->{counts}->{ns}}) { my $nscount = 0; foreach my $n (values %{$data->{counts}->{ns}}) { $nscount += $n; } $html .= '
Sequences with N: '.($nscount ? &addCommas($nscount).'  ('.sprintf("%.2f",100/$data->{numseqs}*$nscount).' %)' : 0).'
Max percentage of Ns per sequence: '.(exists $data->{stats}->{ns}->{max} ? $data->{stats}->{ns}->{max} : 0).' %
'; if($nscount) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{ns},1),undef,'Percentage of N\'s (> 0%)','Percentage of N\'s per Read (1-100%)','# Sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } } if(exists $data->{pairedend} && $data->{pairedend} && exists $data->{counts2}->{ns} && keys %{$data->{counts2}->{ns}}) { $html .= '


File 2
'; my $nscount = 0; foreach my $n (values %{$data->{counts2}->{ns}}) { $nscount += $n; } $html .= '
Sequences with N: '.($nscount ? &addCommas($nscount).'  ('.sprintf("%.2f",100/$data->{numseqs2}*$nscount).' %)' : 0).'
Max percentage of Ns per sequence: '.(exists $data->{stats2}->{ns}->{max} ? $data->{stats2}->{ns}->{max} : 0).' %
'; if($nscount) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{ns},1),undef,'Percentage of N\'s (> 0%)','Percentage of N\'s per Read (1-100%)','# Sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } } if((exists $data->{counts}->{ns} && keys %{$data->{counts}->{ns}}) || (exists $data->{counts2} && exists $data->{counts2}->{ns} && keys %{$data->{counts2}->{ns}})) { $html .= '

'; } #tails if(exists $data->{tail} || exists $data->{tail2}) { $html .= '
Poly-A/T Tails
'; } if(exists $data->{tail}) { my $tail5count = 0; foreach my $n (values %{$data->{counts}->{tail5}}) { $tail5count += $n; } my $tail3count = 0; foreach my $n (values %{$data->{counts}->{tail3}}) { $tail3count += $n; } if(exists $data->{pairedend} && $data->{pairedend}) { $html .= 'File 1
'; } $html .= '
5\'-end 3\'-end
Sequences with tail:'.($tail5count ? &addCommas($tail5count).'  ('.sprintf("%.2f",100/$data->{numseqs}*$tail5count).' %)' : 0).' '.($tail3count ? &addCommas($tail3count).'  ('.sprintf("%.2f",100/$data->{numseqs}*$tail3count).' %)' : 0).'
Maximum tail length: '.(exists $data->{stats}->{tail5}->{max} ? $data->{stats}->{tail5}->{max} : 0).' '.(exists $data->{stats}->{tail3}->{max} ? $data->{stats}->{tail3}->{max} : 0).'
'; if($tail5count) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{tail5},1),undef,'Poly-A/T Tail Distribution (> 4bp)','5\' Tail Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); if($tail3count) { $html .= '
'; } } if($tail3count) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts}->{tail3},1),undef,'Poly-A/T Tail Distribution (> 4bp)','3\' Tail Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } } if(exists $data->{pairedend} && $data->{pairedend} && exists $data->{tail2}) { my $tail5count = 0; foreach my $n (values %{$data->{counts2}->{tail5}}) { $tail5count += $n; } my $tail3count = 0; foreach my $n (values %{$data->{counts2}->{tail3}}) { $tail3count += $n; } $html .= '


File 2
'; $html .= '
5\'-end 3\'-end
Sequences with tail:'.($tail5count ? &addCommas($tail5count).'  ('.sprintf("%.2f",100/$data->{numseqs2}*$tail5count).' %)' : 0).' '.($tail3count ? &addCommas($tail3count).'  ('.sprintf("%.2f",100/$data->{numseqs2}*$tail3count).' %)' : 0).'
Maximum tail length: '.(exists $data->{stats2}->{tail5}->{max} ? $data->{stats2}->{tail5}->{max} : 0).' '.(exists $data->{stats2}->{tail3}->{max} ? $data->{stats2}->{tail3}->{max} : 0).'
'; if($tail5count) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{tail5},1),undef,'Poly-A/T Tail Distribution (> 4bp)','5\' Tail Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); if($tail3count) { $html .= '
'; } } if($tail3count) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{counts2}->{tail3},1),undef,'Poly-A/T Tail Distribution (> 4bp)','3\' Tail Length in bp','# Sequences','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } } if(exists $data->{tail} || exists $data->{tail2}) { $html .= '

'; } #tag sequence check if(exists $data->{freqs} || exists $data->{freqs2}) { $html .= '
Tag Sequence Check
'; } if(exists $data->{freqs}) { my $tagmidseq; if(exists $data->{tagmidseq}) { $tagmidseq = $data->{tagmidseq}; $tagmidseq =~ s/\,/\
/g; } if(exists $data->{pairedend} && $data->{pairedend}) { $html .= 'File 1
'; } $html .= '
5\'-end3\'-end
Probability of tag sequence:'.(exists $data->{tagprob}->{5} ? $data->{tagprob}->{5}.' %' : '-').''.(exists $data->{tagprob}->{3} ? $data->{tagprob}->{3}.' %' : '-').'
GSMIDs or RLMIDs:'.(exists $data->{tagmidnum} ? ($data->{tagmidnum} == 0 ? 'none' : ($tagmidseq ? $tagmidseq : $data->{tagmidnum})) : '-').' 

'; $html .= ''; foreach my $pos (sort {$a <=> $b} keys %{$data->{freqs}->{5}}) { $html .= ''; } $html .= ''; foreach my $pos (sort {$a <=> $b} keys %{$data->{freqs}->{3}}) { $html .= ''; } $html .= ''; $html .= ''; foreach my $num (1,0,0,0,5,0,0,0,0,10,0,0,0,0,15,0,0,0,0,20,0,20,0,0,0,0,15,0,0,0,0,10,0,0,0,0,5,0,0,0,1) { $html .= ''; } $html .= ''; $html .= '
'.&insert_image($FREQCHART_L,undef,undef,1).''; foreach my $base (qw(A C G T N)) { if($data->{freqs}->{5}->{$pos}->{$base}) { $html .= &insert_image($BASE64_BASES->{$base},$data->{freqs}->{5}->{$pos}->{$base},14,1).'
'; #''.$base.'
'; } } $html .= &insert_image($MMCHART_B2,6,16,1).'
 ... '; foreach my $base (qw(A C G T N)) { if($data->{freqs}->{3}->{$pos}->{$base}) { $html .= &insert_image($BASE64_BASES->{$base},$data->{freqs}->{3}->{$pos}->{$base},14,1).'
'; } } $html .= &insert_image($MMCHART_B2,6,16,1).'
 '.($num ? $num : '').' 
 Position from Sequence Ends
'; } if(exists $data->{pairedend} && $data->{pairedend} && exists $data->{freqs2}) { $html .= '


File 2
'; $html .= '
5\'-end3\'-end
Probability of tag sequence:'.(exists $data->{tagprob2}->{5} ? $data->{tagprob2}->{5}.' %' : '-').''.(exists $data->{tagprob2}->{3} ? $data->{tagprob2}->{3}.' %' : '-').'

'; $html .= ''; foreach my $pos (sort {$a <=> $b} keys %{$data->{freqs2}->{5}}) { $html .= ''; } $html .= ''; foreach my $pos (sort {$a <=> $b} keys %{$data->{freqs2}->{3}}) { $html .= ''; } $html .= ''; $html .= ''; foreach my $num (1,0,0,0,5,0,0,0,0,10,0,0,0,0,15,0,0,0,0,20,0,20,0,0,0,0,15,0,0,0,0,10,0,0,0,0,5,0,0,0,1) { $html .= ''; } $html .= ''; $html .= '
'.&insert_image($FREQCHART_L,undef,undef,1).''; foreach my $base (qw(A C G T N)) { if($data->{freqs2}->{5}->{$pos}->{$base}) { $html .= &insert_image($BASE64_BASES->{$base},$data->{freqs2}->{5}->{$pos}->{$base},14,1).'
'; #''.$base.'
'; } } $html .= &insert_image($MMCHART_B2,6,16,1).'
 ... '; foreach my $base (qw(A C G T N)) { if($data->{freqs2}->{3}->{$pos}->{$base}) { $html .= &insert_image($BASE64_BASES->{$base},$data->{freqs2}->{3}->{$pos}->{$base},14,1).'
'; } } $html .= &insert_image($MMCHART_B2,6,16,1).'
 '.($num ? $num : '').' 
 Position from Sequence Ends
'; } if(exists $data->{freqs} || exists $data->{freqs2}) { $html .= '

'; } #Sequence duplicates if(exists $data->{dubslength} || exists $data->{dubscounts}) { $html .= '
Sequence Duplication
'; } my %dubs; if(exists $data->{dubscounts} && keys %{$data->{dubscounts}}) { my $exactonly = $data->{exactonly}||0; foreach my $n (keys %{$data->{dubscounts}}) { foreach my $s (keys %{$data->{dubscounts}->{$n}}) { $dubs{$s}->{count} += $data->{dubscounts}->{$n}->{$s} * $n; $dubs{$s}->{max} = $n unless(exists $dubs{$s}->{max} && $dubs{$s}->{max} > $n); $dubs{all} += $data->{dubscounts}->{$n}->{$s} * $n; } } $html .= '
'; unless($exactonly) { $html .= ''; } $html .= '
# Sequences Max duplicates
Exact duplicates:'.(exists $dubs{0}->{count} ? &addCommas($dubs{0}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{0}->{count}).' %)' : 0).''.($dubs{0}->{max}||0).'
Exact duplicates with reverse complements:'.(exists $dubs{3}->{count} ? &addCommas($dubs{3}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{3}->{count}).' %)' : 0).' '.($dubs{3}->{max}||0).'
5\' duplicates'.(exists $dubs{1}->{count} ? &addCommas($dubs{1}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{1}->{count}).' %)' : 0).' '.($dubs{1}->{max}||0).'
3\' duplicates'.(exists $dubs{2}->{count} ? &addCommas($dubs{2}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{2}->{count}).' %)' : 0).' '.($dubs{2}->{max}||0).'
5\'/3\' duplicates with reverse complements'.(exists $dubs{4}->{count} ? &addCommas($dubs{4}->{count}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{4}->{count}).' %)' : 0).' '.($dubs{4}->{max}||0).'
Total:'.(exists $dubs{all} ? &addCommas($dubs{all}).'  ('.sprintf("%.2f",100/$data->{numseqs}*$dubs{all}).' %)' : 0).'-
'; } if(exists $dubs{all} && $dubs{all}) { if(exists $data->{dubslength} && keys %{$data->{dubslength}}) { $surface = &createStackBarPlot(&convertOdToStackBinMatrix($data->{dubslength},5,1),'Sequence duplication level','Read Length in bp','Number of duplicates','',0,' bp'); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '
'.&insert_image($png); } if(exists $data->{dubscounts} && keys %{$data->{dubscounts}}) { $surface = &createStackBarPlot(&convertOdToStackBinMatrix($data->{dubscounts},5,1,100),'Sequence duplication level','Number of duplicates','Number of sequences','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{dubslength}); $html .= &insert_image($png); my %dubsmax; my $count = 1; foreach my $n (sort {$b <=> $a} keys %{$data->{dubscounts}}) { foreach my $s (keys %{$data->{dubscounts}->{$n}}) { foreach my $i (1..$data->{dubscounts}->{$n}->{$s}) { $dubsmax{$count++}->{$s} = $n; last unless($count <= 100); } last unless($count <= 100); } last unless($count <= 100); } $surface = &createStackBarPlot(&convertOdToStackBinMatrix(\%dubsmax,5,1,100),'Sequence duplication level','Sequence','Number of duplicates','',0); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{dubslength}); $html .= &insert_image($png); } } if(exists $data->{dubslength} || exists $data->{dubscounts}) { $html .= '

'; } #Sequence complexity if(exists $data->{compldust} || exists $data->{complentropy}) { $html .= '
Sequence Complexity
'; if(exists $data->{complvals}) { my $complseq; foreach my $d (keys %{$data->{complvals}}) { foreach my $m ('minseq','maxseq') { $complseq = $data->{complvals}->{$d}->{$m}; $complseq = substr($complseq,0,797).'...' if(length($complseq) > 800); $complseq =~ s/(.{60})/$1\
/g; $data->{complvals}->{$d}->{$m} = $complseq; } } } $html .= '
ValueSequence
Minimum DUST score:'.(exists $data->{complvals}->{dust}->{minval} ? $data->{complvals}->{dust}->{minval} : '-').''.(exists $data->{complvals}->{dust}->{minseq} ? $data->{complvals}->{dust}->{minseq} : '').'
Maximum DUST score:'.(exists $data->{complvals}->{dust}->{maxval} ? $data->{complvals}->{dust}->{maxval} : '').''.(exists $data->{complvals}->{dust}->{maxseq} ? $data->{complvals}->{dust}->{maxseq} : '').'
Minimum Entropy value:'.(exists $data->{complvals}->{entropy}->{minval} ? $data->{complvals}->{entropy}->{minval} : '').''.(exists $data->{complvals}->{entropy}->{minseq} ? $data->{complvals}->{entropy}->{minseq} : '').'
Maximum Entropy value:'.(exists $data->{complvals}->{entropy}->{maxval} ? $data->{complvals}->{entropy}->{maxval} : '').''.(exists $data->{complvals}->{entropy}->{maxseq} ? $data->{complvals}->{entropy}->{maxseq} : '').'

'; } if(exists $data->{compldust}) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{compldust},0),undef,'Sequence complexity distribution','Mean sequence complexity (DUST scores)','Number of sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); } if(exists $data->{complentropy}) { $surface = &createAnnotBarPlot(&convertOdToBinMatrix($data->{complentropy},0),undef,'Sequence complexity distribution','Mean sequence complexity (Entropy values)','Number of sequences','',1); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

' if(exists $data->{compldust}); $html .= &insert_image($png); } if(exists $data->{compldust} || exists $data->{complentropy}) { $html .= '

'; } #Dinucleotide odd ratio PCA - microbial/viral if(exists $data->{dinucodds} && keys %{$data->{dinucodds}}) { $html .= '
Dinucleotide Odds Ratios
'; $html .= '
'; foreach my $d (map {join("/",(m/../g ))} sort keys %{$data->{dinucodds}}) { $html .= ''; } $html .= ''; foreach my $d (map {sprintf("%.4f",$data->{dinucodds}->{$_})} sort keys %{$data->{dinucodds}}) { $html .= ''; } $html .= '
 '.$d.'
Odds ratio'.$d.'

'; my @new = map {$data->{dinucodds}->{$_}} sort keys %{$data->{dinucodds}}; $surface = &createOddsRatioPlot($data->{dinucodds},'Odds ratios','Dinucleotide','Odds ratio',''); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= &insert_image($png); $surface = &createPCAPlot(&convertToPCAValues(\@new,'m'),'PCA','1st Principal Component Score','2nd Principal Component Score',''); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

'; $html .= &insert_image($png); $surface = &createPCAPlot(&convertToPCAValues(\@new,'v'),'PCA','1st Principal Component Score','2nd Principal Component Score',''); $png = ''; $surface->write_to_png_stream(sub { my ($closure, $data) = @_; $png .= $data; }); $html .= '

'; $html .= &insert_image($png); $html .= '
'; } $html .= '
'; $html .= &footer(); #write html to file $file = &getFileName('.html'); open(FH, ">$file") or &printError("Can't open file ".$file.": $!"); print FH $html; close(FH); &printLog("Done with HTML data"); } sub insert_image { my ($data, $height, $width, $noencode) = @_; my $content .= ''."\n"; return $content; } sub inline_image { return "data:image/png;base64,".MIME::Base64::encode_base64($_[0]); } sub convertIntToString { my $int = shift; $int =~ s/(.{2})/chr(hex($1))/eg; return $int; } prinseq-lite-0.20.4/README0000644000076700007670000001200612240000433015250 0ustar rschmiedrschmiedPRINSEQ ======= PReprocessing and INformation of SEQuence data (http://prinseq.sourceforge.net) PRINSEQ will help you to preprocess your genomic or metagenomic sequence data in FASTA or FASTQ format. LITE VERSION ------------ The lite version is a standalone perl script (prinseq-lite.pl) that does not require any non-core perl modules for processing. The used modules are: Getopt::Long Pod::Usage File::Temp Fcntl Digest::MD5 Cwd List::Util To run the lite version, you can either use "perl prinseq-lite.pl [options]" or rename the "prinseq-lite.pl" into "prinseq-lite", add the execution mode ("chmod +x prinseq-lite") and use "prinseq-lite [options]". The available options are processed in the following order: seq_num, trim_left, trim_right, trim_left_p, trim_right_p, trim_qual_left, trim_qual_right, trim_tail_left, trim_tail_right, trim_ns_left, trim_ns_right, trim_to_len, min_len, max_len, range_len, min_qual_score, max_qual_score, min_qual_mean, max_qual_mean, min_gc, max_gc, range_gc, ns_max_p, ns_max_n, noniupac, lc_method, derep, seq_id, seq_case, dna_rna, out_format GRAPHS VERSION -------------- The graphs version is a standalone perl script (prinseq-graphs.pl) that generates graphs and HTML report files. The input is generated by the lite version. The used modules are: Getopt::Long Pod::Usage File::Temp Fcntl Cwd JSON Cairo Statistics::PCA MIME::Base64 Due to issues with the Statistics::PCA module on certain platforms, a graphs version without this module is additionally provided (prinseq-graphs-noPCA.pl). To run the graphs version, you can either use "perl prinseq-graphs.pl [options]" or rename the "prinseq-graphs.pl" into "prinseq-graphs", add the execution mode ("chmod +x prinseq-graphs") and use "prinseq-graphs [options]". If you have trouble installing the required modules or want to see an output example report, upload the graph data file at: http://edwards.sdsu.edu/prinseq -> Choose "Get Report" WEB VERSION ----------- The web version runs the lite and graphs version in the backend. Therefore, all dependencies for those apply to the web version. Additional Perl modules required are: CGI File::Path IO::Uncompress::AnyUncompress LWP::Simple File::Copy File::Basename SETUP: 1. Copy the files in the html directory to your html directory 2. Copy the files in the cgi-bin directory to your cgi-bin directory 3. Change the forwarding URL in the index.html file in the html directory. 4. Adjust the config file (prinseqConfig.pm) if necessary (defaults should work on most systems). 5. Example data is commented out. If you want to show example data, process data using the web version, put the example Data IDs in the config file and uncomment the code in the 'access' function to show the example data in the interface. 6. Use Firebug (http://getfirebug.com/) or similar to find any other issues such as links and change them according to your system setup. 7. Setup a cronjob (or similar) to clean the output directory and store the data for the stats in the archive directory. 8. To update the web version with a new lite or graphs version, simply replace the files in the cgi-bin directory with the new ones. Note: The image files are by default written to a directory which your Apache is configured to execute files from (cgi-bin) and is therefore trying to execute image files. Search for a file called "httpd.conf" on your web server. In that file, you have to specify that images should not be executed. Here is a copy of this part from my config file. The important line starts with "AddHandler" and all file extensions specified will not be executed. ScriptAlias /cgi-bin/ /var/www/cgi-bin/ AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch AddHandler default-handler .html .jpg .png .gif .zip .gz .fasta .qual .fastq .txt Order allow,deny Allow from all BUG REPORTS ----------- If you find a bug please report it at http://groups.google.com/group/EdwardsLabTools/ so that we can make PRINSEQ better. MAILING LIST ------------ If you want to receive emails for new releases and updates, please sign up for the mailing list at https://lists.sourceforge.net/lists/listinfo/prinseq-news COPYRIGHT AND LICENSE --------------------- Copyright (C) 2010-2013 Robert SCHMIEDER 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 . prinseq-lite-0.20.4/example/0000775000076700007670000000000012240000655016034 5ustar rschmiedrschmiedprinseq-lite-0.20.4/example/example1_qd2.png0000664000076700007670000003447712240000123021031 0ustar rschmiedrschmied‰PNG  IHDR™mLDqÀbKGDÿÿÿ ½§“ IDATxœíÝ{tõÝÇñφ$ Ø@‚´Š@½¢B[À&„ Š(ö‘VÀhÖÁnyÀ×j}P° <4Ø¢P¼µID@ÁV„ƒ!Q‘™ç<rÛÍN2»3³û~“svó›™ï\vö›¹|×g†!ÀFqN€èC’ Û‘dÀv$™°I&lG’ Û‘dÀv$™°I&lïtÍ6n ­ßõׇ76uª½ýIšâj?/âL&¸XFF†ÆW©m„ ÊÈÈ0ß1"äéÍš5K;vìiºNèÑ£‡£ó·jëÖ­ÊÌÌÔàÁƒuûí·kÇŽæ°ŒŒ eff*33S¯¾úªÙ¾téÒJÓu™«ŽªÇÜŒcàÀêÝ»wXâs«ªËSñóâæe³û3Ú«W/óµ•cF}p&\¬Aƒ:zô¨Ž;¦fÍšé믿ÖW_}¥ÄÄD³•äãßÿþ·&MšÒtQ»””Í›7OÍš5Ó| iӦ饗^’T¶íV¬XQmœgŸ}¶N_òuï¾ûî3_¯\¹R»wïK|v(--U\œ½ç¿ª.O]“õH çg4Rë€3™àr7Üpƒ6þÿu÷7êú*×Ö+žéÑ£‡ž{î9 >\·Ür‹þùÏšÃöîÝ«‹/¾Øü¯mºk×®ÕðáÃ5dÈÝqÇÚ¹s§$içÎ2dˆJJJtòäIýæ7¿ÑþóŸJã>õÔSzñÅÍ÷Ï<óŒ–/_tºUU=ËTñḺcÇ4nÜ8 ùä“k/¼.¹ä5kÖL’tÕUWéèÑ£Aû/X°@§NRff¦ü~¿Ùh›ïСC1b„¬‘#GêСCµÆ»aÃõë×Ïöø¤²íõä“O*33SC‡ÕÁƒÍaÁ¶W=4oÞ< 6LÛ¶mÓ±cÇ4~üx 4HC† ÑÖ­[CšFM1Ö´<Î^ºeŸª¨¶Ïh°˜<¨¡C‡*33SO>ùd¥ñ*®ƒ`ŸÇ`Ç“Pd€Ëõë×Oëׯ—$½öÚkêß¿À¾gÏžU‹-´lÙ2Íž=[sçÎ5‡åååUºÔVÛt{õê¥eË–);;[S§NÕ#<"IºâŠ+Ô³gO=ýôÓš;w®nºé&]rÉ%•ƽþúëõÆo˜ïßxã ó 2Ðt­ÈÊÊÒ°aôråJM›6M³g϶< »­Y³FÝ»w7߆¡ÌÌLýþ÷¿×Þ½{%IøÃÔ°aC­X±BYYY’‚o³r5÷ØcéW¿ú•V®\©[n¹E=öXÐø<¨ƒªK—.¶ÇWÞ¯uëÖZ±b…n»í6s|)øö:{ö¬.¹ä-_¾\]»vÕc=¦Ÿþô§zñÅõ·¿ýM:ti5ÅXÓòâÆ}ª¶Ïh°˜³²²tÛm·iÅŠjݺµJJJjœG°Ïc¨Û>.—€ËµhÑB7ÖÛo¿­Fé‚ .Ø×çó™É\ÇŽUPP`ËÏÏ×”)SBžî¾}û4þ|;vLñññúòË/Ía¿ûÝï4|øp%&&jâĉÕâh×®Ž;¦‚‚}ýõ×jÒ¤‰9ý`Ó Õû￯}ûö™ï‹‹‹-OÃN»wïÖòå˵hÑ"³míÚµJIIѺuë4cÆŒ€—(ƒm³`¶oß®Y³fI’n¼ñÆjg«ªÚ¸q£úôécžÉG|7ÜpCñÔ¶½®»î:óõæÍ›õÐC™óNJJªuu]‡¹mŸ’jÿŒ‹¹êþñè£Ö8`ŸÇú®W’Lð€›nºIÓ§O×½÷Þ´_\\œâã«Ú¿ÿþ{8qBiii!O÷¡‡Ò´iÓÔ©S'•””˜ŒHÒ7ß|£ï¾ûNgΜѩS§tÞyçU¿OŸ>zóÍ7uôèQ3ù¨mºU†!ŸÏ§³gÏêìÙ³f{ii©–.]ªF]‘pøðaMžCŸÏgyáŽÑIÁ>£vÄìóXßõÊårð€Þ½{kذaêÓ§OÆßºu«y™4Ôé~÷ÝwjÑ¢…$éå—_–aæ°™3gêü£n¼ñF=õÔS5Îóúë¯×Æõæ›oVš~°éVÔ²eKóþ°7VJ2»uëf>`#ɼÜiÅÅÅš0a‚Æo^Ö•¤ãÇ›ËõÏþS­[·6‡%$$èÔ©S–çUu¼Î;›÷ë­_¿^:u 8îgŸ}¦ï¾ûNW^yeØâ“dƳaÃuîÜÙl·²½®¹æýãÿTöOFùÙ¹ºnóP—Ç-ûTUÁ>£Áb®¸lذ!àç,ÔÏc]d€4nÜXwÝu—7n\§ñ«ÞÊtÇŽk^ÿöÛoͳMkÖ¬Qbb¢úõë§»îºKü±¶lÙRmüÿøÇ*..VË–-͇c‚M·ª{ï½W“'OÖðáÃõå—_Vê7qâD½ÿþû4h ¤×^{Íò:±ÃK/½¤ýû÷kÁ‚f9 ÒÒR½÷Þ{UU°Ïh°˜ÿô§?iåÊ•ÊÌÌÔÞ½{~ÎBý<օϰ3eTâ–bìwÜq‡žþùˆ\–õŠ±Û£Gz÷ÝwÃ5(ÆN’ l@’‰ª»\þè£êšk®©ÔvâÄ 3FC† ÑØ±c]ñd¨ &ªr$ÉüðÃuüøñj×ý/^¬nݺ);;[]»vÕ’%Kœõñ$³¤¤Dsçέñܼ¼<ó—ú÷ïo¹²<Ü!âw€/X°@¬ô¤a¹#GŽ˜5ÆRSSUXXh«Xz£ü'¦àNM2wîÜ©]»viܸq–Ç­˜XÙ@LKNN¶}š½\¾}ûv}öÙg0`€  ï¿ÿ^ Pii©$)--ÍüÉ¢ÂÂB¥¦¦F2<ØÄÑFUË<þøãJMMÕðáõlÙ2;vLãǯ6g2ìãù3™µ5j”ù+›7oÖÈ‘# uàÉbìœÉ°OÔŸÉ@t É€í"^'Ó.›6%+1±ìJ÷îüüd¸ZÏVÛ@lñl’™˜hÄD@ õlµÄ.—Àv<]ãxºž@’ Ûy6ÉÌÍMr:„˜h=[m±Å³O—#¸ŠÉO{€H#ÉŒb$—À)ž½\÷¢„Q”ÊÍMâL&I8J‘dÄ8êdÀ<›dR*'2(aê³I&‚#ÙNŠºF›6%+1±ì6ÓŠ¾x¥=ÜœŠÇ©õæÔtܶÿ¸-ΪíYYÕïJO7ÌqÜg]Û E]’™˜hÔxp÷J{¸9SëÍ©é¸mÿq[œ5µ§§Ÿ{1?ßçxÓ5+óD; ºxör9‰Udð€ºðl’ˆÕ$Ç®$ÊmÉX´Æîíku:ឯÕéÛÕßmÜö9åŸ,¨]Ô%™^Ç—êƒýàžM2¹+2xºÔ…g“Ì@¼^Å.ÑÛJ…{¾V§oW·qÛ甲 vQ—dzý^5·}©qùÞ­g’€[DM £Šõ÷ÊU,•j’¤2ÖO~¾ÏR{¤Öç¦MÉJL,ÛÞѼ Ùo^áÙ$³¦/Õªõ÷jcµ¬ ´~¬¶GBbbì$Zì·/ˆºËåvñz©“h‡FuãõÜm%‰Ü¶}ÀH2]†/µºa=”a=ܳI&8¸—g“Ìpóz©“h‡FuãõÊÜV’ÈmÛ܈$ÓeøR«ÖCÖÀ-<ûty¸T,“Ÿ_öÚï/r*ü?¶Klb»€wyöLf8pHO7Ì?‰³CnÁv‰Mlwð&Ï&™NñJ©â±wú”0r'·•*ŠÖõ uA’é2|©Õ ë¡ ëàžM2¹dà^žM2â•R'Äcïô)aäNn+U­ëê‚$ÓeøR«ÖCÖÀ-<›drïYpn[?n‹„—çêdN*IÉ•ÚÊK› r]Áréé†cIžÛâ‘á¹$SªœTæçû":o/”: ¶~b-J9;ßps[©¢h]ÏPž½\­øR«ÖCÖÀ-H2`;’L‹¼^ê$Öâ¡„‘³ó 7·•*ŠÖõ uA’é2|©Õ ë¡ ëà$™°'Ÿ.wBÅR<ùùe¯ýþ"ÏO?Üó w(C #ˆ’LàK µ©Z'q¹¶#É´ ¥N¼…F±‰F9Ž\.ñŵjÕ*ù|e—ôÆŽ«îÝ»K’Nœ8¡É“'«°°Piiiš3gŽ’’8pú‰I»zÀŽœÉ¼ù曵råJeggköìÙš6mš9lñâÅêÖ­›²³³ÕµkW-Y²Ä‰PŽœÉlܸ±ùú»ï¾Ó\`¾ÏËËÓüùó%Iýû÷×èÑ£5nÜ8uéÒE’tóÍ[Í3 åÊß;Ñ^~–µâë@}jk·kúnZ?nk¯m}¾þºO}ûÕÆsKü´;ÿ9­K;Ä"Çž.ÏÎÎVvv¶Nž<©gžyÆl?räˆÒÒÒ$I©©©*,,”$mݺU’4uªd“ßÿ¿÷9Ò^\\v©:#C*®áªuèíÉA§oIæëŠª·×<§ÖÛÚ§M;—€ä啽öû‹*•ªØÎúŒŽö@Û½\ý?¿ÁÛÀí’“«—«/Çü2dˆV¯^­qãÆé‘Gq* Ï „‘}ÒÓ óO:÷°F vD¶/D–ãO—÷ë×Oÿþ÷¿Í÷iii*(($*55Õ©ÐPGŽ$™4_¿óÎ;jÛ¶­ù>##Cëׯ—$­[·N¯.(ux%ŒÀ~ŽÜ“ùüóÏkûöí2 C?øÁ4uêTsبQ£4iÒ$½úê«JMMÕœ9sœÑu(a¼Ä‘$sòäɇ5mÚTO?ýt£€Ý¿'ч$Ó&VŸþæ7àv}~ù\À9ŽÕÉ„5|©àMYYÉÊÉ™j¾ïÕkªY£Ù-í± I&@ùýEòûýZŠ\ØEÅØ£ ¥NØ$Ó#øR^B’ Û‘dÀv$™6¡Ô à]”0ûñty=eeUËï/ Kÿüüd³ v7 É´Azºa¾ÎÏ÷Õú{â5õ·:ýºL R¸\f$~€ûQÂìG’ Û‘dÀv$™°If˜QÒp?J€ýH2`;’LØŽ$3Ì(i¸%ŒÀ~$™°I&lG’ Û‘d†%M÷£„Ø$¶‹¯ÏÈEEEjܸ±ââÈU«ÊÊJ®Öæ÷9 @äYÎÏœ9£x@Í›7W“&MôÙgŸI’¦OŸ®Å‹Û —¥§æŸDyÀ­(aö³œdN›6MûÛß4oÞ<5jÔÈl¿üò˵téR[ƒ€7YN2—.]ªE‹éöÛoWƒ ÌöŸýìgú׿þekpð&ËIfAAÚµkW­=!!A%%%¶o³œd¶iÓF;wî¬ÖþÎ;ï¨}ûö¶‘D #°Ÿå$óž{îÑøñ㕟Ÿ/Iúꫯ´bÅ M˜0AcÆŒ±=@xåFãÆÓ×_­ë®»N'OžT=Ô¨Q#Mš4I¿ûÝïÂ#<ÆR’yúôimذAcÆŒÑĉõñÇ«´´T;vTrrõº€Ý^xaš$iÿ~)=}ŠÃÑÀëjªg›žn˜—½ss“j¼nµb‘¥$3>>^Ôž={”ššª®]»†+. FC‡–%–ùù>I†³Á *”×±•Ê÷+€,Ý“éóùtÕUWiß¾}a ÑÀòƒ?3fÌÐøñãõÊ+¯èàÁƒ*,,¬ôX~ð禛n’$ 0 Æá†Á%LÑFPw–“ÌM›6…#DËIf¯^½Â¢‰å$³¢S§NI’6lhK0@]*mDÉ#ÔG¨¥Šj*…ä÷™Ãrr¦ší½zM•ß_övpZ’ÌgŸ}V<òˆvïÞ-Ijß¾½&Mš¤;ï¼ÓÖà€P*mDÉ#DJÕRH剨ß_$¿ß_¡gYîvpšå$sñâÅ3fŒî½÷^]{íµ’¤·ß~[wß}·JKKõÛßþÖö à-–“ÌÇ{LóçÏ×È‘#Ͷþýûë²Ë.Ó#}º–-[V­ý¹çžÓÌ™3m Þf9É\°`®¸âŠjí:tЂ l Ü€FPw–“Ì‚‚‚Kýð‡?ÔáÇm Þf9ÉlÕª•òòòªµçåå©U«V¶o³üàÏï~÷;=Z'OžÔ/ùKIÒ[o½¥ûî»O'N´=@p %Œ î,'™ÿýßÿ­£Gêî»ïVII‰$©aƺ÷Þ{I2D…¬¬dóu~~Ùk¿¿È©pÀ“,'™qqqÊÊÊÒ”)SôÉ'ŸH’®¸â %''×2&xGzºa¾ÎÏ÷qö,ªsÌ&Mš¨[·n’¤“'OÊ0 ù|>Û€wY~ðç‰'žÐ+¯¼"I:{ö¬n½õV5nÜX_|±¶mÛf{€à6œÑ€ÚYN2{ì1]xá…’¤U«VéwÞÑßÿþwõîÝ[cÇŽµ=@xåËå‡VóæÍ%Ik×®Uff¦~ó›ß¨sçÎêØ±£íÀ{,ŸÉüÑ~¤+Vè£>ÒÚµkuà 7H’Μ9£óÎ;ÏöÀmrs“œ\Ïr’9iÒ$ÝÿýêÔ©“Ú·o¯~ýúI’Þxã uéÒÅöà=–/—ßsÏ=êß¿¿Ž=ªÎ;+>¾lݺuÓu×]g{€ë²²’•“3Õ|ß«×TùýEžià}u*aÔ¶m[µmÛ¶R[y9#€óüþ"ùýþ -Ežjà}–/—@¬£„ÔŽ$¶«ó/þÔÕÖ­[õøãëìÙ³Š‹‹Ó¤I“Ô©S'IÒ‰'4yòd*--MsæÌQROqxå3™ãÆÓG}T禤¤hÞ¼yZ¹r¥þüç?kÚ´iæ°Å‹«[·nÊÎÎV×®]µdÉ’:ÏÂ…FP;Ëg2·mÛ¦§žzJ]ºtѨQ£tûí·«iÓ¦!É%—˜¯¯ºê*=zÔ|Ÿ——§ùóçK’ú÷ï¯Ñ£Gkܸq’d–Gºùæ­Õ~#½ü=í´ÓN{8Û˯¬T|]u¼šú@,²œdæææj÷îÝZºt©¦M›¦ûî»O¿ùÍo4räHõìÙÓÒ´Ö¬Y£îÝ»›ï9¢´´4IRjjª Ía[·n•$M*†Qa*¾ÿï£Ýƒí/¼Pv&{ÿ~)=}J­íឯÛÖO¸×g´¶‡k=—=ðcIæë2ÉAû€Û%''Û>Í:ݓٮ];=òÈ#š5k–Ö­[§¥K—êºë®SÛ¶m5räH1ÂLÙ½{·–/_®E‹Õ)pD‡¡C§H’òó}’ŒZÛÃ=_¯³º>£µà¼z=]^RR¢o¾ùFß|óJKKuÑEéÙgŸU›6mô /ïðáÚŸO_}õUµöÂÂÂjuâ›lûYIÃ0çüO¡W¯›çÎþ´»“—÷Ÿ²2>çtï^¬üüÀuÏ¢¹¿]ûa¸û#°¬¬dåäL5ß÷ê5U~‘'Úk’žnp‹bNÈIæñãÇÍ×ß~û­5jd¾/--Õ«¯¾ª .¸ÀÞèêÀjÝ<§úÓîN^Ýüþ"I¡ß+íýíÚõ£Wös/ðû‹ä÷û+´y¦=++Yééç¶Õˆ€Xr’™’’b¾n×®]}þò—¿Ô?"x^ÈIæ¦M›$I½{÷ÖªU«Ô¬Y3sXƒ Ô¦MµjÕÊþ„Ìêå¸X눜“Ì^½zIªú»á{(aµ )É,,,TóæÍåóùTXX´/? €OKKÓáÇÍ×Áþ8'77‰þWéLæ¦M›Ì{0ËïÍtšÛJ‘PºÄ;=鬽b‰’@%ƒ"ÙߊXë_¡~~³²ÊJ$UÜ^¯¼âбŽïĺ’Ìòû1«¾v’WJÍÀ]•¾éÞ]AÛÓÓ§Th/v¼¿WJ Eº]Yùü¦§•þÈÍåóŽšñ½€Xò=™¡âžL„”dZ¹×’§Ï縭dÛú"'ä{2h(9ñz{ ±Öà<Ë÷dµ ©„QM ÃЉ'tüøñJœã¶’An눜ñ§Ü×_­±cÇjõêÕ*.®~ ‹{2ážVÔ¾iS²ËöíŠÃÝÖ?Xëpžå$óž{îÑǬ^xA·ß~».\¨Ã‡ë©§žÒÌ™3ÃcÄU­Ë×½{±òó“¶Û5}úïoG{]õî]DôwÛþŒØèø“••\©Îj¯^Så÷Em;b›å$óÕW_Õ+¯¼¢=z¨AƒJOO×e—]¦Ë.»Lýë_5|øðpÄ1êòÙU¯Ïmu½Òß®vD7·íψMÁ’+¿¿H~ÅþEQÝŽØfùžÌï¿ÿ^mÚ´‘$wÞy:vì˜$©sçÎz÷Ýwm €5n{ÊÛmý‘c9ÉìСƒöìÙ#Iºúê«õÌ3Ïhÿþýzúé§•’’b{€N±«tŒÕéÓ?xJ!lpžåËå&LÐ$IÓ¦MÓ7Þ¨¥K—*>>^‹/¶=@xå3™wÞy§† &IúÅ/~¡ýû÷+77WŸþ¹î¼óNÛ:·• r[@äXN2kª‹yÅW¨qãÆQU'3З—]_jnûòõJÿp·oÚ”¬Üܤãu[ÿ’ýå¾ýb‘åËåµÝw‹u2«–ª¨­Ýêtè9‰‰†¥ûíèïþѰ^cG)¤šPÉ,'™UǼ´´Tÿþ÷¿5wî\M:Õ®¸<#PI“îÝUc»ÕéÐ?²ÜöÀýíé-û'à5v”BÊÊJVzú¹Xùù>>›a9ɬéwÌùË_êÒK/Õÿþïÿš÷k vÕù·Ë«êСCTÕɤ„‘;û;UªÞâ¶ýb‘å3™………ÕÚ 4}útµjÕÊ– ¼(Zë.º­?PìŸ9–“Ì´´´€íûÛßê¼ÏòåòM›6UúËÉÉÑ| èºë® GŒŽ „‘;û‡»ÑÁmû3Ä"ËIf¯^½Ô«W/eddèç?ÿ¹®½öZýä'?QBBB8âó »’ú— Tÿ0Üíˆn$“9–.—kæÌ™ÊѨ¥ÖèIDATÎÎÖ¾}û$I]t‘¬‡zH矾$éÌ™3Š·|%0õî]s ´p·{„œ ~ûí·êÙ³§¾ùæýáÐÕW_-IÚ±c‡,X W^yEùùùÚ¾}»¶mÛV¥ÎbIÈIæŒ3” ýë_JNN6Ûo¼ñF=Z½{÷Ö¯ýk½÷Þ{Z´hQX‚$J9Û¨ögp^ÈIæßÿþw=óÌ3•ÌrM›6Õ¬Y³Ô¯_?͘1CwÜq‡­Az%Œ"Ó¨öOˆœü9xð :tèpx‡§|ЖÀà]!'™))):pà@Àá_~ù¥Z´haKPn@ #gûõÁþ Î 9ÉìׯŸæÌ™#Ã0ª +--ÕìÙ³Õ¯_?[ƒóJE¦?PìŸ9!ß“9mÚ4uíÚU×_½î»ï>]uÕU’¤>úHÿó?ÿ£>úH[·n [ ðŽÏd¶iÓFyyyŠ‹‹ÓM7ݤV­Z©U«Vºù曯¼¼<µnÝ:œ±À#,UL¿ì²Ë´aÃ=zTŸ~ú©ÙÖ¬Y³°ç$J9Û¨ögp^~–§yóæjÞ¼¹Ý±x%Œ"Ó¨öOˆË¿]Ô†$3J9Û¨ögpI¦M(a™þ@}°@ädÀvuzðÇiùù¾Jï»w/V~~²-íPO 2Ï%™S§JEEEÊÍMªt÷û‹$©Þíå(aäl >"½?×v<€XÄår›PÂ(2ýú`ÿ€Èñl’i5© ÷™Iàxçx6É 7J9Û¨ögpI¦M(a™þ@}°@äx6É´šÔ…ûÌ$p<€s<÷t9ˆ=/¼0M’´¿”ž>Åáh ’Ì(aäl >ØŸè3thYbYV“Öp6„ij—Ë݆F‘éÔû'DŽg“LJpŽ'pŽg“Ìp£„‘³ýú`ç‘dÚ„F‘éÔû'DŽg“LJpŽ'pŽg“L¸If”0r¶?PìÏà<’L›PÂ(2ýú`ÿ€Èñl’I #nÃñÎñl’n”0r¶?PìÏàå—ËÄíhOL4ø’<*Ðç7ÜíÉ%”sÝ=™×^{­rrräóù$I¿üå/õÖ[o9UätéÒ¥RBíXÞèÆòF7–7º±¼¨/×Ý“™––¦‚‚IRaa¡RSSŽV¹.ÉÌÈÈÐúõë%IëÖ­SFF†ÃÀ*×].ÿöÛo5iÒ$=zT©©©š3gŽš4iâtX°ÀuI&¼Ïu—Ëà}®+aK¶nݪÇ\gÏžU\\œ&Mš¤N:I í—¼îÑGÕªU«´yóf³-Z—{áÂ…zóÍ7e†n»í6 4HRt.ïÛo¿mÖºõù|ºçž{Ô³gOIѳ¼ .ÔÚµkUPPPiÿ•‚/£W—?ÐòFë1,Øö-Mǯږ7ÚŽ_Á–7Ž_eÀ1Ÿ~ú©qôèQÃ0 cÛ¶mÆ­·Þj{üñÇçŸÞ0 Ãxþùç¹sç:c¸|ðÁÆäÉ“_üâ•Ú£q¹W¯^mL™2Å8{ö¬a†ñõ×_›Ã¢qyûöíküç?ÿ1 Ã0öíÛgÜpà æ°hYÞýë_Æ‘#Gªí¿†|½ºü–7ZaÁ¶¯aDßñ+ØòFãñ+ØòÆÂñ+’¸\î K.¹DÍš5“$]uÕU:zô¨9,//Oýúõ“TöËGÿüç?‰1JJJ4wî\ùýþjâq¹_~ùeýö·¿U\\ÙÇí?ø9,—÷¢‹.20áĉúÑ~d‹–å½òÊ+ͨ*Ø2zuù-o´Âmßh<~[Þh<~[ÞX8~E—Ë]bÍš5êÞ½»ù>Ð/Eƒ hàÀæ—SEѸܟþ¹^{í5åää(%%E÷ß¿Zµj%):—wæÌ™5j”|>Ÿ ÃТE‹ÌaѸ¼U[Æh^þX9†qüâø%EÏò†g2]`÷îÝZ¾|¹&L˜àt(a·sçNíÚµK·Ür‹Ó¡DÌÙ³gÕºukeggëÖ[oÕôéÓ)¬}ôQ7N¯¾úªÆ¯Ç{Ìéf±r ãøÅñ Öd:ìðáÚÊÌÌÔúõëµvíZ­]»V5ÒÚµkÍû}¢q¹322ôþûïK*{÷â‹/®4,Ú–÷¢‹.2—wóæÍºð ÍaѸ¼U[Æh[þX;†qüâømËncwÐòåËõÌ3Ϙ÷·HÒ /¼ ¸¸¸˜ùå£=zèÝwß5ßGãr顇Ò” )S¦èòË/—ËûñÇë/ù‹JJJ”˜˜¨x@;v”=Ë;oÞ<­[·NJKKSÿþý5fÌIÁ—Ñ«Ëhy£õlûV-ǯ`Ëǯ`Ë ǯH"É€í¸\Û‘dÀv$™°I&lG’ Û‘d1,''G>ŸOÇwE¡üL›•¾‘Š)œÓ¨ÍŒ34tèPËã…;¶Hm'«ìŽëg?û™þñØ2- Úd*ÿÂ+ÿ;ÿüóÕ¯_?íܹÓéÐ"*##C‡RóæÍ%O~«öTLntìØ1eeeéÁ4ÛªîSçwžzöì©?ü°Ò¸á^>§ÖßĉÕ±cG%&&*55UwÝu—Ž;¶ùÝÿýz衇D5@ :’LÀ>þøc:tH›6mRii©ètH•˜˜¨–-[ÊçóÙÚ7R19eÉ’%êØ±£Ú·o_mXù>µeË%%%Uۧ½|N­¿;vhúôéÚ³gÖ®]«-[¶èŽ;îÛü  Ã‡ëõ×_Û<¯"É\ E‹jÙ²¥~úÓŸêOú“vïÞ­ï¿ÿ¾RŸ'Ÿ|RíÚµSbb¢.ºè"=üðÃ:{ö¬9üùçŸWçÎÕ°aC¥¤¤hèС•Îž9sF~¿_iiiJJJÒ-·Ü¢/¿ü2h\ågÅÞxã edd¨Q£FjݺµæÍ›W©ß™3gôàƒªU«VJLLT»ví´dÉ’J}.\¨‹/¾Xñññºð õÄOT›Où%ÌÞ½{K’RRRÌ3rú†2ïòq6nܨŸýìgjذ¡ºvíªÝ»w׺ìåó©Ë4Êmß¾=èú u=W•­_ýêW5+ß§®¼òJ3Fûöí«´OÙ±|V¶ių«ÿ*ªmņ ôë_ÿZ­[·VzzºfΜ© 6èÔ©S•úÙµMÕ¯_?­\¹ÒRœ@L08fÓ¦M†$£  À0 Ã8~ü¸1lØ0£C‡•úM™2Åh×®±nÝ:cÿþýÆë¯¿n´iÓÆ¸ÿþûÍ>Ë–-3Þ|óMã‹/¾0rrrŒ+¯¼Ò:t¨9|ܸqF‹-Œ5kÖŸþ¹±páB#55Õd|ýõ×Aã»ôÒKÍñ-Zd4lØÐXºt©ÙoôèÑFZZZÀ>{÷î5|>Ÿ1{ölcß¾}Æ–-[Œ5kÖ\«V­2$»wï6:d:t(`ßÚæ]qœŒŒ #??ßøä“OŒŸÿüçF¯^½BÞ6õ™Fmë/Ô~}ûí·†Ïç3Þ|óÍ q÷Ýwƈ#ŒN:Ùº|V·iùvíÚµ3 Ã0¶lÙbH2vìØt>UžšâªØ7”yWç­·Þ2ÛV®\iÄÇǧOŸ¶S]¦lýYéWÑ|`H2öìÙSã<Ë÷)ŸÏg´hÑÂxûí·m]>«Û´¢É“'_|±qøðaÃ0BßÇ7oÞl´k×.àþZÕñãǶmÛþóŸ«Åeç6Yµj•áóùŒ’’’âb—ËØ´i“¶mÛ¦§Ÿ~Z{÷îÕŽ;Ìaü±Nž<©¾}û*99Ùü1b„Ž;¦¢¢"IRnn®úôé£-Z¨I“&ºýöÛU\\¬¢¢"íÚµK%%%ºöÚk+Í·ü²tmªŽwíµ×j×®]:uê”víÚ¥Ó§Oרg÷îÝ:uê”:w]»ªgÏž6l˜þþ÷¿[¾ Z“Pæ]QÇŽÍ×-Z´Ð™3gT\\ližu™F°õW—~’Ìížœœ\ã<7mÚ¤íÛ·k×®]Zºt©þøÇ?jñâÅAã”B_¾ºnÓ_|QO>ù¤V¯^­-ZH }ïÖ­›víÚ¥üàµÎçÔ©Súõ¯­V­ZiƌՆ۹Mš6m*Ã0Ì8”‰w:RÛ¶m•ššªvíÚi÷îÝš0a‚  „„•––J’Ö¯_¯–-[V·qãÆ:~ü¸n¼ñF 8P3fÌPjjªòóóuçwVúâ¯ëCõ}x#>>^¹¹¹Ú°aƒÖ¯_¯»ï¾[+V¬ÐË/¿\¯éZWýÿjÃâSÁu™F¨ëÏÊz.O.Oœ8Qã~Q¾OIÒå—_®“'OjäÈ‘úío« œn¨ËW—múá‡jĈZºt©~ò“Ÿ˜í¡ìãVœ9sFC† ÑñãÇõÖ[o©aÆÕúعM¾ýö[ù|¾€ ?«8“ ¸Ì}÷ݧ˜µ÷:vì¨Fé‹/¾Ð¥—^Zí/..N;wîÔ‰'4cÆ ¥§§ë²Ë.Ó‘#GÌi¶oß^‰‰‰zûí·+Í+'''¤˜ªŽ÷Î;ï¨}ûöjذ¡:tè „„„j}Þ~ûm³$%$$èæ›oÖ¼yó´páB­^½Z'Ož¬q~åIPyòH¨óvZ°õW—~’t饗ÊçóéóÏ?)†¸¸88qBgΜ±}`V¶é‘#Gô_ÿõ_º÷Þ{5hРJÃBÙÇCUZZªáÇkÏž=Ú°aƒš6mZc?;·É矮¶mÛ*!!!ä8XÀ™LÀe.¾øb 0@O>ù¤n¿ýv%''kÒ¤I;v¬Îž=«ž={êôéÓÚ¶m›vïÞ­‡~XmÚ´Qƒ ôÔSOiôèÑÚ¾}»ž|òIsšM›6Õïÿ{ùý~¥¤¤èª«®Ò믿®çž{.¤˜¦OŸ®””]}õÕzýõ×5wî\ó)ÛªÓîÔ©“6nܨ¹sçê¯ý«$éý÷ß×û￯>}ú(>>^k×®Õ…^¨FÕ8¿Ö­[K’Ö¬Y£›nºI>ŸÏ<+WQ(óvƒ`ë¯.ý$©I“&êܹ³¹^«:räˆÎœ9£ÒÒR}úé§š:uªúöík[âmu›–?ñ}Ï=÷諯¾2Û[¶lÒ>^>ÏáÇë½÷Þ xÉü÷¿ÿ½rrr´nÝ:>}Úœ×\P鬤Ûäý÷߯vY€xºpR ‡#Þ|óMC’±e˳máÂ…ÆÕW_m$&&IIIF·nÝŒE‹™Ã—,Ybüð‡?45jd\wÝuÆsÏ=Wéá™’’c„ FóæÍóÎ;ϸñÆåË—‡ôàφ Œk®¹Æhذ¡ÑªU+cîܹ•ú>}Ú¸ÿþû /¼ÐHHH0.¿üòJ±íܹÓèÝ»·Ñ¤I#!!Á¸æškŒÍ›7]3gÎ4~øÃqqqFÅCUÕ¾µÍ;Ðôƒ=\TÓ8õ™Fmë/Ô~UÍ™3ÇèÖ­[Ó*ÿóù|Æ\`Œ5Ê8zô¨mËgu›VŒ©â_Eµíã¡<]h>åË`÷69uꔑ’’b¬_¿>`L@¬ò?S f999êÝ»· j<“{Ôu==zTmÛ¶Õ{ï½§+®¸"ŒÆžP·ÉªU«ôÀè“O>quá~À Ü“ Õ¼ysùý~ýå/q:”˜5kÖ,͘1ƒ¨÷d€‡•߯glÛ¶Íé×âr9lÇårØŽ$¶#É€íH2`;’LØîÿRî[¸-FÖyIEND®B`‚prinseq-lite-0.20.4/example/example1_td5.png0000664000076700007670000001626412240000123021031 0ustar rschmiedrschmied‰PNG  IHDR¨ú]ôwbKGDÿÿÿ ½§“iIDATxœíÝypUõýÿñ×ÍBB ˜@@–( P¤ÜbCAe@8Ek­–iu€)e‰Ñ!ÁÊ"¢AlÙE,ÁZ5ŠQ4 K‹A!PP. Q²’œß~s~„$pNò¹ÇçcæÎä~ÎÍyÞ„åÅY>ÇgY–%ÀAM=àlT…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £x* Îž=[7ÝtSSO—Á3uûöí***R³fÍšz*¸ ž¨ÊÌÌÔĉ›z*¸L!M=',X°@÷Þ{¯Z·n]ïö~ýúÙ_oÙ²¥±¦€KðuÏž=*((PJJÊy?sv(-..nŒiü,´lÙÒñ}ü)þ¼¼<*99YÉÉÉ*//Wrr²ª««›zj¸>˲¬¦ž„“’’’ôé§Ÿžw;GPœÃTxžçŽ þŽ 8‡#¨ð<*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q|–eYM=‰Æô3kÀU>ŸÏñ}†8¾GÕ””4õ<£eË–Žï“Sü0 F! À(PËÊʸI äZ@}á…ôî»ïJ’ªªª4tèPEDD¨K—.Úºu«[eà\ ¨Ï=÷œ®ºê*IÒÊ•+•››«7ß|SÔ¸qãÜ* €çÚ2SÇŽSLLŒ$)''G=ô~ûÛߪoß¾Šw«,œkGP;vì¨åË—+??_999ù¤®¿þzÅÅÅiÈ!’¤uëÖ©_¿~n•@€sõQ§ÐÉ“'Õ·o_…„üx5Á矮ÈÈHõìÙÓ­²T\\Ü$u¼È'I¹Pk+""BAAM¿ì*À9õ¨ÓÊÊJMžø ‚ƒƒíñ„„íܹӭ²p®T¿ß¯=zÔ UEE…[eà\ ¨±±±Ú³gOñÜÜ\ÅÅŹUε€:fÌ?^›6m’$=zTË—/WjjªÆŽëVY8×uš’’¢S§NéöÛoWYY™’’’®´´49Ò­²p®¯ƒZZZªÝ»w«ººZñññ®¬•Õ¬ƒ àœ€]¨ß$TçÔBýzíµ×ꌿúê«zæ™gÜ* €çZ@]°`zõêUg¼gÏžZ°`[eà\]õÊ+¯¬3Þ¡C;vÌ­²p®ÔÎ;kãÆuÆ7nܨÎ;»Uεe¦FŽ©Ñ£G«¬¬L·Ýv›$é£>Ò„ ôÄO¸Uε€ú׿þU'OžÔŸÿügûѦaaazôÑG ¨8/×—™:}ú´¾øâ IR¯^½XÀCrÔÊÊJ•””èÜ2QQQn–=/*€sjÔ‚‚ 0@Í›7WTT”¢££k½€ú¸v ê°aêýë_j×®[eà1®â S~~¾zôèáÆî/§øœP§ø{÷î­¢¢"·vr- Î˜1C&LÐúõëuüøq8q¢Ö ¨k§ø}>ß·»¼xÀyqŠÀ9nœâwí&©õë×»µkx˜ëë š†#¨Î ¨›¤ÎV\\¬êêêÆ(€çZ@­¬¬ÔäÉ“£ÈÈHJ’222´dÉ·Ê À¹PÓÓÓ•­ùóç+<<ÜïÞ½»²²²Ü* €çZ@ÍÊÊÒâÅ‹õàƒ*88ØOHHÐÎ;Ý* €çZ@õûýõ>E*44Tn•@€s- ÆÆÆjÏž=uÆsssçVY8×ê˜1c4~üxmÚ´I’tôèQ-_¾\©©©;v¬[eà\[¨?%%E§NÒí·ß®²²2%%%)<<\iii9r¤[eà\_¨¿´´T»wïVuuµâãã]Y̵!X¨À9nd;×jQQÑ·GEE¹Qö'PœãF@uíttô·ÿÌž° €‹äZ@]¿~}­÷ÕÕÕÚµk—2335mÚ4·Ê À¹~ ê¹V¯^­_|Qk×®m̲6ŽÜ8Ççó9¿ÏƨP¯^½TVVÖ˜em\ƒ àœ€ºõĉuÆü~¿222Ô¹sg·Ê À¹PÛ¶m{Þñììl·Ê À5ÚMR>ŸO­ZµRïÞ½êVY¸&[õl¹&*× 8' ®Aý©uPÏÆõ¨áZ@]¶l™&L˜ ‡~X ôãiÿW_}U/¼ð‚:uêäVi0×Nñßu×]º÷Þ{5bĈZã‹-һᆱwÞyDz?‰SüÎqã¿k5""BêÒ¥K­ñC‡©gÏž*))q£ìO" 8Ç€äøÿODD„vîÜYg|ÇŽŠˆˆp«,œkõü£†®×_]‡Ö¡C‡´lÙ21BúÓŸÜ* €çÚMR³fÍÒ™3g4|øpUTTH’š5k¦Q£FiæÌ™n•@€síÔßÿ½ $IqqqjÕª•›å~× 8' n’:[qq±"""äÚ š œP7IUVVjòäÉŠ‰‰Qdd¤ %IZ²d‰[eà\ ¨éééÊÎÎÖüùónwïÞ]YYYn•@€s- feeiñâÅzðÁl'$$Ô»ü ¹Pý~¿zôèQg<44Ô¾«8—k566V{öì©3ž››«¸¸8·Ê À¹PÇŒ£ñãÇkÓ¦M’¤£GjùòåJMMÕØ±cÝ* €çÚBý))):uê”n¿ýv•••)))IáááJKKÓÈ‘#Ý* €çú:¨¥¥¥Ú½{·ª««ïÊZY Á:¨Î Ø…ú%©ªªJ••• kŒrçE@pN@,Ôÿþûï+;;»ÖØ /¼ ¨¨(5oÞ\wß}·¾ÿþ{§ËÀ#¨3fÌßï·ßoÙ²E=ö˜žxâ ­ZµJû÷ï×´iÓœ. püLLŒ>üðCõíÛW’4qâDåççkíÚµ’¤÷Þ{O)))Ú¿¿“e/§øœ§ø‹ŠŠÔ®];ûýæÍ›Õ¿û}Ÿ>}tøða§ËÀ#¨QQQúæ›o$I•••Ú¾}»~ùË_ÚÛËËËâÚêVpŽÔ(==]ÔóÏ?/IµŽ æçç«[·nN—€G8~(sæÌ™8p ®¾újù|>½øâ‹ŠŒŒ´·¿ùæ›JJJrº,<•uPËËË•——§:¨k×®µ¶mذA×\s:tèàtÙ‹ÂMRÎ è…úMA@pN@ÜÅ\*ŒB@€Q¨0Š«5**Jt³<Æñ€š››«²²²:ã-[¶Ô¾}ûœ.q< Ž1BQQQºùæ›UZZª7ê‡~pº <Êñ€úå—_êСCzüñǬiÓ¦)&&F¥¥¥Z²d‰6mÚ¤3gÎ8]áøBý_~ù¥ºwï.éÇkPóòò¢ë®»NƒV~~¾Ž;¦’’'Ë^4êpŽ õ‡8½Ã~ýú)<<\‰‰‰*++ÓW_}¥Aƒ)88XsæÌѵ×^«¯¿þÚé²ðÇOñiݺu2dˆ|>ŸxàuîÜYåååzûí·uàÀuêÔÉé²ðÇOñŸ-**JÛ·o—ßïWÿþý• üü|EEEéðáÃn•½ Nñ8' NñŸËçóéÆoTHHˆ–.]ªØØXmÙ²Åí²P®Ô¢¢¢ºCBtóÍ7»YÌõ#¨58µ€‹áê£N€†" À(®ÞÅo¢ŸY»®òù|Žï³Ñ®A5ES=Á À‹r™)À…Í™S÷/÷‰¹±ÀÏ× À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒÒÔpÒéÓ§5iÒ$8qBmÛ¶ÕÌ™3Õ¢E‹¦žÀSGP—,Y¢o¼Q+V¬Ð 7Ü þóŸM=%4§êÆ5dÈIÒ]wÝ¥Ï>ûL’Ô¯_?û³yêÿñãÇÕ¶m[IR›6mtâÄ IÒ–-[ìÏ7ÉÜp‘,éß¿¿U]]m¿8p`½ŸKHH`œqÆgœqÆgÜÁq'y* Þwß}Ö±cÇ,˲,¿ßoÝÿýM2ÆøÁQ—ºÔ¥.u©K]êz•§®AMLLÔš5k$I«W¯VbbbÏ å³,ËjêI8åûï¿WZZšNž<©6mÚhæÌ™ŠŒŒlêi <PøIÒ¸qãtë­·JònÏ’4{öl­\¹²Öïi/ö›˜˜¨ØØXIÒþðÝ}÷Ý’¼Ùk… êÃ?”eYºÿþûõ»ßýN’w{ž;w®½Ôayy¹N:¥õë×{²ßO>ùD/¿ü²$Éçói̘1êß¿¿$oþ|÷îÝ«ôôtUVVªsçΚ>}º"""$y³ßFפ·há²íܹÓ:~ü¸õ«_ýªÎ¶¹sçZK—.µ,˲–.]jeff6öôµoß>ëäÉ“–eYÖÖ­[­¡C‡ÚÛ¼Ök’’ûëÂÂBkРAö{¯ö¼mÛ6kÒ¤Iu~O{±ßúþÜZ–7{µ,Ëzë­·¬©S§ZUUU–eYÖ©S§ìm^íùl+V¬°ÒÓÓ-Ëòf¿ƒ ²öïßoY–eø@wÞy§>øà=zÔÞæÅ~GPpöîÝ«eË–)55µ©§Ò(~ÿûßë­·ÞRJJŠfÍšÕÔÓqÍž={TPP {î¹§©§Òhrrr´|ùrýæ7¿ÑôéÓ›z:®«ªªR×®]µbÅ :TM=¥F³víZÝqÇöÑc/š={¶RRRôÞ{ïiüøñzî¹çšzJ®š2eŠV­Z¥x@ûöíSpppSOÉS¼û'jÛ¶­ü~¿$éĉjÓ¦MÏèò;vL“&MÒŒ3j]ÚàÅ^Ï5dÈíÚµË~ﵞóòòTXX¨ääd%''«¼¼\ÉÉɪ®®–ä½~%)::Z’4xð`íß¿ß÷b¯’Ô¾}{ 4H’tÇw諯¾²·yµçgŸÞ—¼ÙïöíÛuÇwHúñç»cÇ{›û½æšk´hÑ"½ñƺçž{Ô¥K{›ûmlTóÚ“µJJJ”ššªñãÇ«gÏžµ¶y­×Gޱ¿ÎÍ͵OKÞëù¡‡Òš5k”““£œœ…‡‡+''Ç>âäµ~‹ŠŠdýß2ÔŸ}ö™ºvíjoóZ¯5õùçŸKúqU޳ÿA÷jÏ’TXX¨ÒÒRõîÝÛób¿:u²¾›7oÖUW]eoób¿ß}÷¤/Õyå•W”œœloób¿…úÜüùóµzõjùý~µmÛVwÝu—ÆŽ+É{OÖZ¶l™-Zd_³&I¯¿þº‚‚‚<×k3f(//O–e)**ªÖuŠ^í¹FRR’>ýôSû½×ú]³f²²²$Iááázê©§Ô½{wIÞëµFqq±¦L™¢o¾ùF¡¡¡š:uªç{–¤üã²,K£G¶Ç¼ØïîÝ»õ·¿ýMjÖ¬™&Ož¬øøxIÞì÷?ÿù²³³¬þýûk̘1ö’€^ì·±P`NñÀ(T…€ £P`*ŒB@€z|üñÇòù|ö# Ï}¨.¥'z÷ʯ€ÆA@`”š sîkÅŠu>S_Ø©ï{Ï}]ŒÄÄD}ûí·Š‰‰iмM`5s)**rd ýµ€ËÒÔ€úìÞ½[­[·¶ßGEE]Ô÷}ûí·ö×7nÔ}÷ݧ½{÷ªU«V ªß¬Y3µoß¾AßãUüZhlA`¤víÚ©}ûöö+<<ü¢¾ïìï© ¸çîK’–.]ª¾}û*,,LÑÑÑ6lX­#Žn7ožzôè¡fÍš©S§Nzúé§UUUU§æÚµk• °°0Ýpà ڻw¯ý™ŠŠ ¥¦¦ªmÛ¶jÑ¢…†ªìììZGL(IŠŽŽ>ïQãmÛ¶·Æ¹Îw¹Ã…æy>yyyJLLTxx¸ºvíªùóç×[kݺuüo# 0RBB‚Z·n­~ýúÙuRPPæÎ«}ûöé­·ÞÒŽ;4nÜ8ÇëÔ˜6mšþþ÷¿ëÅ_Taa¡^}õU-[¶LO?ýtϦ§§ëå—_ÖŽ;¢Q£FÙÛ}ôQ½ñÆZºt©¾øâ %''+55µÖ÷¯\¹R’´wï^}ûí·µŽ*_L‹u)ûøË_þ¢I“&éË/¿Ô”)S4qâD½òÊ+—ü9e€A ¬… ZÛ·o·vìØa͘1ÃjÖ¬™5gΜïkýúõ–$ëÔ©S?ùÙU«VY-Z´°ª««k}¯ßï¯÷ýùjÕ·½¤¤ÄjÞ¼¹µqãÆZãË—/·Z·n]g}ô‘=öÆoX!!!Ö™3g¬ï¾ûÎ µ²³³kí'--­VŸêû§j\Lo—³×^{­ÖøO:sæŒfÍš¥Ç{̱:6lÐÔ©S•ŸŸ¯²²2UVVª¼¼\ÅÅÅŠŒŒt¬Žôãõ´eee4hP­ñªª*»fË–-íñøøxûëvíÚ©²²R%%%*((Й3gtë­·ÖÚORR’fΜ٠9¯ÆW\áê>~ýë_×y?{ölýðà kðçx§ø鍊n’ßïWii©#û+**ÒwÞ©N:éí·ßÖ¶mÛ´páBIªuM¨Sª««%IkÖ¬Q^^žýÚ¹s§¾úê+EDDÔú|PPÝ¿š-˲¿>÷šÒ‹]™ !5ÜÚÇÅÎõRzàTÆÛ¾}»Z·n]'È]ª={öèôéÓš>}ºn¹å]wÝu:~ü¸#û®O||¼ÂÃÃuèÐ!]{íµu^õ½úÄÅÅ)44T6l¨5þé§ŸÖz,éÿc“|òÉ'µÞçææ*..®ÎQÑ‹ýoâ?£Ì™3G½zõR¯^½T]]­Õ«W+==]“'Ov¬Fll¬‚ƒƒõÒK/iôèÑÊËËÓ¼yóÙ÷®]»ê,‰Õ§O¥¥¥iܸqªªªRÿþýuæÌmݺU{÷î­÷F©ú\qÅ>|¸&L˜ V­Z©wïÞúè£ì›‡jŽ:víÚU’ôÎ;ïèî»ï–ÏçS›6méïredd(::Z}úôÑ| ÌÌÌzïпØÏð&*£|÷Ýw;v¬¾þúk)..NÏ?ÿü%Ýe~>;vÔ¢E‹ôÔSO饗^Ò­·ÞªéÓ§ëᇾì}×,ñt¶Ó§OkêÔ©êСƒæÌ™£#F(44Tñññ9rdƒöŸ™™©°°0 6Låååºí¶Û4cÆ =òÈ#öR\]ºtÑ3Ï<£'Ÿ|RÇWuuuƒOß»eþüùzúé§•——§víÚiÖ¬Y>|ø%€7ù,SþÖ\’gŸ}V‹-ÒÁƒ›z*—íã?ÖÀå÷û9ê  ñqÈŽ;´sçNÝrË- Öºuëôì³ÏjÊ”)M=5p Lff¦F¥~øA±±±š2eŠüñ¦ž8†Sü0ÊÿÉ7¤ö¥?UIEND®B`‚prinseq-lite-0.20.4/example/example1_dl.png0000664000076700007670000002413712240000123020732 0ustar rschmiedrschmied‰PNG  IHDR¨ú]ôwbKGDÿÿÿ ½§“ IDATxœíÝyX•uþÿñ×A%PpI¬TP3.3+fÜrÉe°rÆ4+uÔ$³rÉt,—lÜ*÷­­üê„4æn騨Œä’6¦•¨˜ €ÂýûÃg@ QÏ çÜ<×Åuq>÷}î÷çs{Îáå½|ŽÍ0 C€“p+ëùPàT¨p*T8*œ N…€ §B@€S! À©PàT¨p*T8*œ N…€ §B@€S! À©PàT¨p*T8*œ N…€ §B@€S©PÖ€ut|eu‰ÖÛôNo“{b=ÓõT‰Ö{M3¹'Îáã'Û—h½Ÿo1¹'ÎaÞGûK´^TÏ0“{+k>xp‰ÖÛ·`É=AyÀT8ððpEFFÚ-ZäðK—.-ñºmÚ´¹ëz-[¶¼ëm8Bþ}›˜˜ho/iÿ¬´/$é£>R¯^½Ô»woõîÝ[_~ù¥}YyÜ'y¯^½zéÙgŸÕʺKç,ûZâs¨¼¿ÎJúy|X±±±Z¹r¥rrrÔ¯_?M›6M÷ß¿ôñÇ+;;[îîî?~¼5j$Iºpá‚bccuêÔ)¹¹¹iôèÑÚ·oŸ²²²©ÚµkkæÌ™j:uJ¯½öšrssõØcXÖ²eKíܹÓþ¸M›6Ú¶m›}Y=ôüCnnnš>}ºj×®mîŽqªU«Ùnõ}áíímÿýÊ•+ªQ£†ýqyÝ'yš7o®S§NÙ_¸pA“&MÒÙ³gU¡B½ñÆ ÕܹsU£F ûÎ… ªR¥Jêׯ_±Û.ê}Ù¼ys>}ZãÇWFF†*W®¬)S¦¨V­Z’nì¿^xAÛ·oWZZš^yå}÷ÝwÚµk—.\¸ W_}Õ~dçn÷uqcåsÈñÊóë¬8ù?{Ž?®{ï½WnnnåöóŠSüp999Nñ'&&ªQ£FjÕª•Þ{ï=Íž=[]»vÕý÷ß/鯛jåÊ•Z½zµ&Mš¤iÓ¦Ù·5cÆ 5kÖL}ô‘âããª!C†¨bÅŠŠ‹‹+ôGA’fΜ©=z(..NuëÖUvvv‰û]·n]ÅÅÅ©GEn»¬†¡ÈÈHýéOÒñãÇííû[Ñ׬Zy_äY½zµž~úi5JS¦L±·—ç}"I_|ñ…êÕ«g]sæÌ)°îÝìëâÆÊçã•ç×YI>wïÞ­ððpûãòøyE@…ÓÈ;í‘÷ÓµkWIÒ Aƒ´wï^}ûí·êß¿¿}ý~øAC† QÏž=5qâÄoô½{÷êü£$Éf³ÉÇÇç–õ÷ï߯'Ÿ|R’Ô¹sgÙl¶÷=ÿó’““Kü¼Ò’ ¸¸8=ýôÓšÜnÅ•÷ÅÍ:uêTî÷IÞsss5wî\-^¼X³fÍ’$åææjéÒ¥òòò*ô¼öíÛkëÖ­:þ¼ýÚ¯¹“÷¥›››<<<ì===åæfα•_+ŸCw×Ù ·ú<ÎÌÌÔåË—XhYyú¼â*œÞ”)S4tèPuîÜYsçε·_¹rEÕ«W—$­[·N†aØ—=úè£úä“O$Ýx#fddH’<<<”••Ud°°0û…çŸþyíÕ¬YS‡–$mÚ´©Ð:ÿóœk*Ÿ´´4ûXvíÚ¥ºuëÞò9VÝyò_û¶cÇŽ§‹cõ}"Ýø#=tèP}÷Ýw:tè$©E‹ú¿ÿû?û:ùvìØQ›6mÒÖ­[Õ¾ý­§þ*î}™ßnܸQ=ôÐánöõ¯•Ï!Ç)ϯ³’|ïÛ·OÍ›7·?.¯ŸWT8›¯A5k–>ýôSyzzªS§NzþùçuèÐ!ýóŸÿ”$½üòË4hž{î9ýòË/òôô´o+ïf„ž={*22RGŽ‘$uïÞ]½{÷ÖèÑ£ Õå•W´fÍEFFêøñã¶7bÄ;VÏ=÷œ~úé§ËÜÝÝuâÄ EFFjõêÕzå•WŠ_YݵûüC½zõRÏž=µdɽñÆ·|ŽU÷Ež+VØ÷I||¼&MštËçX}ŸäñôôÔàÁƒµdÉIÒk¯½¦¯¾úJ={öTÏž=õ÷¿ÿݾî}÷ݧŒŒ Õ¬Y³ÀÍÅ¥¸÷åèÑ£µ~ýzõêÕKëׯ/òýYw»¯‹+ŸCŽW^_g%ù<¾ùúÓòúye3òÇjà.”׉úo¾#Ò ®2Qiì ɵ&ê/}ÂDý7”ÖëÏ•ÆØ™¨ÿ³÷õ³Ï>«+V¨B…Ò¿ Ó™ÞC\ƒ ‡±Zðt&e<3Ogbõà ç`õàé,þú׿–uœ‚¥Ž NŸ>]k×®ÕÞ½{˺+¸C–¹õßÿþ·ÒÒÒ \K×c‰€š­Ù³gßñÏp–¸õƒ>P÷îÝ‹ýʯüÓ5ìÛ·¯´º€;àòõðáÃ:r䈆^ì:ùCizzzit ÀrºOÜP¨ÍŒ›¤]þÿþýûuìØ1EDD(""B™™™ŠˆˆPnnnYw wÀå æMêž§eË–JHH(Ãàn¸üTX‹åª³|îŒå*\N…€ §B@€S! À©PàT¨p*T8*œ N…€ §B@€S! À©PàT¨p*T8*œ N¥TêÕ«WeFi–€‹1- ¾ûî»Ú°aƒ$)''GÏ<󌼽½uï½÷ê믿6«,\œiuÆŒúÍo~#IZ»v­vìØ¡?þXmÛ¶ÕË/¿lVY¸¸ fmøìÙ³ªV­š$)!!A‘‘‘úãÿ¨°°05nÜØ¬²pq¦A­]»¶âââôÍ7ß(!!AO>ù¤$éúõëªT©’YeàâL ¨cƌѸqãôÐC)$$D:u’$mÙ²EÍ›77«,\œi§ø‡ ¦.]ºèüùó S… 7JµhÑBíÚµ3«,\œiU’êÕ«§zõê)==]ÞÞÞrssS‹-Ì, gÚ)þëׯküøñªV­šªT©¢cÇŽI’bccµxñb³ÊÀÅ™Pcbb¯yóæÉËËËÞÞ A-]ºÔ¬²pq¦Ô¥K—jÑ¢EêÓ§ÜÝÝíí?ü°8`VY¸8ÓjJJŠ6lX¨ÝÃÃCÙÙÙf•€‹3- ëðáÃ…ÚwìØ¡³ÊÀÅ™P‡ ¦‘#GjÏž=’¤3gÎ(..NÑÑÑŠŠŠ2«,\œiÓL >\/^T»vítõêUµlÙR^^^3fŒ dVY¸8›a†™®\¹¢C‡)77W7VåÊ•Í,wKéééeZÀUuŸ¸¡PÛ¦wz;¼Ž©õK’···yä³ËÀ"L»Õf³éÌ™3…ÚSSSe³ÙÌ* gZ@-Žars+õ²p?ÅŸ––fÿý—_~)ð-R¹¹¹JLLT5]áð€êïïoÿ½¨‰ú%éÏþ³£ËÀ"P“’’$ImÛ¶ÕÚµkUµjUû2www+((ÈÑe`¨mÚ´‘tãZSàv™>Í”aJOOWNNNv???³KÀ™v;ýŋշo_U©RE¾¾¾ò÷÷/ðÅ´#¨Ã† Ó¡C‡ôᇪOŸ>Z°`Ξ=«¹sçjÊ”)f•½%Ÿ2« €[3- &&&jÆ jÙ²¥ÜÝÝõøã«~ýúª_¿¾Þÿ}=÷Üsf•þUeR%cÚ)þÌÌLK’*Uª¤ .H’´sçN³ÊÀÅ™PCCCõŸÿüG’Ô´iS-\¸P?þø£Þ{ï=®A@±L;Å­ŸþY’£Î;kéÒ¥ªP¡‚/^lVY¸8Ójÿþýí¿ÿîw¿Ó?þ¨Ã‡+88Xµk×6«,\œéó æñóóSxxxi•€‹2íÔØØX­\¹²PûòåËËtš)87Óê| Fj Õ|`VY¸8ÓjJJŠjÔ¨Q¨½V­Z:{ö¬YeàâL ¨AAAÚ½{w¡öÝ»w+((Ȭ²pq¦Ý$5hÐ ½ôÒKºzõªžxâ IÒ_|¡Q£Féµ×^3«,\œiõõ×_×ùóç5xð`eggK’*V¬¨#FPP,›a†™._¾¬o¿ýV’Ô¨Q#U®\ÙÌr·”žž^¦õ\U÷‰ µmz§·Ãë8ôjjjªªU«&›Í¦ÔÔT{û}÷Ý'IÊÌÌTff¦$) À‘¥` ¨:}ú´jÖ¬©ÀÀÀ_]×ä·pQ ¨IIIªZµªýwàv94 ¶iÓ¦È߀’rø5¨%Å5¨(ŠÃ¯A-)®A@Q~ *p7L»¸n¥Q$++KYYY¥Q .ÎÔ€ºdÉ…††ÊËËK^^^ Õ²eËÌ, gZ@3gŽ¢¢¢ôÔSO)11Q‰‰‰êÖ­›†ªyóæ™U.Ρנæ7sæLÍŸ?_/¾ø¢½­K—.ª_¿¾&Ož¬¨¨(³JÀ…™võܹsjß¾}¡öŽ;êìÙ³f•€‹3- †……éÀ…Ú“““Õ¬Y3³ÊÀÅ™vŠ?66VQQQºxñ¢Z·n-Ã0´}ûvÅÆÆêý÷ß/ð­S|«òØ “¾ÒÉf³•xÝÒüV©ôôôR«`%Ý'n(Ô¶éÞ¯cÚT¾U w´€Ê·JàN˜PÓÒÒ~u¹ŸŸŸY¥àÂL ¨þþþ¿º¼4¯;€ë(µkPsssuðàAÍž=[“&M2«,\\©^ƒúÄOèÐ_þòõë×ϬÒpa¦MÔ_œÐÐPíܹ³´ËÀE˜v5ÿDüyRRR«   ³ÊÀÅ™P‹m7«,\\©Ý$e³Ùäëë«&MšÈÃÃì²pq ¨ùç> +rŒŒ Ĩ €¢94 ÞjîÓü˜Eqh@ÍZÿ§Ÿ~Ò¨Q£ôüóÏÛ§œJJJÒòåËõî»ï:²,,Ä¡5ÿܧ]ºtÑÔ©S5pàÀmõë××G}¤¾}û:²4,´yP·mÛ¦Ž;jïÔ©“¶nÝjVY¸8Óª···8P¨=99YÞÞÞf•€‹3- >÷Üs0`€>üðCýøã:yò¤V­Z¥ªÿþf•€‹3mÔiÓ¦éÚµk0`€²³³%Ižžž2dˆÞ~ûm³ÊÀÅÙ “ç{úå—_täÈIRHHˆ|}}Í,wKéééeZÀUuŸ¸¡PÛ¦wz;¼ŽiGPóøúúªE‹f—€E˜POYw¿¢ÜÔ¼¯Z€s2í.~àN84 Úl69s¦Ðï@I94 º¹¹ÉäI`q½5((H êÑ£‡¤SLyyy¹®ŸŸŸ#KÀ"P_ýu :Tƒ–$5lذØu9Ò €¢84 :T:vì˜Z·n­µkתjÕªŽ,‹sø4SuêÔQ:u8B €;R*ÓLeee)++«4JÀÅ™P—-[¦yyyÉËËK¡¡¡Z±b…™%àâLû&©Å‹+**J#FŒPëÖ­%IÛ·o×àÁƒ•››«^xÁ¬Òpa¦Ô3fhþüù0`€½­K—.ª_¿¾¦M›F@@‘L;ÅüøquèСP{ÇŽuüøq³ÊÀÅ™P«W¯®äääBíÉÉɪQ£†YeàâL ¨ýû÷×ÀµjÕ*\/^T»vítõêUµlÙR^^^3fŒ dVY¸8›aòwŽ^¹rE‡Rnn®7n¬Ê•+›Yî–ÒÓÓË´>€«ê>qC¡¶MïôvxÓŽ æñööVÓ¦M%I+V4»\œ©ß$µdÉ…††ÊËËK^^^ Õ²eËÌ, gZ@3gŽ¢¢¢ôÔSO)11Q‰‰‰êÖ­›†ªyóæ™U.δSü3gÎÔüùóõâ‹/ÚÛºté¢úõëkòäÉÜÉ€"™võܹsjß¾}¡öŽ;êìÙ³f•€‹3- †……ù•¦ÉÉÉjÖ¬™YeàâzŠ?55Õþ{ll¬¢¢¢tñâEµnÝZ†ahûöíŠÕûï¿ïȲ°‡ÔÀÀÀBmýúõ+ÔÖ¡C™<ý*\”CjRR’#7€rÈ¡µM›6ŽÜÊ!Ó¿I*''Gééé…Néûùù™].È´»ø¿ûî;µk×N^^^òóó“¿¿ (¦AŒŒT¥J•¯€€³ÊÀbL ¨ÐÔ A³JÜŸ²î~…iµI“&JKK3ków,##£¬»€_aÚ5¨óçÏ×믿®;wêÂ… JKK+ðÅ´#¨º|ù²ZµjUär&ê@QL¿Iêã?æ&)”˜iõ›o¾Ñ7ß|ãt7IÀ¹™v j£FtñâE³6‹2- N:UÑÑÑJJJÒ¹s甚šZà(Ši§ø;wî,Izâ‰'Š\ÎMR(Ši5))ɬMÀÂL ¨mÚ´1kÓ°0Óê­&ã÷óó3«4\˜iÕßßÿW—s *ŠRj× æææêàÁƒš={¶&MšdVY¸¸R½õ‰'žÐ< ¿üå/êׯŸY¥àÂL›µ8¡¡¡Ú¹sgi—€‹0íjQ“ñ§¤¤(66VAAAf•€‹3- ÛoVY¸¸R»IÊf³É××WMš4‘‡‡‡YeàâPóæ? +ryFF†$æA@ÑPo5ÿiæA@QPo>µŸÇ0 ­[·N‹-’···£ËÀ"PožÿÔ0 ­_¿^111:yò¤Æ§#F8º,,´›¤n¦ÑÑÑ1b„|}}Í* px@5 CûÛߣ'NhäÈ‘9r$Á%âð€Ú¬Y39rDƒ ÒÚµkåëë«ìììB÷8º4,Àf8øvz›ÍV¢õÊê.þôôô2© àêºOÜP¨mÓ;½^§ÔîâJÂô»ø€ÛáVÖò# À©PàT¨p*T8*œ N…€ §B@€S! À©PàT¨p*T8*œ N…€ §B@€S! À©PàT*”uéòåË;v¬RSS¨·ß~[>>>eÝ-ÜKA]¼x±Z´h¡Õ«Wë‘GÑ’%KʺK¸M– ¨»wïV§N$I]ºtÑ®]»$IÍ›7·ÿÀ¹Yêÿ¹sç(I Pjjª$iß¾}öuÒÓÓˤo(!ÃBZµjeäææÚ·mÛ¶Èõ~øaÚi§vÚi§vÚØîH– ¨øÃŒ³gφa)))F=ʤ¥ñG]êR—ºÔ¥.u©kU–º5<<\7n”$}öÙg /ãàvÙ Ã0ʺŽòË/¿h̘1:þ¼ôöÛo«J•*eÝ-ÜKT¸>Kâ€ë³Ô4SåÑ‚ ” ””íÝ»·À2«}³Ö¾}û4kÖ,åääÈÍÍMcÆŒÑC=$ÉzcÍóÑGiíÚµ²Ùl’¤—_~Y¿ýío%YwÌ’4}út­]»¶ÀkÚŠã Wpp°$éÙgŸU×®]%Ys¬y,X ­[·Ê0 õèÑC={ö”dÝ1Ïš5Ë>Õaff¦.^¼¨¤¤$KŽwûöíš?¾$Éf³iذajÕª•$kþû=zT111º~ýº‚‚‚4yòdy{{K²æxK]™Þ¢…»vàÀãܹsÆï~÷»BËfÍše¬X±Â0 ÃX±b…1{öìÒîžC}ÿý÷Æùóç Ã0Œ¯¿þÚxæ™gìˬ6Ö<öß;ftèÐÁþتcþ׿þeŒ;¶ÐkÚŠã-ê}kÖ«aÆúõë‰'999†aÆÅ‹íˬ:æüV¯^mÄÄĆaÍñvèÐÁøïÿk†aüðÃÆ“O>i_fÅñöíÛרµk—a†ñå—_sæÌ±/³âxK§ø]\“&Mì_Np³â¾YËUÝÿýªZµª$éÁÔùóçíˬ6Ö|XGŽQ·nÝʺ+¥&!!Aqqqzúé§5yòä²îŽérrrT·n]­^½ZÏ<óŒbcc˺K¥fÓ¦Mjß¾½ýè±MŸ>]ÇWbb¢FŽ©3f”u—L5a­[·N½zõÒ÷ß/ww÷²î’¥X÷*%%E’”ššª€€€2îÑÝ;{ö¬ÆŽ«·Þz«À¥ VëÍ:u꤃Ú[mÌû÷ï×±cÇ¡ˆˆeff*""B¹¹¹’¬7^Iò÷÷—$=ùä“úïÿko·âX%©fÍšêСƒ$©}ûöúÏþc_fÕ1çÉz_²æxÿýï«}ûö’nüû&''Û—Yq¼÷+ÓõûIDATÝwŸ.\¨5kÖ¨[·nº÷Þ{íˬ8ÞÒF@µ0«}³VFF†¢££5räH…††Xfµ±æ9uê”ý÷;vØOKÖsdd¤6nܨ„„%$$ÈËËK ö#NVoZZšŒÿ? õ®]»T·n]û2«5Oxx¸¾úê+I7fåÈÿݪc–¤cÇŽéÊ•+jÒ¤‰½ÍŠã­S§ŽýßwïÞ½úÍo~c_fÅñ^ºtIÒKu–-[¦ˆˆû2+Ž·´1Q¿‹›7ož>ûì3¥¤¤(00P]ºtQTT”$ë}³ÖªU«´páBû5k’ôá‡ÊÍÍÍrcÍóÖ[oiÿþý2 C~~~®S´ê˜ó´lÙR;wî´?¶Úx7nܨ¥K—J’¼¼¼ôÆo¨Aƒ’¬7Ö<éééš0a‚~þùgyxxhâĉ–³$½ÿþû2 C/½ô’½ÍŠã=tèþüç?+;;[žžž?~¼7n,Éšãýä“O/wwwµjÕJÆ ³O hÅñ–6*œ §øàT¨p*T8*œ N…€ ÅØ¶m›l6›ÒÒÒʺ+w%o·óu‹wò3¶ |" pZy'ïçž{îQ§Ntøðá²îš$ç `ŽÓááá:}ú´ªU«æíÀí  pz‡ÒéÓ§•””¤ÜÜ\uïÞ½¬»dyžžžªY³¦}âq(MTN¯zõêªY³¦š5k¦W^yEGUfffuæÌ™£† ÊÓÓSuêÔÑ›o¾©œœûò+V(,,L+V”¿¿¿úöí[àhãõë×5zôhÊÇÇGݺuÓO?ýt×}¿U¿òŽ|nÚ´I?ü°*V¬¨GyDGµ¯“­èèh{ßžyæÅÇÇ8bÚ¶m[I’¿¿¿ýˆóÍþõ¯[ãf7.I?‹³ÿ~…‡‡ËËËKuëÖÕ¼y󊬵eË–_]@9b€“JJJ2$)))†aFZZšÑ¯_?#44´Àz'N46lh|öÙgÆ?þhlÞ¼Ù6Æg_gåÊ•ÆÖ­[“'OÛ¶m3š4ibôíÛ×¾|øðáFõêÕO?ýÔ8qℱ`Á# Àd\¼x±Dý»YIú•·ððpcÏž=Æ·ß~k<öØcF›6mìë 2ĨU«–‘˜˜hœ8qÂX²d‰Q£F}[»v­!É8zô¨qúôiãôéÓ·UãVc»›m<ðÀöýºhÑ"£bÅŠÆÒ¥Ko{=å€ÓÊ .>>>†!ÉhРñý÷ßÛ×ÉÈÈ0*UªdìÞ½»Àsãâ〉U«»íuëÖ>>>Fnn®qéÒ%ÃÓÓÓX¹reuF}ǵ¤ýÊÛÆ_|ao[³fQ¡BãÚµkÆ¥K— #>>¾ÀvÆŒS oyÛ)ª¯·ªQ’±ÝÍ6nÞ¯¯½öšrÛë(?8ÅÀé%%%é믿Ö{ï½§ãÇ+99Ù¾ìСCºzõª:tè Ê•+Û^|ñE]¸pAééé’¤/¿üRíÛ·WõêÕU¥JõéÓGJOOב#G”­Ö­[¨›wÚüN”´_y7nlÿ½zõêº~ýº222ôí·ßêÚµkúío[`ý–-[ÞvŸŠ«aö6nÞ¯­[·Ö‘#G”••uGë°¾ eݸ•zõê) @ 6ÔÑ£G­ˆˆyxx(77W’´qãFÕ¬Y³Ðs½½½•––¦Î;«{÷͛7kùòå%êÓÁƒåççW ­iÓ¦·ìWIÜsÏ=0`€F%___5iÒD_|ñ…–-[&éGëÖ­+IúôÓOÕµkWÙl6”¨†ÙbccåïﯦM›jóæÍš={v‘wè—t=å@_ Å*î&¤­[·’ŒþóŸö¶ M›65<== £E‹Æ¢E‹ìË—,YbÔªUËðòò2Úµkg,_¾¼ÀMEÙÙÙFtt´Q­Z5£R¥JFçÎU«V•è&©¢~._¾\¢~5Æ›oxÊÊÊ2FŒaT­ZÕðöö6~ÿûßË–-3$™™™öçM™2ŨU«–áææfäÿx/I[íû»ÙÆçŸn<úè£FÅŠ   cöìÙw´€òÃf·y ÌM:U .Ô?üPÖ]¹kÛ¶mSÛ¶m•’’â4G}”-Nñ€“KNNÖôøãËÝÝ][¶lÑÔ©S5a„²î˜‚€ .`öìÙ2dˆ²²²¬ &èÕW_-ën€)8ŧòÿÊ‘:€BR¹IEND®B`‚prinseq-lite-0.20.4/example/example1_pm.png0000664000076700007670000006217012240000123020746 0ustar rschmiedrschmied‰PNG  IHDRISÍ‚ÉbKGDÿÿÿ ½§“ IDATxœìÝ{\ÔUþ?ð×#ÃE ÅkæfÀ{–éf…hi»m^6ËR{¸¥_-·¼Ôny+ÍeWqmÍ ï奭ßnkJØa+ZyctD+S¼!0 :Üß.³ 3ó>0¼ž‡™ÏçÌù¼çsf†7çœÏù(„DDDDdÃÇÓy£Ÿ$•”” 11:#GŽÄ7$×\g[HHˆáÕ1dÈF©·Ú;ï¼#K=o½õºví ¥RévMy^åðè£Âh4^ýuôîݳfÍj”cUŸ£ÑˆÄÄÄÕ•‘‘„„ÄÆÆ"..\G@@Fe³íñÇG@@@ƒb“Csm—jkÖ¬All,t:t:öìÙ#¹¹Û§1¾‡j¶SSò]×íJ-„háæÌ™#Þ}÷]!„+V¬¯½öšä:‚‚‚êl»ë®»›B˜ÍfYêq•½×âŽC‡‰Ë—/7¨¾Æ<¯r;pà€˜-ùù®´£×Uû;ÉÕï!wÛ©¾sïè=ä(~{ï¡ÚïO´+5 !œ_ÝV^^Žÿûß8~ü8W(ˆÇÃ?Œ   Y“9wÝu×]())B¡´oß×®]“TGpp0ÊÊÊl¶…„„ ¤¤À±…BñãÇãÉ'Ÿ„J¥Bxx8¢¢¢¬åKKKqöìYwæC¥R9ÏÞkiˆ†Ôçì¼:z())A›6mÜ9eeeðõõ­SöСCxýõ×QPP???œ={¥¥¥Özê;Ç5µoß………ÖúkÇæ¨½ÃÂÂpþüy›gqÕ¬ßb± }ûövã’âØ±cxê©§°ÿ~ɽ€Õñ<òÈ#˜9s&RRRðÕW_Ùœ¯öíÛãÒ¥K’ß“R??5µ„v©iË–-زe þýïKzž+íãèuÕþNrõ{ÈÝvªïÜ;z9ŠßÞ{¨ö{Á“íJÍ—Ÿ³ùùùؾ}»Ko!Ž;†sçÎaâĉÖ.~OêØ±#®\¹‚¨¨(äåå¡C‡uʼ÷Þ{øàƒ{öì©ó $ åååÖį²²þþþÖýÿüç?ñÕW_açÎØ¸q#þýïÃb± ++ uŽçëëk7AªÍÇÇÇí‰ÑB( ˜Íf˜Íf·êh(gçÕõ½k‚þþþÖ/àÚ&Mš„Í›7ãþûïGee%Ú·ooS«çØÑŽÚ»:A——«u¸êâÅ‹?~NMMÅC=d}|ùòe<òÈ#øãÿˆììlësÖ­[g-“““#Ûkª¶sçNwæ<ðÀÖí]ºt±Ž·ïܹUUUÖ}mÚ´AEE…ì±Øãì¼:ãèuHQsžÇ|à𗪣XÍåqÔÞ?ü0Þÿ}w~QT_aéj\W¯^EçÎ%Ç\íÆ3f þô§?¡_¿~v˸ÚV¿úÕ¯ðꫯâ׿þu}C‡µ¾'·oߎûï¿ßºÏQ[6äóӜۥZÍù„»víBLLL2r´ŸƒÚÜm§úν£÷£øí½‡j×5u»RËPo’d±XðñÇ£¼¼Ü­ŠËË˱sçNX,·ƒ“Ûo¾‰½{÷"66_~ù%~ÿûßK®ã/ù öíÛ­V‹ØØXìÛ·«W¯¶îŸ8q"âââ0tèP¼ûî»î\Ö»oß>h4h4|øá‡²½&àÎ_~gΜABBV¯^•+WZ÷ýñÄ„ 0`Àœ={Ö¦×kúôéÐét ž¸½`ÁtêÔ 7oÞD§N°`Á‚Õg£×!Żヒ| @qq±[õ<ðÀ8|øp½ûµ÷êÕ«‘‘‘Fƒøøx=zTR\ß}÷†*9æjûÛßðã?âøâããïvÂŒùóç×&€””¤¦¦"66©©©HII±îsÔ– ùü4çv©¶bÅ ÄÆÆB£Ñ`ÕªUØ´i“Ûu9j9>µ¹ÛNõ{Gï!GñÛ{Õþ®kêv¥–¡Þ9IGÅ¿þõ/ëãnݺá¹çžÃ­[·œœ “ÉdÝní"^¾|9*++­ûÆŽ‹„„„ÆŠ¿Õ’{n9vðàA¬[·®A¿ÀÜõüóÏã…^hô5´š#¶KóàÉv’ŠíJ5ÕÛ“”••ew{ee%4Ͷ„„\¿~Ýnùƒ6 <"ïpß}÷áÊ•+MºáòåËü®Û¥yðT;IÅv¥Úì&IF£±Þ7óñãÇmz†|}}‡ãÇÛ-_PP€¢¢"B¥šØ‹ÔôöîÝ µZÝ¤Ç ÃÞ½{›ô˜Í Û¥yðD;IÅv¥Úì&Iyyyõ>A¯×#**Êze@¯^½pûömœ?¾Þç8ªˆˆˆÈÙM’õRTTTX' w†ÚŽ;æðJ‰êµ(ˆˆˆˆš ·nKrôèQÄÅÅá®»îB=êj#"""j®ì&IöîÎ^ÓÏ?ÿ !~ùË_âܹsÖ5.êcïrT""""of7Ir¶ðŸÇG·nݬë[8ÒØ7B%"""’›Ý$),,ÌéUû÷ïÇŠ+œ®$ápù÷¦òÿ÷nßâ# £F²Ùöøã# À­úãòÒG}Ôë/¯m*F£‰‰‰²Ô`]€±úÎòRŸß’ß;ï¼óŽÌÑÔOÎv€·Þz Z­111X³fäç×|oÄÇÇãÌ™3œ·‘³žúšäø\×l#¹Îá+¯¼b}ݽzõBhh¨¤ç{ù«Y—ÜŸ+¹ß«ä9õÞ»mÈ!6‹IÖVUU…›7o:=À}÷Ýç^d2úæ›o`4Ý^aÖ××W¯^EAA"""PXXˆ .¸U_UUU½kP¹+++ ;vôúËk›ŠZ­FÇŽqðàÁ¿ÿ|}}4箥¿wÞyç¼þúë²ÆTUUe÷>|r¶ëúõë‘›› ½^·‘úÞrµ‘\Ÿëšm$×9¬¹Âÿ_þòÉŸo;wr®ä|¯’gÕ;q;>>Þæf°çÏŸÇÂ… ëMŒª÷×\m»C‡ˆ—1\é*++ñÚk¯aÕªU ªgâĉرc€;÷J›0a‚ÍþM›6aàÀÐétèÛ·¯õ>UÀ¿X,X€þýû#33Óæ/˜àà`,_¾D÷îݱ{÷n뾂‚Œ5 ±±±èÛ·/Ž9b7¶mÛ¶á‰'ž°>ÎÍÍÅý÷ߨØX<ðÀÈÍ͵9Þ¼yó€~ýúÙÜ7ÊÑñÅY“£cà±ÇƒF£N§CFF†Óã:;¯õÅ4vìXë=û<­9½w=oÕªUèÕ«âââ0þ|¼ù曨¨¨@||¼õÖµÿÒ ‘ü:‡ fóy}ã7¬·§«]?øà,X°>>w¾åü£æ9¨}Ϊ¹òYªÝ6gÏžEß¾}‘€¹sçÚœÛúλ½6’û³±}ûvLœ8Q–ºëÜÕW—½ããwÞÁ AƒÐ£GìÚµ K–,ÁàÁƒÑ½{w|þùçÖ²Ž>/ÞôD (..+V¬o½õ–ä+V¬%%%Žªo¯½öšX¿~½Bˆ   ·ê —.]ƒ B1hÐ qáÂq×]wYË[ÎÎδ>ö÷÷~ø¡M}ÕT*•غu«Bˆo¿ýVDGG[÷?^ìÛ·O!„^¯ýû÷·_\\œ¸xñ¢õñã?.RSS…B¤¦¦Š1cÆØ¯¾}ŽŽç(Κ{ܸqbÅŠB!,‹¸~ýºÓã::¯Žbº|ù²ˆµ£">>^<øàƒâÔ©S’ŸßÜÞ;Žž*®]»&„¢´´´N<ö»ó:Ï;'„BTUU‰{î¹GF!„|í"þð‡?ˆØØXñÐC‰üQr*•JÄÅʼn¸¸8‘””dÝ^óØ;g®~–j·Íc=&6oÞ,„bóæÍB¥RÙ=¦¶ç½ö>¹Î¡wÚªC‡Âl6Kz^SŸ;gïÝÚŸ«M›6 !„8räˆ Û¶m³>võs&çy&Ï©÷ÞmÕòóó±cÇ»œx…††b„ ˆŒŒlpׇƂ ðå—_pÿ~gÕÏ{ä‘G0sæL¤¤¤à«¯¾BHHJJJ‡Âë¯¿Ž‚‚øùùáìÙ³Öõ¡P\\ •JU'ŽÀÀ@\¿~Ý:_ªfáááˆŠŠ²ÆQZZгgÏÖ‰¯}ûö(,,´Q´oß—.]B`` *++Ñ©S'ëpB@@ŠŠŠìîstòÈ#X±bòóó‘ššŠO>ù€|íÚ®];¬]»O?ý4vî܉÷Þ{û÷ï—TG}ß'5·Û;gR>Kõ}®oݺ…ÐÐPkϾ£ó^{Ÿ\ç¸Ó«“——gs#ZW4õ¹söÞ­ý¹*))A›6mÜyo–••Yërõs&çy&r%“*//Ÿ}ö™X´h‘ÃÞ£E‹‰Ï>ûL”——7nj碕+WŠ:ˆ®]»Š®]» …B!ºvíZ篞5kÖXÿª¹|ùrzªÿÊØ¼y³ 6lBØþµÖ£GñŸÿüG!DEE…¨ó|{ýؾ}{—Îehh¨0™L6«ŸWQQ!¬ûT*U½ûÏQœµc©¯þ°°0qãÆ:Ïqt\)çµfLUUU"$$Änî0™L¢]»vu¶·´÷Ž£ç™Íf±wï^1uêT1bĈzã³X,Bˆ;ç¬æ~)¯sÇŽbÖ¬Ybܸqb÷îÝÖírµkLLŒ¸}û¶õuÙ{?»Ú¶Ž¶»rÎ}–j®oÞ¼)„¢²²²Îù«ï¼×>žœŸ N':Tg»·;gu¹ú¹ªýØÑçEîï ò —’¤jF£Q|ýõ×býúõ"99Y,^¼X$''‹õë׋ÌÌLk—¸·jÈp›wºi—-[fýE_óÃ!Ο?/„bõêÕ»Â]ý@>õÔSâÏþ³õq}Ã=µ»–ÇŒcýe¼aÆ:ÃmÕû6nÜ(ÆŽëÒñ\ýrrtìñãÇÛnst\)çµfLrtuZñüóŸÿ¬wÈÊ‘æöÞqô¼ÜÜ\!„×®]jµZaû‹[!¢££Å·ß~+„âÃ?´y-R^ç­[·D¯^½D÷îÝmþ¨‘kãw¿ûسgBˆ/¿üR 0@r®ü¢·wÎ\ý,Õn›Ñ£G[‡šjŸ[Gç½vÉu ƒ¸çž{ÜznSŸ;gu¹›$9ú¼p¸­e”$5w M’j«ùaÙ¸q£èÒ¥‹èß¿¿X´h‘Ã9®~ óóóÅèÑ£ELLŒˆ‰‰¯¿þºÝ8f̘!þñXŸ;wN 2DhµZ1dÈqîÜ9›ãÍ›7OÄÇÇ‹„„ñóÏ?»t}º˜7ožÍ69ÚU!JJJÄc=&4HHHµmkn·wÎ\ý,Õn›~øÁú¹ýÝï~gÓKëè¼×n#¹Îáïÿ{ñÆo¸õܦ>wÎêr7Irôy‘ë<“gµª$©¥ÊÊÊ“'Ov©¬»‰bsóÜsωx: ¯'å½Ó”,‹ˆgΜ±ÙÞšÚµvÛܼyÓÚ³ùé§ŸŠ_üânÕÛΡ7¼¯[Ãyn ܺwy—ûî»W®\áb’ÿUTT„Ë—/7Ê‹-7¾wN:…Þ½{cذaèÕ«—u{kk×ÚmsòäIÄÇÇ#&&o¿ý6V¯^-¹ÎÖr=ý¾n-ç¹5pzuQkÄž$"""";˜$ÙÁ$‰ˆˆˆÈ&IDDDDv0I""""²ƒI‘L’ˆˆˆˆì`’DDDDd“$"""";˜$ÙÁ$‰ˆˆˆÈ?OàŽ²²2O‡Ðd‚‚‚P^^îé0ˆˆˆ¼^pp°¬õ±'‰ˆˆˆÈ&IDDDDv0I""""²ƒI‘Írâv}„ ?dg+a4úÔê*ÄÅ™ Ñ˜¡Px8@"""j6dM’JKK±`ÁF„‡‡cùòå ªSîã?ƧŸ~ ų–ÿû¿ÿÃý÷ßøóŸÿŒÃ‡*++Q\\ŒŒŒ §Ç¶X€´4rrl_R^ž/òò|‘›kFRR%|ØwFDDD.P!„\•­\¹aaaxöÙg±eË”””`Ö¬YuÊݼy€sçÎaúô騻wor;wîÄ™3gðæ›oÚl··À‰J¤§û;Œ/1ñbcMR^’Çq """×xõYYY9r$`Ô¨QøÏþc·\u‚ÜI˜"##í–KOO·ÖçŒ^ï¼SÌ•2DDDD€ÌÃm¨ÕjÆzËîØ±;vì@EEþö·¿ÕÙåÊ\¹rýû÷ëÿðõ×_×)o4:Ï÷\)CDDDxpâö„ 0aÂìÞ½ï¾û.þú׿Úìß»w/~øaøüwQõ<% u­¸MDDDž!k×Jxx8 F£jµÚésFމ“'OÖÙ.e¨ Ôj‹,eˆˆˆˆ™“¤!C†à‹/¾ìÙ³C† ±[îÊ•+ÖŸ÷ïßîÝ»ÛìÿùçŸqóæMhµZ—­Ó™–‰‹«[æÕW_Ehh¨ËÇ!""¢ÖAÖá¶iÓ¦aþüùؽ{7Ôj5–/_nÝ7eÊlذ°yóf?~B„„„`áÂ…6õ¤§§#11QÒ±µZ._öÅÉ“ö_’Vk†Fc{e[VVŠŠŠÐ¦MIÇ"""¢–OÖ%šJ}s’„Nòƒ^¯DAÁN²ˆ t:bbl“¬¬¬DRRvîÜ‰ØØXäçç7Eè’q """×Ƚ@‹º&^¡434çCoK—.Å”)SÑ‘QsÓ¢’$WoKrôèQèõz,]ºÔƒÑ‘7k1I’”Û’ÁþðäççcäÈ‘8p ºté‚víÚáÆÈÍÍÅwß}‡/¾ø‘‘‘Xºt)~ýë_7ZÐeeeV·· Byy¹§Ã ""òzÁÁÁ²ÖçR’Ô¯_?¼þúëxüñÇѦM›zËݾ}ÿú׿°lÙ29rDÖ@kb’DDDDµy$Iò6L’ˆˆˆ¨6¹“¤_Ýf2™pëÖ-9b!"""ò~î>ñòåËxþùçñÕW_Áb±`èСشiºwï.g|²0ü­„Ñè P««‘K5 IDATg‚Fc†BáቈˆÈ+¸=Ü6zôh„††b„ ¸}û6Ö¬Y“É„o¾ùFîëpw¸ÍbÒÒTÈɱŸvèP!€¢"ïIž8ÜFDD乇Û\îIúôÓOñä“OZŸ8qçÏŸ‡Ï»¸¸8ÄÄÄÈœÜ e½ äåùÖyœ—ç‹Ü\3’’*áÃ¥7‰ˆˆZ —í/\¸cÇŽÅÅ‹QQQHNNÆ¥K—pîÜ9$''£G¨ôz÷Fsrü`0(eކˆˆˆ¼™ËIÒÑ£G1xð`ôïß«W¯ÆªU«’’‚Î;ãž{îÁ'Ÿ|‚µk×6f¬ f4ºßän‚EDDDÍ“ä9IgϞŋ/¾ˆââb¼÷Þ{ðõõEUUt:T*UcÅiÃÝ9I))A0™Ü›\¤T ÌžÝôsƒ8'‰ˆˆÈ5_ C‡Ø»w/fÏž'žx;vì€V«m²©!Ôj‹§C ""¢fÂå$é»ï¾C÷îÝ„èèhôíÛ'OžDQQ´Z-ÒÒÒ3NYètfIå¿ûn Ö®ÅÚµ:¬]«Czzz#EFDDDÞÆåá¶„„Ü{x2e öìÙƒÁ€¯¾ú ™™‰éÓ§#>>;vìhÔ€÷‡Û„ÒÓU8yÒµùE·o—¢M›¶€>}²1{ö£8{ö,Ö­[‡ 6@ñßu-Z„ÄÄD·br†ÃmDDD®ñØmI”J%NŸ>=zÀb± ** yyyÖý·nݲe˰páBY´§!·%8uÊz½w:Ò"",P(€K—|í>G«5C­>€9s^ÁþýûQVVfmˆ3gÎ`Ô¨Q8{ö¬Û19Â$‰ˆˆÈ5['©sçÎØ°a^|ñEìÙ³;v´Ùïïïß$ RC)€Fc†Fc;ôV_òtúô*ÌûnÞ¼iR¬ÙeeeˆŠŠjº@DDDMÂ垤?þÏ<ó nß¾€€ü¿ÿ÷ÿ0räÈÆŽÏ.OÜàvÛ¶mؾ};víÚX»v-Ö®]kMžzöìÙ(ÇeO‘k<6ÜøñÇѧO„……ɈžH’Ìf3:uê„«W¯Úl¯<ÉI‘k<º@DDúöík“ ™L&ܾ}[Ö ¼Enn®õç´´4ôéÓ§N™qãÆáûï¿oʰˆˆˆ¨ ¸œ$ýðÃèÓ§ñØcáöíÛxõÕWŒ€€<úè£ÈÏÏoÌX›ÜÊ•+1hÐ 0ï½÷Ö­[Àµä‰ˆˆˆš7—‡ÛFŽ “É„W^yÛ¶mCyy9~úé',Z´>>>X´hzöì‰O>ù¤±cöÈp[M/¿ü2<‹Å‚°°0¤¤¤ wïÞr,·¹Æcs’‚ƒƒqàÀÄÅÅ¡´´wÝu2331tèPÀ‘#GðÐCáúõë²h§“¤¦Ä$‰ˆˆÈ5›“d2™P©TðññAPPM`-unµ>.'IñññX¶lΟ?¥K—B§Óaþüù0 8}ú4^{í5 8°1c%"""j2.·}ýõ×=z4nÞ¼‰{î¹À³Ï>‹/¿üбcGìÙ³qqq0Àá6"""ªË£ë$Füøãˆ·½eggÃd2A§Ó¡M›6²W&IDDDT›G“$oÁ$‰ˆˆˆjóÈÄíI“&áôéÓ.Uh0ðôÓO7((""""Osé·½zõÂÀ¡Õj1vìX 0]ºtApp0JKK‘››‹o¿ýŸ}öNŸ>W_}µ±ã&"""jT.·]»v ©©©Ø±cŽ?ŽšOS(ˆÇ„ 0uêÔF¿¯‡Ûˆˆˆ¨6¯˜“TZZŠŸ~ú eeehÛ¶-zôè¶mÛʘ#L’ˆˆˆ¨6¯H’<Í[“$!ƒÁÙÙJ¾µº qq&h4f(Òëd’DDD乓$—æ$‘s –¦BNŽí)ÍËóE^ž/rsÍHJª„ËËw‘'ñW¶L e©¦œ? Ê&Œˆˆˆˆ‚I’Lôzçr®”!"""ïÀßÚ21ç›®”!""jõ„€ŸÁev6|F@•Z S\Ì Üšäë&IDDDä=,¨ÒÒà—“c³Ù7/¾yy0çæ¢2) M1É—]2Q«-NËøùÝ™àMDDDö) †: RM~99P M “$™ètf§e**ÖÉÛë֭àAƒ0xð` <ééé"‘×óÓëe)#‡%Ieee°°k Õšè|É©C‡”xúé§ñí·ßâСCؼy3^zé¥&ˆ’ˆˆÈ»ùüwRCËÈAr’d6›ñÆo ,, mÛ¶ÅÏ?ÿ X¼x1RSSe°¹P(€Û·—»~Ý{ö¨ø¿¯ÊÊÊՈёT’“¤E‹aûöíX³f T*•u{¯^½°aÃYƒkn\l_½fÒÚµk¡Óé0~üx¬_¿¾qƒ#""j,jµ,eä 9IÚ°a>øàLœ8¾¾¾ÖíýúõÉ'd ®¹qeòv5½Þ/¾ø"ôz=/^Œ9sæ4bdDDD̓Y§s^&.Îúóõë×ñÄO`ðàÁ9r$nܸ![,’“¤ÂÂBôîÝ»Îv¥R‰Û®Œ7µ`®LÞ®f4úX'o§¤¤`ÿþýœ¼MDD­žI«…Y«­w¿Y«…I£±>~÷Ýw1|øp:t#FŒÀÒ¥Ke‹Er’Ô­[7œ:uªÎöýû÷£OŸ>²Õ\iµ&hµ®%JÅÅ笓·ÿûß#::š“·‰ˆˆ T&&¢2) UQQJ%„R‰ª¨(T&%¡21Ñf~ËÞ½{1nÜ8À¤I“°{÷nÙB‘¼˜äŒ3ðòË/[çÐ\½zß}÷^yå,_¾\¶Àš#…HL¬Ä¥K()qœ~ÿý Œñ , ÂÂÂ0wî\¬Zµª‰"%""òb ÌÍÕµ¸rå :tèèСòòòd CrOÒ¬Y³0nÜ8Œ1ååå:t(¦NŠY³fá…^-°æJ¡ 29-÷î»)øöÛo1eÊœ>}S§NEii)×L"""ò !„óÅ}þËd2!==ƒF`` , 4 ‚ƒƒW “²²²&;–;„ÒÓU8yÒ~GVkFbb¥µ·°¬¬ ÿú׿°}ûv$''cÔ¨Q8{ö, ((åååM:Q³Ò¯_?ìÚµ ;vDii)~øadZ‘[RO’ŸŸ~õ«_¡¼¼0` Ô¤ RsP=ì–”T‰¨¨*(•J¥@TT’’*m$Ƹqãðý÷ßsÍ$""" yäüýï|øá‡HJJ’­nI=IÀŒíÏþ3† &[Ry{O’«rssѵkWwæzíܹ!!!HKKCÏž=°'‰ˆˆÈ‘’’<ûì³ÈÏÏGTT>þøc„„„ÈR·ä$iÏž=xã7°dÉôíÛmÚ´±Ù¯n‚žZJ’ôòË/ãàÁƒÖÉÛ)))8rä¶oߎ]»v`’DDDä*¹G¶$'I 'ËJK¬Î--%I²Çl6£S§N¸zõ*&IDDD®’;I’¼@FF†¬í°[ZZZ«_oŠˆˆÈHN’†Þa´n+W®´v[·n§C"""jõ$·ÕtëÖ-€¿¿¿l¹¢%·ÕÆá6"""×È=Ü&y1Iظq#úôé•J•J…èèhlÞ¼YÖÀˆˆˆˆ}ZÖíápÕæñ%Ú´iƒŸ~ú ]ºt±Ù~áÂôìÙÓ:O©11I"""¢Ú<>')""ÙÙÙu¶ggg#22R– ˆˆˆˆ·oßøûûcöìÙL’ˆˆˆ¨Åp{ €ÒÒRäääbbbd¿ìÎ.@DDDµyÝ:IUUU0›Íð÷÷—+&§˜$Qm[')-- Û·o·Ù¶råJ„„„ £GÆ7d ŽˆˆˆÈS\N’–-[†ÂÂBëãÇãw¿ûæÎ‹üã8{ö,.\Ø159—‡Û°oß>ÄÇÇ^}õUèõzìÝ»°{÷nÌš5 gÏžm¼hÿ‹ÃmDDDT›Ç†ÛJJJa}üí·ßâÁ´>Öét¸xñ¢¬ÁyŠËIRHH._¾ 0›Í8vì¬û+++áç'yE""""¯är’4|øp,Z´çÏŸÇŸþô'°éIÒëõèÑ£‡üy€Ë]?Ë—/Ç/~ñ tïÞ …«V­BÛ¶m­ûÿþ÷¿cèС$QS“´NRee%Ž?Ž: k×®6û8€{î¹:t=ÈÚ8q›ˆˆˆjóºÅ$=IÕæ±«ÛˆˆˆˆZ&IDDDDv0I""""²ƒI‘’“$…B«W¯ÖÙn4¡P(d ŠˆˆˆÈÓdëIBÀLJSDDDÔ2¸¼˜dII‰õç7n@¥RY[,ìÞ½‘‘‘òFGDDDä!.'I¡¡¡ÖŸ{÷îm·ÌÛo¿Ýðˆˆˆˆˆ¼€ËIRFFà¿ø>ýôS´oßÞºÏ××ݺuCçÎ刈ˆÈ¸âv ~ÈÎVÂhô¨ÕUˆ‹3A£1CŽyì\q›ˆˆÈ5r¯¸írORmf³ååå¨c…„„48¨æÀbÒÒTÈɱ=…yy¾ÈËóEn®II•à\v""¢æIò¯ðÓ§Ocøðá@HHBCCmþµƒ²N‚TSNŽ eFDDDDr’Ü“4iÒ$(•J|ôÑGˆˆˆhŒ˜š½Þù©Óëýkj‚hˆˆˆHn’“¤'N@¯××{…[ka4:ï„s¥ y'ɿŵZ­ÍšIDDDD-‘ä$iÙ²e˜3g222PPP£Ñhó¯µP«-²”!"""ï$y g÷gkмa €'”HO÷wXfäÈ[ÐjïÌI GÏž=3gÎÄo~ó—ŽÃ%ˆˆˆ\ãñ%ª•lí´Z._öÅÉ“öO¡Vk†Fó¿IÛ>>>ÈÊÊjªðˆˆˆ¨¸˜dœ:å½^‰‚‚;#—èt&ÄÄØ.&‰üü|ÉÇ`O‘käîIjP’TVV†ÀÀ@ø4ñŠ‰Þ’$I‰{ï½mÛ¶EJJŠËW2I"""rÜI’äìÆl6ã7Þ@XXÚ¶m‹Ÿþ°xñb¤¦¦Ê\Kb0pàÀLž<3fÌðt8DDDä„ä$iÑ¢Eؾ};Ö¬Y•JeÝÞ«W/lذAÖàZµZ xê©§pêÔ)GCDDDÎHN’6lØ€>ø'N„¯¯¯u{¿~ýpâÄ Yƒk)ŠŠŠ¬Wý¥§§[¯r#"""ï%ùê¶ÂÂB»ói”J%nß¾-KP-;}ûœœ !‚‚‚°fÍO‡DDDDNHN’ºuë†S§N¡S§N6Û÷ïß>}úÈXK2nÜ8Œ7ÎÓa‘’‡Ûf̘—_~\½zÛ¶mÃ+¯¼‚™3gÊ ‘'HîIš5kŠ‹‹1bÄTTT`èСP©T˜?>^xá…ÆˆÑk  ~ÈÎVÂh¼3?K­®B\œ í:IDDDÔ¼¸½NÒÍ›7a0`±X Ñhd_›ÀoX'ÉbÒÒTÈɱŸgFG›‘”T‰†.!Åu’ˆˆˆ\ãñÛ’TkÓ¦ zõê!Ìf3JJJ!!!²çÍ e½ ääø¡K%bcMõ–!"""ï%¹ŸãôéÓ>|8‚ÐÐP›­…^ï<¿t¥ y'É¿Å'Mš¥R‰>úS³`4:Ï/])CDDDÞIr’tâÄ èõz—ï=FDDDÔIîêÐjµÖùG­™Zm‘¥ y'ÉIÒ²eË0gÎddd   F£Ñæ_k¡Ó™–‰‹û_™ððp 2C† Á¶mÛ34"""’ä%NÿqsEI¼a !€ôtNž´?b©Õš‘˜Xi]+)22ùùù’Ã%ˆˆˆ\ãñ%222d  ¹R(€ÄÄJtîì½^‰‚‚;rèt&ÄÄp1I""¢æÌíÅ$=Éz’¤ŠŒŒÄ½÷Þ‹¶mÛ"%%Åå‰ïìI"""rÜ=I ºFýÖ­[¸uë–\±´hƒÀäÉ“1cÆ O‡CDDDN¸•$mܸ}úôJ¥‚J¥Btt46oÞ,wl-ŠZ­<õÔS8uꔇ£!"""g$ÏIJMMÅÌ™31{öl 6 ™™‰éÓ§Ãb±àù矗=Èæ®¨¨íÛ·‡B¡@zz:zöìé鈈ˆÈ És’z÷î¹sçbêÔ©6ÛSSS‘œœŒÓ§OË =ÍmNÒÇŒääd!„¿üå/ˆu鹜“DDDä¹ç$IN’Ú´iƒŸ~ú ]ºt±Ù~áÂôìÙ³Iæ(5·$©!˜$¹Æã·#""]g{vv6"##e ŠˆˆˆÈÓ$'I“'OÆ´iÓ°uëV\¸p.\ÀÖ­[1mÚ4<÷Üs"QÓ“ú(òóóe ŠˆˆˆÈÓ$'Iñññ8qâDíÙÙÙèÛ·¯,Ayšäu’/^Œ™3g¢¸¸Æ ƒ™™™X¼x1Ö®] £Ñh-[}ç{"""¢æFòœ$…BárÙ¬.àç$QmrÏI’Ü“”‘‘!kDDDDÞ¨A‹Iz {’ˆˆˆ¨6÷$U«ªªBYYY!µEDDDäi’¯nûá‡0bĨT*„„„ 44ÔæQK ¹'é7¿ù °}ûv^½FDDD-–ä$éĉ8qâzõêÕñyÉÃmZ­%%% ‘ל$½÷Þ{˜7o¾ùæ\»v %%%6ÿˆˆˆˆZÉÃmjµ¥¥¥xðÁíîo†+ ÕáöÄí¿ÿýMDDD-–ä$I¯×C¯×sâ6µh’ç$ÅÄÄ ¸¸¸1b!"""ò’“¤wÞy¯¼ò 222PPP£Ñh󈈈¨%|ï6…BápSLÜæ½Ûˆˆˆ¨6ß»-##CÖˆˆˆˆ¼‘äž$oÀž$"""ªMîž$És’jºuënݺ%W,DDDD^í$iãÆèÓ§T*T*¢££±yóf¹ck1„NžôÃG %%))Áøè£œ<釿×GDDÔ:Hž“”ššŠ™3gböìÙ6l 33Ó§O‡ÅbÁóÏ?/{͙Ť¥©“c{ªóò|‘—ç‹Ü\3’’*áÓ >="""’›ä9I½{÷ÆÜ¹s1uêT›í©©©HNNÆéÓ§e Оæ4'éÄ %ÒÓý–IL¼…ØX“Ý}œ“DDDäÏI:wîyä‘:Û}ôQœ;wN– Z½Þyg+eˆˆˆ¨iIN’"""]g{vv6"##e ª%1ŸbWÊQÓ’üÛyòäɘ6m¶nÝŠ .àÂ… غu+¦M›†çž{®B$"""jz’Çy-Z„’’L:&Óy4J¥¿ýíoñæ›oÊ`s§V[—çë´ y·“¼~ýºu’vtt4Úµk'k`ŽxóÄm!ƒÁÙÙJ¾°X€ª*ÇÏ9ò´Zöïß Àl6ÃÇÇ+W®Äˆ#8q›ˆˆÈrOÜæŠÛ2ªïrG´Z3+¡P§N‚Z­FDD8€™3gâ‡~`’DDDä]Ýöý÷ßcôèÑ())©³¯¤¤£GÆÑ£Ge ®¹1”N$__6m|}3gü°mÛ…%££c0`òóó›"l"""²Ãå$iÅŠèׯBBBêì A\\Þ}÷]Yƒkn\¹”ßߨªRàömªª“éÎÂ’_|¡Âž=*Xþ;=iëÖ­HLLl䈉ˆˆ¨>. effâõ×_¯wÿ“O>‰Q£FÉTsåÊ¥üŠz÷åäø¡K%,–ÃHIIAzzºœá‘.÷$C­V×»?<<ÅÅŲÕšefæaòäÉØ¼y3:tèàépˆˆˆZ-—“¤ÈÈH‡+jŸ;wwß}·,A5W ½”ÿÖ­X½ú—X¶ldŠŠˆˆˆÜáòÕm/¼ð ðÙgŸÕÙ'„À˜1cбcG¬[·Nö kóÖ«Û\¹O[µóç3ž>‹ …Fþ+.^<ˆÌÌ…èÝûk¹£G¢²²²±B&""j1<¶ÀÅ‹ѯ_? 0³gφF£ƒ+W®Ä±cÇpäÈtêÔIÖíñÖ$I =]…“'íOõ ¸yóΜ¤‚‚“ GPP$rs÷c×®0sætèP…§Ÿ®°>‡7¸%""rÇ–èܹ38“É„‘#G¢S§Nèܹ3’’’ „@VVV“$HÞL¡+‘”T‰¨¨*(•J¥@TT’’*ñÀ·­e#"´ ºs¯»N£¬ì* .Î Ø¿?î¿ÿ~èt:Üwß}8tèPÓ¿ ""¢VÌ­Å$‹ŠŠðÓO?î½÷^„……ɘ#ÞÚ“äL}=M‡¿ÜÜL¼õÖÖ: KvïÞ{÷îÅÌ™3qìØ1ENDDäý¸â6šo’ÜI”Nòƒ^¯DAòòŽáãÇaãÆ/ñàƒáPÔZ! ((ÅÅÅèÖ­®\¹â™ ‰ˆˆš¹“$É7¸¥†Q(Æ ÆŒK—.á±ÇÆáÓO7"!!¼ÞçpaI""¢¦Ç$ÉCJKK1~üx§—û;vŒ Ky‡Û<$%%ï¼ózôèaÝöÍ7ßÀ×××úøÒ¥K3f Ö¯_Ïu“ˆˆˆœðÈœ$£Ñèr…ŽVå–KKH’œ)--ÅÈ‘#±dÉ<ôÐCž‡ˆˆÈëy$IRÔžMì@StLµ†$©º§©gÏž°ü÷®·µ{šˆˆˆè<’$}ýõ×.W8|øð„ãšÖ$Uãb’DDD®á`’DDDDuyÍB”••¡ªªÊf{HHHƒƒ""""ò4—oKR­¸¸“&MBÛ¶mÑ®];„††Úü#"""j $'I3fÌÀ‰'ðá‡B¥RaóæÍX±b:wîŒÍ›77FŒDDDDMNòpÛîÝ»ñùçŸcèСðõõÅ}÷݇ž={¢gÏžX»v-ž}öÙÆˆ³Ù0ü­„ÑxçÊ4µº qq&h4æ:·!!"""ï 9Iª¬¬D·nݸví >>ß|ó¬Á5w –¦BNŽíiÎËóE^ž/rsÍHJª„äþ<"""jl’=GGGãÇèt:üíoÃÅ‹ñ׿þ•s’j1”u¤šrrü`0(›0""""r•䞤W^y—/_,Z´IIIذaüüüšš*{€Í™^ïüôêõ~ˆ55A4DDD$…ä$iòäÉÖŸxà\¼x§NB·nÝбcGYƒkîŒFçu®”!""¢¦çö:IpëÖ-`È!rÅCDDDäÜêÆX¿~=¢££¡R© R©7Ê[³§V[d)CDDDMOr’´zõjÌœ9cÇŽÅîÝ»±{÷nŒ3/¾ø"Ö¬YÓ16[:Ùi™¸¸ÿ•yûí·à ðDDD^@ò½Ûºté‚… bÊ”)6ÛSSS±dÉäææ6( ÒÒR,X°F£áááX¾|9‚‚‚lÊ4—{· ¤§«pò¤ýQM­ÖŒÄÄJëZI‡FTTâã㑟Ÿ€÷n#""r•Çop«R©ðÃ? K—.6Û/\¸€^½z¡²²²A­\¹aaaxöÙg±eË”””`Ö¬Y6ešK’ÜI”Nòƒ^¯DAÁåDˆã IDATŽ»ˆ t:bbì/&É$‰ˆˆH"ßà6>>'Nœ¨“$egg£oß¾ (++ ï½÷`Ô¨Qx饗ê$I͉Bh4fh4·ވˆˆÈ{HN’/^Œ™3g¢¸¸Æ ƒ™™™X¼x1Ö®] £Ñh-«V«%TPP€ððpëó«ëëß¿¿µÌ÷ß/¹ÞæD¡PX‡kþLDDDMGr’”˜˜xæ™gêì{ä‘GlKÉsèðáÃÖŸ›Óp›;„Ö!6·¹ÆãÃm²P[xx8 £ÑèVoQCIN’†ÞaüÏ!CðÅ_àÙgŸÅž={ZÕB•o½õvìØŠŠ ôîÝ&L@rr²§Ã"""j•\ººÍh4",, …ÂfΑ= íù¹qãæÏŸ¢¢"¨Õj,_¾mÛ¶µ)ÓÒ‡Ûjâp‘k<²€B¡@^^î¾ûn(ì]³^ƒœóêÃ$‰ˆˆˆjóÈœ¤ŒŒ ´oßÞú3QK'y1IoÀž$"""ªMîž$·npKDDDÔÒIN’/^Œ-[¶ÔÙ¾iÓ&,]ºT– ˆˆˆˆ}:nß¾ ð÷÷ÇìÙ³™$Q‹áö:I¥¥¥ÈÉÉÄÄÄȾ6#\'‰ˆˆˆjóÈmIì1›Í(//¯s’Ys„IÕæñÅ$OŸ>áÇ# !!! µùGDDDÔHž“4iÒ$(•J|ôÑGˆˆˆhŒ˜ˆˆˆˆúè#äå塸¸¸±Ã#"""pÅmHOWáäIû9ªVkFbb%Š;+ngff"** ñññÈÏÏoâh‰ˆˆšß»Íd2Áb±Àßß_Ö@Z²úŽŒ5¡¨È……w¦†EDX Ó™c»˜dÿþý=6Q«ær’TXXˆÉ“'cïÞ½°X,4h6oÞŒ^½z5f|Íž³…#££Í˜0¡œ Gy—5Ïš5 /^ÄöíÛñÏþþþþ˜4iRcÆÖ"¸²p¤Á lˆˆˆˆÈ.÷$}ñÅøâ‹/0hÐ À}÷݇ÈÈH\»vÍz˪ËÕ…#¹º6‘wq¹'©¤¤]»vµ>G``àÿoïÞ㪪òÿ¿pL(¯y¿‚£xÃJ-GCªé2éxÉÆË#fr*¿Zš–ô˜F³lJÊÑ"3/šbV’™’—&1Ä*hŠbêÖï~œÙÂAñÐ×óñàñàì½Î:Ÿuغßì³ö‚»­*À‘ÔL•:;Ÿ8q¢Ì‘VÛPµ¦L™¢6mÚèçŸV›6m4eÊO—À5Ïå%l%o·*‡;V¨IK¼ÿ~­ ×Dª_¿PC†ül¹/ €¿•€ <¶‹H^Ž fb1É«¬2 GJÒ¶mÛJ-É•$\SÕW’In`Œ´k—ÒÒì:v¬ü…#‹Ýxã„$*Áã+n£òl6)"¢@7Õ÷žX $Xpéã¶“'OºÜaݺu/»€êÂ¥ìr‡5pxµ2eÊ-Z´È¹pä°aÃôì³Ïzº,®;.ÝÝ–’’âüþàÁƒzê©§ôûßÿ^½zõ’ôËJóçÏ×Ì™3ÝòGokÚÝmW‚»ÛpÇ—èß¿¿xà5ªÔö¹sçjÕªUZ±bE•h….æñT»vmeffªI“&¥¶ïß¿_íÚµsË .VÕ!©Òw·Õ®][;wî,³}ÇŽª]»v•ài•IÆ ÓÈ‘#õÞ{ïéÀÚ¿¿.\¨Q£Fé‘G¹5¸]¥WÜ~ùå—åp84räH]¸pA’äëë«1cÆ(11±Ê ð„ËþÛmyyyÊÌÌ”$µmÛVuêÔ©ÒÂÊÜ$p1OÜ.VPP üüü2ë"¹c1IB¸˜Ç'ngffªW¯^ªU«–êÖ­«àààR_ׂJÏI:t¨ìv»Þÿ}…‡‡_š<®Ò!içÎJKKS›6m®F=ÕB¥?n‹ŒŒ¬Ô¼¨‰*’¦OŸ®§žzJëׯױcÇ”››[ê àZPé»Ûl6[¹û/óf¹Jáî6p±ª¾»­Òs’Ö¯__¥TG—½N’'q% \Ìãë$?^EEEe¶c˜Ð ®.‡¤'N(..NµjÕÒ 7Ü ñãÇëüùóÎýGe1IpÍp9$=õÔS:pà€–.]ªW_}UK–,Qß¾}•——w5ëð—ç$Õ«WO«V­R÷îÝ%I§NÒƒ>¨S§N)99Y‡Cõë×çî¶*Æœ$\ã±9I§OŸVƒ œo¸á}òÉ'ª_¿¾zöì©#GŽTiažärHjÕª•¶oß^j›ŸŸŸ–.]ªÈÈHõï߿ʋð—CR||¼æÌ™Sf»ÝnWRR’ââ⪴0Ob¤jŽ9I¸Æãë$\IIIIIIIIIIIIIIIIIIIIIIIIIIIIII|<]ÀõÄ)=ÝG;vØ•›ë-I -Tt´C²Ù<\ p"$¹IQ‘´f¿22J¿åÙÙÞÊÎöVVVââÎÉ‹k{T œ’Ý$=Ý^& •”‘á£ôt»+å!$¹IZZÅí\i܃ä&¹¹¿Õ®´îÁYÀ!ÉMBC‹ª¤ p&Á¸ITT²³½Ëm]àü~„ Ú°aƒ¼¼¼tæÌåææêàÁƒW»Lðÿ’Ü$2Ò¡C‡¼õý÷Öoydd""Îlj‰‰’¤€€ýíoSZZš[ê¿ $¹‰Í&õëwNû(-Í®cÇ~ù¤3<¼HQQÝrË¥“üè£4iÒ$7V lÆãé"*ëÌ™3ž.Ámrrr«ÌÌLy{—ÿq׳ÀÀÀ*í‰ÛÕÜ¢E‹tÿý÷p3BR5·hÑ" 0ÀÓepÝ!$Uc™™™:sæŒbbb<] ×BR5öÑGiРAž.€ë·«¹€€åçç{º ª=&n¸! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À! À‚§ ¸Þ#¥§ûhÇ»rs½%I¡¡…ŠŽv("¢@6›‡ ’InUT$­Y㯌ŒÒo{v¶·²³½••U ¸¸sòâúÇéØÒÓíeRI>JO·»±"p)„$7JK«øÂ+mÀÕGHr£ÜÜŠßnWÚ€«32€B’…†UIpõ’Ü(*ª Â6ÑÑ¥Û<ÿüóêÒ¥‹bbb4gΜ«U¸³„Ý(2Ò¡C‡¼õý÷Öo{dd""ÎÇ ,PVV–RSSååå¥ãÇ»«T®{6cŒñt•uæÌO—pÙŒ‘víòQZš]ÇŽýr!/<¼HQQÝrKéÅ${÷î­… ªQ£Fª€š#00°Jû#$Uc5ÒØ±cµlÙ2…††êµ×^SóæÍ=]ÕRU‡$æ$Uc………jݺµRSS5|øpýáðtI\7¸’TuîÜY;vìÐ… TXX¨&MšèСCž. €j‰+Iב¾}ûê³Ï>“$mذA­ZµòpE\?¸’TåååiôèÑÚ»w¯|}}õæ›oª}ûöž. €j‰‰Ûªy!É)=ÝG;vØ•›ë-I -Tt´C¥ïh»X@@€òóóÝT)5WU‡¤*]'éôéÓš8q¢rss¦ÄÄD”j³mÛ6͘1C………òòòÒ„ -Iš1c†¶mÛ&I:wîœ~úé'­_¿¾*Kt»¢"iÍed”~«³³½•í­¬¬ÅÅ“|P­T镤™3gª^½z6l˜,X “'OjìØ±¥ÚìÝ»WÁÁÁ Ñ·ß~«iÓ¦iÙ²eeúúðõ{÷n=÷ÜseöÕ¤+I;wÚµv­_¹múõ;¯öí–û¸’€kªõÄíM›6é®»î’$õïß_7n,Ó¦E‹ ‘$µoßþ’«H¯]»ÖÙWM––VñÅ:WÚ÷ªÒ³ó±cÇ&I Unnn¹íW¬X¡=z”Ù~øða>|X111Îm%¿OII©š‚Ý 7·âêJà^»„±{÷n-\¸PóæÍ+³ïÓO?UŸ>}äUb¢Nñ\%©f}Üj¦Ë¾„±xñb ¿:peœÔ4å£]áŽóx IÇŽSXX˜$)44T¹¹¹å¶_±b…zôèá|Ü¢E ­[·N’´nÝ:9räê{*;Njš‹ÏÑ%c4xð`=úè£úñÇÛÝq¯±!©2vïÞ­… êÉ'Ÿtn›}ºóŠŒ$5oÞ\sçΕ$8p@[·n½ú¹ ®Ž€šæRçè’‚ƒƒ%IýúõÓË/¿ìÜîŽóx¸’4`À%%%)))Éù&ÆÆÆ*99Y’´zõjÅÆÆ–y^~~¾ž|òI=ñÄj×®]©}§N’ôËe¼wß}W÷ÜsÏUÅåqeœÔ4壋···n¿ývýñ”ÍfóÔp.©¼qPS•wŽ.>'''ëwÞ‘$ùûûkÒ¤Ijݺµ$¹å<^cCÀÕT#>np7B€B€B€B€BPÅRRRd³ÙªôOÈ\>¯f¿¸>%$$hèСž.C’Ô©S'-Y²ÄÓe †#$¡FyôÑGÕ½{wÉf³éäÉ“.?·8¸òœâ¶Å_!!!ÝìÛ·ÏlݺլX±Â¹éÒ¥F’Ù½{·ÉÎÎ6ÙÙÙö_2<üë_ÿ26›Íœ;w®T›:˜””³oß>“““sÉ@k6oÞl222L·nÝL¯^½œ}?Þ›>øÀìß¿ßlݺÕÌŸ?ÿ’õ?nÙ²¥Y±b…ÉÊÊ2óæÍ3~~~æwÞq>oÁ‚æóÏ?7û÷ï7)))&22Ò :´ÜqËÍÍ56›Í¬]»¶ÂŸÇc=fÂÂÂÊ­¥øµºuëf6mÚd233Mll¬éÔ©“éÕ«—IMMun»óÎ;Ë<¯¢±V¦†ò~S¦L1mÚ´1«W¯60ëÖ­3M›65Ï<óL¥úqõxÛ·oŸ±Ùl&11Ñ8ŽK¾Ç#•ÿÅǬ+c.O^^ž±ÙlæóÏ?wnËÏÏ7M›65Ï=÷œ¹pá‚9}ú´4h‰‹‹3ƳuëV#©T 6ƘeË–™àà`cÌ/Ç ¿¿¿™3gŽ),,4?þ¸iÓ¦1Ƙ>}ú˜W_}µÜºfΜiš7oîÒ+„$ÔHV!©ø?Ý‹3-ï9õ_rrrLÏž=M·nÝÊ´)Ĭž[üø‹/¾p¶ùðÃq8&//Ïøùù™wß}×åzŠ/X° T»ñãÇ›¶mÛ^²ŸåË—›€€STTdÙoI©©©¥~‹¿”“'O»ÝnYKñ ­äk•<‘.^¼ØH26l(µÍÇÇÇyÕ±V¶†Ký,òóóM­ZµÌ¦M›Jõ“””dBBB\î§dWŽ·Y³f™Úµk›ÀÀ@së­·šqãÆ™­[·:÷WtŒTvü%YWÇ\žo¿ýÖH2ÿùÏJm?|ø°ùÕ¯~e¼½½Íf3÷Þ{¯ó—Œ .˜Æ›»ï¾Û>|ØcLff¦éСƒój“1ƬZµÊtèÐÁÜxã¦gÏžfçÎfáÂ…&&&ÆlÙ²ÅÄÆÆšÆ›øøxsèСR¯¿téRc³ÙœWÊbN®:tPçÎuûí·ëá‡ÖG}¤ÂÂÂ+ê³iÓ¦ Txx¸òóóõÏþ³L›N:¹ÔWDD„óûððp(??_:þ¼î¸ãŽJ×׳gÏ2333uþüyIÒ×_­>}ú(<<\AAA4hòóóuæÌ™J¿Ö¥dffÊápXÖ²{÷ng-Å"##߇……I*ýÞ„……©   Låµ²5\êg‘žž®ŸþY¿þõ¯èü1b„Nœ8Q¦¦KõSYcÇŽÕ‘#G´hÑ"õë×O;vìP—.]ôꫯJR…ÇHeÇ_ò˜­ì˜­· ,µ}øðá Õ–-[”’’¢={öè¹çž“$Ùív}òÉ':räˆ4h Ýu×]Š‹‹“$y{{K’âããõïÿ[GŽQJJŠ4h ñãÇköìÙºÿþûuÏ=÷hß¾}ªS§Ž†^êõëÔ©#cL•︾øxº ªøøøè믿ÖÚµk•œœ¬Ñ£G+))IË—/¿ì>ׯ_¯Õ­[÷’w–ùúúºÔ——WÙßIÌÞySÞDî“'O*..N<ð€ªÍ›7ë‘Gq)<¶lÙR6›M»víR£F®¨Î’¬ÞWÞ›ªœ´~©×+**’$%''릛n*Ó¦víÚ.õs9‚‚‚¯øøxMš4I š9ÙívIR^^žl6[™ð¸Š+I¸¦ØívÝ}÷Ýš={¶æÌ™£?þX?ÿü³¤ÿýfZ|RpE³fÍÔ¢E‹«zë}»víäçç§/¾ø¢ÒÏýòË/K=Þ°aƒÚ¶m+???íÚµK§OŸVBB‚ºwï®V­Z騱c.÷]¯^=õéÓÇy5ãbÅ·¶·k×Nv»½L-_~ù¥³–ªPÞX«ª†ˆˆ+‘ IDATùûûkÿþýjÙ²e™/«Pt)—s¼•¥üü|9Ž ‘+UŒ¹8Pgee9·]¸pAÒÿÞ‡âï ÊÉ5jÔHÆ-X°@¿ýío-_çË/¿Ôúõë5uêTgÐw8Î×+***õ~gee©Y³fÎÐTW’P£|÷Ýw’¤={öH’vîÜ©   uèÐA[¶lÑ–-[Ô§OùøøhåÊ•jذ¡üýý%I7ß|³$iÅŠŠ—ÍfShh¨gRBPPþüç?kܸqªU«–bccuôèQ¥§§W¸äÀ /¼ àà`EEEiݺuš5k–fÏž-é— ½½½õúë¯ë±ÇÓwß}§×^{­Rµ½ñÆêÑ£‡~ó›ßhܸqjÖ¬™rssµ|ùrmß¾]Ÿ|ò‰êÔ©£G}TO?ý´‚ƒƒ­O?ýT³fÍÒ›o¾yÙïKeÆZU5j„ züñÇUXX¨Ûo¿]‡CÛ·o×îÝ»¹ÂÕãí믿ÖìÙ³õÐC)**J~~~JKKÓÿýßÿ)..N~~~òóó+÷¹’ñWŘKþìÓ§$©}ûöª_¿¾Æ¯¿þõ¯:{ö¬^xáÝqÇΫDK–,QHHˆZ·n­ììl%&&êøñã–¯yþüy=Zo¼ñ†j×®­¨¨(Õ«WO¯¼òŠÆ§¿ÿýïºõÖ[KÂ-[¶”ù¨·*M·UÆ»ví2½{÷6AAAÆn·›®]»šo¾ù¦Ôó§M›fêׯo¼¼¼*½€«m.5ɺd»‹'õš—^zÉ4mÚÔx{{›† š„„„ û\»v­éÚµ«ñóó376³fÍ*UËÛo¿mêׯoüýýÍwÞiæÏŸ_êu]çþýûͨQ£LÆ 3=ôÙ¾}»³Ãá0Ï<óŒiذ¡óöóyóæUø~YMn¾x›«c­ÊæÌ™c¢¢¢Œ¯¯¯ 0]ºt)Õ—«ý¸r¼>|ØŒ3Æ´k×Îøùù»Ýnš5kfžxâ sêÔ)g»ŠŽ‘Ë¿«c®Hbb¢éÒ¥K©mÛ·o7·Ýv›ñóó3æþûïwNÒ6æ—»Ï6lh¼½½Mxx¸9rä%ïœ2eŠ8p`©m_|ñ…iÓ¦±Ûí&66Öìٳǹïüùó&88Ø$''»<àb6cXލiRRRÔ»woåääT‹«aWÓõ4ÖšìøñãjÖ¬™RSSuË-·xº-]ºTÏ>û¬222ܾ+®ÌI\±zõêéé§ŸÖ‹/¾èéR$I/½ô’H¸"ÌIT‰ÊÌÙºÚ¶oßîép àã6 ÿ¢›¤/éÑØIEND®B`‚prinseq-lite-0.20.4/example/example1_qd3.png0000664000076700007670000001755612240000123021031 0ustar rschmiedrschmied‰PNG  IHDRŸÿ.aÛzbKGDÿÿÿ ½§“#IDATxœíÝ}P÷á?ð÷Ç¡ˆ<0X•!‘‰Š£@cÚdlZ­&ZuŒB«¨™T ãCtbŒX@| «CMDMLˆÕZu%¢6 *NâÃá@$áá>ß?òã~ÂÜí±ìq{ï× 3°wì¾÷vñí>k„DDD rst""r=,""RˇˆˆÇò!""ű|ˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,""Rˇˆˆ×åÊçÝwßÅÈ‘#ƒˆˆ:Q—*Ÿÿþ÷¿¨®®†§§§££Q'ê2åS__ 6`Ñ¢EŽŽBDDÌÃÑšmÙ²¯¼ò üýý-¾>|øpÓ÷çÎS*u‚.Q>eee¸rå RRRÚ|Ï£…SSS£D,"‹Ö­ëfõ=‹q%õèÖÍú:/U—ØíöÕW_¡¼¼“&M¤I“ðÓO?aÒ¤I0ŽŽFDD@#„ŽÑÚèÑ£ñå—_¶ù:·|È‘¸åC®Fµ[>DDäZºdù´·ÕCDDίK–©ˇˆˆÇò!""ű|ˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,""Rœ,åSWW!„£""" ¹|Ö¯_ƒšššðòË/C¯×£ÿþ8þ¼ì‰ˆH}$—ÏÚµkÑ·o_@QQJJJ°oß>ÄÅÅáÍ7ß”= ©‡Ô_¸sçÅÅŘ:u*&OžŒ˜˜DEEɈˆÔGò–OŸ>}PPP€‹/¢¸¸ãÆ466ÂÛÛ[ö€DD¤>’Ë'==Ë–-ÃСCñãÇ>ÿüs >\ö€DD¤>’w»%%%!11÷îÝCLL <<~Ell,dHDDê#¹|`À€0`jjj ×ëáææ†ØØX¹³‘JIÞíÖØØˆåË—# Ý»wGyy9 33¹¹¹²$""õ‘\>(,,Dvv6t:ixXXòòòd GDDê$¹|òòò““ƒ)S¦ÀÝÝÝ4|ذa(--•5©“äò1 7®ÕjQ__/K(""R7Éåв²2³á%%%ˆˆˆ%©›äòIJJBjj*NŸ> ¸}û6 ––†äädÙ‘úH>Õ:%%UUUHHH@]]F N‡ôôtÌ™3§32‘Êh„ÏBxøð!.]º£Ñˆ¨¨(tëÖMîlmª©©QlZD­­[g}]_´ˆë(©Ggüûn×E¦ ×ë1bÄ9³‘‹|Ì'33»wï6¾sçN¼óÎ;²„"""u“\>[¶lÁ!C̆GFFbË–-²„"""u³ë:Ÿ^½z™ ïÝ»7îܹ#K(""R7Éå‚S§N™ ?uêBBBd EDDê&ù„ƒ9sæ`þüù¨««C||<àèÑ£X¸p!/^,{@""RÉå³dÉÜ»wsçÎ5ÝNÇËË ,`ù‘Mì¾ÎçÁƒ¸|ù2`È!¼Î‡\¯ó!WÓ¥®óñööFxx8„hllDuu5ÀÏÏO¶pDD¤N’O8¸rå ÆŽ oooøùù¡gÏž-¾ˆˆˆ¬‘¼å3mÚ4hµZüíoCpppgd²ÊÇÇÇ!Ó%²×Q¢öI.ŸÒÒR\¼xÑâ3}”R[[ë°iÖ÷s%5éŒc>’w»EGG›ŽïÙCrù¬Zµ .ıcÇp÷î]TVV¶ø"""²Fòn·qãÆ€éÓÖìæó¨ššF¹²‘‹\>X¾|9н{w”——øå!s¹¹¹²$""õ‘\>(,,Dvv6t:ixXXòòòd GDDê$¹|òòò““ƒ)S¦ÀÝÝÝ4|ذa(--•5©“]O2µtw­VkzÄQ{$—Ohh(ÊÊÊ̆—”” ""B–PDD¤n’Ë')) ©©©8}ú4àöíÛ(((@ZZ’““eHDDê#ù:Ÿ””TUU!!!uuu=z4t:ÒÓÓ1gΜÎÈHDD*c÷“L>|ˆK—.Áh4"**ŠO2%—Á'™’«éO2}ôŽÖƒ>É”ˆˆ$‘\>ÖžVÊ‹‘5¾±¨ÑhÄ×_ 6`ÅŠrå"""“寢ñññ4hÞÿ}LŸ>]Ž\DD¤bº±è£"##ñå—_Ê5:""R1É[>–žVj0™™‰YB‘ºI.Ÿ   6‡v8©_‡O8Ðh4ðõõEtt4´Z­lÁˆˆH½$—OLLŒÅáµµµfÃxÍY"ûu>â5?DDd‰äòÉÏÏÇÂ… 1cÆ Ói×ÇŽÃÎ;±~ýzôë×OîŒDD¤2’˧  +W®ÄìÙ³MÃ1xð`ìÝ»5 ©äë|Ž?Ž^xÁløøñãñÅ_ÈŠˆˆÔMrùèõz‹Ë¾páôz½,¡ˆˆHÝ$—Ïk¯½†Y³fáÃ?ÄÍ›7QQQüü|Ìž=¯¿þzgd$""•‘|ÌgÍš5hhhÀ¬Y³P__ðôôÄo¼Õ«WˈˆÔÇî‡ÉÝ¿W®\DDDÀ××WÖ`íáÃäÈ‘ø09r5]âarÍ|}}1dÈèõz¸¹ÉvR""r’[£±±Ë—/G@@ºwïŽòòr@ff&rsseHDDê#¹|222PXXˆììlèt:Óð°°0äååÉŽˆˆÔIrùäåå!''S¦L»»»iø°aÃ,ž‚MDDÔšäò1 7®ÕjMg¿µGrù„††¢¬¬ÌlxII """d EDDê&¹|’’’ššŠÓ§Onß¾‚‚¤¥¥!99Yö€DD¤>’OµNIIAUUPWW‡Ñ£GC§Ó!==sæÌ錌DD¤2v_dúðáC\ºt F£QQQrR[x‘)9/2%WÓ¥.2Õëõ1b ®®Bh4Ù‚‘zI>æ³~ýz}PPP€‹/¢¸¸ãÆðË=ß¼½½eHDDê#¹|ÒÓÓ±lÙ2 :?~<àóÏ?ÇðáÃeHDDê#y·[RRqïÞ=ÄÄÄÀÃã—QÄÆÆ"!!Aö€DD¤>vj=`À 0 Å°ØØXY‘úÙ}#ùøø8:Q»¸ŽµÏ)˧¶¶ÖÑÈ¥Y¿Ú›ë(©I—ºÃ)O-·w²él7FƒÛ·o›}ODDd›ÊÇÍÍ vÞ”ˆˆÈŒM»ÝBBBP\\Œßýîw€û÷ïC§ÓY|¯ŸŸŸ|鈈H•l*Ÿ%K–`Þ¼y˜;w.X|Œv3n!‘56•ϼyó0iÒ$”——c̘1(**‚¿¿gg#""•²ùl·~ýú¡_¿~ܲ!"¢“|o·GýüóÏøùçŸåÊBDD.®òÙ±c""" Óé Óé‰]»vɈˆTJòE¦¹¹¹HNNÆ‚ 0fÌÀ‰'0wî\FÌœ9SöDD¤.’ËgíڵشifÍše–˜˜ˆÁƒcÍš5,""²Jòn·k×®áùçŸ7þ /àÚµk²„"""u“\>ÁÁÁ¸pá‚Ùð . W¯^²„"""u“\>¯¿þ:fÏžüü|TTT ¢¢ùùù˜={6fÌ˜Ñ ‰ˆHm$óÉÈÈ@uu5fÍš…††€V«Åo¼·ß~[ö€DD¤>’ËÇÃÛ6mÂÊ•+qåÊ@dd$|}}eGDDêd÷ó|zôè‘#GÊ™…ˆˆ\D‡îp@DDd–)NRù444ààÁƒ¨¬¬ì¬’¯óIIIAUUPWW‡Ñ£GC§Ó!==sæÌ錌DD¤2’ËG£Ñ`ÅŠX¼x1.]º£Ñˆ¨¨(tëÖ­3ò‘ Ùým½^'Ÿ|àåå%[ ""R?»îp°}ûvDFFB§ÓA§Ó!22;vì;©”äòùàƒœœŒßüæ78tè:„—^z óæÍCvvvgd$""•‘¼ÛmݺuØ´iþô§?™†%&&bðàÁÈÊÊâoDDd•ä-Ÿ»wïâ¹çž3þ /àÎ;²„"""u“\>111o£sáÂ<õÔS²„"""u³i·Û£ÇÎÌÌDrr2ªªª0fÌ!pâÄ dffbóæÍ”ˆˆÔæò 26}út³aÏ?ÿ<£MDDVÙT>|t6Éɦòᣳ‰ˆHNvßá ©© 555f»Ùüüü:ŠˆˆÔMòÙnÿûßÿN???ôìٳő5’·|¦N ooo"00°32‘ÊI.ŸÒÒR”––",,¬3òØÄÇÇÇaÓ&²×Qr$gXÿ$—Ott4ª««;#‹Íjkk:}ruÖÂu”:òë_g<2GrùlÚ´ K–,Aff&¢¢¢àæÖò°O8p=ëÖY_1-ªQ I×"÷çÂÏÙ2µ|ή¶|%—O`` ¼Ã5u”äò±vw^dJDDÖH.kw®æ1""²¦ÃÇ|ŒF#¾þúklذ+V¬+©˜,Ç|âãã1hÐ ¼ÿþû˜>}º¹ˆˆHÅ$_çÓ–ÈÈH|ùå—rŽˆˆTLò–¥ I 233"K(""R7ÉåÔæðÂÂÂ"""õëð ¾¾¾ˆŽŽ†V«•-©—ÍåÓ|}OLLŒÅ×›ŸœÇë|ˆˆÈ›ËÇÚõ=ÍxYcsù´uO7!öïßœœèõzÙ‚‘zÙ\>­¯ïBà£>BFF***°lÙ2,X°@î|DD¤B’O8h]:iiiX°`|}};#©Íå#„ÀÇŒŒŒ ܸq©©©HMMeé‘d6—ÏSO=…+W®`Μ9(**‚¯¯/êëëÍ.: ”=$©‹ÍåóÕW_6n܈7¶ù>žíFDDÖtøl7"""©ì>ÛˆˆÈ^²ÝÕšˆˆÈV,""RˇˆˆÇò!""ű|ˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,""Rˇˆˆçáè­=xðK—.Eee%‚‚‚°zõjøøø8:ɨËmùäææ"66{öìÁˆ#°}ûvGG"""™u¹ò9uêÆHLLÄÉ“'Ç7}‘sër»ÝîÞ½‹   @`` *++çÎ3½§¦¦Æ!ÙˆˆH&¢‹yöÙg…Ñh4ý×îû‡ fÓxù>¾ïãûø>yÞ'B8º5yòdüõ¯Epp0*++1þ|ìÝ»×ѱì6|øð[mΊóѵp>ºµÌ‡’ºÜ1ŸQ£FáÓO?>|£Frp"""’[—Ûò¹ÿ>ÒÓÓqïÞ=bõêÕèÞ½»£c‘Œº\ù‘úu¹ÝnDD¤~]îTk55jBCCüã1qâDDzÑÖ­[Q\\ ƒÁ€3gδxÍÙîDÑÞ¼8Ãò9wîÞ{ï=455ÁÍÍ ééé:t(ç[íÍ‹3,‹f{÷îEQQ4 àÍ7ßÄÓO? Àù–‰C(v^ {æ™gÁ.¥¥¥âîÝ»ó¿÷Þ{b×®]B!víÚ%6lØ tß~û­¸wïžBˆóçÏ‹—_~Ùôš³-‹öæÅ–E³ÚÚZÓ÷åååâùçŸ7ýìlËĸÛÚmºà·µ¶îDÑUµ7/Î`àÀð÷÷<ñĸwïžé5g[íÍ‹3Ñëõ¦ï>|ˆ^½z™~v¶eâÜí¦!¦NŠnݺaéÒ¥0`€£#uX[w¢pFζ|8`Ú½8÷²h=/ζ,öìÙƒ={ö ®®Û¶m3 wæe¢nù( ¸¸øío‹¬¬,GÇ¡Vœiù\½zùùùHKKst”³4/δ,àø>úè#¤¤¤`Íš5ŽŽãTX> èÙ³'`ܸqøî»ïœFAAA0 €ÊÊJ:8‘ýœeùܹsK—.ŪU«ZìBtÆeÑÖ¼8˲hmüøñøúë¯M?;ã2Q˧“UWWCü¿K©Nž<‰ÇÜÁ‰ä¡–;Q8Ëò©­­EZZRSSÙâ5g[mÍ‹³,‹f?üðƒéû’’’»m™8/2ídŸ~ú)òòò:o½õœÊ6ÙÙÙ8|ø0 ‚‚‚˜˜ˆäädÎw'жæÅY–O~~>¶mÛ†Ó°?ünnnN·,Úš—Ï>ûÌ)–E³U«V᫯¾‚~~~-ŽQ9Û2q–)Ž»ÝˆˆHq,""RˇˆˆÇò!""ű|ˆˆHq,êmÛ¶aÀ€pww7ÝÝ׎?FcºI량¨kaù(¬ùE___<|ø°Åk—/_†F£F£AuuµƒÚîûï¿Ç¼yó°dÉܼy·nÝrt$“Q£FáÖ­[ðÿ?wgø\‰\ËÇAüüü°oß¾öoߎþýû;(‘tß}÷ŒF#~ÿûߣOŸ>xì±ÇÉÄÓÓ=ö˜C·ÆäÔØØèè’9cfRËÇAf̘aºšŸŸ3f˜½÷ƒ>@xx8<==ѯ_?¼ýöÛhjj2½¾k×.ÄÄÄÀËË ={öÄ´iÓZü¿ùýŸ}ö† ///Œ1W¯^m3_cc#Þzë-„„„ÀÓÓáááØ¾}{‹÷Œ3àïïoÚbkk\‹-BPP|||ðÒK/áÃ?4m‰XÚEÖzKÅÚ<¶Özœqqq~¹wØ£Y333möûO?ý4RRR,Ž{ëÖ­èß¿?<<<зo_¬_¿ÞôšÑhĻヒAƒÁÓÓ}úôAff¦¤Ïµ9û'Ÿ|‚ØØXxzzšnÕbm]h/[[ŸÑ矎Q£FA§ÓáñÇGvv¶Ù{­M·½Ì¶~v¶LGŽuIÊü´÷7cmYÛ2—æ ç¹¬cÇŽ âêÕ«B§Ó‰o¿ýV!Ä?þññ«_ýJ=zTUUUB!þò—¿ˆððpqøðaqóæMñÏþS„††ŠeË–™Æ¹{÷nñÅ_ˆŠŠ qüøq-¦M›f6ÍQ£F‰Ó§O‹Ë—/‹_ÿú×bìØ±mæœ?¾ 7nÜ999ÂËËKäåå™ÞSTTdš—[·n‰[·nYWJJŠ6këÖ­"00Ð4ŸÍù ƒYææÏÁÖylGëŸÛÊzóæMáîî.Μ9cו+Wqá³y¹víšÐh4bÕªUâúõëâìÙ³âÀ¦×/^,zöì) EEE…8{ö¬Ø¹s§¤Ïµ9{LLŒ8~ü¸¸~ýº0 V×kÙZkžÎ AƒÚÍcË:ØVf)Ÿ-Ó‘c]’2?íýÍX[Ö¶LÇ•±|öèÇ«¯¾jZ'Nœ(²²²Zü¡ÔÖÖ oooqêÔ©ã(((þþþmNcÿþýÂÇÇGÆÓú³-ëB{Ù,ižŽ¥<6O·­Ì­µ—Ï–éȱ.IŸ¶þf¬-k{ÿv] ËGaþq9rDôë×OTTTOOOqóæÍ(ÿùÏáããÓâK§Ó âÁƒB!Nž<)DPPèÖ­›éõû÷ï·˜æ;wÌrTWW›eü÷¿ÿ-ˆ7n´~èÐ!@üôÓO-ÆÑ^ùœ9s¦ÝqÙZ>¶Î£=åóÑG‰=zˆ‡ŠÆÆFÑ»wo±yóf‹óÓÐÐ FŒ!zôè!¦M›&öîÝ+ÛW{?×ï¿ÿÞô[Ö…ö²YÒ<öòغZÊ,å³³e:r¬KRç§­¿kËÚÖé¸2>ÉÔž{î9¸¹¹áµ×^C||<úõë‡o¿ýÖôºÑhð˱-Ì×ëõ¨®®Æ„ ðÊ+¯ ++ 8}ú4^ýu³}Ënnæ‡ø„B÷•mïÀ¿¥×šç€¤y´Çĉ¡×ëQTT„=zàÇÄÔ©S-¾×ÃÃÿú׿päÈ|ú駘;w. °ÿþçhÍÓÓÓô½-ë‚›››]ÙÚ[6¶L·­Ì­µ÷ÙI™NGÖ%©ócïߌÔé¸"–¹¹¹aÆŒÈÌÌ4;ó ¢¢¢ ÓéPQQgžyÆâ8ÊÊÊðàÁdee™nQÿñÇw(Wdd$´Z-Nœ8éÓ§›†Ÿ8qðòò²y\ðôôĉ'0mÚ4ÓðãÇ›¾÷õõÐò¡[>˜KŽytwwÐò¢f¦@zôèÉ“'›2Y¢Õjñâ‹/âÅ_Ę1cðꫯ¢®®‘‘‘ðòòÂÑ£G-ž8Ò‘ÏÕ–u¡½lÞÞÞmþNëeSRRbÊcëtmÕV>[¦#Ǻ$×üX[ÖrnªäèM/WÓz·@}}½0 ¢©©©ÅëÍ»‡V¬X!üýýÅîÝ»Åõë×Å7ß|#öìÙ#222„B|ÿý÷ÂÝÝ]üùÏ×®]û÷ï!!!-ÆaÏ1•¤¤$,Š‹‹EEE…ÈÍÍmóÀx{»Ý„"99YôêÕK;[¦ÓÑu©#óÓz}·¶¬m™Ž+cù(ÌÚ©¥зnÝ*ž|òIáéé)|||Dll¬ÈÉÉ1½¾}ûvÑ»wo¡ÓéDBB‚عsg‡Ë§¡¡A,[¶LôíÛWhµZÖbš¶Œ£Y}}½HKKÂÛÛ[L˜0Aäçç·øÝ#GŽˆ ////vïÞÝâu©óhižßyçÑ»woáææ&,ý¿+..N <¸Ýy)++qqq¢{÷îB«ÕŠ‘#G¶8S®©©I¬\¹R„†† wwwÑ·o_‘••e×çjiio]°–­µæé9rDŒ9Rxyy‰±aÃIÓµ–ÙÖÏΖéȱ.Ù;?­×wkËÚ–é¸2>LŽâøñ㈋‹CUUüüüÀ/»ufΜ‰%K–8:Š"š—Á`0í¢rF]q]"ëẋ\žÁ`À¾}ûPQQ™3g::‘K`ùË F`` 6oÞŒàà`GÇ!r ÜíFDDŠû?¶Bíó IEND®B`‚prinseq-lite-0.20.4/example/example1_cd.png0000664000076700007670000002440512240000123020717 0ustar rschmiedrschmied‰PNG  IHDR®÷C„0bKGDÿÿÿ ½§“ IDATxœíÝyTÕõ¾ÿñ×fÜ""(X¤æˆ+§–å¬9íÔ©îÑke7½–j¹Ò* LÓ•ÇÒcæeW­׎Xi¦(•¦eÇ!Moe÷8äóû£ûŠ€@ò÷×çc-Ö‚Ïwóy>{Yûå×Ïþ|]Æ#àçSÙJƒà ¯@p€W ¸À+\à®ð Wx‚+¼Á^à ¯@p€W ¸À+\à®ð Wx‚+¼Á^à ¯@p€W ¸À+\à®ð Wx‚+¼Á^à ¯@p€W ¸À+\à®ð Wx‚+¼Á^à ¯@p€WpTp}íµ×Ô¶mÛÊ,pLpýÇ?þ¡S§N)  ²‡ \/^¼¨Y³fiìØ±•=XâWÙ(o½õ–|ðAÕ¨Q£Èã­Zµò|ÿÝwßUÔ°P޼>¸îÙ³G{÷îU|||±¹2¬feeUİàåfÌ.Ô6v,ç¥\ø½ôzyýRíÛ·kÿþýêÛ·¯úöí«óçÏ«oß¾ÊË˫졠¹Œ1¦²QžÚ·o¯/¿ü²Øã\qEipÅ€ëÃWÜ´\¯uµÞËqÁÎDp€W ¸À+\à®ð Wx‚+¼Á^à ¯@p€W ¸À+\à®ð Wx‚+¼Á^à ¯P¡Á5''GƘŠ, ‡°\gΜ©U«VI’._¾¬x@AAAºí¶Û´mÛ6[eàPÖ‚ëôéÓU·n]IRrr²ÒÒÒôÑG©sçÎ9r¤­²p(?[?~\5kÖ”$¥¤¤hÀ€z衇§ØØX[eàPÖ®¸Ö©SGK—.ÕÎ;•’’¢=zH’rssU¥J[eàPÖ‚ëøñã5aÂÝy犎ŽVÏž=%I_|ñ…Zµje«,ÊÚRáÇ«wïÞ:yò¤âââäç÷[©6mÚ¨k×®¶ÊÀ¡¬WIjذ¡6l¨¬¬,ÉÇÇGmÚ´±Yem©@nn®&Nœ¨š5kªZµjÚ¿¿$)11Q ,°Ue-¸&$$hÙ²eš={¶Ün·§½iÓ¦Z´h‘­²p(kÁuÑ¢Eš?¾ú÷ï/___O{Ë–-µk×.[eàPÖ‚kzzº¢¢¢ µûûûëâÅ‹¶ÊÀ¡¬× hÏž=…ÚÓÒÒm«,ÊZp>|¸F­Í›7K’Ž;¦¥K—j̘11b„­²p(kÛaÅÇÇ+33S]»vUNNŽÚ·o/·Û­ñãÇkÈ!¶ÊÀ¡\Æc³À¹sç´{÷nååå)66VÁÁÁ6Ë•(++«RëÃ;̘Qø<;–s€Ò²‘ù¬Þ€@’‚‚‚ÔºukÛeàpÖÖ¸&&&ê½÷Þ+Ô¾xñb½üò˶ÊÀ¡¬×·ÞzKÍš5+Ô£·ÞzËVY8”Õ}\o¹å–Bíµk×ÖñãÇm•€CY ®‘‘‘Ú´iS¡öM›6)22ÒVY8”µg 2DÆ SNNŽºté"IZ¿~½žyæ=÷Üs¶ÊÀ¡¬×qãÆéäÉ“:t¨ç¯5jÁef}׳gÏêÇ”$5kÖŒ}\áØÇ€ëã•û¸V©REQQQ2Æ(77W§N’$…††Ú. ±öᬽ{÷ªS§NªR¥ŠBCCVà ( kW\(ý×ý—jÕªe«L™U­Zµ²‡/Ź@å²\wíÚ¥;w***ÊV‰ß%;;»²‡¯Px]ç¥gc«µ¥Í›7÷¬g®—µàúꫯê™gžQjjªNœ8¡ŒŒŒ_@YX[*УGIòÜ|àj–wá€ÃX ®©©©¶ºÀMÈZpíÔ©“­®p²¶ÆõJYYYÊËË«ˆRp(kÁ577W'NTÍš5U­Z5íß¿_’”˜˜¨ Ø* ‡²\´lÙ2Íž=[n·ÛÓÞ´iS-Z´ÈVY8”µàºhÑ"ÍŸ?_ýû÷—¯¯¯§½eË–Úµk—­²p(kÁ5==½È»fùûûëâÅ‹¶ÊÀ¡¬× hÏž=…ÚÓÒÒm«,ÊZp>|¸F­Í›7K’Ž;¦¥K—j̘11b„­²p(kû¸ÆÇÇ+33S]»vUNNŽÚ·o/·Û­ñãÇkÈ!¶ÊÀ¡\Æò½WÏ;§Ý»w+//O±±± ¶Y®DYYY•ZÞaÆŒÂç騱œ;”–ÌgíŠë©S§<ß7iÒDÒo{»æ·‡††Ú* ²\îyÜò…^8ŒµàšššZàç¼¼<ýðÚ5k–^zé%[eàPÖ‚k§N µuéÒE7Ö_þò=ú裶JÀ¬m‡Uœ˜˜}ùå—]^ÎÚ׌ŒŒBméééJLLTdd¤­²p(kÁ5""¢ØöeË–Ù* ‡ª°g¹\.…„„¨yóæò÷÷·Ue-¸ÆÅÅÙž]¨=]P’JÛÇõJìé €’X ®K–,Ñ3Ï<£Aƒy¶ÆJMMÕâÅ‹5sæLÕ«WÏVi8µàºtéRM™2Eƒö´õîÝ[Mš4ч~¨•+WÚ* ²¶ë† tß}÷jïÙ³§Ö­[g«,ÊZp Ò®]» µïرCAAA¶ÊÀ¡¬×Ç{LO>ù¤Þÿ}>|X‡Ò’%K4xð`=þøã¶ÊÀ¡¬­q6mš.]º¤'Ÿ|R/^”$è©§žÒÔ©Sm•€C¹Œå½¨Îœ9£½{÷J’¢££b³\‰²²²*µ>¼ÃŒÁ…ÚÆŽåÜ ´‚ƒ ¿—^/kW\ó…„„¨Y³f ’µ• p8kI277W'NTÍš5U­Z5íß¿_’”˜˜¨ Ø* ‡²\´lÙ2Íž=[n·ÛÓÞ´iS-Z´ÈVY8”µàºhÑ"ÍŸ?_ýû÷—¯¯¯§½eË–En“\‹µàšžž®¨¨¨Bíþþþž]€Ò²\4h ={öjOKKStt´­²p(kÁuøðá=z´6oÞ,I:v옖.]ª1cÆhĈ¶ÊÀ¡¬m‡¯ÌÌLuíÚU999jß¾½Ün·Æ¯!C†Ø* ‡²~‚sçÎi÷îÝÊËËSll¬•ÍhË‚ 4¸×Ç+o@¤Ö­[K’rrrdŒ‘Ëå²]cmëÌ™3µjÕ*IÒåË—õÀ(((H·Ýv›¶mÛf«,ÊZp>}ºêÖ­+IJNNVZZš>úè#uîÜY#GŽ´Uem©ÀñãÇU³fMIRJJŠ  ‡zHqqqеUeíŠk:u´téRíܹS)))êÑ£‡$)77WUªT±Ue-¸Ž?^&LÐwÞ©èèhõìÙS’ôÅ_¨U«V¶ÊÀ¡¬->|¸z÷î­“'O*..N~~¿•jÓ¦ºvíj«,ÊêvX 6TÆ ´µiÓÆfI8”õ}\o4U«V­ì!ÀKqîP¹nºàš]ÙC€W(|·ÎJÏ+ïœåTÅÝ´¬í(rÝUÀår騱c…¾®W¹WcʳK@R9/ˆŒŒTJJŠ~øaIÒ™3gäv»‹|lhhhy–€Ã•kp7nœž~úi :T’Uìc¹2 €²(×àúôÓO«oß¾Ú¿¿:vì¨äädÕ¨Q£}$I}ûö-ò¸1ÆVi8µàšššj«kÜ„¬×N:Ùê7¡ ÙÇ5++KyyyQ e-¸æææjâĉªY³¦ªU«¦ýû÷K’µ`Á[eàPÖ‚kBB‚–-[¦Ù³gËív{Ú›6mªE‹Ù* ‡²\-Z¤ùóç«ÿþòõõõ´·lÙR»ví²Ue-¸¦§§+**ªP»¿¿¿.^¼h«,ÊZpmРöìÙS¨=--MÑÑѶÊÀ¡¬×áÇkôèÑÚ¼y³$騱cZºt©ÆŒ£#FØ* ‡²¶k||¼233ÕµkWåää¨}ûör»Ý?~¼† b«,ÊZpu¹\z饗ôÜsÏi÷îÝÊËËSll¬‚ƒƒm•€ƒY ®ù‚‚‚Ô¢E IR`` írp(«wÎZ¸p¡bbbäv»åv»£wÞyÇfI8”µàúÆohĈºÿþûõÉ'Ÿè“O>Q¿~ýôôÓOköìÙ¶ÊÀ¡¬-˜1c†æÌ™£ÿøÿð´õîÝ[Mš4QRR;  L¬]q=q℺uëV¨ý¾ûîÓñãÇm•€CY ®qqqEÞÚuÇŽºë®»l•€C•ëRŒŒ Ï÷‰‰‰1b„233Õ±cGc´qãF%&&jîܹåY7r ®…Ú}ôÑBmÝ»w—1¦œ€²°\SSSmu €›µàÚ©S'[]à&d-¸–t×,o¹n Ö‚kXXØ5³ÆeQak\óòòôÃ?hÖ¬YzÉÆ=ÀàhºÆµK—.jܸ±þò—¿èÑGµUdm×âÄÄÄèË/¿¬è²ðrÖ®¸u“ôôt%&&*22ÒVY8”µàQlû²eËl•€CU؇³\.—BBBÔ¼ysùûûÛ* ‡*÷àš¿k\\\‘dz³³%±+ʦ܃kIû·æcW”E¹׫—ä3ÆhÅŠš?¾‚‚‚Ê»,®ÜƒëÕû·côñÇ+!!A‡Ò„ 4jÔ¨ò. ‡³öᬫë˜1c4jÔ(…„„Ø* +÷àjŒÑßÿþw%$$èàÁƒ=z´FM`Àu)÷àz×]wiïÞ½2dˆ’““¢‹/º!Axxxy—€ƒ•{pݾ}»$éÍ7ßÔ›o¾YìãØUeQa» ×Ãú®@yð©ì¥Ap€W ¸À+\à®ð Wx‚+¼Á^à ¯@p€W ¸À+\à®ð Wx‚+¼Á^à ¯@p€W ¸À+øUöÊÓÙ³gõüóÏ+##Cš:uªªV­ZÙÃ@9pÔ× ¨M›6Z¾|¹Z·n­… VöPN\7mÚ¤ž={J’z÷î­¯¾úJ’ÔªU+ϼ“£– œ8qB’¤ððpeddH’¾ûî;Ïc²²²*el¸NÆA:tè`òòòþøcóâ‹/šË—/cŒÉÌÌôsꜯ´|ùr“`Œqæ|»wïn~ùåcŒ10=zôðsâ|h¾úê+cŒ1_ýµyã7<Çœ8ߊÆR‡jÞ¼¹çf W+îcÞªQ£FªQ£†$éŽ;îÐÉ“'=Çœ6×|ùÿz—¤sçÎé–[nñüìÄ9_¼xQ³fÍÒØ±c sâ|‹ãÔ¹®X±BO<ñ„||~{K õsꜯ´fÍÏ8ßzõêynþsöìYÕ©SÇs̉ó=xð Ú¶m+Iºûî» Ìɉó­h,¸ w‡1'X¹r¥ç¿Ì%gÏuùòåZ¾|¹rrrôöÛo{Ú8ç·ÞzK>ø ç(Wrâ|10`€‚ƒƒõüóÏ«aÆ’œ9Wé·7úÏ>ûL6lPXX˜&L˜ ÈÈHIÎs¾#GŽèÈ‘#ž[’;q¾/¿ü²,—Ë%cŒæÏŸï9æÄù6jÔHk×®U¯^½´víZ;vÌs̉ó­h\q…cìÛ·OK–,ј1c*{(âÏþ³>þøcÅÇÇkÚ´i•=köìÙ£½{÷ª_¿~•=” “’’¢¥K—êü£’’’*{8Ö]¾|Yõë××òåËõÀ(11±²‡Ta>ÿüsuëÖÍsµÙ‰^{í5ÅÇÇë“O>ÑèÑ£5}úôÊ’U“'OÖŠ+ôoÿöoúùçŸåëë[ÙCrçþ¥ XJOO—$edd(<<¼’GtýŽ?®çŸ^¯¾új%NœëÕzöì©~øÁó³Óæ¼}ûvíß¿_}ûöUß¾}uþüyõíÛWyyy’œ7_I “$õèÑC¿üò‹§Ý‰s•¤[o½UÝ»w—$uëÖM?ýô“ç˜SçœïÊe’3çûüCݺu“ôÛë»cÇÏ1'Î÷öÛo×Ûo¿­>ø@ýúõÓm·Ýæ9æÄùV4‚ëMÈiwËÎÎÖ˜1c4zôhÅÄÄ8æ´¹æ;räˆçû´´4Ï%KΛó€´zõj¥¤¤(%%En·[)))ž+TN›ï©S§dþÿöÚ_}õ•êׯï9æ´¹æk×®¶nÝ*é·]B®|£wêœ%iÿþý:w7oîisâ|ëÕ«çy}·lÙ¢ºuëzŽ9q¾§OŸ–ôÛ’ŸwÞyG}ûöõsâ|+7 p¨Ù³gëÓO?Uzzº"""Ô»wo1B’óî0¶dɽýöÛž5q’ôþûïËÇÇÇqsÍ÷ꫯjûöí2Æ(44´À:H§Î9_ûöíõå—_z~vÚ|W¯^­E‹I’Ün·&Mš¤¦M›JrÞ\óeeeiòäÉúç?ÿ)½øâ‹ŽŸ³$Í;WÆ 6ÌÓæÄùîÞ½[¯¼òŠ.^¼¨€€Mœ8Q±±±’œ9ß¿ýíoZ¶l™|}}Õ¡C >ܳu¡ç[Ñ®ð ,€W ¸À+\à®ð Wx‚+8À† är¹Êõ’6ú¼RRR’h¥oÖ²eKýío«ìa×…à X”ÿÆ¢sçÎ8öã?ÊårÉåréÔ©S•4B xíÚµÓÑ£GU³fMIÿw>—Çùú¯ýK3fÌФI“sss5iÒ$EFF* @QQQZ¸pa>òǾf͵jÕJn·[wß}·~ùåmÙ²E­[·–ÛíVëÖ­õÓO?ú½/¾øBíÚµ“ÛíVýúõ5{öìbÇ[šy¦§§«víÚJHHð<~çÎr»Ýžd]ýºuîÜY’VàŠdbbbÛ–æ»çž{_䨖/_®ûï¿¿ÈcµjÕÒ­·Þª¦M›êÏþ³¾þúkùúúêÅ_,qÎù¶oß®ÿýßÿÕ_ÿúWµmÛVuëÖU\\œâããÕ¿IÒ­·ÞêùªQ£FÚù_E¹ÖßKyž+Ÿ}ö™Ú´i£€€ÏUâ’ÎÝk- @={öÔ|Pêç¸áÖ¤¦¦Ifß¾}Æív›ŸþÙcÌÿ÷›Ûo¿Ý¬_¿ÞH2™™™Æc^|ñEe>ýôSsøða³víZÓ A3aÂOŸï½÷žY·n9tèÙ°aƒiÞ¼¹8p`¡šíÚµ3›7o6?þø£¹ûî»M§NŠ㯿þj\.—yõÕWÍÌ·ß~kV®\é9^š1ÅÇÇ›Zµj™•+Wšƒšyóæ™ððpÏÜòÇ”žž^hœe™{iæöÜsÏ™°°0³lÙ2sèÐ!óí·ßšÅ‹—i>W+©ÏaÆ™ˆˆÏüçÏŸoÍ¢E‹ ýî»ï6›6m2{÷î5íÚµ3-[¶4:u2ß|ó§­k×®…~¯qãÆ¥ê?ÿ9.Í=zÔ=zÔcÌáǯ¯¯Ù²e‹çw÷îÝk$™;vz>Ïœ9c\.—Y·n]ö¢Î“|3gÎ4µk×¾æã®<§8`\.—™:uª¹téR¡þ®võùXœ’þ^Êó\‰‹‹36l00ééé%¾¦%-ÿy¼ýöÛK|>€Á°èÊ7ØGyÄóÓ§O“””TàÍ2;;ÛT©RÅlÚ´©@K—.55jÔ(¶ÆŠ+LÕªUM^ª?û*®IDAT^^šëׯ÷<æƒ>0~~~E¾ûí·ÅŒÒŒéôéÓ& À¼÷Þ{3vìØR×Òν¤¹9sÆšwÞy§Èçê÷<Ç%õyêÔ)ãïï_hþÏ=÷œ‰ŠŠ*4ö+ÃÚ‡~h$™´´´m~~~&77·ÀïÕttt¡þÓÓÓË4ÏQ£F™† šAƒ™F™³gÏÙç•?îúôéc†Z`|­Zµ*ò9ûþûï$óÓO?h¿Vpýì³ÏŒ$sáÂ…RWcŒ™5k– 2ÁÁÁæÞ{ï5Ï>û¬ùöÛo‹Siƒëµþ^Êû\¹2t–æ5½ÖØò%''—Ëe.^¼xÍy7*‚+`Ñ•o°kÖ¬1õêÕ3‡2æðáÃÞ,·nÝj$™ªU«ør»ÝF’'P|õÕW¦k×®&""Â{ŽŸ9s¦@ÍãÇÇ©S§ ñÒ¥K¦uëÖ¦zõêfàÀæÃ?ô„¦ÒŒiË–-F’9xð`~?ùä“R×Òν¤¹7–|¥­s¥’úüæ›o®9ÿóçÏ—8ö“'OûZåÿ\ÚþÓÓÓË4ÏóçÏ›¨¨(ãããc¾ùæ›5Ê\?þøcS½zusîÜ9“››kj×®mæÎ[äs–––f$y®ØWïJŸ~úi™ƒ«1¿…ÉU«V™¤¤$Ó­[7ãr¹ÌÌ™3 õ_Úàz­¿—ò>WþùÏzSš×ôZcË·víZ#Éüë_ÿºæ<•_V¸ݺu“{ì1uéÒEõêÕÓÏ?ÿì9ž——'IZ½zu‘kë‚‚‚têÔ)õêÕK>ø ’’’®Í›7ëñÇ/´FÓǧðvSħ‰ýüüôõ×_kÍš5Z½zµ†ª¥K—jÅŠ¥S¾k}€§¨cù}_ù}iêH¥Ÿ[q5K[dž¢Æ^šù”åRe™çtøða¹\.íß¿_mÛ¶-u+õéÓGAAAJNNVõêÕuúôi 0 ÈÇK’Ξ=[ì:Ò«ýøãªS§Ž IºpáBÇœ?^’èi«V­šúôé£>}úhÒ¤IJJJÒäÉ“_äó^’ký½”·üyJ¥{M}||JÛ™3gär¹<¯àm®@ñññÑ Aƒ”˜˜Xh‡IŠ•ÛíÖ¡C‡tï½÷ÙÇž={töìY%%%)22R’ô÷¿ÿýºÇæïï¯?üáúÃþ Ž;ê‘GQNNN©Æ­€€mܸ±Àžœ6lð|"IÊÈÈPxx¸$é‡~ð/MÒˆ‰‰Q`` Ö¯__äß~O’úŒ‰‰‘¿¿¿6nܨG}ÔÓ¾qãFEGGQ×ãêç7--­ØþK;ÏK—.iÀ€êׯŸÚ¶m«aÆéž{î)v· ___IÿÑ‘ÏÏÏÏó!Äêի롇ò¼îWkܸ±\.—<¨&Mš\sÞ’”““£·ß~[üã%I5’ËåÒÎ;U·n]Ïã¶oß®:uê¨J•*ÅöÕ¢E eggëÒ¥K¿ûµ)îïÅæ¹RÚ×´¸±å?'TÆ åïïÿ»æT6‚+P&Mš¤‘#Gz>Á|¥àà`?^#GŽÔåË—Õ¡C]ºtIÛ¶mÓ¾}ûô /¨AƒòõõÕ›o¾©aÆiûöízã7®kL[·nÕÖ­[Õ­[7ùùù)%%EuëÖ•Ûí–Ëå*qL!!!úÏÿüO;VaaaºãŽ;´víZ-^¼ØS#66VáááJJJÒ+¯¼¢½{÷wiæ^ÕªUÓ¨Q£ôì³ÏªJ•*j×®Ž?®Ý»wëñÇÿ]uJêóêùßyçúüóÏ5kÖ,Í;÷º^›+%&&*,,L-Z´ÐÚµk5kÖ¬bw(í<'Ož¬ôôt­[·NÕ«W×êÕ«õØciýúõE^¬_¿¾$iåÊ•êÓ§\.—ç"’4xð`M›6M>>>Z·n]±s©V­šâââ<çÝÕNœ8¡ÜÜ\={Vßÿ½¦M›¦Ë—/륗^’$ÝrË-ºÿþûõì³ÏªjÕªºýöÛõÝwßiúôé5j”$é믿ÖìÙ³õðëE‹ ÔÎ;5nÜ8õêÕëw‡Ö’þ^l+¥yM¯5¶+Çß±cÇß5wà†PÉKG»Öš½+_¹®nÞ¼y¦E‹& ÀT­ZÕ´iÓÆÌŸ?ßs|áÂ…¦víÚÆív›®]»šÅ‹è£4Ÿà¿Òž={LçÎMµjÕŒ¿¿¿iÛ¶mO‡—fL/^4cÆŒ15kÖ4UªT1½zõ2K–,)PsÍš5¦Q£F&00ÐtéÒż÷Þ{ež{iævùòe3eÊÓ AãëëkêÖ­k’’’Ê4Ÿ«•Ôç¥K—Ì„ Lݺu¿¿¿iÚ´i¡þJûº\Ý–ÿóš5kLÛ¶mM`` ‰ŒŒ4³fÍ*±ÿkÍsÆ ÆÏÏϤ¦¦zôèQa¦L™RlŸ/¿ü²©]»¶ñññ1E½…tîÜÙ4iÒ¤Øç2ßÔ©SM›6mŠœƒ$ãr¹LHHˆiÕª•IHH0§OŸ.ðØÓ§O›¡C‡šZµj???S¿~}“˜˜èYÓyäÈóÔSO™˜˜hüýýMÆ ÍèÑ£ õUÔó^œ’þ^l+ù®õš–4¶ .˜°°0³zõêkθ‘¹ŒáÊ߆ Ô¹sgeff*44´²‡ãµòŸÇôôôW7oTÑÑÑzâ‰'4nܸk>îäÉ“jذ¡¾ùæ5kÖ¬‚FwsKNNÖĉ=wí¼7 \·ôôtýõ¯Õ¡C‡ôÄO”øøš5kjìØ±zå•W*`t¤)S¦())‰Ð ¯ÆWÀu«U«–ÂÃÃ5wî\ÕªU«T¿SÚµË(Û¶m«ì!×¥ð ÿù¥>L®ˆwIEND®B`‚prinseq-lite-0.20.4/example/example_readme.txt0000644000076700007670000000475612240000123021545 0ustar rschmiedrschmiedThis file will contain example commands for newly introduced options. (If you want to copy and paste the commands, do not copy the $-sign.) For more examples and information, take a look at the Manual (http://prinseq.sourceforge.net/manual.html). (1) Graph data ============== To generate the graphs from the web version or the HTML report, you can use the -graph_data option: $ perl prinseq-lite.pl -verbose -fastq example1.fastq -graph_data example1.gd -out_good null -out_bad null The verbose mode shows the progress and the "-out_good null -out_bad null" prevents PRINSEQ from generating any other output files than the specified test.gd file containing the graphs data. To generate the graph as PNG files, you can use the prinseq-graphs -png_all option: $ perl prinseq-graphs.pl -i example1.gd -png_all -o example1 To generate the HTML report containing all the tables and figures from the web version, you can use the prinseq-graphs -html_all option: $ perl prinseq-graphs.pl -i example1.gd -html_all -o example1 (2) Consider exact duplicates only ================================== When you process large files, the duplicate removal will require a lot of memory. To reduce the amount of memory required and speed up the process (at the cost of only removing forward and reverse exact duplicates), you can use the option -exact_only when generating the graphs data: $ perl prinseq-lite.pl -verbose -fastq example1.fastq -graph_data example1.gd -out_good null -out_bad null -exact_only Note that for processing the data, if you specify -derep 1, -derep 4, or -derep 14 then the exact_only option will be used automatically. (3) Duplicate threshold and no quality header information ========================================================= Process the data (-fastq example1.fastq) with status report (-verbose), remove exact sequence duplicates (-derep 1) that occur more than 2 times (-derep_min 3) and save the sequences passing the filter in example1_good.fastq (-out_good example1_good) without the quality header (-no_qual_header) and the filtered sequences in example1_bad.fastq (-out_bad example1_bad): $ perl prinseq-lite.pl -verbose -fastq example1.fastq -derep 1 -derep_min 3 -out_good example1_good -out_bad example1_bad -no_qual_header (4) Paired-end data =================== Paired-end data is processed similar to single read data. The only difference is that two input files are required (either two FASTA or two FASTQ files). The second file is specified either with "-fasta2 file.fa" or "-fastq2 file.fq". prinseq-lite-0.20.4/example/example1_ce.png0000664000076700007670000002405012240000123020714 0ustar rschmiedrschmied‰PNG  IHDR®÷C„0bKGDÿÿÿ ½§“ IDATxœíÝ{TWu¾ÿñ×—ëWDÓ”ÒR±b·–W4MgjªsôXéI“w;.3í"Pv]9–3•,´Ž%]4S”MË/ix*ò²&/`Š˜"ŸßýøŽøä~·ÏÇZ¬Ÿýe¿?Ÿ½¿›ïËíÞŸí2ÆW8¿úîPWø‚+|Á>à Ÿ@p€O ¸À'\à®ð Wø‚+|Á>à Ÿ@p€O ¸À'\à®ð Wø‚+|Á>à Ÿ@p€O ¸À'\à®ð Wø‚+|Á>à Ÿ@p€O ¸À'\à®ð Wø‚+|‚£‚ëóÏ?¯nݺÕw7`c‚ë?þñ*((¨¾» \Ïž=«¹sçjêÔ©õÝXPߨ ¯¾úªîºë.5iÒ¤Âå;wö|ÿå—_ÖU·P‹|>¸îÝ»W999š8qb¥¯¹0¬ž:uª.º8Ú‹/†zµMʱø—ÐPïÏŠËåó— ìØ±C¹¹¹JJJRRR’Μ9£¤¤$•––Öw×P‹\ÆSߨM=zôЧŸ~Zérθ—3®€ªpÆW-Ç×Km€ïr\p€3\à®ð Wø‚+|Á>à Ÿ@p€O ¸À'\à®ð Wø‚+|Á>à Ÿ@p€O ¸À'Ôip-..–1¦.KÀ!¬×9sæèý÷ß—$?^wÞy§BBBtÝu×iûöí¶ÊÀ¡¬×^xA-[¶”$edd(;;[+W®TŸ>}4aÂ[eàP¶V|ôèQ5mÚT’”™™©aÆéî»ïVBB‚âããm•€CY;ãzíµ×*==]»víRff¦  I*))Qƒ l•€CY ®Ó§O׌3tË-·(66V”$}òÉ'êܹ³­²p(k— Œ7Nƒ ÒñãÇ• €€_JuíÚU‰‰‰¶ÊÀ¡¬WIjÓ¦Ú´i£S§N)$$D~~~êÚµ«Í’p(k— ”””hæÌ™jÚ´©5j¤ÜÜ\IRJJŠ/^l«,ÊZpMNNÖòåË5oÞ<¹ÝnO{ûöí•––f«,ÊZpMKKÓ¢E‹4tèPùûû{Ú;uê¤Ý»wÛ* ‡²\óòòãÕ¨³gÏÚ* ‡²\[·n­½{÷zµggg+66ÖVY8”µà:nÜ8Mžø Îž=+I ÒŸþô'=ûì³¶ÊÀ¡¬×ÀÀ@½òÊ+zúé§•““#IŠUXX˜­’p0kÁµLXX˜:tè ùùY»2g-I–””hæÌ™jÚ´©5j¤ÜÜ\IRJJŠ/^l«,ÊZpMNNÖòåË5oÞ<¹ÝnO{ûöí•––f«,ÊZpMKKÓ¢E‹4tèPùûû{Ú;uêTá4YÀ¥X ®yyyЉ‰ñj ôÌ2T—µàÚºukíݻ׫=;;[±±±¶ÊÀ¡¬×qãÆiòäÉÚ²e‹$éÈ‘#JOO×”)S4~üx[eàP֦Ú8q¢ ”˜˜¨ââbõèÑCn·[Ó§O×èÑ£m•€CY ®.—K³fÍÒ´iÓ´gÏ•––*>>^¡¡¡¶JÀÁ¬?€ $$D]ºt‘$Ë#—Ëe»,ÆÚ5®sæÌÑûï¿/I:þ¼î¼óN…„„èºë®ÓöíÛm•€CY ®/¼ð‚Z¶l)IÊÈÈPvv¶V®\©>}úh„ ¶ÊÀ¡¬]*pôèQ5mÚT’”™™©aÆéî»ïVBB‚âããm•€CY;ãzíµ×*==]»víRff¦  I*))Qƒ l•€CY ®Ó§O׌3tË-·(66V”$}òÉ'êܹ³­²p(k— Œ7Nƒ ÒñãÇ• €€_JuíÚU‰‰‰¶ÊÀ¡¬N‡Õ¦MµiÓ¦\[×®]m–€CYŸÇõJÓ°aÃúîàH[À•ƒãNuÕ×¢¢¢úîàÞOÀãØê Ç#®L6ž–zÕWàíŽCÆÔ©§ê¡'@åjuV—Ë¥#GŽx}\®Z ®~~~2ÆÔæ*Iµ|©@tt´233uÏ=÷H’Nœ8!·Û]ákÃÃÃk³4®Vƒë#<¢‡zHcÆŒ‘$ÅÄÄTúZÎÌ &j5¸>ôÐCJJJRnn®zõꥌŒ 5iÒ¤6Kà*Uë³ ´jÕJ­ZµâŒ*jU­ÞœU™ŸþY?ÿüs]”€CY ®¯¿þºbccåv»åv»§7ÞxÃfI8”µ,^¼XãÇפI“Ô«W/IÒ¦M›4fÌ•––jäÈ‘¶JÀ¬×^xAóçÏ׃>èi4hÚµk§çž{Žà €±v©À÷߯þýû{µß~ûíúþûïm•€CY ®Íš5ÓÎ;½ÚwîÜ©k®¹ÆVY8”µàúÀhÔ¨QZ¶l™<¨ƒjÙ²e5j”FŒa«,ÊÚ5®ÉÉÉ*,,Ôƒ>¨sçÎI’õ§?ýIO<ñ„­²p(kÁ5 @óçÏ×ìÙ³•““#IŠ‹‹SXX˜­’p0kÁµLãÆÕ­[7Ûeàpuòä,àr\à¬×sçÎéý÷ßW~~¾Õà*d%¸è®»îRQQ‘Õà*d%¸º\.ÝtÓMÚ¿¿Õà*dí×ÔÔTMž%%EãÇWAAzõê%cŒ6mÚ¤””-X° 6Ëà*P«Á5**Ê«í¾ûîójëß¿¿Œ1µYW«Á5++«6WxÔjpíÝ»wm®ð°þä¬óçÏëÔ©S^—„‡‡Û. ±6«Àÿýßÿ)11Qn·[ááኈˆ(÷Ô„µ3®Ã† Sƒ ´|ùrEFFÚ*€«„µàº{÷níÞ½[íÛ··UâWiذa}wp$Ž-àÊQ[Ç#Ç5®4Ö‚kÇŽUXXhkõ¿ZQQQ}wp€P¯Ž- ¾ÔÖñÈqÚêýžº\Ö‚ëüùóõÈ#(%%Eñññòó+9m}Ýœõâ‹ÞqêÔSõЮ|¶?7ù\FMX ®‘‘‘:yò¤zöìYár@€š°~sÖÊ•+¹9 —ÍZpݵk—víÚuÅÝœßdm×:¨  ÀÖêp•±\gÏž­)S¦(++KÇŽS~~~¹/ &¬]*pÇwH’úöí[árnÎ@MX ®YYY¶V €«µàÚ»wo[«ÀUÈZp­ê©Yõõø&kÁ5""â’˹Æ5Qg׸–––ꫯ¾Òܹs5kÖ,[eàPuzkß¾}Õ¶m[ýùÏÖ}÷Ýg«4ÈÚ<®•‰‹‹Ó§Ÿ~Z×eàã¬q­è!yyyJIIQtt´­²p(kÁ5**ªÒöåË—Û* ‡ª³›³\.—ÂÂÂÔ±cGÚ* ‡ªõàZ6kBBB…Ë‹ŠŠ$1+j¦ÖƒkUó·–aWÔD­׋/(cŒÑªU«´hÑ"…„„ÔvY8\­׋ço5ÆèÝwßUrr²<¨3fhÒ¤Iµ]gíæ¬‹ë”)S4iÒ$………Ù* «õàjŒÑ{ï½§ääd8p@“'OÖäÉ“ ¬¸,µ\ó›ß(''G£GVFF†ÂÂÂtöìY¯DFFÖvi8X­×;vH’^yå½òÊ+•¾ŽYPu6«p9¬Ï*Ô¿úîPWø‚+|Á>à Ÿ@p€O ¸À'\à®ð Wø‚+|Á>à Ÿ@p€O ¸À'\à®ð Wø‚+|B@}w 6ú¨òóó¥gŸ}V 6¬ïn 8êŒëâŋյkW­X±B]ºtÑ’%Kê»K¨%Ž ®›7oÖÀ%Iƒ ÒgŸ}&Iêܹ³ç ¾ÉQ— ;vLQQQ’¤ÈÈHåççK’¾üòKÏkfͪžà²éÙ³§)--õüܧOŸ _שS'Úi§vÚi§vÚë ½69*¸þñ4G5Æ“——gî¹çžzîQyu±C©K]êR—ºÔ¥.uÊQ׸vïÞ]kÖ¬‘$}øá‡êÞ½{=÷µÅeŒ1õ݉ÚrâÄ MŸ>]ÇWdd¤ž}öY5jÔ¨¾»€Zà¨à çrÔ¥p.GM‡…Y¸p¡233•——§­[·–[æ´'Œ}ùå—z饗tþüyùùùiúôéºå–[$9o¬eÞyçeddÈårI’&L˜ Ûn»M’sÇ,IÏ?ÿ¼222ʽ§8ÞîÝ»«uëÖ’¤ÿøÿÐàÁƒ%9s¬e.\¨õë×Ë£{î¹G÷Þ{¯$çŽù¥—^òLÕxæÌ(++Ë‘ãÝ´i“æÏŸ/Ir¹\7nœzöì)É™ûwß¾}JNNVII‰¢££•ššªIÎo«×[Ã`ÍîݻͱcÇÌoû[¯e/½ô’yã7Œ1ƼñÆfîܹuݽZõí·ßšãÇcŒÙ¾}»¹óÎ;=Ëœ6Ö2EEEžïsssMÿþý=?;uÌÿûßÍ£>êõžvâx+:nqæX1æÝwß5O>ù¤9þ¼1Ƙ‚‚Ï2§ŽùB+V¬0ÉÉÉÆgŽ·ÿþæ»ï¾3Ƴÿ~3`ÀÏ2'Žwøðáæ³Ï>3Æó·¿ýͼüòËžeNo]ãR‡êر£ça «ì c¾êÆoT“&M$I7Ýt“Ž?îYæ´±–)û×»$>}Z×\sçg'ŽùìÙ³š;w®¦NêµÌ‰ã­ŒSǺjÕ*9R~~¿|$…‡‡{–9uÌZ»v­gŒNo«V­têÔ)I¿œq¼öÚk=Ëœ8Þ¨[·n’¤[o½µÜ˜œ8޺ƥW¡Êž0æ«W¯öü—¹äì±®X±B+V¬Pqq±^{í5O»ÇüꫯꮻîòüåBN¯1FÆ Shh¨}ôQµiÓF’3Ç*ýòAÿÑGiãÆŠˆˆÐŒ3-ɹc.óÃ?è‡~ð<’܉ã}ê©§4jÔ(¹\.c´hÑ"Ï2'Ž÷ÆoÔºuëtÇwhݺu:räˆg™Ç[×8ã ÇØ·oŸ–-[¦)S¦ÔwWêÄ¿ÿû¿ëÝwßÕĉõÜsÏÕww¬Ù»w¯rrr4dÈúîJÉÌÌTzzºþð‡?(55µ¾»cÝùóçuýõ×kÅŠºóÎ;•’’Rß]ª3ü±úõëç9ÛìDÏ?ÿ¼&Nœ¨>ø@“'OÖ /¼Pß]²êñÇתU«ôoÿöoúöÛoåïï_ß]rç)¨TTT”òòò$IùùùŠŒŒ¬ç]¾£GêÑGÕ3Ï\î«]»vµÞ‡2%%%ÖÖíDIII:zô¨Ö­[Wß]*Dp.Óˆ#’¤ˆˆÏ™PIJII)÷HÒ2·Ýv›&NœXaßV¬X¡ßÿþ÷.kÖ¬™š7o^îËßß¿\Ÿ.õ¨¬ŸþþG}¤®]»*((HkÖ¬©Ñ>¼Ô¾¨é¶xíµ×tÍ5×x½ÿ† ¦!C†Hªú˜¯¨—{¬]êoBPP¨·ß~»Â>õÎøU²²²Œ$³oß>ãv»Í·ß~kŒ1æÿ÷Í 7Ü`6lØ`$™‚‚cŒ1O>ù¤‰‰‰1~ø¡9tèY·niݺµ™1c†go¾ù¦Y¿~½9xð Ù¸q£éر£>|¸WÍîÝ»›-[¶˜¯¿þÚÜzë­¦wïÞöñûï¿7.—Ë<óÌ3fÿþýæ‹/¾0«W¯ö,¯NŸ&Nœhš5kfV¯^m8`.\h"##=c+ëS^^žW?k2öêŒmÚ´i&""Â,_¾Ü}ÚtèÐÁŒ1¢ÒufddxÞχ6‡6ÆsèÐ!ãïïo¶nÝêùÝœœ#ÉìܹÓk{ž8q¸\.³~ýúrí½O.V÷@eý¼ð÷ÌÆÍþýûM^^^öá¥öEM·Å?þh‚‚‚ÌG}äi;yò¤ 1o¿ý¶1¦úÇ|^^^­kUýM0Ƙ9sæ˜n¸¡ÒýÔ'‚+ð+]ø!rï½÷z>lRSSË} ™ ˜Í›7—[GzzºiÒ¤I¥5V­Ze6lhJKKËÕܰaƒç5o¿ý¶ 0çÎóúý/¾ø¢ÒÕêôé§Ÿ~2AAAæÍ7ß,÷š©S§V;¸VwìUíĉ&88ؼþúën«_³«Zgaa¡ ôÿ´iÓLLLŒWß/ kï¼óŽ‘d²³³Ëµ˜’’’r¿WÑúcU*\œÑIDATcc½ÖŸ——W£qNš4É´iÓÆŒ1ÂÜxãæäÉ“®óŸËÐ…lÆŒS®;w®p›ýýï7’Ì7ß|S®½lý 6,÷Õ²eK¯×\êý}©~–-»0ˆÕtVµ/j²-Œ1æøC¹ ºlÙ2fŠ‹‹+|}eÇ|u‚kuÞ—ú›P&##ø\.söìÙJ_Ô‚+ð+]ø!²víZÓªU+sðàAd:TîeÛ¶m~h»Ýn#É(>ûì3“˜˜h¢¢¢Lhh¨gù‰'ÊÕ¬êu5ÙÆ³råJjŠŠŠŒ1Æ 8ÐŒ9Ò³¼ºÇ|u‚kuÞ—ú›PfݺuF’ùñÇ+P_ª¾˜@Uúõë'???ÝÿýêÛ·¯Zµj¥o¿ýÖ³¼´´T’´fÍ5oÞÜë÷CBBTXX¨;î¸CwÝu—RSS©-[¶èðºFÎÏÏûòtSÁ]ÀúÛßþ¦µk×jÍš53fŒÒÓÓµjÕªjõ©Ì¥nà©hYÙº/ü¾:u¤ê­²šÕ­cCE}¯ÎxjrƒTMƹÿ~:tH.—K¹¹¹êÖ­[µë\hðàÁ QFF†7n¬Ÿ~úIÆ «ðµ¡¡¡’¤“'OVØ¿6mÚ(22ò’õ~í{ LPPPµ_{±ªöEM¶…ôËÍNþþþzï½÷”˜˜¨O>ùDk×®•¤ó•õ­¦ÇšŸŸ_¥Êœ8qB.—˳/+ Á¨~~~1b„RRR¼f¤øøx¹ÝnmÛ¶MÛ¶mS¿~ý ÌÌLµlÙRn·[.—«Ê>………é¿þë¿4uêTEDD覛nÒºuë´téROøøxEFF*55UO?ý´rrrÊõ»:c¯ŽFiÒ¤Iúïÿþo5hÐ@Ý»w×Ñ£GµgÏ=ðÀ¿ªNUë¼xü·Ür‹>þøcÍ;W ,¸¬}s¡””EDDèæ›oÖºuë4wîÜJg¨î8üqåååiýúõjܸ±Ö¬Y£ûï¿_6l¨ðŒæõ×_/IZ½zµ,—ËUîÌè¨Q£ôÜsÏÉÏÏOëׯ¯t,5RBB‚ç}w±cÇŽyMQÕ¤I“jŸ%­ªŸ«é>¬Î¾¨î¶(3|øpÝ~ûíúþûï5tèPÏö¯é1_ÇÚ¥þ&”Ù¶m›zõêU帀zQ¿W*¾«ª»¤+ºoáÂ…ææ›o6AAA¦aƦk×®fÑ¢EžåK–,1-Z´0n·Û$&&š¥K—–[Guî*¾ÐÞ½{MŸ>}L£FL`` éÖ­[¹;¢«Ó§³gÏš)S¦˜¦M›š ˜;î¸Ã,[¶¬\͵kךo¼Ñ›¾}ûš7ß|³Æc¯ÎØÎŸ?ofÏžmZ·nmüýýMË–-MjjjÆs±ªÖyîÜ93cÆ Ó²eKhÚ·oïµ¾êî—‹ÛÊ~^»v­éÖ­› 6ÑÑÑfîܹU®ÿRãܸq£ 0YYYž×>|ØDEE™Ù³gWºÎ§žzÊ´hÑÂøùù™Š>úôécÚµkWé¶,óì³Ïš®]»V8†Š¾Êîv¬¬Ÿ•“5Ù‡U틚n c~yµjժ›¢jzÌ_î±VÕß„ŸþÙDDD˜5kÖTkl@]sÃã1ÔÌÆÕ§O(<<¼¾»ã³Ê¶c^^^•×}^ bcc5räH=òÈ#—|ÝñãÇÕ¦M}þùçêСCõîòÔt_Tw[øšŒŒ Íœ9Óóô?àJ×”——§ÿùŸÿÑÁƒ5räÈ*_ß´iSM:UO?ýtô®nÕt[øšÙ³g+55•Њ+׸.©Y³fŠŒŒÔ‚ Ô¬Y³jýNu¯]ö5¿f[ø’íÛ·×w€KâRø„ÿLž§2„#ÜIEND®B`‚prinseq-lite-0.20.4/example/example1_df.png0000664000076700007670000002502212240000123020716 0ustar rschmiedrschmied‰PNG  IHDR¨ú]ôwbKGDÿÿÿ ½§“ IDATxœíÝy\W¾÷ñoƒ@‹âˆâ5c" fäF³ ÷j\£ÆÑI¼q#1fÑ1‰+ÑqP³:1j—{Eq›ÇÑHL\ã£Ñ˜;®½‰[2n¸ ²„®çúAÓÝÅçýzñzѧªëwα»øY§Î)›a†7áUÑnE‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·R¥¢+ëxrÌŠ2í·ñÿô7¹&Ö3]¿/Ó~ãô‰É5q+»v.Ó~}6l6¹&îaÞÇûË´ßð¾&×VÖfèÐ2í·oþ|“k‚Ê€+¨p‘‘‘ŠŠŠrþÄÇÇ»ø`¥<_‘ Â­¥¤¤(..NË–-S~~¾¨iÓ¦©Y³fJNNÖÊ•+•››+oooMœ8Q-Z´$]¾|Yqqq:s挼¼¼4vìXíÛ·O999ŠŠŠRƒ ôþûïŠuæÌ7N‡C?þx¡mmÛ¶Õ—_~é|ݾ}{m۶͹­OŸ>úúë¯ååå¥éÓ§«AƒævŒ‹ÔªU«Ør«÷…¿¿¿ó÷¬¬,Õ«WÏùº²öI6mÚèÌ™3Î×—/_Ö¤I“tþüyU©REo¾ù¦ÂÂÂ4wî\Õ«WÏù‡sÁ‚ªZµªXⱋû^¶iÓFgÏžÕĉ•™™©êÕ«kÊ”)ºï¾û$Ýì¿—^zIÛ·oWzzºÆŒ£cÇŽiçκ|ù²þøÇ?:¯ìüÒ¾.©­œ‡\¯2ÎJrë¹çĉjܸ±¼¼¼*íùŠ!~¸üüüBCüëÖ­S‹-Ô®];ý÷ÿ·fÏž­=z¨Y³f’n~©–-[¦+VhÒ¤Iš6mšóX3fÌÐÃ?¬?þXIII Ó«¯¾*???%&&ù£ Iï¿ÿ¾úôé£ÄÄD5iÒD¹¹¹e®w“&M”˜˜¨>}ú{ìŠf†¢¢¢ô‡?üA'Nœp–òIñ÷¬Z¹/ ¬X±BO?ý´Þxã M™2ÅY^™ûD’¾øâ ÝÿýÎ×ï¿ÿ¾¨>úH±±±š:uª$éÉ'ŸÔæÍÿÿßÍ›7ëÉ'Ÿ¼ã±‹û^”ÿþ÷¿×G}¤^½ziÆŒÎ÷äçç«nݺZºt©¦M›¦ &(88XK–,ÑôéÓ5gΜBûþ’¾.©­œ‡\¯2ÎÊr>Þµk—"##¯+ãùŠn£`Ø£à§G’¤!C†hÏž=úî»ï4hÐ çþ'OžÔ«¯¾ª¾}ûêwÞ)ôEß³gž}öYI’ÍfSµjÕJ¿ÿ~uíÚU’Ô½{wÙl¶2×ýÖ÷8p Ìï+/ÉÉÉJLLÔÓO?­É“'—º¿•û¢@ÿþýµfÍ9²PRQ+÷IÁ{ôè¡·ÞzKüãÛöîÝ«Y³f)**Jo¿ý¶®^½*I ÑåË—•––¦cÇŽ)  Ð•â”ô½¼½ooí#›ÍæÜ*‡Ã¡.]º8_§¥¥ŠñKúº¤¶Jœ‡\ÏÙMe9ïÞ½[¿ýío¯+ãùŠ!~¸½«W¯*++KyyyÊÉÉQÕªU%Io½õ–bccÕªU+åææªC‡Î÷ÜÍ—±¬ ÃÍfS~~¾òóó]~|3Jºyâ)ËÉ­4žÜ·ëÖ­[¥ï“‚ÿ:Í;W .ÔÌ™3%I‡C ²ÛíEÞ×¹sgmÙ²E—.]rþQ»“{ù^zyyÉÇÇÇùÚ××W^^æ\[¹S[9ýr|În*í|üóÏ?ëúõëªS§N‘m•é|ÅT¸½)S¦èµ×^S÷îÝ5wî\gyVV–êÖ­+IZ½zµ Ãpn{ì±Çô÷¿ÿ]ÒÍ/bff¦$ÉÇÇG999ÅÆ‰ˆˆpÞx¾aÆBÇ«_¿¾RRR$I7n,ò…¾õ}îµ”Ozzº³-;wîT“&MJ}Uû¢À­÷¾íر£ÐPcI¬Þ'ÒÍ?Ò¯½öšŽ;¦#GŽH’}ôQýãÿpîsëÂ'Ÿ|R7nÔ–-[Ô¹séK•ô½¼µoׯ_¯V­ZÝs~I_ß©­œ‡\§2ÎÊr>Þ·oŸÚ´iã|]YÏW$¨p·ßƒ:sæL­]»V¾¾¾êÖ­›^|ñE9rDß|ó$iĈ2dˆ^xá]»vM¾¾¾ÎcLFèÛ·¯¢¢¢”šš*IêÝ»·ú÷ﯱclj?fÌ}ôÑGŠŠŠÒ‰' oÔ¨Q?~¼^xáýôÓO…¶y{{ëÔ©SŠŠŠÒŠ+4f̘bÛWQ³v¿þúkõë×O}ûöÕ¢E‹ôæ›o–ú«öE¥K—:û$))I“&M*õ=V¾¾:t¨-Z$I7nœöîÝ«¾}ûªoß¾úüóÏûþú׿Vff¦êׯ_h²FIm)é{9vìX­Y³FýúõÓš5kŠý~–Å/íë’ÚÊyÈõ*ëç¬,çãÛï?­¬ç+›qkZ ü•u¡þÛgDšÁSê/¾î¨<ÚÎBý7™Ý×Ï=÷œ–.]ª*UÊÿ.Lwúq*\Æj‰§;©èÄÓݸCâéN¬žxÂ=X=ñtûÛß*º nÁRWP§OŸ®U«ViÏž=]Ü#Ë܃úÏþSééé…ç±D‚š››«Ù³gßó Ïp–¸õÃ?TïÞ½K|ä×­Ë5ìÛ·¯¼ª€{àñ jJJŠRSS5räÈ÷¹5)ÍÈÈ(jT Õ«Wwù1=~ˆÿþý:~ü¸zö쩞={êçŸVÏž=åp8*ºj¸–šÅ/•¾†WP\‡+¨°<Ë]A- WP\‡+¨°<T¸T¸T¸T¸T¸T¸T¸T¸T¸T¸T¸T¸T¸T¸T¸T¸•rMP³³³eFy†€‡1-A5k–>ýôSIR~~¾žyæùûû«qãÆúöÛoÍ gZ‚:cÆ 5lØP’´jÕ*íØ±C+W®T‡4bijÂÀÃU1ëÀçÏŸWíÚµ%IÉÉÉŠŠŠÒ³Ï>«ˆˆ…‡‡›δ+¨ 4Pbb¢<¨ääduíÚU’”——§ªU«šδ5&&F&LP«V­ªnݺI’6oÞ¬6mÚ˜Îf˜8­þĉºté’"""T¥ÊÍ» öîÝ«€€………™öŽ222*$.€U¯^ÝåÇ45A-‘‘!yyUü²«$¨®cF‚jZƘ——§‰'ªvíÚ ÐñãÇ%IqqqZ¸p¡YaàáLKPccc•””¤yóæÉn·;Ë›7o®„„³ÂÀÙ– &$$(>>^ ···³¼uëÖ:tèYaàáLKPÓÒÒR¤ÜÇÇG¹¹¹f…€‡3-AmÚ´©RRRŠ”ïØ±C¡¡¡f…€‡3-A6l˜F­Ý»wK’Î;§ÄÄDEGGkøðáf…€‡3íQ§#GŽÔ•+WÔ©S'egg«mÛ¶²Û튉‰Ñ!CÌ gú:¨YYY:r䈇ÂÃÃMY+ën°*€ëxìBýî„ÀuýôS­]»ÖŒ°¥bˆÀuÌâ7-Aõ÷÷Wjjª7n\¨üôéÓ Sff¦aKE‚ à:µP¿¿¿¿:T¤üÀò÷÷7+,<œi ê /¼ W^yEýë_õã?êôéÓZ¾|¹¬Aƒ™δIRÓ¦MÓ7ôÊ+¯(77W’äëë«W_}Uï½÷žYaàáL»µÀµk×”šš*I U5Ì W*îApš$u«ŒŒ ùûûËËË´; îª.p š$•——§‰'ªvíÚ ÐñãÇ%IqqqZ¸p¡YaàáLKPccc•””¤yóæÉn·;Ë›7o®„„³ÂÀÙ– &$$(>>^ ···³¼uëÖÅ.?H&&¨iii )RîãããœÕÜδµiÓ¦JII)R¾cÇ…††šδuذa=z´vïÞ-I:wáÇ›δ…úGŽ©+W®¨S§NÊÎÎVÛ¶me·Û£!C†˜ÎôuP³²²täÈ9…‡‡›²VÖÝ`T×ñØ…ú dggËn·Ëf³•WÈ"HP\Ç£êŸ5k–>ýôSIR~~¾žyæùûû«qãÆúöÛoÍ gZ‚:cÆ 5lØP’´jÕ*íØ±C+W®T‡4bijÂÀÙ6Iêüùóª]»¶$)99YQQQzöÙg¡ððp³ÂÀÙvµAƒJLLÔÁƒ•œœ¬®]»J’òòòTµjU³ÂÀÙ– ÆÄÄh„ jÕª•BCCÕ­[7IÒæÍ›Õ¦M³ÂÀÙ:‹ÿĉºté’"""T¥ÊÍ» öîÝ«€€………™öŽ˜Åà:¿Ì”; ApT¨dÍ0•ëÛ›6‹ß]effVt,ãêî…KT›Í¦sçÎù(+—&¨^^^Üã €_Ä¥÷ +99Y}úô‘$]»vMv»½Ø}kÖ¬éÊа—Îâÿàƒ4|øp9ŽR÷­¨+­,3à:±ÌÔO?ý¤ãÇë‰'žÐªU«T«V­b÷kß¾½+Ö *€ëxD‚êîHP\Çc—™ÊÉÉQNNNy„€‡35A]¼x±BCCe·Ûe·Û¦¥K—šδ'I-\¸PÇרQ£ôÄOH’¶oß®¡C‡Êáp襗^2+4<˜i÷ †„„hܸqzå•W •/\¸Pï¿ÿ¾RSSÍ[*îApš$åëë«ï¿ÿ^7.T~úôi=øàƒvO* *€ëxÔ$©ºuëêÀEÊ8 zõê™δuРA>>zõÕW5sæLU©bÚü¬;bˆÀu<êÔW¯^uNˆ S5Ì W*T×ñÈÕÝ ¸ŽGM’î *ÜŠ) ê7ôé§ŸêâÅ‹ffJ‚Z¥JõîÝ[™™™ffJ‚j³ÙôÐCéäÉ“fæ=iÒ¤If888XãÆS£FT½zuåää(++ËùãïïoFØRåææVH\+òõõuù1M[fÊf³Ýq{E­nÅ2S®cÆ2S¦=ÎiëÖ­fÆBý¸g»PFF†Gy„€‡3-AÍËËÓĉU»vmèøñã’¤¸¸8-\¸Ð¬°ðp¦%¨±±±JJJÒ¼yód·ÛåÍ›7WBB‚YaàáLKP¯ÈÛÛÛYÞºuk:tȬ°ðp¦%¨iii )RîããÃZ¤(‘i jÓ¦M•’’R¤|ÇŽ 5+,<œi ê°aÃ4zôhíÞ½[’tîÜ9%&&*::ZÇ7+,<œi õ9RW®\Q§N”­¶mÛÊn·+&&FC† 1+,<œé õgeeéÈ‘#r8 7e1×»ÁBý®cFnW.O’ÊÉÉ‘$ùùù™ªT$¨®ãqO’Z´h‘ÂÂÂd·Ûe·Û¦Å‹›δuΜ9>|¸~ÿûßkݺuZ·nzõê¥×^{MóæÍ3+,<œiCü7Ö¤I“ôòË/*_¸p¡&Ož¬S§N™¶T ñ¸ŽG݃j·ÛuìØ15nܸPùéÓ§Õ¼ysýüóÏf„- *€ëxÔ=¨Å>ÒôÀzøá‡Í çÒuP/^¼èü=..NÇו+WôÄOÈ0 mß¾]qqqúàƒ\âÒ!~›ÍVæ}Ëau«b1Äà:f ñ»ô êÖ­[]y8TBå²P¿;á *€ë¸ýÔâäçç+##£È~Íš5Í dÚ,þcÇŽ©S§N²ÛíªY³¦ ýÅ1í jTT”ªV­ª¤¤$™cÚ=¨~~~:tèš7onÆáïY%»åÀTw³ŠSY™vµeË–JOO7ëð÷,33³¢«`õ¨Ó¯¿þZãÇW\\œÂÃÃååUøv׊š$õä˜EÊþû»÷ïýΧwµ?@eâQ³øƒ‚‚týúuµk×®Øí µ 8¦O’Z¹r%“¤Pf¦%¨ÔÁƒÝn’Ü›ië ¶hÑBW®\1ëð°(ÓÔwß}WÑÑÑÚºu«.\¸ ‹/úŠcÚ÷îÝ%I;v,v;“¤PÓÔ­[·šuhX˜i jûöíÍ:4,Ì´µ´§HUÔBýpo¦%¨wÜÎ=¨(N¹Ýƒêp8tøðaÍž=[“&M2+,<\¹ÞƒÚ±cG=ðÀúË_þ¢šÌ´uPK¦/¿ü²¼ÃÀC˜vµ¸ÅøÓÒÒ§àà`³ÂÀÙ– Ö©S§Äò¤¤$³ÂÀÕÛ$)›Í¦5j¨eË–òññ1+,<œËÔ‚õO#""ŠÝž™™)‰uPP<—'¨¥­Z€uPP—'¨·í0 C«W¯V||¼üýý]áòõöõO ÃК5k«Ó§Ok„ 5j”«ÃÀ"L›$u{b­Q£F©Ff…€¸ª+Vè‘GÑ¢E‹*ºJ¸K–JPwíÚ¥nݺI’žzê)íܹS’Ô¦MçÜ›¥†ø/\¸ :uêH’‚‚‚tñâEIÒ¾}ûœû<9fE…Ô edXH»ví ‡Ãá|Ý¡C‡b÷kݺ5å”SN9å”SN9å.,w%K%¨ÿùŸÿiœ?Þ0 ÃHKK3úôéS!õ(8â—¸Ä%.q‰K\«²Ô=¨‘‘‘Z¿~½$é³Ï>Sddd×wËf†QÑ•p•k×®)&&F—.]RPPÞ{ï=Ttµp,• ÀóYjˆžÏRËLUFóçÏWrr²ÒÒÒ´gÏžBÛ¬öd­}ûöiæÌ™ÊÏÏ————bbbÔªU+IÖkk?þX«V­’Íf“$1Bÿþïÿ.ɺm–¤éÓ§kÕªU…>ÓVlodd¤š6m*Izî¹çÔ£GIÖlkùóçkË–-2 C}úôQß¾}%Y·Í3gÎt.uøóÏ?ëÊ•+Úºu«%Û»}ûvý×ý—$Éf³iذaj×®$kþû=zT±±±ÊËËSpp°&Ož,IÖlo¹«Ð)ZøÅ:d\¸pÁøÿø"ÛfΜi,]ºÔ0 ÃXºt©1{öìò®žK}ÿý÷Æ¥K— Ã0Œo¿ýÖxæ™gœÛ¬ÖÖ™™™Îß?ntéÒÅùÚªmþŸÿùcüøñE>ÓVloqß[ðf[ Ã0Ö¬Yc¼óÎ;F~~¾a†qåÊç6«¶ùV+V¬0bcc ðf{»tébüðÆaÆÉ“'®]»:·Y±½Ï?ÿ¼±sçNÃ0 㫯¾2æÌ™ãÜfÅö–7†ø=\Ë–-'¸]IOÖòTÍš5S­Zµ$I=ô.]ºäÜfµ¶(øß¸$eee©^½zÎ×Vlsnn®fÏž­±cÇÙfÅö–Īm]½zµ^zé%yyÝüÓS³fMç6«¶ùV6lp¶ÑŠímÔ¨‘222$ݼ‚Ø Aç6+¶÷Ô©Szì±Ç$I?þx¡6Y±½å!~ +éÉZV°víZçP·dí¶®X±B+V¬Pvv¶,Xà,·b›?üðCõîÝÛù‘[Y±½†a(**JÕ«W×øñãuÿý÷K²f[¥›Ð?ÿüsmÛ¶Mš0a‚‚ƒƒ%Y·ÍΜ9£3gÎ8¹mÅöN™2Eƒ–Íf“aŠwn³b{›5k¦M›6©{÷îÚ´i“Î;çÜfÅö–7® Âã=zTË—/WtttEW¥\ôïß_kÖ¬ÑÈ‘#5mÚ´Š®ŽiRRR”ššª^½zUtUÊMrr²õôÓOkòäÉ]Óåçç«I“&Z±b…žyæÅÅÅUt•ÊÍÆÕ¹sgçÕc+š>}ºFŽ©uëÖiôèÑš1cFEWÉTo½õ–V¯^­~ýúéûï¿—··wEWÉR¬ûMêÔ©£´´4IÒÅ‹TÁ5úåΟ?¯ñãÇkêÔ©…nm°b[o×­[7>|ØùÚjmÞ¿¿Ž?®ž={ªgÏžúùçŸÕ³gO9z§¨ »IDATIÖk¯$J’ºvíª~øÁYnŶJRýúõÕ¥KIRçÎõ¿ÿû¿ÎmVms[‡÷%k¶÷Ÿÿü§:wî,éæ¿ïœÛ¬ØÞ_ÿú×Z°`>úè#õêÕK7vn³b{Ë ª…YíÉZ™™™ŠŽŽÖèÑ£Vh›ÕÚZàÌ™3ÎßwìØá–¬×樨(­_¿^ÉÉÉJNN–ÝnWrr²óŠ“ÕÚ›žž.ãÿ-C½sçN5iÒĹÍjm-©½{÷Jº¹*Ç­ЭÚfI:~ü¸²²²Ô²eKg™ÛÛ¨Q#ç¿ïž={Ô°aCç6+¶÷êÕ«’nÞª³xñbõìÙӹ͊í-o,ÔïáæÍ›§Ï>ûLiiiªS§Žžzê) >\’õž¬µ|ùr-X°ÀyÏš$ýõ¯•———åÚZ`êÔ©Ú¿¿ ÃPÍš5 ݧhÕ6hÛ¶­¾üòKçk«µwýúõJHH$Ùív½ùæ›jÞ¼¹$ëµµ@FF†Þzë-ýë_ÿ’ÞyçË·Y’>øà†¡×_ÝYfÅö9rDþóŸ•››+___Mœ8Qááá’¬ÙÞ¿ÿýïJJJ’···Úµk§aÆ9—´b{Ë *Ü Cüp+$¨p+$¨p+$¨p+$¨p+$¨*•mÛ¶Éf³¹å£,X ûï¿_ÞÞÞÎåjÊ¢ Mééé.­Ïí}åÎ}ÀZHP”«‚$çßþíßtë*wf%Yžâ_ÿú—^{í5ýéOÒ?þ¨³gÏVt•ŠˆŒŒÔÙ³gU»vm—¯²ÿ›( *€ ‘ššªO>ù¤¢«áryyy÷ô¾~øA‡CýúõSƒ T¿~}×ì—óõõUýúõïêê.Ü TbÈ!ŠUqÏ )n(ùö«m¯7lØ 6mÚÈn·ëñÇ×?ü ={öè‘G‘Ýn×#*___çã o•——§7ß|SÁÁÁòõõUHHˆ-ZThŸ'žxB’T«V-Ùl¶“À¼¼<;VuêÔQµjÕÔ«W/ýôÓO÷Ôw›7o.µnuû±‡¦OŸ®x@¾¾¾jРâââœû/]ºTòóóS`` žþùBWK;tè I ,¶Í¥õÿüùóÕ¸qcU©RE 6Ô¬Y³îXÄ€r´uëVC’ñý÷߯êÕ« •_¹rÅù{ZZZ‘÷]¹r¥ÐëÇÜØµk—‘ššjDFF­[·6Ú·oo|ýõ×βN:9Î<`¬]»Ö8uê”oøùù ÎýÞyç#$$Äøì³ÏŒüÑØ´i“Ñ´iSc„ EŽalÛ¶Í8yòd¡:xýõ×:uêÜ1ÞªU« IÆÑ£G³gÏgÏž-¶ÿFŽiÔ­[×y¬ùóçAAA÷Ôw¥õÁíǺýõ¸qãŒÀÀ@#))É8}ú´ñÍ7ßK–,q¾Ù²eÆ–-[ŒÓ§OÛ¶m3Z¶li<ÿüóejsiýâÄ Ãf³S§N5Nž}Z<ð@‘Ÿâà’„……ÉÇǧH¼íÛ·;ã•Uhh¨|}}‹kÛ¶mÎßï¦ïîÔ¥ “ŸŸŸ¾øâ‹b·§¤¤èúõëšýôSõë×ÏÇ=BEñwçßø¾³7ª8p@‹/V||¼§íÉ'ŸTJJŠÚ·o¯>ø@S¦Lñaq­X'::ZaaaÚ¸q£\.—êÔ©ãë.¡‚ø»ó_|ßÙIÙÄ©S§4aÂMŸ>½Ä᪦M›ªiÓ¦zàôÀ”¹ŒC‡©Q£FVw׈õxî¿ÿ~%''ë¹çžóuWpø»ó?|ßUìAµÜÜ\ÅÇÇkìØ±jݺu±iÛ¶m“1F’ôÝwßyÎϹÜÏ?ÿ¬Y³féᇶ¼¿¨8Öc`êÑ£‡† ¦^½zùº+¸üÝù¾ï*‡)Z›X‹/Ö›o¾©† zÚÞ{ï=9NMš4Iiii RHHˆžþyµmÛV·Ýð7óæÍÓêÕ«•‘‘¡Úµk«_¿~Š‹‹“$Öc€éÒ¥‹¾üòËíÝ»w׆ n|‡P&þî ßw•~…Cüð+Tø*ü ~…€Z lÚäëÀX&)É×=€ðwXX_öa«õoܸQ¯¿þº$ÉáphôèÑêÚµ«{€Š°U@6mšÞxã ÝrË-:zô¨žzê)*@€±Õ!þ (''G’töìYÝ|óÍ>î*ÊV{P§Nª‘#GÊápÈ£ H’:tèà™gÇŽ¾êÊÁVõ•W^ј1cÔ·o_­[·N¯¾úª^{íµb¡´hkeâv‡)33Ë×ÝÀu*(¸I?üpÒ×Ý@95ôÃ?”kÞ… ”h9²|¿ kåçG+3󬯻r*(¸I99ç}ÝJ'<<ÜëË´Õ!þ]»v©W¯^’¤^½ziÏž=>î*ÊVµAƒÚ¶m›$iëÖ­ª_¿¾{€Š²Õ!þ‰'jÚ´iš5k–BBB4iÒ$_w d«€«%K–øº¸¶:Ä€ÀG@€_! À¯PàW¨ð+Tø*ü ~…€ ¿B@€_! À¯PàW¨ð+Tø*üŠåõâÅ‹ÊÊÊÒÅ‹­.ðz@5ÆhíÚµ>|¸n¹å…††ªfÍš U³fÍ4|øp­]»VÆo—€ ysa|ð^xá:uJ}ûöÕ˜1cÔ¨Q#U¯^]gΜÑÑ£GµmÛ6=ú裪S§Ž¦Nª‡zÈ›]@€ój@>}º¦Nªþýû+$$¤ÌùòóóµbÅ MŸ>€ €b¼PwîÜY®ùBBBôÐCNP‚Wji ”››[âœÓÈÈH«K YvZZšºwﮪU«*22R5jÔ(öJcÙÔ¡C‡*88XûÛßmUØŒeuïÞ½úæ›oÔªU+«JÀ†,;ÄߦMegg[µxØ”euúôé7nœRSS•žž®Ó§O{¥±ìŸ>}$I÷Þ{o©Óy’JcY@MMMµjѰ1Ëj÷îÝ­Z4lÌ«õôéÓŠŠŠ’Ãá¸êy¦µjÕòfiØ„WjíÚµuâÄ Õ­[Wµk׾⼜ƒ €Òx5 ¦¦¦ªfÍšžåÕ€zéy§œƒ €kaÙ}P/uáÂ]¸páF”@€³4 .Z´H­[·–Ëå’ËåRëÖ­õÖ[oYYβ€:wî\ÅÅÅiàÀZµj•V­Z¥è™gžÑ¼yó¬* €gÙ}PgΜ©×_]Ç÷´õë×O-Z´Ð”)SgUi0Ëö ¦§§«W¯^%Úï»ï>:uʪ²p–ÔvíÚiïÞ½%Ú÷ìÙ£;ï¼Óª²p^’T‘äädÅÅÅ)++Kݺu“1F7nTrr²þú׿z³,lÄëO’ºÜ°aÃJ´õîÝ›'I T^’p=,{’p-,»Í”¿ªV­š¯»pÃ9ŽJ9n»q: óu7P׳¾X×þÁét²ý ¬/û¨t577××]¸áÜî°J9n»q»ƒtîÜ9_wåTSªÀúªY¢…uíÜîp¶ŸÄíRnîy_w£Ò ÷ú2-}Ô)PQ–Ô‹/ê“O>)vÛ) <, ¨AAAùDÿ÷ÿ§Ó§O{¥±ì*þûï¿_’Ô¿ÿR§ó$)”Ʋ€ÊS¥p-, ¨,IJNNÖÂ… ­* €gY@>^qqqV•@€³ì>¨cÆŒQVV–zö쩼¼ÜÓÖ¯_?µhÑBS¦LáJ~”ʲ=¨éééêÕ«W‰öûî»O§N²ª,œeµ]»v¥>ÒtÏž=ºóÎ;­* €gÙ!þäädÅÅÅ)++Kݺu“1F7nTrr²þú׿êôéÓžykÕªeU7`, ¨}úô‘$ 6¬Ä´Þ½{ûÙcU7`, ¨©©©V-6fY@íÞ½»U‹€Yz£~ ¢¼P‡ª´´´rÍ»oß>=þøãÞ,ðê!þ–-[ªS§NjÓ¦¨Ž;ªQ£F ×Ù³guôèQmݺUü±ÒÒÒ4~üxo–€ x5 ¾øâ‹Š‹‹ÓÂ… µlÙ2M˜0¡Øú‡CíÚµÓ£>ª#F(**Ê›å`^¿HªfÍšJHHPBB‚Ξ=«C‡)''GjÖ¬™"""¼]6bÙUü’¡;î¸Ãʰ®â€_! À¯PàWnh@ÍËË+vU?p9ËêìÙ³õÉ'ŸH’ 5hÐ ………©Q£FÚ¹s§Ueà, ¨¯¾úªêׯ/IZ¾|¹6mÚ¤÷ß_=zôгÏ>kUY8Ën3uêÔ)ÏøW®\©Ç{L=ôÚµk§ØØX«Ê ÀY¶õæ›oÖ’%KôÍ7ßhåÊ•êÓ§$©  @U«Vµª,œe511Q'NÔí·ß®˜˜õíÛW’ôù矫C‡V•@€³ìÿèÑ£Õ¯_?effª]»v ú¥T§NÔ³gO«Ê ÀYú¨Ó¦M›ªiÓ¦ÊÉÉQXX˜œN§:uêdeI8ËñhÒ¤IŠŠŠRDD„>,IJNNÖÂ… ­* €gY@¨U«VU«V­dŒQAA²³³%I‘‘‘V—@²ì"©´´4uïÞ]U«VUdd¤jÔ¨Qì”Ʋ=¨C‡Upp°þö·¿)::Úª2°ËêÞ½{õÍ7ߨU«VV•€ Yvˆ¿M›6žóM€ò², NŸ>]ãÆSjjªÒÓÓuúôéb/ 4–âïÓ§$ynÒ9cŒU¥À, ¨©©©V-6fY@íÞ½»U‹€Yvê¥rrräv»oD)8ËjAA&M𤍍(EDDèðáÃ’¤ääd-\¸Ðª²p–ÔÉ“'kéÒ¥š7ož\.—§½eË–JII±ª,œe5%%E ,Ð!CT¥JO{ûöíµwï^«Ê ÀYP322J}ŠTpp°òóó­* €gY@mÒ¤‰öïß_¢}Ó¦MЉ‰±ª,œe·™=z´ÆŽ«E‹I’Nž<©mÛ¶)>>^3f̰ª,`©¿ü%ªDÛ³Ïfú 'Ø—eu̘1ÊÊÊRÏž=•——§.]ºÈår)11Q£F²ª,œeÕáp())I Ú·oŸÜn·bccnUIØ€e5;;Ûóï-ZHúåÞ¨Eí‘‘‘V•@³, Ö¨QãŠÓ1V•@³, ¦¦¦ûÙívë_ÿú—æÌ™£¤¤$«Ê ÀYP»wï^¢íÞ{ïUóæÍõÚk¯iذaV•@³ì>¨eiݺµ¾üòË]²=¨§OŸ.Ñ–‘‘¡ääd5lØÐª²p–ÔÚµk—Ù¾téR«Ê Àݰ‹¤‡ªW¯®6mÚ(88ت²p–ÔvíÚ•Úž››[¢{¢ ˆÏîƒz)î‰ €"–ÔÅ‹kܸqúýïï¹åTjjªÞ~ûmÍž=[ 4°ª4˜euÉ’%zùå—5räHO[¿~ýÔ¢E ýãÿЊ+¬* €fÙ}P7lØ ûD{ß¾}µ~ýz«Ê ÀYPôwïÞí{öìQXX˜Ueà, ¨O<ñ„FŒ¡÷Þ{OÇ×±cÇ´xñb9R¿ûÝï¬* €gÙ9¨ÿùŸÿ©‹/jĈÊÏÏ—$…„„èé§ŸÖŒ3¬* €gY@ Ö_þòM›6Miii’¤˜˜U¯^ݪ’°Ëj‘êÕ«ëÖ[oUXX˜œNËÎ(€MX– 4iÒ$EEE)""B‡–$%''káÂ…V•@€³, Nž, ¨jÕªU‰öàà`ÏUý¾››ë³Ú¾âv‡UÊq[ÃU¢åF½·nwÎ;wCjáúÕ”*°¾j–ha]û·;œígq»ƒ”›{Þ×ݨtÂÃý¾LËñ7iÒDû÷ï/ѾiÓ&ÅÄÄXUβ€:zôh;V[¶l‘$,¿QXX˜:vì¨ÂÂBX]Îëç ~úé§Zºti±¶Ù³g+22RU«VÕý÷߯3gÎx»,lÂëuúôéÊÈÈðü¼cÇýéORBB‚>üðC}÷ÝwJJJòvYØ„×ê¾}ûÔµkWÏÏË–-S¯^½ô /hàÀúóŸÿ¬?þØÛe`^¨ÙÙÙŠŽŽöü¼uëÖbµmÛ¶:~ü¸·ËÀ&¼P###õã?J’ ´k×.ÝqÇžéçÏŸWPå×f @y= vïÞ]“'OÖ‘#Gôç?ÿY’ŠíAýæ›oÔ¬Y3o—€Mx}WæŒ3Ô£G5mÚT‡C¯½öš"""<Óßÿ}uéÒÅÛe`^¨-Z´Ð¡C‡´{÷nÕ«WO7.6ýÙgŸÕ-·Üâí²° KNu¹\ºë®»Jv÷Ýw[Q6áõsP€ëA@€_! À¯PàW, ¨‘‘‘:r䈕%`3^¨›6mR^^^‰öððp:tÈÛå`3^¨#GŽTdd¤îºë.;wN›7oÖ… ¼]6åõ€ú¿ÿû¿:v옞þyU©REIIIŠŠŠÒ¹sç´páBmÙ²E/^ôvYØ„%µN:zðÁªuëÖ)--M¡¡¡JKKÓã?®ÈÈHo—€MxýIR:tËåRçΕ——§ƒªwïÞªR¥ŠfΜ©æÍ›ë‡~ðvYØ„×÷ fggëóÏ?Wß¾}åp8ôÛßþV 6ÔùóçõñÇëûï¿Wƒ ¼]6áõ=¨N§SmÛ¶UÛ¶m•˜˜¨;w*##C]»vÕÿ÷+))I‘‘‘:~ü¸·KÀB3g†—hKJò~¯ÔË9uêÔIAAAzçwÔ¤IíØ±Ãê²P–Ôììì’ƒ‚t×]wYYÌò=¨ErrrnT)0Ku T~…€ ¿B@€_! À¯PàW¨ð+Tø*ü ~…€ ¿B@€_! À¯PàW¨ð+Tø*üJ¯;àMgÏžÕ„ túôiÕ®][3fÌPµjÕ|Ý-T€­ö .\¸P:uÒ²eËÔ±cG-Z´È×]@Ù* nÞ¼Y}ûö•$õë×Oÿó?ÿ#IêСƒçÿf«Cüéééª]»¶$©V­Z:}ú´$iÇŽžyrrr|Ò7”“±‘®]»·Ûíù¹G¥Î×¾}{Úi§vÚi§vÚ½ØîM¶ ¨>ø 9uê”1ƘŒŒ óðÃû¤7bÅQ—ºÔ¥.u©K]êÚ•­ÎAíܹ³Ö¬Y#IZ½zµ:wîìã ¢ÆãëNxË™3g”˜˜¨ÌÌLÕªUK3fÌPDD„¯»€ °U@@à³Õ!~>[Ýfª²Ù±c‡fÍš¥ÂÂB9N%&&êöÛo—dÿ§j½òÊ+Z¾|¹¶nÝêi³ë˜çÏŸ¯õë×Ë£‡~X<òˆ${ŽwãÆzýõ×%I‡C£GV×®]%Ùg¼óçÏ×Ê•+•‘‘Qìó+]yŒ:þ²Æk×íוÖo;m¿®6^»m¿®4Þʰýº¡|y…®Ï¡C‡Lff¦1Ƙ;wšAƒy¦Íš5˼óÎ;ÆcÞyç3gΟôÑ _ýµ™0a‚¹çž{еÛqÌ}ô‘y饗Laa¡1Ƙ¬¬,Ï4;Ž·wïÞæ»ï¾3ÆsäÈÓ§OÏ4»ŒwïÞ½&==½Äçט+1PÇ_ÖxíºýºÒú5Æ~Û¯+׎ۯ+·2l¿n$ñ°fÍš©fÍš’¤Ûn»M™™™žie=U+ÐåççkΜ9?~|‰ivó‡~¨?üár:ùSŒŒôL³ãx4hày˜ÆÙ³guóÍ7{¦Ùe¼mÚ´ñøÀ+Ë슀 ¸¢/Ï¢×M7ݤ¾}ûjÿþý¾îš$ÿ !ÞÓ;wÖ‰'å•åYá§Ÿ~ÒÌ™3õÿñž¶Ë?3U«VU×®]µk×®b¿kõø|õþ%$$(66V!!!ªU«–~ÿûßë§Ÿ~ºaõ'Nœ¨^xAÜå(°‰}ûöéĉJMM•ÛíÖàÁƒ}Ý%Û Qݺuåp8|Ý•2-Z´H±±±Š‰‰)1­è3³}ûvU«V­ÄgÆêñùêýÛ³g’““uðàA­\¹RÛ·o×ã?~Ãê÷ïß_§NÒgŸ}vÃj†€ ØDtt´êÖ­«;ï¼SúÓŸtàÀ?¾Ø3ÞßüùóÕ¨Q#©~ýúš={v™Ë¿t¯î¥¯K]í³Rk×®Õƒ>¨Æë׿þµ¦Nªµk×êÂ… Wü=o­£õíÛWÿûß+Ôo R1Zjjª‘d222Œ1Ædgg›aƙ֭[›ï¥—^2­Zµ2«W¯6Ç7Ÿ}ö™iÒ¤‰™8q¢gžwß}׬_¿Þ;vÌlذÁ´iÓÆ :Ô3}̘1&::Ú¬X±Â=zÔÌŸ?ßÔªUËH2YYYåêßåÊÓ¯¢etîÜÙlÙ²Å|ûí·æ®»î2Ý»w÷ÌóôÓO›zõê™U«V™£GšE‹™:uêëÛòåË$sàÀsâÄ sâĉ Õ¸ÚØ®gÍ›7÷¼¯ ,0¡¡¡&%%¥Âó]êÌ™3Æáp˜õë×_±ßçÎ3Ç7·ß~»WÇ÷ý÷߇Ãa¦OŸnŽ9b¶oßnV¬XQæò‹Öɉ'Ì?þhºtébºté♿"Ÿ•²>o¥Y´h‘ 7………¥N·bÍž=ÛÜrË-åî#PÙPWô¥X­Z5S­Z5#É´lÙÒ:tÈ3Onn®©ZµªÙ¼ys±ß]²d‰©Y³f™ËþðÃMµjÕŒÛí6?ÿü³ 1ï¾ûn±yÆÍµ¼ý*ZÆ_|áiûûßÿn‚‚‚ÌÅ‹ÍÏ?ÿl‚ƒƒÍÒ¥K‹-'11±Xߊ–SZ_¯V£ú¨²³³õÅ_(44ôª¿ãÍutæÌ9Ž2ÿóTvìAlhܸqúñÇ=÷ZŒ•ËåÒ±cÇÔ¼yó/§Ó©ýû÷ëìÙ³š2eŠ~ýë_«E‹JOO÷,3&&F!!!Ú¸qc±Z6l¸æ~–§_å£àà`}õÕWÅÚ¿üòËb?…®¢°ãO._7mÚ¤˜˜˜Á©¼óIRóæÍåp8tôèÑrõÁétêìÙ³*((¨`ïˬx@óæÍÓüùóõÑG)//¯ÔyÓÓÓõoÿöozî¹çôÈ#›æ­ÏŠôËúâ‰'tðàA­]»VÕ«W/×ïys=zTM›6Uppp¹û T&ìAl¨Q£Fêß¿¿æÎ«!C†(<<\‰‰‰zöÙgUXX¨®]»êâŋڹs§8 _|QMš4Q•*Uô—¿üEüãµ{÷nÍ;׳ÌêÕ«ëÉ'ŸÔøñãU£F ÝvÛmúì³ÏôöÛo—«Oÿú׿JvmÛ¶íUûU7Ýt“FŒ¡qãÆ©zõêjÓ¦¾øâ ½õÖ[’þÿ=Z7–$­X±B÷ß¿‡g¢¯%''«FjÛ¶­>ûì3Í™3§Ô+ôË;Ÿ$EDD¨]»vÚ¶m›zõêUbzzzº äv»uèÐ!%%%©wïÞåÚ›XÛ¶móÔ ÒÊ•+U¿~}¹\®Rç/º²~ôèÑ:yò¤§½nݺåú Õ|â‰'ôÏþ³ÌÃüO>ù¤6lØ Õ«WëâÅ‹žZuêÔ¹âÞOo®£mÛ¶•8À%|z,€ëVÖ…&ëׯ7’ÌöíÛ=móçÏ7mÛ¶5!!!¦Zµj¦S§NfÁ‚žé‹-2õêÕ3.—ËôìÙÓ¼ýöÛÅ.*ÊÏÏ7ñññ&**ÊT­ZÕüæ7¿1‹/.×ER¥½Îž=[®~•6ÆË/xºpá‚yî¹çLÍš5MXX˜yàÌ[o½e$™óçÏ{~oêÔ©¦^½zÆétšK7å©qµ÷þz–±víZó«_ýÊ„††š† š9sæ\Ó|—›1c†éÔ©S©Ë*z9S§N3räH“™™éµñíß¿ßôèÑÃDDD˜àà`ó«_ýÊlݺµÌå—õ9¹Ôµ|V.WVµŽ.\¸`jÔ¨aÖ¬YSfÊÎa ²`O/¿ü²Þ|óM9rÄ×]¹n6lP=”‘‘Q¡½¾™™™jÚ´©þùÏêÖ[oµ°‡(ï:Z¾|¹&Mš¤o¿ýÖ¯òøç °…={öè½÷ÞÓwß}§#GŽháÂ…zùå—õÌ3Ïøºk>¥ñãÇkÚ´i¾î þ?/¿ü²¦L™B8®€sPØÆœ9sôôÓOëÂ… jÒ¤‰^xá=ÿüó¾î–Ï•÷\^Ü;wîôu¿Ç!~ø•ÿ9Ò³ÈÑšÇÛIEND®B`‚prinseq-lite-0.20.4/example/example1.fasta0000644000076700007670000000260612240000123020560 0ustar rschmiedrschmied>seq1 length=100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT >seq1_dupl1 length=100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT >seq1_dupl2 length=100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT >seq1_dupl3 length=100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT >seq2 length=200 ACGTGACGTGACGTGGTGTACACAGAGATATATGAGACACACAGATAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTGCGTGTACGTGACGTGACGTGGTGTACACAGAGATATATGAGACACACAGATAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTGCGTGTAACCACGT >seq3 length=100 TAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTGCGTGTACGTGACGTGACGTGGTGTATAGATTGCGTGCGTACGTGTGTGCATGCG >seq3_dupl1 length=100 TAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTGCGTGTACGTGACGTGACGTGGTGTATAGATTGCGTGCGTACGTGTGTGCATGCG >seq4 length=50 TAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTAGAGA >seq5 length=100 Ns_begin=10 NNNNNNNNNNTACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAAGTGAGAGTTGAGAAGAGGCGTGGAGGAGATGACACACCCCGTGTGTTCTC >seq6 length=100 Ns_end=10 TACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAAGTGAGAGTTGTACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAANNNNNNNNNN >seq7 length=50 TACACCAGAGGTGTCTCTGTGTGGGTACACCAGAGGTGTCTCTGTGTGGG >seq8 length=50 As=50 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAprinseq-lite-0.20.4/example/example1_pv.png0000664000076700007670000007127412240000123020764 0ustar rschmiedrschmied‰PNG  IHDRIbÓëVÁbKGDÿÿÿ ½§“ IDATxœìÝy\TUÿðÏÈ€h,æ‚i” â‚ae¥…¨©-Oê“¿,­ÇJËlQlqÍ5+·v\H3íIí)‘°Œ¬$­LQËwYÄd˜óûØf†;Ã\¸Ì0ðy¿^½rîræ{ï9sýzî¹çª„DDDDd¦™³ """jˆ}’T\\Œ„„èt:ôë×/^”]†Oµe¾¾¾J„WM|||½”[eöìÙŠ”3uêTÜpà ððð¨uŽ<¯J¸çž{PPPxùå—Ñ¥K<ûì³õò]U禠  u*+##ÑÑшˆˆ@dd$¶oß^ëxL¹J]9Š’uVeéÒ¥ˆˆˆ€N§ƒN§ÃæÍ›k—©¦XwJ]ûL)Y×Ô05ú$iæÌ™èÓ§²³³Ñ§O¼þúëÎÉLee¥ÙçÌÌÌzý>¥.ýû÷ÇÏ?ÿ OOOEÊkè233Ѷm[h4Àûᅵœ,^¼¸^¿W£Ñ mÛ¶øùçŸk]F`` ¾þúkäää`É’%5j”‚6<–uåhJÔY•‘#G"''ÙÙÙX·në®ê#IR²®©ajôIRZZ~øaÀˆ#ššªøw,\¸;wFdd$’’’ùùùèß¿?"""ƒ]»v·÷ññÁäɓѽ{wl۶ͬ,Óõùøø`îܹˆE§NÌb÷ññÁ¤I“nݺáèÑ£’eÿü«qÊ”)¸rå ¢¢¢pß}÷Õé˜ãââжmÛ:•QkÇQµnöìÙˆ‹‹CHH¾úê+Ìœ9={öD§N°iÓ&ã¶+W®Dll,t:bbbð믿š•cí›Z³f † xðÁQRR‚ØØX|üñÇl×w~~>­V N‡ŒŒŒã25xð`¬Y³FΩ3ŽÖ­[zö쉳gÏÖº,kj]Õ´Ÿ­ï“ú];ªÎª´lÙÒøçÒÒR´oß¾ÎeZjÈu'UJ]û”:n¥êš(a'½^/öîÝ+þûßÿŠ%K–ˆY³f‰Y³f‰%K–ˆÏ?ÿ\ìÝ»Wèõz{‹s˜V­Z ƒÁ`üìçç'»Œ-ZT[vÝu×™•YXX(„¢´´T!ÄСCÅÖ­[…Bdgg‹îÝ»·÷ôô«W¯®ñ»ÔjµXµj•Bˆ;wŠÐÐP³uÉÉÉB!’““Å Aƒ¬Æk«Ô±ÔE]ÊS«Õ"22Òì?///«e›‡Z­+W®B±k×.áíí-Ö¬Ycülz®ŠŠŠŒÎÊʱ±±fåX;Ǧ"##ʼn'¬Æf«¾zè!1þ|!„ƒA”””Ô—iù§N’qÉõÞ{ï‰aÆÉÞÏ•ëÊÖ~¶¾OêwíŒ:[´h‘ ×_½8pà€ìý]¹î¤ê@©kŸRÇ­d]Sã¢æ§ÛöíÛ‡o¿ý………6·ó÷÷Gß¾}¦XWW×]wŠ‹‹¡R©\‹±¦ã°äããƒK—.™-óõõEqq1àÞ{ï…J¥ÂСCñÀ@­V#00íÚµ3n_ZZŠÃ‡¼¼¼PTTµZmó»¼½½QRRb÷cú^^^¸pá¼½½QVV†öíÛïã[ÆkºŸÔ±ÔE]Ê«é¼Ú:ooo£yóæ®K—.ÁÍÍ­Ú¶;vìÀË/¿Œüü|¸»»ãðáÃ(--5–cí›ò÷÷Çùóçå[Æf«¾pìØ1³^šâ2-ß`0Àßß_2.9vïÞýë_øá‡d÷ºr]ÙÚÏÖ÷Iý®]g¦>þøc|üñÇøöÛoeíçÊu'UJ]û”:îú¨kj8lÞn3 زe >ûì3»‹ÂÂB|öÙgزe ƒbAÖEÛ¶mqúôiÀ™3gЦM›jÛ¼óÎ;ˆŠŠBTT”q[S^^^øë¯¿ŒŸËÊÊÌÆâ|ñÅxæ™g‘‘¸vî233±gÏìÙ³Çø&¸¹¹I&H–š5kVëÑU¹¯^¯‡^¯¯UuUÓyµ‡µãhÖ¬™ñžžžÆ ˜¥#F`æÌ™Ø»w/vìØa6LÎ9¶õï [õ]• Ë‰Ë’µ2ìuâÄ :ëÖ­“Ls]ÙÚÏÖ÷Iý®Yg–þýïcçÎÕ–7溓ªƒÚ‹œmå7 |]SÃa3IúöÛok5833[·n­uPJêׯŸñ~ñêÕ«‘˜˜Xm›±cÇÿr“ú ¤OŸ>X¾|¹ñsrr2îºë.ãçS§Náî»ïÆo¼¬¬,ã>|ðq›ýû÷+vLUÖ­[X»v-n½õVãò:Ǭ[·ÎìbÕ¼ys\¹rEñX¤Ôt^kbë8ä0ËñÑGÙLvlÅbk,­úîÛ·/Þÿ}×.ÊUOXÚ×Ù³g,;æ*/^Ä Aƒðæ›o¢[·n’Û4¥º²÷û¤~׎ª³*¦ãm¾úê+É^úÆ\wRuP'P·kŸRÇ­T]SÃd5IÚ·o_ž´Ú¾};8Pëý•2eÊlÙ²øæ›oðꫯÊ.cÉ’%غu+ÂÃí[·š=Õ4|øpDFFâ¶Ûnüyó\{twëÖ­ÐjµÐjµX½zµbÇ\ëúã?Å‹ãí·ß6®{ã70lØ0ôèч6ëõ3f t:]nOž<íÛ·Çå˗Ѿ}{Lž<¹NåI±urÌ›7·ß~;zô袢¢Z•së­·â·ß~³ºÞV}/^¼ÐjµˆŠŠÂï¿ÿ.+®_~ù·Ýv›ì˜«|øá‡8xð ^{í5cCmÿB°Æ•êÊÞï“ú];ªÎªÌŸ?ÐjµX¸p!V®\Yç2-5亓ª¥®}J·RuM “䘤ÊÊJ,]ºEEEÆeÇGóæÍ‘’’R­ÀÀ@Œ;«V­2»Íàïï±cÇÚ즤ÚQzlÙöóÏ?ãƒ>¨—¿¤jòØcá‰'ž¨÷9´ gÖUÖYíØSw íÚǺnÜ${’öïßo– ×}vìØQr²èèhãÈ‘#fË DoQ]ÝrË-8}ú´Ã'(¼páN:Å ° Ϊ«*¬³ÚsvÝÉźnü${’Ö¯_œœ³eÍš5ÃóÏ?]»vçy®u}>ÿüóøå—_ªÍù:÷ß=„NDDDT${’¤ž0 سg¢¢¢ÌFòwîÜÞÞÞØ³gäœ:uJ¡P‰ˆˆˆG2I²v¿w÷îݸîºëpã7—ÅÄÄàðáÃ())‘ܧ!Ý;&"""²—¬×’\¸pÇŽCtt4€kS懄„ŸÖ!"""j,$“$©·FWÙ½{7ºví ///DEEáÊ•+øã?¬no9Ë0‘+L’lMH¶oß>èõzèt:DGG#++Ëæœ+õýT"""¢ú ™$uíÚÕêÈÉÉÁwÜìÞ½ÛæØ*Ë‘žyæ™Z¿âCªgMj*„†âž{î©—GhgÏž­x™5Y¿~=ºw¨(„††âé§Ÿ6¾ò¦ª7³ê¿?þøHHHPä»MËÿøãë´U|J°ÕÓ[JÖ¯i¬Ëï§>Û\]ÛV²­ÀÔ©Sް°0,]ºTöþloÿ\ó¾øâ ¨T*YSÐÔ%Ë}å¶-{ϱܺPº6EV“$«;ýþûïðòò‰'pþüy«Ûùûû£K—.u²Ž~üñGÔzFUW’™™‰¶mÛB£Ñ(^¶£“¤ÔÔTÌŸ?›7oÆž={°wï^DFF߱俿f|Þ={Ð¥Kh4´mÛ?ÿüs¿ß´üGy¤NûWÅgI陯뢶õky J¶Áújs•••uz£EÛÚ²eË——‡ììlìÛ·Æ “]ÛÛ?ííÓO?Å€ðé§Ÿ:$Ë}ëÚ¶”¢dmª$“$777Ü}÷ÝVw:sæ ¦M›†eË–Ù,>>˜úè#Lž<Íš]»$+ùœ¦ÖÞ.]º„;vàwÞ1¾ãÍ´©c‘Ч¦ëqU<½{÷¶ymÌÏÏÇÀ¡Õj¡ÓéÌæ”bë{«ãöÛoÇÆkOOO±zõjãç¡C‡Š­[· !„ÈÎÎÝ»w7®³VRm!33S<øàƒB!n½õVÑ£GqõêU1mÚ4ñþûï !l·1Ëú´—å1˜²lƒ5ý~î½÷^»Û£)¹mÛ2fÓ²mý¾(RRR„B¤¤¤µZm\§T[óõõ¯½öšˆˆˆwÝu—8xð ì2ØÞ®Y½zµxâ‰'ŒqýöÛofçÈZ=[Æc+v[mÉòóC=$æÏŸ/„Â`0ˆ’’’jÇ`º}M笠 @ÜrË-bÓ¦MÆå¶ÎRm´©’œq»ŠÁ`ÀÖ­[±}ûvY‰W¯^½Ð§O㿊œå·ß~ÃäÉ“ñÍ7ߨý;¤öóõõEqq±äzÓuÞÞÞ(..6ö~xyyáÒ¥KÆ6ÓmwìØ—_~ùùùpwwÇáÇQZZj,§¤¤Ä8®Êt?Sþþþ8þ¼±ü{ï½*• C‡Å<µZ ///\¸pÞÞÞ(++CûöíÍÆX;ËuJ·5þþþ8wîœÕ±dÖêÓ`0Àßß¿ÆòkrþüybÕªUxÿý÷eÿ¬Åçåå…¢¢"¨Õj×Þ}Ø®];ãúÒÒRã;¥êÏZ[¸zõ*ºt邬¬,ÜÿýÐjµ6l^{í5,^¼aaa6Û˜e¼¶â²<S–m°¦ß¿¿?Nžúè#ÀæÍ›kõDž*• z½Þ8f¸vMoyzzZ½9bĤ¤¤ W¯^(++3Ö¬Y3»ž›æ½_|ñ¾ûî;¬[·+V¬À·ß~[ëc‘³­œã¶&""»víBÏž=eíÀlVøÚ píåÎãÆ«¶¾¶íÆÍÍÍìbo0™™ ooïjÛJÕŸµ¶Ð¼ysÜpà X¹r%âãã]û‡Bhh(ÛmÌ’­¸,Á’{)FnÛ¶sM¿/[íI‰¶Œ‡zðàƒb̘1Õ¶a{«¹½â»ï¾CNNT**++¡R©ðÆo@¥RɺŽÚн¦xLÉm¶¾W¥R¡gÏžHKK3K’l»ÚÄ@&ìírÒëõbïÞ½býúõbÉ’%bÖ¬YbÖ¬YbÉ’%býúõbïÞ½B¯××Go—bj{»Mj?Ó[K¡¡¡bçÎBˆk]½¦Ýñ¶nIY~ ÇŽB±xñbYåT±ìzÎËËBQXX(4âZ—óòåË…B¬X±B <Ø®cñóó—/_Vü¸cbb$åË/¿={öùùùB!*++Ň~(ÊËË%¿£ŠÝËçÏŸƒA!Ä_|aÖ}m/kñY.ÿ׿þ%Þzë-ãgÓ[{Rõgëܾúê«"88X|óÍ7âìÙ³"88X 2ĸÞV³¬_[qÙú-Y¶Áš~?ƒ 2¶ÇåË—›Ý"³ŒÉ”ܶmë–ˆ­s:`Àã-Ëv®Ô­Œ^xAlÞ¼Y!Ä7ß|#zôè!» ¶7!>øàñŸÿüÇlýí·ß.¶mÛVã±XÆ#çzl¹¯éú¡C‡ÊºÝVÓ÷VVVŠÿûßâµ×^3.·uîx»­nìN’ƒúJ’6mÚ$:uê$ºwï.¦OŸns­daÅŠ¢C‡µ*§ÊرcÅÆŸããã…N§Z­ÖllÖ¤I“DTT”ˆŽŽGޱëX’’’ÄM7Ýd¼*qÜ%%%",,LòX„bݺu¢[·n"22R„……‰±cÇŠÊÊJÉ免qãFñôÓO[-ÓŸ|ò‰Ðjµ",,LôèÑCìÙ³Gvöþ¥uîÜ91`À&ÂÂÂÄË/¿l\g­þL™žÛôôtáîî..]º$„âæ›oo¾ù¦q½­6fY¿¶â²õ[²lƒ5ý~Ž=*âããExx¸ˆGµ“)¹m»¶IÒŸþi,ï…^ÆuJ´5!„(..Z­VDGG³½Õ²½ÝqÇ"--Ílý¢E‹Ä“O>Yã±XÆ#çzl¹¯éúsçΉÄÄD&t:ÈÈȨv ¦ÛÛó½bРAÆäËÖ¹Sª6UM*Ij 233ÅÈ‘#mnSÛd±>|óÍ7fU%<úè£bûö튖Iö³§ Ö—úhÛ—/_6ö*®_¿^ÜyçÆulkÎçÌöæ ØFëÆ¹#«Iq·Ür NŸ>]/“IÖ‡¾}ûâùçŸW¬¼ .àÔ©Suž(jÏÕÚ`MöîÝ‹¨¨(„……aÖ¬YÆÇÞÙÖ†ÆÖÞ”Ä6Zw6Ÿn#"""jªØ“DDDD$I‘&IDDDD˜$I`’DDDD$¡Ñ'I&L@TT¢¢¢Ð¹sgøùùÉÚßËË˸TTþøãEâ2}K´’fÏž­XY÷Üs¢ÕÚ{ÌŽx\µêMîHHH¨syÿûßÿ ÕjŽˆˆ|õÕW²ËðòòBÿþýÍ–Ý{ï½ðòòªs|ueÚ”j»µ©gËöí¨G›•j'»wïFtt4´Z-† R«wIZ»&Õt.äÔ›¿}ÓºRêüM:7Üpƒä«EŠ‹‹‘N‡~ýúáâÅ‹²ËoH¿AÓúTòºN29{¢&GZ¼x±5j”¬}왜®6¯c©¯ k[®å1lß¾Ýêmµ}ýLCšÄÒtÛG}TdffÖ©¼Ö­[‹ÜÜ\!„mÚ´‘]F‹-Dtt´8wîœBˆüü|¡Óé¬Î®î(–mÁÞz¬×9³ )ÑNºuë&RSS…BlÞ¼YLš4IvJ¾9@Š­ß~]¾O‰ó·cÇqêÔ)Écyþùçżyó„BÌŸ?_¼ôÒK²Ëo¨¿Á†tílj}O’©O?ýÇW¤,Lž<Ý»wǶmÛŸŸþýû#""111صk—qÛ… ¢sçΈŒŒDRR’qùܹs‹N:!550þ|ãdu&LÀ]wÝøî»ïððÃV®\‰ØØXèt:ÄÄÄà×_L™2W®\ATTî»ï>°—å1˜Z³f † R«ãÍÏÏÇÀ¡Õj/½´díª¾ËôϳgÏF\\BBBðÕW_aæÌ™èÙ³':uê„M›6™}¯µ˜Ž=Šnݺ!::'N4‹eðàÁX³fMµå¸ñÆoÙ...6¾TY®áÇcíÚµ€µk×bذafëóòòЫW/DDDàÖ[oE^^žqeOAUo Ým/S–m&Mš„èèhtëÖ G5‹Á´È©g©ßƒ)©ömZ†Ô1J-³užl%ÚÉüa|1é=÷Ü#yœµUÓ¹¤¯9–,ëûðáȉ‰1þvLÏ—µs)UWJœ¿¸¸8«/öMKK3^#GŒQës[—ß Ôy·¼öØsþL×IK[1œ¥9ÊÑ£GE›6mdÿëV­V‹ÈÈH)Ë===ÅêÕ«Ÿ‡*¶nÝ*„";;Ûì…¨~~~¢°°P!Dii©±Üª—fîܹS„†† !®M±ÿàƒ !„¸õÖ[E=ÄÕ«WÅ´iÓÄûï¿/„¢¨¨ÈXvVV–ˆ5~¶ü‡­¸,Á”åKJåïC=$ùBGÓØì=µZ-V®\)„b×®]ÂÛÛ[¬Y³Æø¹ê¼ÕÓ AƒDrr²BˆäädÅ_RzäÈѾ}{,Úµk'>,»Œ-Zˆ“'OЏ¸8!„qqqâøñãfÿн÷Þ{ÍŽÃôe°5½¼Ó² Ú:_¦,Û‚Z­¶ƒe;‘SÏR¿K¶Þ¿&uŒRËl'[çD‰vÒ³gOãùY³fhÕª•ì2¬]“j:öžcËú8p HIIB‘’’b÷‹¬-×)ù¢U©ž•V­Z_#ĵsP›rëò”:ï¶®=öž?ËílÅ@Êj2IÒœ9sijÏ>+{?kÝœjµZ\¹rÅøY£Ñ/\‘‘‘âÆo4®8p ¸÷Þ{ÅêÕ«ûxyy‰«W¯·©úq”——‹Ž;Š’’ѧOñì³ÏŠÌÌLѧOã휟þYÜyçB«ÕŠÈÈHáããc5^[qYƒ)???³„RÎñúûû‹‹/V+Ó46{ÁËËK”——›Åa—éE¥¦˜þúë/!„W®\^^^Æu•••uîN0`€øä“O„B¬]»V 0@vUÇÝ·o_ñÅ_ßf™ì˜‡éËVm]p¥Ú ­óeJª-X‹Á²È©g©ßƒµs$õY꥖Ù:O¶Î‰í$77WôîÝ[„‡‡‹É“' ÙeØó"[9×K–õmÚæÊÊÊÌ~;r’$%Οµ²…P.I¢ö¿A©ónëÚSÛ$ÉV ¤¬&“$ét:±cÇŽjË—.]j¼ ž:uªÚz{߬múC°¤×ëÅ–-[ÄèÑ£EŸ>}$÷7ýqôîÝ[,Z´H¼öÚkâ¿ÿý¯˜5k–¸á†Œ€ñÓO? !jþÑÙŠËÖ}n???QQQQ«rjL’ì=[çÉò³­˜jJ’|}}%÷³W«V­ŒéõzÉòìmk)))" @,_¾\!/Iªj#fçNª Ú:_¦,Û‚­$ɲ¾”ªgkÛÕtŒÖ~{ÖΓ­s¢D;1uðàAc…)%®Ir¯9¦,ëÛÏÏO\¾|Y!$Y;—RI’RçOêtíÚUœ5=—¶b e5‰$éÕW_¯¼òJ­öµ7I:wîœ0`€ aaaâå—_6®‹:NhµZ±lÙ2ÉýM„éééÂÝÝ]\ºtI!ÄÍ7ß,Þ|óMãú+Vˆ:ˆîÝ»‹éÓ§›í›””$nºé&cRe+.[IÒØ±cÅÆku¼çΉ‰‰",,Lèt:‘‘‘Q­ [ÇPÛ$ÉVL‡ÑÑÑ"**J¼ôÒKfûmܸQ<ýôÓVÏ…=vîÜ)"##E×®]Edd¤ñÂ'‡µú0õèÑ£">>^„‡‡‹øøxqôèQãºM›6‰N:IžS©6hë|™’j “&MQQQ"::Z9rÄê1(UÏU,Û·é~RÇ(µÌÖy²uN”h'ï¾û®èÒ¥‹Ðjµ"))Éìö½ì¹&ɽ昲¬ï?ÿüÓX×/¼ð‚Y¯…­siYWJœ¿¤¤$Ñ®];¡R©D»víDRR’q]aa¡èÛ·¯wß}·Ùx8{Õõ7(uÞm]{l?ÓX,Ï¥­HY*!„pöàqjx~þùg|ðÁX¹r¥³¿|†è IDATC©w=öžx⠇͹ãjšR[°¥©´Ëú¾rå Ôj5T*6lØ€¥K—â»ï¾“]nS95ñõõ5> K _“š€ìwË-·àôéÓŠN&Ù]¸p§Njòn[šJ[°¥)µËúÞ»w/¢¢¢†Y³f§(‘£)?j\Ø“DDDD$=IDDDD˜$I`’DDDD$I‘&IDDDD˜$I`’DDDD$I‘&IDDDD˜$IpwvµqéÒ%g‡Ð$´hÑýõ—³Ã ""²‹¢å±'‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’à’·­ÈÍuGV– ÜM%"#+ Õê¡R99@"""rŠ&I¥¥¥˜wdg{ ?ÿZ‡YP:]ÂÂôP©ªïsõêUtìØ§OŸV:d—Äy’ˆˆÈ•(=OR£ìI• ÐjõÐjk¾õVeÕªUHHH¨Ç¨ˆˆˆÈU4Ú$I®¬¬,,Z´éééÎ…ˆˆˆ€F9p[®“'ObäÈ‘HIIA›6mœ5M>I*--ÅСC1gÎDGG;;"""j š|’´|ùr:t3gÎD||<âããQYYéì°ˆˆˆÈÉíÓmTw|ºˆˆ\‰ÒO·5ùž$"""")L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’àîì!€Ü\wdey  À  ÑT"2²Z­*•“$"""‡a’ô7ƒHKScÿ~óSræŒΜqC^ž‰‰ehƾ7""¢&åÿ-7×£Z‚djÿ~wäæz80""""r&&IËή¹SÍžmˆˆˆ¨q`’ô·‚‚šO…=ÛQãÀ¿õ‰ˆˆˆ$0Iú›FcPd"""j˜$ýM§Ó׸Mdä?Ûdee¡W¯^èÑ£† †¿þú«>Ã#"""c’ô·ð𠄇[O”ÂÃõÐj+ŒŸŸyæL™2¿þú+F…yóæ9"L"""r•B8;¹.]ºT/å ìÛçŽìläç_˃‚ Ðé*f>™äõ×_'NÀÃÕ••ˆÇÎ;ë%.giÑ¢{ȈˆÈeøøø(ZŸi7¡RZ­ZmÍ·Þ°aà :6lÀ‰'!9 o·Õһヒ•+W"..¹¹¹pwg¾IDDÔ˜ðoöZêÚµ+ÒÒÒGŽÁ¶mÛœ)‰=IµTXXB`Á‚1b„“#""""%1Iª¥ 6 &&qqq ĨQ£œ)ˆO·‘U|ºˆˆ\‰ÒO·±'‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$0I""""’À$‰ˆˆˆH“$"""" L’ˆˆˆˆ$Ô:Iª¨¨@QQ***”Œ‡ˆˆˆ¨A°;IB ==£FÂ7ÞOOOøûûÃÓÓ!!!5jÒÓÓ!„¨Ïx‰ˆˆˆB%ìÈj>ÿüs¼öÚk8wîúõë‡ØØXtèЭZµÂÅ‹‘——‡_~ù_ý5Z·n×_>ø`½}éÒ¥z+›þÑ¢E üõ×_΃ˆˆÈ.>>>Š–gW’Ô­[7¼üò˸÷Þ{Ѽys«Û]½z_~ù%æÌ™ƒ]»v)¨)&IŽÁ$‰ˆˆ\‰S’¤††I’c0I"""W¢t’Tç§Û***P^^®D,DDDD F­“¤S§Náž{î——¼¼¼Ð»wo=zTÉØˆˆˆˆœ¦ÖIÒþóá‹/¾ÀçŸ777<òÈ#JÆFDDDä4îön¸~ýz<ðÀÆÏ9998vìš5»–gEFF",,Lù‰ˆˆˆœÀiÓ¦aðàÁ8qâ ]»vX°`Nž<‰£GbÁ‚ ©·@‰ˆˆˆÉî§Û***°`Á,\¸¯¼ò âââpÿý÷ãôéÓFƒÏ?ÿ½{÷®×€>Ýæ(|ºˆˆ\‰Ó§8|ø0žzê)áwÞ››*++¡Óé V« Î&IŽÁ$‰ˆˆ\‰Ó§hÓ¦ ¶lÙ‚ñãÇcÈ!X»v-ÂÃÖ 9‚ÝIÒ/¿ü‚N:¡E‹ ELL öîÝ‹ . <<iiiõ'‘CÙ}»-::7ÝtF…Í›7#77ß}÷`Û¶m3f ¢¢¢°víÚz àí6Gáí6""r%N“äáá $$ƒíڵÙ3gŒëËËË1gÎL›6MÑ¥0Ir &IDDäJœ6&)88Ë—/ÇÉ“'‘œœŒ¶mÛš­÷ôôtH‚DDDDäv÷$}öÙgø¿ÿû?\½z^^^ذaúõëWßñIbO’c°'‰ˆˆ\‰S§ÈÏÏÇÁƒѵkW(ˆL’ƒI¹¥“$»_KAAAðöö6 ¢¬¬ *• žžžŠFDDDäLvI:~ü8ÂÃÃѲeKôëט0aZ¶l Œ1åååõ+‘ÃØ$½øâ‹ð÷÷ÇæÍ›áëë‹#F`ãÆøä“O°jÕ*üøãxýõ×ë3V""""‡±{LR@@ÒÒÒ‹ÂÂB`ýúõ¸ÿþû6lÀ¤I“pðàÁz à˜$Gá˜$""r%N› ¸¸íÛ·øûûÃÛÛáááÆõÝ»wG^^ž¢Á9‹ÝI’ŸŸ.\¸`ü|ûí·£E‹ÆÏW¯^åàm"""j4ìN’´Z-víÚeüœ––†víÚ?ÿþûïèÚµ«²Ñ9‰ÝS¤¤¤ÀÃÃÃzAîîxõÕW ŠˆˆˆÈÙdM&ÙPpà¶cpà6¹§ Ü&"""jJK’öìÙ•J¥TqDDDDNe÷˜¤ââb›ëKKKë QCaw’äççWŸq5(v'I>>>xíµ×+¹þСCxâ‰' ŒˆˆˆÈ™ìN’´Z-<==qÇwH®÷õõU*&""""§³{àvDD²³³ë3"""¢ƒó$Õ’@n®;²²ñã]{Ð3n‘£y}òɵ$*Û´Á‰»VN¸íïï‰'bâĉ(--Å¡C‡péÒ%´lÙ!!!hÙ²¥¢5dgθո ÉÓìï1HuÝF µ8Ó²eKDGG+‹ËÐéô5&I‘‘z㟳²²ðôÓOãêÕ« Á²eËТE‹ú“ˆˆˆê€gj!<¼áázëõÐjÿy²í™gžÁ”)Sð믿bÔ¨Q˜7ož#Â$""r9F‘m”ÀÉ$kI`ß>wdg{ ?ÿZ®d€NW°0óÉ$¯¿þzœ8q¨¬¬D||û ­ZµR$ö$Õ’Jhµz ~ãÇÿ…ñãÿÂðáW$gÛ Æ 6lÀ‰'œ1QÃWýß }x8*´ZãçyóæáŽ;îÀŽ;ЧO¼þúëŠÅž$8pà&L˜€ÂÂB$&&bùòå8~ü¸³Ãª{’ˆˆÈ)„€û¾}ðÈÎF³ü|€!(:ôaaf“IvïÞ_~ù%Ú¶m‹ÒÒRôíÛ¹¹¹Š„Á$ÉÁŽ9‚Ñ£G###ÃÙ¡ÔˆI5tmÛ¶Å©S§ R©àãã*R6o·9@Ue !°`ÁŒ1ÂÉQM˜$9À† ƒ¸¸8bÔ¨QΉˆˆ¨QhÓ¦ Îü=ùä™3gЦMÅÊ®Óí¶K—.ÁÛÛÍüº{W¾ÝæJx»ˆˆº¤¤$´iÓãÇÇ{gsçÎaÁ‚Š”-;»Ñëõxå•W€–-[âÈ‘#€3f 99Y‘ ˆˆˆˆì‘””„­[·"..ß|ó ^}õUÅÊ–$MŸ>Ÿ~ú)–.] µZm\Þ¹sg,_¾\±Àˆˆˆˆjâëë‹/¿ü;wîÄ–-[àëë«XÙ²“¤åË—ã£>ÂðáÃáæöÏ«9ºu놜œÅ#"""r&ÙIÒùóçÑ¥K—jË=<û,ŠŠŠÐ§O\¹r·ÝvÔj5’’’ðÄOÔGŒDDDD'kž¤ŠŠ ¤§§£gÏžðööFnn. ´Z-|||ê3N3œ'É18O¹¥sYI’žžž8xð n¸áE‘ƒI’c0I"""W¢t’$kL’J¥BDDŽ;¦hDDDD ìÛ3gÎÄsÏ=‡M›6áôéÓ(((0ûˆˆˆ¨1ýî6•Jes}^g7Þns Þn#""W¢ôí6ÙO·edd(QC$»'©!`O’c°'‰ˆˆ\‰Sn[*//Gyy¹R±5µJ’V¬X®]»B­VC­V#44)))JÇFDDDä4²Ç$%''cܸq?~‰)S¦( ‘3Ôz2É’’ã íÐÐP´jÕJÑÀlá˜$Çà˜$""r%N¸Ý0Ir &IDDäJœ>p{ÆŒøøã«-_¹r%^ýuE‚""""r6ÙIÒûï¿°°°jËCCCñþûï+‘³ÉN’Ο?/ù¨›6mpîÜ9E‚""""r6ÙIRpp0233«-ÏÌÌDpp°"A9›ì)žxâ <ýôÓ¸rå îºë.Àwß}‡çŸ'NT<@""""g$Mš4 .\À˜1cpõêU€§§'ÆÏ$‰ˆˆˆZOPZZŠýû÷ÂÂÂìÎNàœ€ˆˆ\Iƒ›'©²²z½žžžJÅT#&IŽÁ$‰ˆˆ\‰ÓæIJKKçŸ~j¶ìí·ß†¯¯/¼¼¼0`À\¼xQÑàˆˆˆˆœÅî$iΜ98þ¼ñóo¿ý†^x'NÄÆqøðaL›6­>b$"""r8»o·`ëÖ­ˆŠŠ¼øâ‹ÈÎÎÆ–-[©©©xöÙgqøðáú‹öo¼Ýæ¼ÝFDD®Äi·ÛŠ‹‹dü¼sçNÜ~ûíÆÏ:'NœP48""""g±;IòõõÅ©S§z½»wïFtt´q}YYÜÝeÏ(@DDDÔ Ù$Ýqǘ>}:Ž;†7ß|Ìz’²³³¢|„DDDDN`w×Ïܹsqçw¢S§NP©TX¸p!Z¶li\ÿßÿþ·Ýv[½IDDDäh²æI*++Þ={ЦMÜpà fë¶oߎo¼mÚ´QÙÝ €»îºKr=nQc ;IªšT’êŸFcÀ™3n5nCDDDÊ“$ÝqÇõIÑéô5&I‘‘ÿLÚšŠiÓ¦A¥RA¥RaÚ´iHLL¬ï0‰ˆˆ¥:͸}éÒ%x{{£™ƒŸAo*3n ¤§«±w¯t.®GBB™q®¤¤¦¦¢k×®8xð ú÷ïƒÖúû9ã6¹¥gÜ–Ýèõz¼òÊ+@Ë–-qäÈÀŒ3œœ¬hpMJ$$”!1± íÚUÂÃCÀÃC ]»J$&–™%HбcG”””JJJСC'ENDDäúdßn›>}:>ýôS,]º£F2.ïܹ3/^ŒÇ\Ñ›:• ÐjõÐj«ÏnniùòåHHH€J¥‚Á`@zzº"$""jœd÷$-_¾}ô†7·ÆËtëÖ 999ŠGò¼ð ˜1cöïßÙ³gãÅ_tvHDDD.Kv’tþüyÉÙ¶=<®\¹P«ÕHJJÂÔ©SëPii)&OžŒ‚‚bîܹhÑ¢…Ù6Me gãDDäJ”ž Öó$]¾|¹¹¹0 ÐjµŠööÛo# <ò>þøcãÙgŸ5Û†I’c0I"""Wâôy’ª4oÞ;wF—.] ×ëQ\\Œâââ:”™™‰~ýúú÷ïŸ~ú©ÎeÉ%{LÒðä“ObûöíÐë«ÏÝS×Üæçç#00 ÑhPPPèÞ½»q›_ýµNßAöQ©TÕnu5²“¤#FÀÃß|ò ‚‚‚ê#&I¿ýö›ñÏ¼Ýæ¼ÝFDD®DéÛm²“¤œœdggKΕ¤„ÀÀ@œ?AAA(((€F£©—ï!"""²Eö˜¤ððpEÆY¯¿þ°yófÄÇÇ×ÛwY#ûé¶-[¶`úôéxýõסÕjѬ™yžUמŸ‹/")) .\€F£ÁܹsѲeK³mx»Í1x»ˆˆ\‰Ó§P™¾v^B]nÛƒI’c0I"""Wâô1IŠ@DDDÔÕz2IgbO’c°'‰ˆˆ\Iƒ™LÊËËQ^^®T,DDDD F­’¤+V k×®P«ÕP«Õ EJJŠÒ±9ì1IÉÉÉ7nÆÞ½{¶mÛ†1cÆÀ`0à±ÇSù$¦L™¢x€DDDDÎPëÉ$KJJŒƒ´CCCѪU+E³…c’ƒc’ˆˆÈ•8}à¶©ªAÚžžžŠd&IŽÁ$‰ˆˆ\‰ÓnÀ²eËj6™äŠ+ ŒˆˆˆÈ™d'I‹/Ƹqã0xð`¤¦¦"55ƒ ÂSO=…¥K—ÖGŒDDDD'ûv[‡0mÚ4Œ5Êlyrr2fΜ‰¼¼&)** 999Õ–gee!&&F‘ è¹¹V$ؿ߹¹Œˆˆˆ¨i=OÒŒ30nÜ8¡wïÞB`Û¶m˜1cÞ{ï=·Õh4ŠÛeg×\EÙÙ¨p@4DDDM‡ìÛm*`ê0»€MMévÛ¢E-PQaûœ{xŒ¯üm1Þn#""W¢ôí6Ù=IŠ@DDDÔÉN’î¸ãŽzƒ¬Ñh 8sÆ­ÆmˆˆˆHYµ~&ª²²%%%(..6û”¥ÓékÜ&2òpŸŸ IDATŸmRSSÑ£GÄÆÆ"..iiiõQ£%{LÒŸþ‰§žz ?üðôúê××8$SMiL’@zº{÷Jwú…‡ë‘Pfœ+)$$©©©èÚµ+<ˆþýûãàÁƒµúnŽI"""Wâô1Iÿþ÷¿áåå…O?ý”O¯9€J$$”!8ØÙÙÈÏ¿Öùd€NW°0óÉ$;v숒’×^Bl9ŸÙGvO’§§'rrrйsçúŠ©FM©'I®¼¼<$$$@¥RÁ`0 ==;v¬UYìI"""WâôÉ$ÃÃÃ9ö¨{á…0cÆ ìß¿³gÏÆ‹/¾è숈ˆ\’잤;v`òäɘ1c´Z-šY¼Ã××WÑ¥°'ɺ¶mÛ"//¨¬¬Ä 7Ü€“'OÖª,ö$‘+qú˜$FƒÒÒRÜ~ûí’ë1p›¬»ñÆñý÷ßãî»ïFFF:uêä숈ˆ\’ìž¤ØØXxzzbüøñ’·1{’¬Ûµkžyæ”——ÃÓÓK–,A·nÝjU{’ˆˆÈ•(Ý“$;IR«ÕÈÎÎæÀí&€I¹§Ü CQQ‘¢A54²“¤Ù³gc„ ÈÈÈ@~~> Ìþ#"""j dßnS©l¿‘ž3n7¼ÝFDD®ÄéO·edd(QC$»'©!`O’c°'‰ˆˆ\‰Ón›*//Gyy¹R±5µJ’V¬X®]»B­VC­V#44)))JÇFDDDä4²Ç$%''cܸq?~p;((YYYÕ–gee¡uëÖŠEDDDäl²Ç$9?þ8,X`6&éÅ_Ę1c\‹@n®;²²úè#TTT<<<ðä“Oâ­·Þ‚»»ì¼K6Þns ¹·Û  -Mýû¥Û@h¨‰‰ehV§‰'ˆˆˆ¤9}LR•’’ã íÐÐP´jÕJÑÀla’är“¤œ¤§{ÚÜ&!¡u ˆˆ¨§¿–¤Êu×]‡¸¸8%c!—]ssÊÎvg’DDD.Áî¿þú+ €âââj늋‹1`ÀüþûïŠG®¥  æædÏ6DDD ÝcÍŸ?ݺuƒ¯¯oµu¾¾¾ˆŒŒÄ¼yó ŽˆˆˆÈYìN’¶mÛ†ûî»Ïêúxßÿ½1‘‹Òh ŠlCDDÔØ$A£ÑX]ˆ¢¢"E‚"פÓékÜ&2òŸmfÍš…°°0øùùÕgXDDDµbw’Ôºuk=zÔêú£Gâúë¯W$(rMáá·ž(…‡ë¡Õþ3h;!![·nEóæÍ‘,vOðÄO ??ÿûßÿª­B`РAhÛ¶->øàŃ´Ä)£6¯%Ø·ÏÙÙÈÏ¿–ƒ ÓU ,Lz2ÉÖ­[ãܹsJ„LDDM˜ÓæI:qâºuë†=z`üøñÐjµB 77o¿ý6vïÞ]»v¡}ûöŠ(…I’c8êÝmL’ˆˆH N{w[pp0¶oßŽŠŠ ôë×íÛ·Gpp0!„@ff¦C$""""G¨ÕŒÛ.\À¡C‡7ÝtÌö$9{’ˆˆÈ•4ˆ·ž9§?&§™:u*ºté‚+W® K—.˜:uª³C"""2ªõ n‰·ÛÃQ·Ûˆˆˆ”à´ÛDDDDM‰]c’ ì.ÐÖ¬ÜDDDD®Â®$)00Ðî]ðîQ5v%IõQƒÂÛdn‘+ió$×n«]ºt •••fË}}}둳É~º­¨¨#FŒ@Ë–-ѪU+øùù™ýGDDDÔÈN’ÆŽ‹œœ¬^½jµ)))˜?>‚ƒƒ‘’’R19œìÛm©©©Ø´in»í6¸¹¹á–[nÁÍ7ߌ›o¾ï½÷yä‘úˆ“ˆˆˆÈ¡d÷$•••¡cÇŽ///¢¢¢ðã?*‘³ÈN’BCCqðàA€N§Ã‡~ˆ'NàÝwßå˜$"""j4dßn›0aN:˜>}:±|ùr¸»»#99Yñ‰ˆˆˆœ¡Îó$cß¾}èØ±#Ú¶m«T\6qž$ÇàÐO<¡¹sçÊåryÛ:΀‹àÚ¶­îៜœ³‡/aªOwÀj ±ù}¹ÍæÇu“.ÁT#.·ÇóÏ·Ò™3µ·q8ŒœÎrÚkmW¦±cO°:ªjòËmÙÙÙ-çsçy<¾½Îåªû:š/m8Ÿø’† Òe ©•—Ër^Q]œÎr YòéŒèr¹Ô¾}{Ùl¶*sެ0)4åæ:üH’Ô·¯G;v„«°Ð®§kûöE:yòM›Vuþ‘ÓY¨R Ÿ†bbbtèÐ!ïïµý 4ULÀöGR’G‰‰n%'Ÿ½.×£ÇPM˜°Yv{õÛÔôíûóµ»Y³f©wïÞjÛ¶mý  ‘ùtfÌÎÎV»ví¼¿£ùñå’™Í&…‡ÅÆ–+9٭޽Ϯ””äÖ÷ßÛ% ´|]E˜ªššªñãÇ«_¿~*€€ó)$Už‡Äœ¤ Wx¸ÑƒV¿á­Í&¥¦–ªsçpåä8d³ýÖÛ¹aªBÿþýƒX5õãÿ54K¾|¿¶yE6›”˜èQb¢G“&Y‡)B‰ß_Kzâ‰'´xñâjÛ-Z¤™3g¤(_ż¢Ú0¯p!ñ;$Í›7O½{÷®¶½W¯^š7o^@ŠBð%%¹•”TsP²šWôÞ{ï)"""åt~‡¤#GލC‡Õ¶ÇÅÅy¿‡ÐS1¯(-­Tññer8Œ""¤øø2¥¥•*5µ´Ú¼¢¸¸¸*}LŸ>] :uê”4}úô ïã÷mIºuë¦'Ÿ|RéééU¶¿ñÆzôÑGõõ×_´@+Ü–$8¢££URRûÜ¢:øާOŸ®7ÞxC………Š‹‹Óo~ó͘1£!¥Ðô·%¹ë®»tï½÷êÔ©Súå/)Izÿý÷5yòdM:5 Å¡yš1c¡pÞó;$=üðÃ:zô¨&Nœ¨3ÿ¾ûidd¤|ðABh6ü¾ÜVáäÉ“ÊËË“$õîÝ;àC\µár[p4Öå6C ³H½ïLÚ¢E %$$èŠ+®ÇãQQQ‘ŠŠŠYÎcLÒ4w~$åççëž{îÑ'Ÿ|"§úWÆë90åF’‚ב$ÎM>q{ܸqr8Z²d‰bccZ ÀùÂï´sçNåää(!!¡1ê8/ø=')))‰¹G Ùó;$=ù䓚…¤˜˜ªcÇŽŠ‰‰©µmL]prsÕReyyáêÒÅ¡Aƒ‚XçŸBRvv¶Úµkçý¡-'§î?{NN8! pAó)$ 2D’äv»U\\¬AƒqY­‘ù2g¨¾\®ºW~ð¥ Í™_ßn ׈#ôÕW_’‘¯s†ÂÈ14¿N³6›M}úôÑ·ß~ÛHå@òmÎPn®£Þý;åi@sæ÷XDFF†&Mš¤wß}W?üð+n7_ç ÕWr²§Î6}ûVm3kÖ, 0@ýû÷×üùóëýÞ„ ¿Ï´Ã† “$ >Üòy¾ÝÖp=g()É­ï¿·k×.ë?R’G‰‰nI’¤Å‹ëÀÚ²e‹ÂÂÂtôèÑz¿7¡‚·/@6›”šZªÎÕ“ãÐáÃgWll¹’“ÝêÝ»êÄðW_}U ,PØ¿'Aµoß¾)Ê ¨üIßtCãq:ËUXh¯³MCØlRb¢G‰‰u_zûꫯ´|ùr½ûî»r:zþùçÕ­[·½?ç;¿¯Ù¸Ýn>}º1jÁ¿µkW÷%Ëöí«·y衇ԶmÛ€×SVV¦=zhË–-úýï¯?üáÎ7>‡¤#GŽhèСjÑ¢…Z´h¡k®¹F_~ùecÖvÁ:z´îE\®ªm6mÚ¤£G*"""àõtêÔI#FŒ$ÝvÛmÚµk—÷9c¤]»ÂµdI ef¶Rff+-YÒB»v…‹éi€PæsHzàtàÀ-[¶Lo¿ý¶"##5nܸƬí‚uôhÝ–ÊmJKKõØcé©§žj”zn¾ùfï\´?üP=zôtv=§µk£”•¥ÂB»ÜnÉí>»žSVV”Ö®R9+ B”Ïs’²²²”••¥J’®¹æuèÐAÇŽóÞ²McæÌ™?~¼bcc¥ÿ‡~X&LÐã?®ˆˆÍ;W’ï÷€ëÓÇÝ(uИ|IEEEºôÒK½cbbÔ²eK?~œ`þLÜþ׿þ¥œœÍœ9³Ñê¹è¢‹ôæ›oVÛîëzN„$@(òëÛmÇŽSxxxµm_|±÷1·+i¸ädO!©b±ÇÍ›7+//O‰‰‰:~ü¸~úé'%&&*''Gv{í}4÷€4g6ããê6兀Å$‹‹‹ý=š’1ÒúõQµ.ö˜šZZe-£M›6饗^ÒÊ•+uòäÉ€Ô­’’’ŸÏÌŒ–Û]ûqáp=ø`Í}(­Zµ h>$±ˆdðø»ØcÅÄíåË—kåÊ•A«3ë9ÐT|I,"\þ,öXyâvË–-ƒPÝYþ\¬0kÖ,½óÎ;*//×]wÝ¥‰'6f‰Ô[ýï’ŠóB0&n×Ä÷{ÀÅ=à¡„â*OÜ–¤S§Nmâ6÷€4g>OÜ>Ÿ4÷‰Û Ñ¡C:t( }Õ5qÛ_:uÒ=÷ÜÃ=à"зù~6‚†{ÀB‰O#IEEE>wئM›ä F’‚#Ð#IW_}µ6mÚ$‡Ã¡²²2uéÒEßÿ}Àú\Øšd î,‚Wï$÷€»ù曫Ü€ó‘O#I7nôþþÝwßiòäÉú¯ÿú/ï²ÙÙÙZ´h‘ž{î¹ Üô–‘¤àôHÒ‰'4aÂxï×§OŸ€õ¸°z$Éï‰ÛC‡Õˆ#tçwVÙ¾`Á½ûî»Z½zu@ ´BH Ž@‡$S“‡¤–-[*??_]ºt©²}ÿþýêÕ«WPNª„¤à $BI“»­eË–Ú¹sgµí;vìêjÏÉïô»ßýN&LÐ믿®hÿþýzíµ×tçwêŽ;îhŒ‚Îï·Ÿzê)¹ÝnM˜0AgΜ‘$EDDèž{îÑìÙ³^ @S¨÷ŠÛ'NœP~~¾$©gÏžºè¢‹ZXm˜“ÌI„’&Ÿ¸]Áãñ¨¤¤¤ÚºH,&Ù|’¡¤É'nçççkÈ!jÑ¢…Ú´i£¶mÛVùhüž“4nÜ89-Y²D±±±Q@“ó;$íܹS999JHHhŒzÎ ~_nKJJò놷¡Èïôä“OjòäÉÊÎÎÖáÇår¹ªü4~»Íf³Õú|=¿,ç¾Ý|» Jýí6¿ç$egg´„c¤ÜÜpíØáËe—$9eêÛ×­ÄDêÈЄŒz¯“Ô”I ŽsG’ÊË¥u뢔—g­{õò(-­Ta~_Ä áš|¤Ó§O«¼¼¼Úvc º›¹Ü\GI’òò•›ëbE4ŸCÒ±cÇ”––¦-Zèâ‹/ÖÔ©Suúôiïó‡b1ÉF`Œ´kW¸–,i¡ÌÌVÊÌl¥%KZh×®p{ 0'§î«³¾´ ø|F›ýôS­Y³&¨÷m»Ôty«°Ð®ÂB» ‚{yËåªû|i@(ðùŒ¶fͽôÒKºýöÛ5aÂmÛ¶M‡C7Þx£Ž=Ú˜5^°¸¼@Óñ9$¸ÜÖL-]ºTË–-Óš5kêÝGC.·­X±BÏ<óŒŒ1ŠŽŽÖ /¼ >}úÔ»êèËm„¤fÊãñ¨S§N Z䳡s’&æ$¡FÞß×­[§ž={6a5„6æ$5#Ï=÷œ6oÞ¬òòrµoßÞrñOà.·¡F\n„.·! À! À! À! À! À! À! À! À! À! À7¸ 1ÆH¹¹áÚ±Ã!—Ë.Ir:ËÔ·¯[‰‰ÙlM\ Í!)„”—KëÖE)/¯êŸ­°Ð®ÂB» }º÷¹GyDï½÷ž¨÷ß_S§N |K4S;w:´~}¤~úÉ¥–-ÛK²iÏžwôá‡3u×]gWÞNM=­>}Ü5ö­’’’ U @Ãz æ$5S·%Ù·ïú裿J2r8¢uë­/WiS[HàBFHj¦*n]Ò§Ïõé3¦Ö6 :Î’IÍ7¦ aIÍ”¿·.™5k–z÷î­¶mÛVk÷ã?ê¶ÛnÓ Aƒtûí·ëäÉ“­€ó!©™JJr+)©æ tî­KRSSõÞ{ï)""¢ZÛ§žzJC† Ñ–-[4dÈ=õÔSR3ç–hÆŒ‘vïöïÖ%:tСC‡$ý¼@ÿþýµzõjïJÙÇ×Ö­[ƒ¹+Ô‰%à3nL @ýq¹ À! uª¸1­$nL ¸`’P'nL ¸’ ‰Óp.¾Ý†qƒ[@( ô·ÛI°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°@H°ÞÔàügŒ”›®;r¹ì’$§³L}ûº•˜è‘ÍÖÄÐI¨Uy¹´n]”òòª*……vÚUPàQZZ©Â“43œÚP«Ü\Gµ€TY^^¸rsA¬€à $¡V99u6úÒ€PCHB­\®º‘#G8ŒÍOÀÎn'OžÔÿøGýæ7¿Ñý÷߯’’’ZÛ?ýôÓ8p`•m{öìј1c4zôhM™2E?ýôS ÊC#*/·©¼¼©« °’^~ùe 0@o¼ñ†®¾új-\¸°Æ¶Û¶mSQQ‘"""ªlŸ9s¦î»ï>­X±B#Gެµ‡ÓYwú)/ó’ÍNÀBÒ¦M›tË-·H’†ª?þزݙ3g”™™©‡z¨ÚsÞÑ¥AƒÕØ‚'9ÙãS»ŠyI<òˆRRR”’’¢~ýú©S§NY&`3n>¬˜˜I’Óé”Ëå²l7oÞ<1BíÚµ«ö\÷îݵaÃ¥¥¥iÆ :xð ÷¹þýû{߸qc ÊF’’ÜÚ°!²ÎËis—fÏžíÝ6oÞ<åää4fy4š Î¸Ý½{·òóóuë­·Z>?΋Ä3MIDATmÚ4½õÖ[JOO×Þ½{e·Û½Ï}þùçÞÍ&Ùí¦^¯}óÍ75jÔ¨W@pÔk$iÅŠzûí·%I™™™Š‰‰QLLŒŽ9¢ØØX¹\.9Îj¯Û¾}»¾þúk >\’TZZªáÇëwÞQXX˜ºuë¦ H’8 ­[·Öw¿@Ng¹ íu¶©lÿþýÚ¿¿®¿þúÆ, €Fc3ÆÔo˜àÏ>û¬œN§~÷»ßiñâÅ:vì˜&MšTëk~ñ‹_è£>ò>þñÇuñÅË£ŒŒ %&&jäÈ‘Õ^W\\ˆ’Q‡èèh•””hçN‡Ö¯¬µí-·œVR’[ÒÙyI«V­’ÛíV›6mär¹ôÝwߣdÀ¬U«Ví/`—Ûî¼óNmÙ²EéééúôÓO5aÂïsãÇ÷© 6häÈ‘JOOW»ví4bĈ@•‡HJr+)©æ ÜII%&º½gÏž-§Ó©•+Wêž{î©ñò*ç³€$#IÁQ1’$½ÉíîÝáÊÉqèðá³Ù:6¶\ÉÉnõî]õ&·ùùù5j”vîÜ©o¼Q?þ¸n¸á†¦ØÀ$Ð#IÜO>±Ù¤ÄDë^ bÂ6ó’¡Œ‘$Ô¨òHR}<ûì³:xð ž~úéV€µóvNp®7ß|S£Gnê2¨BE~~¾Š‹‹«, @(!$¡Q°$ Ô…äœ$_ôïߟչˆÏÐÔšò\ÄH€B€…f{¹  !I°@H°²·%9yò¤þò—¿Èår)&&F³gÏVtttíŸ~úi­ZµJŸ~ú©wÛž={4cÆ y<uîÜYjÙ²e0Ê þ~ÆøêóÏ?׳Ï>«²²2………é‘GQß¾}«µKIIÑe—]&I;v¬† &)8ç¨Izùå—5`À½ñƺúꫵpáÂÛnÛ¶MEEEŠˆˆ¨²}æÌ™ºï¾û´bÅ 9²Ö>.Dþ|Æø£mÛ¶š3gŽ–/_®?ÿùÏš1c†e;»Ý®¥K—jéÒ¥Þ€$ç²!iÓ¦Mºå–[$IC‡ÕÇlÙîÌ™3ÊÌÌÔC=Tí¹‚‚ 8P’4hРû¸Pùúà¯îÝ»«]»v’¤>}úèèÑ£~½>ç¨ I‡VLLŒ$ÉétÊårY¶›7ožFŒáýCTÖ½{wmذA’´aÃgŒÑ˜1ct÷Ýwë›o¾ñnÆ9*dC’/vïÞ­üü|Ýzë­–ÏO›6Mo½õ–ÒÓÓµwï^Ùíö WÀ…mÏž=zíµ×ô§?ýÉòù5kÖhéÒ¥ºí¶Û”‘‘ÔÚB"$­X±Bcƌј1ctäÈIRLLŒ÷w—Ë%§ÓYíuÛ·o××_­áÇkøðá*--ÕðáÃU^^.IêÖ­›,X åË—ëÖ[oU—.]‚·S!À—Ï€ú:tèþò—¿èÉ'ŸôŽ «mÛ¶’¤ÔÔTíÛ·Ï»=ç¨I£GöNÚªøSRR”••%IZ»v­RRRª½n̘1ÊÊÊÒš5k´fÍEEEiÍš5 ;»Û?þø£¤³Cy¯¾úª†¤= ¾|ÆÔGII‰þô§?iÒ¤IêÕ«—e›¢¢"U¬yýñÇëÒK/õ>ŒsTÈ®¸}âÄ =òÈ#:zô¨œN§fÏž­Ö­[K’ƯW^y¥Úk~ñ‹_è£>ò>^¹r¥–-[&»Ý®ë¯¿^÷ÝwŸl6[Ðöá|WÛg @C¼öÚkZ°`:wîìÝöúë¯+,,Ì{ÏÊÊòžÏ£¢¢ôøãëŠ+®œsTȆ$€Æ—Û‚````ÐÆe³Ùº<~côÙ˜ý┑‘¡qãÆ5u^W]u•V®\ÙÔe Ä’2î¾ûn]sÍ5jݺµl6›ŠŠŠ|~mE ðå5m+~ÚµkWeµ÷Ú¤¤¤¨°°PíÛ·÷¹¶¦èÓWß}÷&Nœ¨.]º(""B±±±5j”¶nÝôZB‰?ÇÛ¾}û4zôhÅÄÄ(<<\N§Sƒö.’ Ž;¦gžyF?þ¸w[åC•ZµjåW›U«V©{÷îr8ºòÊ+õÙgŸyŸs»ÝêÓ§V­ZU­¦G}TÓ¦M«Ü !IeeeJOO×´iÓ‚ò~¹¹¹*,,ÔÚµk•““£;ÖöGêØ±c@%mŒ>}±oß>]uÕU:xð ^ýuíÛ·OëÖ­S=ô?ÿó?A­¥¹*--Õ!CT\\¬wß}Wúç?ÿ©‘#Gêøñãþþ' ý,\¸P‰‰‰êÙ³§w[aaa•Ÿ‚‚µiÓFcÇŽõ¹ÍáÇ5fÌ=ZyyyêÚµ«ÒÓÓ½¯æ™gÔ­[79²ZMÇסC‡¼71êÅ!&;;ÛH2ǯ²}Þ¼y¦sçÎÆn·›K.¹Ä<ûì³Þç$Uû©«ÿ#GŽx·­X±ÂØívsæÌ™*mÖ®]k®¾újãp8Ìš5kª½¶âñúõëÍ•W^i"""LÿþýM~~¾·ï²²2óÔSO™îÝ»‡ÃaâââÌŒ3j¬§âñ† Ì5×\c"##M—.]Ì /¼Pe?-Zdúöík"""L›6mÌØ±c«|fVûYÙÍ7ßl†jù\å~Ün·yì±ÇL§NŒÃá0W\q…yùå—-?Ó¬¬,sÕUW™ÈÈH3pà@³wï^³eËÓ¿iú÷ïo¾üòËj¯«k_ý©¡¶¿…1Ædffš+®¸Â8o¦M›f<_ýøz¼mÞ¼ÙH2ß|óåóê:FüÙÿsY_ö¹.W^y¥™={v­m–,Yb$™;vøÜæã?6’ÌŒ1Ƭ]»ÖH2%%%fïÞ½&&&Æìß¿¿Æþ~ûÛßšñãÇû¼À¹I9V!é›o¾16›Í<ù䓿Ûo¿5[·n5«W¯ö>¿jÕ*#ÉìٳǚÂÂÂ:û¯Þyçc³ÙLiii•6ýúõ37n4ß~û­9räH&%%ÅlÞ¼Ùäåå™Aƒ™!C†xûž:uªiÛ¶­Y¶l™Ù¿¿Ùºu«Y´hQõT<¾üòËÍêÕ«MAAy饗Ldd¤yå•W¼¯[¼x±yï½÷ÌþýûÍÆMRR’7n\­ûYÁår›ÍfÖ¯__çßãÞ{ï5111µÖRñ^ƒ 2›6m2ùùù&%%Å\uÕUfÈ!fË–-Þm7Þxcµ×Õµ¯þÔPÛßbúôé&!!Á¬]»Ö8pÀlذÁ\vÙeæÑGõ«_·o¿ýÖØl63{ölãv»küŒë:FüÙÿsY_ö¹6'Nœ06›Í¼÷Þ{µ¶KII1×]w_m\.—‰ŠŠ2óçÏ7eeeæþûï7 Æcnºé&ó·¿ý­Öþž{î9Ó­[7Ÿö°BHBȱ I[·n­õ©5>ÕÖ¶"<9rÄ <Ø 4¨Z›ÊAÌêµßÿ}o›åË—›ððpãv»Í‰'Ldd¤yõÕW}®§âñâÅ‹«´›:uªéÙ³gý¼õÖ[&::Ú”——[ö[Ù–-[ªü¾&EEEÆápXÖRq2«ü^•O¤+V¬0’̇~Xe[xx¸w×}õ·†šþ%%%¦E‹fÓ¦MUúYºt©i×®ÏýTnãËñ–™™iZ¶liZµje®»î:3eʳuëVïóu#þîåcÖ×}®Í¿þõ/#É|õÕW5¶Ù¶m›‘d–-[æw›wß}×ôë×ÏtèÐÁ <ØìܹӼöÚk¦ÿþæ³Ï>3)))¦sçÎfذaæû￯òÚU«V›ÍæüÅœ$4 ýúõÓÕW_­ë¯¿^ÿùŸÿ©7ß|Seee êó²Ë.S«V­«’’ýßÿý_µ6W]u•O}%&&z•ÇãQII‰òòòtúôiýò—¿ô»¾ÁƒW{œŸŸ¯Ó§OK’>ùäÝtÓMŠUëÖ­õÛßþV%%%*..öû½j’ŸŸ/·ÛmYËž={¼µTHJJòþ#©êg#ÇS­ÆÚöÕßjú[äææêÔ©SúÕ¯~¥V­ZyƯcÇŽU«©¦~üõÀèàÁƒzã7”ššª;vhÀ€úÛßþ&Iu#þîåcÖß}¶RѦòdës½øâ‹êر£åÜ¡ºÚ 6LÛ¶mÓÁƒµqãF]rÉ%š:uªæÌ™£Ûo¿]Ç×·ß~«‹.ºH¿ÿý﫼ö¢‹.’1& Ç<.,áM]áááúä“O´~ýzeeeiâĉZºt©Þzë­z÷™­víÚ©M›65~³,""§¾ÂªÿÄ4ð[7µMä.**RZZšFŒ¡ŒŒ 9NmÞ¼YwÜq‡OáñòË/—ÍfÓîݻթS§ÕY™ÕçàËgÈIë5½_yy¹$)++K;v¬Ö¦eË–>õS­[·Ö°aÃ4lØ0=þøãÊÈÈдiÓôÀÔ«¿ÚT>fýÝg+áèäÉ“–}iéÒ¥š2eЇe¾´©ðç?ÿYcÇŽUxx¸¾ÿþ{7Naaa3fŒn»í6¹Ýno'Nœ¨öm9ÀŒ$¡Ùp8úÿøÍ™3GóçÏ×Ûo¿­S§NI’ìv»¤ŸO ¾èÚµ«ºwïÞ¨_½ïÕ«—"##õþûïûýÚ>ø Êã?üP={öTdd¤vïÞ­“'O*##C×\szôè¡Ã‡ûÜwûöíuÓM7yG3ÎUñÕö^½zÉápT«åƒ>ðÖµík jHLLTTT”öï߯Ë/¿¼ÚU(ªI}Ž·Ê’““URR"·Û]ç1ÒýÄ>Wê‚‚Ëç_}õU9sF'N¬±_ÚTìSvv¶f̘á ûn·[’tæÌ•——WùÌ Ôµk×:ƒPF’2¶oß.IÚ»w¯$içÎjݺµúõë§Ï>ûLŸ}ö™nºé&…‡‡kÍš5ŠWTT”$éÒK/•$­^½ZÆ “Íf“Óélš©¤uëÖzðÁ5eʵhÑB))):tèrssë\rà‰'žPÛ¶m•œœ¬ 6(33SsæÌ‘töR¡Ýn× /¼ {ï½WÛ·o×óÏ?ïWm/¾ø¢®½öZýú׿֔)SÔµkW¹\.½õÖ[úâ‹/ô÷¿ÿ]]t‘î¾ûn=ôÐCjÛ¶­úöí«üãÊÌÌÔܹsëý¹ø³¯ª¡U«Vzä‘Gtÿý÷«¬¬L×_½Ün·¾øâ íÙ³Gÿýßÿís_¾oŸ|ò‰æÌ™£Q£F)99Y‘‘‘ÊÉÉÑÃ?¬´´4EFF*22²Öc¤!ûˆ}®üoð¦›nªòœ1FsçÎÕ¯ýkÅÇÇ[¾Þ—6’túôiMœ8Q/¾ø¢Z¶l©äädµoß^Ï<óŒ¦L™¢ÿýßÿÕu×]W%~öÙgÕ.C~iÂùP€_dñµêŠCx÷îÝæ†n0­[·6‡Ã 8Ð|úé§U^?sæLgÂÂÂü^À×65M²®ÜîÜI½eeeæ¯ý«¹ì²ËŒÝn7ñññ&##£Î>ׯ_oh"##MçÎMfff•Z.\hâââLTT”¹ñÆÍ¢E‹ª¼¯/û¹ÿ~sçwšøøxnbbb̨Q£Ì_|ámãv»Í£>jâãã½_?饗êü¼¬&7Ÿ»Í×} d óçÏ7ÉÉÉ&""ÂDGG›TéË×~|9Þ~øásÏ=÷˜^½z™ÈÈHãp8L×®]ͤI“Ì?þèmW×1Rßý÷uŸë2{öl3`À€jÛ³²²ªMr¯OcÎ~ó0==½Ê¶÷ßß$$$‡ÃaRRRÌÞ½{½Ï>}Ú´mÛÖdeeù¼À¹lư)J6nܨn¸AGŽ9/FÃÓ…´¯¡ìèÑ£êÚµ«¶lÙ¢Þ½{7u9’ήÔýØc)///è ±¢ù`N AÚ·o¯‡zH³fÍjêR¼þú׿*##ƒ€„aN Áü™³ _|ñES—€f€Ëmþ¸DÜÓAáIEND®B`‚prinseq-lite-0.20.4/example/example1_or.png0000664000076700007670000002513012240000123020745 0ustar rschmiedrschmied‰PNG  IHDR5 ô!AbKGDÿÿÿ ½§“ IDATxœíÝyxUºð·ºÓÝÙ'!„%€&˜BÈYd ‹Ê€QA… ‚ˆ²Üy¸:²8€l²Š,WAÜ.H®a!ˆQ$ a  €¬A ½—º„Ôdí®Nw§;÷÷<nÓ¾©þxû‰ˆ\ŽÛÅ‹P>\3¡Q„úða¸]¼Øð‘]1©!"—£:~Ü&uˆ¨qá˜"r9Š7ÌשgC–PT·3g üþ;4:Œ-[Bß±#DOOG‡F¤†ˆ\Ž`0˜¯£×7@$d/nçÏC“œ A§¨àÔ)¨Fé“OBæÐøÈ1xû‰ˆ\ŽÑÏÏ|ÿˆ„ìAqãÜ¿ùFJh*ÊÊàþÍ7²®Ö‘ëaRCD.Gß©“ù:  ÙƒúÈÀÔÕ8ƒ¡¼59LjˆÈå”uéCëÖu–Z·FY—. Ù’ò·ßlR‡\“"r=nn(~öY”ÅÇCtw—‹îî(‹Gñ³ÏnRØX ¥¥6©C®‡ßj"rM*ÊúôAYïÞð2PTTÑÇGGFV2úø@qïžÙ:ÔôðJ ¹6Aþðˆ¾¾Lh\„AÆ“MrêëaRCDDJY÷î&Ÿp3úù¡¬{÷Œˆœ“""jTDww'&Bß¾}Õ«o‚}ûö(NL¬2–Šš«ÆÔ”>ˆ¥Ñhl ‘¢JFŽ„ ÕÂ3?¥¥¥0–›¢&«^Wj6oÞŒŽ;ÂÝÝîîˆÀ–-[l‘I¢}ûöLhÈò+57nÄ+¯¼‚©S§¢oß¾€ôôtLš4 F£/½ô’̓$"""2Çâ+5K–,ÁêÕ«±hÑ"$$$ !!‹-ªU«°hÑ"{ÄHDDÔè|òÉ'ˆEll,âââ°cÇG‡äô,XPïuýüü,Oj.]º„AƒÕX>xð`\ºt©ÞÁ¹Š={ö`ùòåHMMEff&RSS±téR$''Û¬ƒ™·š+·U?¶dMRÔãJM‹-••UcyVVZ¶liU0DDD®àý÷ßDzeËмys@@@>øà,Y²0kÖ,¬^½ZªÿöÛoãý÷ßܺu ˆŠŠB—.]püøq©ž··7fÏžnݺ!==½F¿ÕË͵5sæLÄÅÅ¡k×®U.LXÒÎòåËŽ˜˜Ìš5KÖ6,\¸ñññ ÁÞ½{sçÎEqq1bccñÌ3ϘmçÒ¥KèÚµ+âââðÖ[o¨GR3~üxLœ8Û¶mÃåË—qùòelÛ¶ 'NÄ‹/¾hisDDD.çäÉ“ˆ¯²,>>'Ož$&&â³Ï>“ÊvíÚ…ÄÄDÀk¯½†3fàäɓزe ’’’¤zz½;wƱcÇпÿýV/7Õ–Á`@xx8Nœ8¿ýío˜6mZ½ÚùÇ?þ#GŽ ++ ÿûßÍnƒÁ`@Û¶mqôèQìܹo¾ù¦Ôއ‡233ñÕW_™mgÚ´iøÛßþ†'N C‡(--… Š¢(÷ UlèÔ©S±aÃè¼ö]¥R!)) K—.…›½O¥  Àfmyyy¡°°ÐfíÙã³ã³ã³㳎=âóöö6]aÏžÿ|>¼Fq³fÍpóæM¨T*i™Á`@Ë–-‘——ˆˆˆÀþýûqûömL™2‡¢M›6ÒzZ­.\xxxàîÝ»p¯cžêåæÚºsç<==QRR‚¶mÛJ±YÒÎðáÃ!ñ§?ý îîî&ë{zzâþýûÒ¾ñóóý¯½ðöö®òo·©vpåÊ)þfÍšYþô“››V¯^ àÌ™3ÊŒ¯¯¯Eí¤¥¥!33Z­sçέ³Þ¼yó¤Ëw=zô@LL  ¤¤»víBAA|||0zôhΗCDDN!** ?ýôzöì)-ûé§Ÿ%ý}:îܹøý÷ß1mÚ4¼ñÆRÄÄDìØ±Ÿþ9F--0`Ö­['ýœ““SkS¦LAff&233Tksmíܹ°cÇôêÕ«Îí1ÕÎo¿ý†AƒaÉ’%Ò˜[¹ÛPZ­Fqq±¬~{õêU%~Qå%5¸yó¦ôÙÔ¹Ú¶m +&JÊÍÍ•2Þèèhœ;w®ÞmÙÒSO=…)S¦`À€ˆEÿþýñꫯbذaRÈÈHhµZ<ôÐCU´YµjöïßÈÈHDFFbûöíõŽÃT[J¥gÏžE\\V¬XeË–Õ«±cÇ"&&½{÷–¦v©ï6Lš4 ÑÑÑÒ@aSí,[¶ +W®D\\NŸ> F#oLÍÁƒѳgO¨Õjþ|@£Ñ`ذaRâôÞ{ïaÖ¬Y¼÷cÑ¢E˜9s&ºuë&­kË9<==QTTd³ölñY‡ñY‡ñY‡ñYÇñ…††š®`fLMcP}üŠ+5¦¦r¢biÒb­iÓ¦ÁËË YYYؽ{7&L˜`²þ±cǤÏ(ì<ŸuŸuŸu5Nÿ–n///僮nݺ%-÷ññV«P>ÚìHu"""’¸ÚU I ¸qãFåyyyÒ­ [)**’(Ÿ;wRYhh¨ô¼vv6ÂÂÂlÚ75.6›TFE(òs¤ÔÔTdggC§ÓaéÒ¥ˆŽŽÆÀ›6m„ páÂ|÷ÝwEjµ#FŒÖïÛ·/víÚ…¬¬,é‘n"""jºd'5ã@~~~ç×÷îÝkÑk(%1ÕUŒ›‰ŠŠªòLe7nœìþˆˆˆÈµÉNjüýý¥Ï:t¨µÎüù󭈈ˆˆ¨d'5iii€~ýúá‹/¾@³fͤ2¥R‰àà`´k×ÎöÉ ;©©x”ÛÂWE5ˆzE0 U–ûùùY‘¥,~¤ûîÝ»xþùçáãã___øûûWùCDDDä'5S¦LÁÉ“'±}ûv¸»»cË–-X¼x1Úµk‡-[¶Èngݺu6lºwï^gcÇŽáÏþ31vìXéEYðÙgŸ!11cÆŒÁ˜1cðý÷ß[º)DDDäB,¾ý´wï^|óÍ7èÝ»7”J%zôè°°0„……áÃ?”ý˜õã?Ž‘#GbäÈ‘uÖñ÷÷ǪU«Ð¬Y3üüóÏxçwðå—_† †gŸ}péÒ%Lš4 ûöí³tsˆˆˆÈEXœÔ””” 88@ù\1¿ÿþ; 66ß}÷ìv:wîl¶Î#<"}ŽŠŠ’^ᔿÀ¬BQQ‘Esä‘ë±8©‰ˆˆÀùóçÑ®];DGGcýúõ š5kì:¦f÷îÝxüñÇ«,Û±cvìØââb¬_¿ª¼¥{Ö¬Y6ë_£Ñ ´´ÔfíÙã³ã³ã³㳎=â5j”é ôÍÜ®N-|F{Ë–-P(xá…pøða<ùä“(((€››6n܈ñãÇ[@ïÞ½Í^á9{ö,fΜ‰ 6 00°FùÞ½{±wï^¬Y³¦Êr¾¥Ûy0>ë0>ë0>ë4Åøø’äÆÉ¢+5:xì±Ç½zõ•+Wpúôi#((ÈæÞ¼y³gÏÆ{ï½WkBC† Á¢E‹lÞ75%5nnn9r$Ο?æÍ›(Ÿ—¦gÏžv ®°°¯¿þ:¦M›†ˆˆˆ*e×®]“’¨C‡!$$Ä.19Ra¡€Ó§Ýp÷®½Þt꤇—'Á$"ªÎ¢¤FDEEá—_~ÁÃ?lUÇ«V­Brr2JJJ€„„¼òÊ+€—_~}ô¾üòK\¹rk×®ÅÚµkÛ·o‡B¡À–-[™™ Qáç燷ß~ÛªxˆœMNŽöís‡NW±Ä €224<¸zFGDä|,S“œœŒÿú¯ÿ»ヒ.]º@­VW)¯¸‚ã 8¦Æy0>Ë\¿®Ä§ŸzÀh¬½\¡ÆŽ-FëÖ†Ú+40gÛÕ1>ë4Åø8¦¦q²øé§¡C‡†×1ò›ï†"²ÞÑ£ª:0Ëë<õ”s$5DDÎÀ⤦âmÝDd?¿ý¦´I"¢¦Ä⤦âmÝÖHKKCff&´Z-æÎ[g½’’ìÚµ ðññÁèÑ£¡ÑhÌ–5v¥¥‚Mê5%¿ûÉÂÂÂ0qâD¸¹™Î©ÒÓÓѾ}{Lž<!!!8tè¬2¢ÆÎÇÇĽ' ê5%IjÚ¶m ³õrssˆŽŽÆ¹sçd•5vaaæŸl çÓODD•Y|û©!åççKÉO•§™ê*«üš„;vØ,OOOÙ¬=[c|Öq¶øBB”8s¦-´ZU­å>>:<üðUܸáWkœmÿUÇø¬Óã µi{Ô0œ:©©cÇŽIŸùH·ó`|–{î¹2¤¦ ¸pÁ  ªÇ€eðönáØ+qÆýWã³ã£ÆÂ&IMqq1ÜÝÝ!¶¸èãã­V ___hµÚ*ó˜*#rÞÞ"ž~º……òó=QRR‚-ŒœM˜ˆ¨©Y¶l¾ùæ€Á`À3Ï<OOO<ôÐC8~ü¸Mƒ ÅÉ“'ÙÙÙ “UFäJ¼¼D„†!!&4DD&XœÔ,Y²mÚ´|ñÅ8tèvíÚ…~ýúáÕW_•ÕFjj*–.] N‡¥K—"55U*Û´i“ô¹oß¾¸páÖ¬Yƒ‹/¢OŸ>²Êˆˆˆ¨é±ø5 J¥—.]ÂC=„^x~~~X¹r%rss‰ÒÒR{Åj1Ž©qŒÏ:ŒÏ:ŒÏ:M1>ihœ,¾R„O>ùÙÙÙØ³gþøÇ?ôz=<<> ÝŽV«ÅìÙ³‘——‡ÀÀ@,\¸^^^5ê-]ºTzL»¤¤wïÞEZZÒÓÓ±zõj€ ˜2e ÇÕ5a²’š{÷îUùÙßßþþþUƬ„‡‡[ÔñÆqãÆaëÖ­Ø´i^{íµõ¦OŸ.}Þ¹s'Ξ= ˜?>Ö®]‹öíÛã×_ŤI“˜Ô5a²n?U$1rþÈ•‘‘!ݺJHHÀáÇͮ“’’"­Ó¶m[)©Òjµ ’Ý7¹YWjÒÒÒ¤ÏW¯^ÅôéÓñâ‹/JoìNKKÃÇŒeË–ÉîøÖ­[ 4oÞyyy&ë_»v ×®]“ÆíÌ›7'N„ E6lPõ5 ³fÍ’9Æ©žìªŽñY‡ñY‡ñY‡ñYÇñ5ʦíQÕÔT$/@ùU• `âĉU–………á³Ï>ÃóÏ?oó `ß¾}8p Šò‹K‹/Æk¯½†!C†`ß¾}X²d –/_Î×$8)ÆgÆgÆgÆW‹={þóyøð†í›êdñÓOÄàÁƒk,2döïß/»ÀÀ@ܾ}——‡æÍ››¬_ùÖœ8q 8YYY²û&"""×cqRãéé)½ž ²¬¬,xzzÊn§gÏžøöÛoÉÉÉèÙ³gu/^¼ˆ¢¢"tîÜYZÖ¶m[=zpäÈi–c"""jš,NjƇ &`ûöí¸rå ._¾ŒmÛ¶aâĉ?~¼ìv&Nœˆü‰‰‰8rä&L˜ •½üòËUꦤ¤H“üU˜3gV­Z…Q£FaåÊ•˜={¶¥›BDDD.Äâ×$èt:LŸ>ëׯGYY@­V#)) ÿüç?¥ykœÇÔ8ÆgÆgÆgQ„—ш¢¢"ˆÞÞ€ 8:¢òšŽ©qJg *• +W®ÄüùóqæÌ@ÇŽáëëkóàˆˆÈAôz¨øª“'!Á €èé ]TÊzôœè?°Dê5ù^…Š ÷ŒF£TÇÏÏÏF¡‘Cèõðøì3(¯]«²X(*‚úÈ(¯\Añ³Ï2±!§#댴dR= ïf‘“QŸ8Q#¡©LyíÔ'N ìÑG0*"ó6ù9'·Ó§Í×ÉÉaRCN§ÑL¾G—P\ ܾ eI ŒÍ›CôðptHDd‚âî]óu~ÿ½"!²ŒÅ7D<ˆµk×ÖX>dȼþúë²Û)))Á®]»PPPŒ=¦F½yóæIóõèÑ111­OŽ#BsàÜÎD Ї‡£´ˆµ¼•ˆOT*!èõ¦ëp< 9!‡M¾—žžŽöíÛcòäÉ Á¡C‡jP¡@RR’’’¤„Æ’õÉ1„ÒRx|ú)ÜΞ*³E¸= O?…àÄï’!jÊŒ-[Ú¤QCsØä{¹¹¹ˆŠŠDGGãܹsÅaíúd_ª#G ¨ã©9PܻՑ# ‘ó  >z—_Â}ïÞòÏ6œ_«¾t]»Ú¤QC³øúá¢E‹ Óé0a„“ï-\¸Pv;ùùùðññøøøÔ9Qž(ŠX»v-4 † &½Ù»®õ+¿¥{ÇŽ–n^<==QTTd³ölÍÙâ{8'ÇláÌÜx0-€£9Ûþ«ŽñYÇãó¹x-Ž•nó¸@NT¸mûöŽ ÎË ÍbbÐ,;»ê•Vüß==7_5ö8¾¡¡¡6m†ÓO¾7mÚ4xyy!++ »wï®ò:…ÚØú-ÝŠ;w ú÷¿¡ºsƒÆ- ëÜÆ€«Û¶%g›‘T%㌪°­Zµj€hÌs¶ýW㳎³Å§¼~?þ5ʽ-ü¾!!0´ní€èhÕ Å;Ã-+ ª¼<FZ´€>&êÖ­áßÜrÎv|Éqê=ÒËÝݱ±±P«ÕõZßÇÇZ­¾¾¾ÐjµuNIíõ`0iTT’““-^ߪŸ†æàAé€ò×_¡:~¥O<]—.6ïÓUˆjuùSO¦ê8ÓÀîÂBÅÅ|2‹„êÈ‘Z‰ÑÕ‘#0<ýtÃU CëÖ0´n 7//1i°ˆ··wÿXûùùÕ9™­)õ]ÏÕ,X°sæÌ1YÇ¢15˜={6‚ƒƒ¡Ñh ÑhŒÙ³g[œ%‡††J޳³³V£NQQ‘4™ß¹sçPéꈜõ­¡üõWhÒÒjÿÅc4B“–ååË6íÓ•‚‚lRÇ®Lïµn„÷߇×êÕðZ·ê~Ì<ùAd åo¿™¯cbò;"s ƒUå¶êÇ–,X`¶Žì¤&??½zõÂŽ;0yòd$''#99IIIøôÓOñøã#??_vp}ûöÅ… °fÍ\¼x}úô‘Ê6mÚ¸pá>üðC¬^½ß}÷FŒ!k}[P;Vó^re¢õO?Ù´OW¢{ì1@aâôR( ëÞ½áªÎ`€ÇW_Aýý÷´Zi± ÕBýý÷ðøê+ ¿¬Ô´Æ#š¬Ã§]š··7.\ˆøøx„„„`ïÞ½RÙ¥K—еkWÄÅÅá­·Þª²Þ­[·€¨¨(téÒÇ¯Òæìٳѭ[7¤§§×ÚgårsmÍœ9qqqèÚµ+.]ºT¯v–/_ŽððpÄÄÄ`Ö¬Y²¶¡¶ý2wî\#66Ï<óLíÈ~K÷›o¾‰ƒ"--­Æ­žüü|ôë× ÀâÅ‹å4× ¬Sãµj„’“uDN™Rï>lÉï)»:÷ÔT@§«Z R¡dà@è##Õ±cå·M(}â è* ËxnÜhòé@0úû£È̆âlû¯:g|K·¹ÛOذažþy=z/¾ø"N?˜Éù©§žÂˆ#0aÂlÚ´ ¯¼ò ŠÜÎ3f þú׿¢ÿþ8yò$^~ùeüôà?ØîîîØ´iž{î¹ZC®^nª-¬ZµJŠa÷îÝøßÿý_‹ÛiÖ¬.\¸ÀÛÛÛl¿uí—êû´¶vd'5ÁÁÁX¿~=\kyJJ &OžŒ‹/Êi®AX“Ôx/_nþ„› ¦M«w¶ä¬¿t­ªÓ§¡¾{z½ÆÀ@è:u‚øàÉ5GñܺŠ[·LÖ1¶h¢qã("ÓœòøŠ"TÙÙPegCqû6”ßèh袣App€ÿálûO}èÔGš¬S2_®/gÛÕ5ƤÆÓÓ÷ï߇J¥ªQ€+W®ÀÓÓ%%%hÖ¬™ôtW`` Ú´i#µ©ÕjqáÂå ÁÝ»wáîî^kÈÕË͵uçÎ)†¶mÛ"//Ïâv†A˜˜ˆ?ýéOpww7YßÔ~©¾OkkGö@ák×®!""¢Îòˆˆ\½zUnsNÏèëkvpãþÐ@Ñ4^¢ʺw‡ÊË %NôKQÎïr¦Šo²ŒF¸ïÙ·óç«,Vܼ Í¿þå/¿ døpÓ· ›0]÷îp;w®Î«5F??ÇÞž%«yxx °°PzØ¥¤¤¤Ê¬÷ …Bú‡ÛF£µNv«T*¥DcõêÕØ°a 99AAAUÊ͵eŠ%í|ýõ×8pàvî܉͛7#55Õd}KöKmíÈþãïïßL n»zõj•¼¾cG›Ô!ç$*•æëðä:©Nž¬‘ÐTævþúHúyãÆèß¿¿¬u{õê…;w(Ÿo­ò •`ݺuÒÏ9uÌ 6eÊdff"33Au<”a®­Ê1ôêÕ«ÎxMµóÛo¿aРAX²d ²²²,Ú†êÔjµt®®vdÿÖ2d.\ˆÚîVF¼÷Þ{øãÿ(·9§§{ôQLôWc` ÓŒ· Ë[´0_‡ÓÀ×ÉMFÂ"§NS&zy¡dÄNž ñ…Pú(bcc1}útéÙÙÙøç?ÿ‰ììl;v ?ü°¬à‚µ“ï eeP§§CuêÔÆ×¨TÐEF¢¬Oˆõœ£Çšâ=ok¸?÷ƒÞêRòôÓÐ;ɬ¢Î¶ÿ¼?ø æðjD• …S§6PD¦9Ûþ«ŽñYÇÇÔ4vµ j d© FFF^yå :Tºb# „ŒŒ §JhlAT«Q:hJûõƒWI Š‹‹aô÷øvÚFO†²îÝ¡®íýS‚€²îÝ&¡qF"³Ã€h 05 ý놔”ܹs¹¹¹Ê'Ás¥±4µrsZ¶„щÿ§B–+ë݆à`¨²³áö`xc‹ÐEGÃЮ£ÃsjÆÀ@³“Û7o hˆÈÖãU ž¯IpýD†šC»v0´k/No]LŒÙ¤FÓ@Ñ•ããDd1}§NÐuî\g¹®sgè;ujÀˆˆˆ¬x¡%5a‚€Ò!C`hߪ¬,(óò ŠbùS11å*50&5DToúðpèÃÃþé"jxû‰ˆˆˆ\“"""r LjˆˆˆÈ%0©!"""—À¤†ˆˆˆ\“"""r LjˆˆˆÈ%0©!"""—À¤†ˆˆˆ\‚ Š¢èè ƒnÝºáØ±cŽ£NŒÏ:ŒÏ:ŒÏ:ŒÏ:Î5^©!"""—À¤†ˆˆˆ\o?‘Kà•"""ã•B IDATr LjˆˆˆÈ%¸9:G8xð f̘Ï?ÿÁÁÁ²Ë,X€;wîàúõë€ÜÜ\„†† …Bo¿ý¶Ö²_|ÑêØ8€Í›7Ã`0 ¬¬ ݺuÃ[o½…B!Å7tèPÄÄÄ`×®]øüóÏ¡P( Š"F…Q£FaëÖ­VÅh*¾ºú¬¼ÿ*â«k[¶oßnõ>¬Ï6X»_,aî8ZsVÄjîXÔ76[œƒê£µÛ`¯~å´m‹cknûì½ öî¿.r¾£¦ö/5b4kÖ,qêÔ©âÚµk-*;v¬h0¤Ÿ{õêUg¦ÊêÛwß}'Ž7N¼sçŽ(Š¢h0Ä/¾øB,++«_rr²8yòd±°°PEQ¼ÿ¾ø?ÿó?6‰±®øäôYŸœm©o|Ölƒ½ûEyÇÑÚsPîñ·46[žƒõÑÚm°W¿rÛ¶öØÊýîØkìÝ¿\u}GÍ}·Éõ5¹¤¦°°P:t¨xíÚ5qäÈ‘²Ë.^¼(Μ9³Ê2['5¦úÿË_þ"feeÕ¹nåø^zé%1''Çl–Æh*>s}VŽÏܶÔ7>9Lmƒ=û­`nÛmqÊ=þ–ÆfËs°¾1šc.F{õ+§m[[¹ßú2· öî_®Úöœï6¹¾&7¦&===zô@ëÖ­áïYeèÙ³§ÃbËÍÍE§Nê\·r|—.]BXXXƒÆg®ÏÊñ™Û{2µ ÁܶÛâ¬ïñ7›-ÏA{£æb´W¿rڶűµ÷wÇÜ68ò»kŽ£¿Ûäš\R“’’‚Aƒ „””Ye?üðzôèá°ØÌ©Ÿ €Ý»wãÏþ3†n÷øLõÙûOköqC°Õ9hãoŽ¥ç #b´w¿¦Úvôï¹u\¬åìßmjMj p~~>~úé'äææB ‚€©S§B«ÕÖYVZZ ­V‹ÀÀ@‡Ä&BCC‘““ƒ¨¨¨ë–””T‰/$$¹¹¹Lj#0bÄ<ñÄvÏTŸÕã3µ-ödn‚©m7Ÿ%ç`}¿¹ãbËsÐ稜m°W¿æÚ¶Õ±µ÷wÇÜþqÔw×gøn“shRWjRSS1tèP|óÍ7سg’““ѦMœ8qÂdÙ±cÇЭ[7‡ÅÏ?ÿ<–.]Š»wïŒF#¾úê+ètºñ5 «V­Bqq1@§ÓA´rŽEsñ™ê³z|¦¶ÅžÌmCC0µí¶:ë{üÍ[žƒö8Gålƒ½ú5×¶­Ž­½¿;æö£¾»æ8Ãw›œC“ºR“’’‚ñãÇWYÖ¿¤¤¤à—_~©³L©TbÀ€‹­K—.èÓ§JKKñÚk¯Á`0@¯×£[·nP*•ÈÈȨ_BB´Z-^zé%(•J(•Jüå/±k|¦ú¬Ÿ©m±'sÛÐLm»©ø,9ë{üÍ[žƒö8Gålƒ½ú5×¶­Ž­½¿;æö£¾»æ8Ãw›œ_“ ÃsÏ=‡-[¶ÀÍÍ9s@Æçúœ}:{|ÎŒûŽÈv˜Ô‘KhRcjˆˆˆÈu1©!"""—À¤†ˆˆˆ\“"""r LjˆààÁƒyyyM¾ÏŠ:÷îÝk°¸ˆÈ51©!²‘ŠœA€B¡€ŸŸâããñî»ïB«ÕV©Û³gO\¿~ŠÖvL%%®´Däü˜ÔÙØ©S§píÚ5=zÓ§OÇW_}….]ºàöíÛRµZV­Z¹üîMe;‰È90©!²±-Z U«Vǘ1cðý÷ßC©Tâ¿ÿû¿¥:ÕoËTü¼oß>tíÚ>ú(Ξ=[kýÊË*®F,^¼¡¡¡P«Õ Â?þñ“±®X±:t€Z­FÛ¶m1wî\ ©\¯×ãïÿ;ÚµkµZ:`Ó¦MUÚèׯÀßß_ºRU×vêõz̘1ðòòˆ#põêU‹ã""ª “";óðð@RR¾þúk³ußyç¬^½YYYpssCRR’ì~fÏž… bÞ¼y¸pávïÞ‡~¸Îúo¿ý6Ö¬YƒåË—ãâÅ‹øøã±mÛ6Ì;Wª3uêT¬_¿kÖ¬Ann.Þ|óML™2›7o–ê|ñÅ€³gÏâúõë¸~ýz}¾ñÆضm>úè#äää`ذaxýõ×-Ž‹ˆ¨V"ÙDZZš@¼}ûv²ÿû¿ÿˆ¥¥¥µÖ­øùÀÒ:;wîÝÜÜDNWkÛËîÞ½+æçç‹Fܼy³¬ø E1##£JO>ùDlÖ¬™(Š¢xïÞ=Q¥R‰[·n­Rç­·Þ;tèPk¦ú¼ÿ¾¨V«k´7cÆ i}9qÕ…/!j¢Ì·‘DFFJŸ[´h½^ÂÂB³ëåää ´´ýû÷—ÕÏ©S§P\\ŒAƒUYn0PRR‚‚‚œ9s:}ûö­R§oß¾X¼x1JKK¡ÑhdõgΜAYYYöúõë‡÷ß_v\ÞÞÞ²û$¢¦…I QÈÉÉAPPÔjµÉz EÍ;¢(Ö:ÐÖh4Ö;žŠu¿ýö[´jÕªF¹§§g½Û6ÇÔ aGÆEDÇÔÙYqq1Ö¯_§Ÿ~ºÞmøúú@•Âÿþ÷¿¥ÏÐh48pà€¬ö"##áîîŽË—/#44´Æ…Bˆˆ¨T*¤§§WY7==;v”®Ò(•J擬Ž;B­V×hïàÁƒÅEDT^©!²±[·nA¯×C«ÕâçŸÆ¢E‹`0ðöÛo×»ÍÈÈH4oÞï¾û.æÏŸ3gÎ`ÅŠR¹¦NŠ7ÞxèÙ³'nÞ¼‰S§Naüøñ5ÚóööƬY³ðꫯÂ`0 OŸ>Ðét8~ü8Ξ=‹¹sçÂ××ýë_1cÆ øûû#&&ûöíÃ|€?üPj«b0òîÝ»1tèP‚€æÍ›×è³z{QQQø×¿þ…?þØ¢¸ˆˆêäèA=D®¢bP,QÑ××WìÖ­›øÎ;ïˆ÷ï߯µnõÂu EQLIIyäQ£Ñˆýû÷·nÝZ¥Ü`0ˆ ,ƒƒƒE¥R)¶iÓF|÷ÝwëìSEqݺubtt´¨V«E///1>>^ܰaƒT®ÓéÄ9sæˆmÚ´U*•^¥¼Â¼yóÄÖ­[‹ …B¬ük¥zŸeeeâ믿.ˆâ“O>)nÛ¶­Æ@csqÕFE™#‰ˆˆˆœoP‘K`RCDDD.I ¹&5DDDä˜Ô‘K`RCDDD.I ¹&5DDDäþ9 Æ ·söIEND®B`‚prinseq-lite-0.20.4/example/example1_gc.png0000664000076700007670000002401412240000123020716 0ustar rschmiedrschmied‰PNG  IHDR®÷C„0bKGDÿÿÿ ½§“ IDATxœíÝ{xTÕ½ÿñÏ !Äp T B¸‡p+ õ 7%Q±E Õ¶*H•[¢HI‚\DP¨ /x€ó` "b5\…„„¨råÊúÓŸþ¤6mÚHb9—+™7ožÖ¬Y£ììlEEE©oß¾9r¤$q>ý¬k×®Ú´iS©ö=zhýúõß¡ ÀûÓ¿øý‰`Gp@P`ª‚ÁAà € @p@P ¸Âq6n tœ…óégÉÉî£ðþô/Î'®vŽºÁ† 4þ|I’ËåÒˆ#Ô­[·÷ þà¨à:uêT-X°@5ÒáÇ5|øp‚+€C8jª@tt´Îž=+Iúúë¯uà 7¸GðG]q}ê©§4tèP¹\.c´hÑ"IRÇŽ}ûlß¾=PÝÀOà¨àúÌ3ÏhôèÑêÓ§Ö­[§™3gjΜ9%ÂjñY8—צS§rÝ Ç(,¼N_|q<ÐÝpŒhI_|ñE »á.ÔÑ©S_ºŽQXxΞý&ÐÝ€C„‡‡ûý˜Žš*ðÑG)>>^’¯]»v¸GðG×èèhmÛ¶M’´uëVÕ«W/À=€¿8jªÀĉ5uêTÍž=[•+WVRRR »?qTp‹‹ÓÒ¥KÝ X਩p.‚+‚ÁAà € @p@P ¸ (\® W‚+‚ÁAà € @p@P ¸ (\® \ÏŸ?/cLE–€CX ®Ï=÷œV¯^-I***Ò€¦o¼Q;vì°Ue-¸Îœ9SõêÕ“$¥§§kãÆZ±b…n½õV5ÊVY8Tˆ­Ÿ8qBµjÕ’$eddhÈ!úõ¯­víÚ)..ÎVY8”µ+®7Üpƒ–.]ªÝ»w+##C½{÷–$ªjÕª¶ÊÀ¡¬×ñãÇkâĉjÛ¶­Z´h¡>}úH’þñ¨cÇŽ¶ÊÀ¡¬M1b„úöí«S§N©]»v ù®T§NÔ³gO[eàPÖ‚«$ÅÄÄ(&&FgÏžUXX˜Ün·:uêd³$ÊÚTÂÂB%%%©V­Zª^½º:$IJMMÕâÅ‹m•€CY ®)))Z¶l™æÍ›'ÇãkoÖ¬™ÒÒÒl•€CY ®iiiZ´h‘¬J•*ùÚ;tè ¬¬,[eàPÖ‚kvv¶š7o^ª=44T.\°Ue-¸6lØP{÷î-Õ¾qãFµhÑÂVY8”µà:bÄ%$$hË–-’¤ãÇkéÒ¥JLLÔÈ‘#m•€CY[kôèÑÊÍÍUÏž=uþüyuíÚUGãÇ×°aÃl•€CY ®.—KÉÉÉ7nœöìÙ#¯×«¸¸8…‡‡Û* ³zI ÓM7Ýd» ÎÚ×ÔÔT½þúë¥Ú_}õU=õÔS¶ÊÀ¡¬× ¨eË–¥Úcccµ`Á[eàPV×q­[·n©ö믿^'Nœ°Ue-¸Ö¯__›7o.Õ¾yófÕ¯_ßVY8”µg 6L>ú¨ÎŸ?¯Ûn»M’ôÁè±ÇÓ¸qãl•€CY ®O<ñ„N:¥áÇûnñZ¥J3†à €r³\Ýn·fÍš¥É“'ë“O>‘$µlÙ’u\ð£X_ǵjÕªjÞ¼¹Œ1*,,T^^ž$)22Òvi8ˆµgíÛ·O=zôPÕªU©5j”xåaíŠë}÷ݧÐÐPý÷ÿ·êÔ©c« ®Ö‚kVV–vïÞ­æÍ›Û*ñ£T«V-Ð]€en·‹×ÙÜn·ÂÂÂÝ Gá|úÛíæçÝ8Ÿ¸ÚY ®­ZµòÍg½šäççº °Ìë ãuö#¯7DçÎ t7£¦Äùô#¯7œŸw?òzC”ŸÿM »‡°ñ|ks\§OŸ®Ç{L™™™:yò¤rrrJ<€ò°vŵwïÞ’ä»ùÀ¥Œ1¶JÀ¬×ÌÌL[‡À5ÈZpíÑ£‡­CàdmŽëÅΞ=+¯×[¥àPÖ‚kaa¡’’’T«V-U¯^]‡’$¥¦¦jñâŶÊÀ¡¬×””-[¶LóæÍ“Çãñµ7kÖLiii¶ÊÀ¡¬×´´4-Z´HƒV¥J•|í:tPVV–­²p(kÁ5;;û²wÍ Õ… l•€CY ® 6ÔÞ½{KµoܸQ-Z´°Ue-¸Ž1B Ú²e‹$éøñãZºt©5räH[eàPÖÖq=z´rssÕ³gO?^]»v•ÇãÑøñã5lØ0[eàPÖ‚«ËåRrr²Æ§={öÈëõ*..Nááá¶JÀÁ¬×¼¼<ß×M›6•ôÝÚ®Åí‘‘‘¶JÀ¬×5j|ïvcŒ­Òp kÁ533³Ä÷^¯Wü±æÎ«ääd[eàPÖ‚k=JµÝvÛmjÒ¤‰æÌ™£ûï¿ßVi8µå°®$66V›6mªè²rÖ®¸æää”jËÎÎVjjªêׯo«,ÊZpŠŠºbû²eËl•€CU؇³\.—"""ÔªU+…††Ú* ‡²\ÛµkwÙöüüüRm¬é €°u\/Æš®ø!Ö‚ë’%KôØcéøƒoi¬ÌÌL½úê«zî¹çm«4ÈZp]ºt©¦M›¦¡C‡úÚúöí«¦M›êoû›V­Ze«4ÈZp]¿~½,XPª½OŸ>JLL´UcñâÒ™:ô‹ô®Ön@¦¬¬¬Rí»víRXX˜­²p(kÁõw¿ûzè!½ñÆ:zô¨Ž9¢%K–hèСúýïo«,ÊÚT§Ÿ~Zz衇táÂIRåÊ•õÇ?þQ3f̰Ue-¸†††ê…^ÐÔ©Sµoß>IR‹-a«$ÌZp-¡–-[*,,Ln·µ™ p8kI²°°PIIIªU«–ªW¯®C‡I’RSSµxñb[eàPÖ‚kJJŠ–-[¦yóæÉãñøÚ›5k¦´´4[eàPÖ‚kZZš-Z¤Áƒ«R¥J¾ö:\v™,àûX ®ÙÙÙjÞ¼y©öÐÐPß*@YY ® 6ÔÞ½{KµoܸQ-Z´°Ue-¸Ž1B Ú²e‹$éøñãZºt©5räH[eàPÖ–Ã=z´rssÕ³gO?^]»v•ÇãÑøñã5lØ0[eàPÖ‚«ËåRrr²Æ§={öÈëõ*..Nááá¶JÀÁ¬ß€ ,,L7Ýt“ŠŠŠTXXh»Êïs\ßyç-[¶¬DÛsÏ=§ÈÈHU­ZUýúõÓ™3gü]ç÷à:}úteggû¾ß¾}»üq7N+W®ÔÁƒ•œœìï²p8¿×={ö¨[·n¾ï—/_®øøxMš4IwÝu—ž}öYýýï÷wY8œßƒk^^žêÔ©ãû~ëÖ­%‚l›6mtôèQ—€Ãù=¸FFFêË/¿”$ê£>ÒÏþsßöo¾ùF!!Ö?‡ñ{píÑ£‡RRRôùçŸëÙgŸ•¤W\wïÞ­Æû»,Îï—>g̘¡[o½U111r¹\š3gŽªW¯îÛ¾bÅ uíÚÕßeàp~®M›6Õ´sçN]ýõjРA‰í£FR£Fü]ge²©ÇãÑÍ7ß|Ùm·Ür‹’eV­Zµ€Ö‡}n·‹×ÙÜn·ÂÂÂÝ Gù)ç“×¢$·ÛÍÏ»q>qµ»æ>%•ŸŸè.À2¯7Œ×Ù¼Þ;w.ÐÝpŒšR9ÎgÍR-¼%y½áü¼û‘×¢üüoÝ 8Dxx¸ßé÷g6\ü\].—Ž?^êkà§òkpu»Ý2Æøó€$?8«~ýúÊÈÈÐÀ%IgΜ‘Çã¹ì¾‘‘‘þ, ‡ókp}â‰'ôÈ#høðá’¤æÍ›_q_®Ì <ü\yäõïß_‡R÷îÝ•žž®š5K/ç”—ß×qŽŽVtt4WTàW²Ö·ß~«o¿ý¶"JÀ¡¬×W^yE-Z´Çã‘ÇãQll¬^{í5›%àPÖnùºxñb9RcÆŒQ÷îÝ%I6lÐðáÃåõzõÀØ* ²\gΜ©ùóç롇òµõíÛWM›6ÕÓO?Mp@¹X›*ðÙgŸ©W¯^¥Úo¿ýv}öÙg¶ÊÀ¡¬×:uêh×®]¥ÚwíÚ¥ºuëÚ* ‡²\ÿûßkèСZ²d‰Ž9¢#GŽhÉ’%:t¨þð‡?Ø* ‡²6Ç5%%Eyyyz衇TPP I ÕÿøGýù϶Ue-¸†„„hþüùš6mšöíÛ'IŠUDD„­’p0kÁµØu×]§_üâ¶ËÀá*äÎYÀOEp@P°\ ´zõjåääØ8<®AV‚kHHˆî¹çåççÛ8<®AV‚«ËåRëÖ­õùçŸÛ8<®AÖæ¸N™2E Z½zµŽ;¦œœœ <¬-‡Õ¯_?IRÿþý/»Ýc«4ÈZpÍÌÌ´uh\ƒ¬×=zØ:4®A²ŽëÙ³gåõz+¢ÊZp-,,TRR’jÕª¥êÕ«ëСC’¤ÔÔT-^¼ØVY8”µàš’’¢eË–iÞ¼yòx<¾öfÍš)--ÍVY8”µàš––¦E‹iðàÁªT©’¯½C‡ÊÊʲUe-¸fgg«yóæ¥ÚCCCuáÂ[eàPÖ‚kÆ µwïÞRí7nT‹-l•€CY ®#FŒPBB‚¶lÙ"I:~ü¸–.]ªÄÄD9ÒVY8”µu\G­ÜÜ\õìÙSçÏŸW×®]åñx4~üx 6ÌVY8”µàêr¹”œœ¬qãÆiÏž=òz½Š‹‹Sxx¸­’p0kÁµXXX˜Ú´i#IªR¥Šírp(«wÎzùå—+Ç#Ç£ØØX½òÊ+6KÀ¡¬×çŸ^#GŽÔ]wÝ¥·ß~[o¿ý¶î¼óN=òÈ#š7ož­²p(kSfÍš¥ùóçëÁôµõíÛWM›6Õ”)SXYåbíŠëÉ“'_ªýöÛo׉'l•€CY ®íÚµ»ì­]wíÚ¥öíÛÛ* ‡òëTœœßש©©9r¤rssÕ½{wc´aÃ¥¦¦êÅ_ôgY\ü\£¢¢JµÝÿý¥Úzõê%cŒ?KÀáü\333ýy8ÀǯÁµGþ<àcýÎYEEE:{öl©©‘‘‘¶KÀA¬­*ðïÿ[={ö”ÇãQdd¤jÔ¨Q┇µ+®C† QÕªUµlÙ2Õ®]ÛV™r«V­Z »ËÜn¯³¹Ýn………ºŽòSÎ'¯EIn·›Ÿw?â|âjg-¸fee)++KÍš5³UâGÉÏÏt`™×ÆëìG^oˆÎ;èn8FM©ç³f©^‹’¼Þp~ÞýÈë Q~þ7î"<<ÜïÇ´\[µj¥¼¼<[‡T°Å‹£Kµ úÅÛÀ߬Íq?¾žxâ mÚ´I§OŸV^^^‰PÖ®¸Ö®][_ýµºuëvÙíÜ€åaýÃY+V¬¸ª>œ€àd-¸îÞ½[»wï¾ê>œ€àdmŽkË–-•››këð¸ÆX ®Ó¦MSbb¢233uòäIåää”xåamªÀ/ùKIÒm·ÝvÙí|8 åa-¸fffÚ:4®AÖ‚k=l× kÁõ‡n2i«4ÈZp­Q£Æ÷ngŽ+Ê£Âæ¸z½^}üñÇš;w®’““m•€CUè×Ûn»MMš4Ñœ9stÿý÷Û* ²¶Žë•ÄÆÆjÓ¦M]AÎÚ×ËÝd ;;[©©©ª_¿¾­²p(kÁ5**êŠíË–-³UUaÎr¹\ŠˆˆP«V­j«,ÊïÁµxýÖvíÚ]v{~~¾$Öq@ùø=¸þÐú­ÅXÇåá÷àzébÆ­\¹R‹-RXX˜¿ËÀáü\/]¿Õ£·ÞzK))):räˆ&Nœ¨1cÆø»,ÎÚ‡³. ¬‰‰‰3fŒ"""l•€ƒù=¸cô÷¿ÿ]))):|ø°”@`ÀOâ÷àÚ¾}{íÛ·OÆ Szzº"""táÂ…R7$¨]»¶¿KÀÁü\wîÜ)Izá…ô /\q¿@­*0kVx©¶±cÏ 'ðÅ‹£Kµ úEÐ*J…­*üÖWüÁèeAp@P ¸ (\® W‚+‚ÁAà € @p@P ¸ (\® W‚+‚ÁAà € @p@P tüé믿ք ”““£¨¨(͘1CÕªU t·àŽºâºxñbuêÔIË—/×M7ݤ—_~9Ð]€Ÿ8*¸nÞ¼Y}úô‘$õíÛW~ø¡$©cÇŽ¾‚“£¦ œÉÉè~2ã ݺu3^¯×÷ý­·ÞzÙý:tè@;í´ÓN;í´ÓN{´û“£‚ë¯~õ+sâÄ cŒ1ÙÙÙfàÀîQIñ‚R—ºÔ¥.u©K]ê:•£æ¸vîÜYk×®•$­Y³F;wpà/.cŒ t'üåÌ™3?~¼N:¥ÚµkkÆŒª^½z »?pTp€s9jªœËQËaáÿ,\¸PÊÎÎÖÖ­[KlsÚƶo߮ٳg«¨¨Hn·[ãÇWÛ¶m%9o¬Åþö·¿)==].—K’4jÔ(ÝrË-’œ;fIzæ™g”žž^â=íÄñvîÜY 6”$ýö·¿U¿~ý$9s¬Å.\¨÷ß_Æ 8P÷Þ{¯$çŽyöìÙ¾¥¿ùæåææ*33Ó‘ãݰaƒæÏŸ/Ir¹\1b„ºuë&É™¯ïþýû•’’¢ÂÂBÕ¯__S¦LQXX˜$gŽ·Âô£a°&++Ëœ}ôñÇû¾wÚ˜wîÜ©C‡©ÿþêß¿¿¾ùæõïß_^¯W’óÆ+I5jÔ$õîÝ[ôµ;q¬’ô³ŸýL½zõ’$ÅÇÇëÓO?õmsꘋ]}ºvîÜ)cŒ"##K̃tꘋuíÚU›6mò}ï´ñ®]»Viii’$Ç£'Ÿ|RÍš5“ä¼±;{ö¬&Mš¤/¿üR¡¡¡š¯  À$%%™èèhjš5kf/^\bÿÌÌL#ɼû}ûö¦råʦcÇŽfß¾}¾}$•z\lîܹ¦Y³f&44ÔÔ«WÏLš4©ÄøýQãbíÛ·73fÌð}ïõzMtt´™6mZ‰ýlúõëwÅã\Nq_/>e9~YöùðÃ$sôèQcŒ1kÖ¬1’L~~¾9pà€‰ŠŠ2G޹bßl|ðÁr@p ¸¨p§OŸ6n·Û¬Y³æ÷ÍÉÉ1.—˼ûî»åªQžç=úè£&**ʬZµÊ>|Ø,Z´ÈT©RŤ¥¥ùö)j;w6[¶l1Ÿ|ò‰¹ùæ›M=|û¤§§Ifÿþýæ?ÿùùÏþãÛ6yòdÓ¼ys³fÍsôèQóÞ{ š‰'ú­ÆÅΜ9c\.—yÿý÷}mŸ}ö™‘d¶oß^bßW_}Õ\wÝu?xž.v¹àZ–ã—eŸœœãñxÌÂ… MQQ‘5j”iÞ¼¹1Ƙøøx3gΜïíÛsÏ=g5jT®ñWnëÖ­%®¨»ûî»MµjÕ|¼¼<óÏþó²ûþ²>///Ï„††š×_½Dû¸qã|aɘÿ j|ð¯í¯ý« 1%ö¹ô*p~~¾©ZµªÙ¼ys‰ö¥K—šš5kú¥Æ¥þõ¯IæÓO?õµmÞ¼ÙH2ÇŽ+±ïºuëŒ$sîܹï=æÅ.ײ¿¬}X½zµi×®©[·®éÞ½»ÉÊÊ2K–,1;v4Û¶m3;w6õë×7ýúõ3_~ùe‰c¥§§—Ëe.\¸PæñÌqpÕøË_þ¢;wjáÂ…ÊÏϯØìÛ·OêÞ½{‰öîÝ»kÿþýúöÛoK´ÇÅÅù¾®S§Ž •ŸŸÿ½5öìÙ£óçÏ«W¯^ ÷=|ðA>}ZgÏžýÉ5.U|ÌðððRÛ\.×÷>÷â>^îù?䇎_–}úõë§>úHÇ×úõëuà 7hܸqš7ož  þýûëóÏ?WDD„xàψˆ1¦ÔyüBÝמ&MšÈívk×®]ŠŽŽöµ_ýõ’¾[ àâ}].—öîÝ[bß²Ôø1Ïû!nwéÿïÿPÀöz½’¤µk×êg?ûY©íaaa?¹Æ¥Šç×_í«Y|~;V¢ÇŽÓu×]§ªU«J’vîÜY®ZÅÊrü²öáRúÓŸôÛßþV!!!úòË/uß}÷ÉívkÈ!ºûî»UPP ÐÐPIÒ™3gär¹~TèpuãŠ+€ W³fMÝqÇš>}º ¾wßZµj)>>^sæÌ¹ìö+- UÖçÅÆÆ*44´Ô§ê7lØ -Z¨J•*?4ŸJ•*Iú¿ Z,..NGGŽQ“&MJ=.TË[ãRÅÁýðáþ¶ (::ZëÖ­+±ïºuëÔ¥K—ϽøQVe9~Yûp± 6(33S)))***’$ßûæÂ… òz½%ÎÇáÇã ²œƒ+®â/ù‹ºt颮]»jìØ±úùÏ®*UªèèÑ£zå•Wär¹|nþüùºå–[t×]wéñÇWLLŒrrr´råJíØ±Co¿ýöek”åyzøá‡5vìXÕ¨QCmÛ¶Õºuë4wî\½øâ‹åSƒ $I«V­R¿~ýär¹T»vm…‡‡küøñ5j”ŠŠŠÔ­[7hÇŽÚ¿¿þüç?ÿä—ª^½ºÚµk§mÛ¶)>>^Òwžâ‰'”””¤¦M›ê¦›nRFF†V¬XQæå£Š¯Æ8p@’”••å«U–ã—·ß~û­†®ùóç+,,LmÚ´Q­Zµ4kÖ,=þøã¾÷ÑÅÿÁضm[©©"°Sl\ËrssÍ“O>iZµjeªV­jªT©b7nl|ðÁRŸ:?räˆ:t¨©W¯ž 1QQQfàÀfÇŽß[£,Ï+((0'N4õêÕó-‡µhÑ¢Ç)þ0Rvvv©¶‹? ôÔSO™ë¯¿Þ¸ÝîRKU-\¸Ð´iÓÆT®\ÙT«VÍtêÔ©DԸ،3L§NJµÏœ9Ó4hÐÀ„††š¸¸8“žžþ}§°]f9®KûP–ã—µ“'O6ƒ *ÑöÁ˜æÍ››ÐÐPÓ¹sgsàÀß¶o¿ýÖÔ¨Qì]»¶Ìc<\Æp{p¢S§N)&&Fÿüç?Õ²eË@w§B¤§§+))IŸ|òI™>$ ¸0ǪV­Z;v¬¦Nè®T˜iÓ¦iÊ”)„VÀ¡¸â € ÀW…ÿ®«ÏfíùÚIIEND®B`‚prinseq-lite-0.20.4/example/example1_td3.png0000664000076700007670000001630412240000123021022 0ustar rschmiedrschmied‰PNG  IHDR¨ú]ôwbKGDÿÿÿ ½§“yIDATxœíÝypUõýÿñ×ÍBB 6!e¢EP16T†mâZ´PZ`jY"¡¨ADI°²h ¶4ŠX‚µJ\( `Ø%ì‹6E Q²’œß~s„„ýœäsÏÇÌÉýœ›óþ¼ Ë‹³|ŽÇ²,K€!üjzÀŨ0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 FqU@:uªî¿ÿþšžn‚kêÖ­[•››«ZµjÕôTp\P‹‹‹•ššª1cÆÔôTp“jzv˜={¶úõë§zõêU¹½cÇŽÞ¯·lÙR]ÓÀ ðù€º{÷níÝ»W —ýÌÅ¡4//¯:¦ð“P·n]Û÷éó§ø³²²”­øøxÅÇÇ«¨¨Hñññ*++«é©àx,˲jzvŠ‹‹Óºuë.»#¨öá*\ÏuGP¯†#¨öá*\€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`eYVMO¢:ýÄÚp”Çã±}Ÿ¶ïÑpùùù5=ר[·®íûä?ŒB@€Q¨0JµÔÂÂBnRÀ9P§OŸ®?üP’TZZª¾}û*$$DÍš5Ó_|áTYø8Çêk¯½¦ÆK’/^¬ÌÌL}ðÁêÒ¥‹FŽéTYø8Ç–™:yò¤"""$I8p ~ó›ß¨}ûöЉ‰qª,|œcGP5j¤… jûöíÊÈÈP=$I%%%ª]»¶Seàã ¨IIIzá…t÷Ýw+::Z={ö”$­ZµJ;vtª,|œ£:=tèΜ9£öíÛ+ àÇ« >ÿüs…††ªuëÖN•½¢¼¼¼© àFNα€š““£V­ZU Tqq±Seàã ¨QQQÚ½{w¥ñÌÌLEGG;U>α€:|øp5J›6m’$8qB .Tbb¢FŒáTYø8Çuš ³gϪk×®*,,T\\œ‚ƒƒ•””¤¡C‡:U>ÎñuP ´k×.•••)&&Æ‘µ²®ë ØÇgê7 À>>µPJJŠÞ}÷ÝJãï¼óŽ^yå§ÊÀÇ9PgÏž­6mÚToݺµfÏžíTYø8G×A½õÖ[+7lØP'Ožtª,|œcµiÓ¦Ú¸qc¥ñ7ªiÓ¦N•€sl™©¡C‡jذa*,,ÔÃ?,IZ½zµF­çž{Ω²ðqŽÔçŸ^gΜÑÿøGï£Mƒ‚‚ôÌ3ÏPpYŽ/3uîÜ9íÙ³G’Ô¦MÖApŸ\µ¤¤Dùùùº´LXX˜“e/‹€ `ŸZuïÞ½z衇T»vm………)<<¼Â ¨Šc× 4Húç?ÿ©ÈÈH§ÊÀe;ŤíÛ·«U«VNìþ†qŠÀ>>uŠ¿mÛ¶ÊÍÍuj÷p)Çê¤I“4zôh­Y³F§NÒéÓ§+¼€ª8vŠßãñ\q»Ã‹\§øìãÄ)~Çn’Z³fS»€‹9¾ªi8‚ `ŸºIêbyyy*++«ŽRðqŽÔ’’7N Uvv¶$)%%EóæÍsª,|œc599Yéééš5k–‚ƒƒ½ã-[¶TZZšSeàã ¨iiiš;w®  ïx‡´cǧÊÀÇ9Psrrª|ŠT`` Š‹‹* çX@ŠŠÒîÝ»+gff*::Ú©²ðqŽÔáÇkÔ¨QÚ´i“$éĉZ¸p¡5bħÊÀÇ9¶PBB‚Ξ=«®]»ª°°Pqqq VRR’†êTYø8Çê/((Ю]»TVV¦˜˜Gs½,Ô`'²c577÷ŠÛÜ({UTû8P;Å~Åí?±'¬à9P׬YSá}YY™vîÜ©ÔÔTM˜0Á©²ðqŽ_ƒz©?þX3fÌЊ+ª³¬GnìãñxìßguÔC‡©M›6*,,¬Î²^\ƒ `ŸºõôéÓ•Ærrr”’’¢¦M›:U>α€Ú AƒËާ§§;U>®Ún’òx<ºå–[Ô¶m[:U>®ÆÖA½Xu®‰Ê5¨öñ©kP¯¶ꟳå ¨ ,ÐèÑ£õÄO衇’ôãiÿwÞyGÓ§OW“&Mœ* æØ)þÞ½{«_¿~2dH…ñ9sæèÃ?Ô²eËœ({Uœâ°§ø ¨!!!Ú»w¯š5kVaüèÑ£jݺµòóó({UTû8Pýlßãÿ ÑŽ;*oÛ¶M!!!N•€s, þáÐàÁƒõÞ{ï騱c:zô¨,X !C†èñÇwª,|œc7IM™2E.\ÐàÁƒU\\,IªU«–ž~úiMž<Ù©²ðqŽ]ƒZî‡~ÐÞ½{%IÑÑѺå–[œ,wU\ƒ `ŸºIêbyyy ‘ŸŸcW\×\`ŸºIª¤¤DãÆSDD„BCC•-IJIIѼyóœ* çX@MNNVzzºfÍš¥àà`ïxË–-•––æTYø8ÇjZZšæÎ«Èßßß;Þ¡C‡*—Ÿ$jNNŽZµjUi<00Ð{W?p)ÇjTT”vïÞ]i<33SÑÑÑN•€s, >\£FÒ¦M›$I'NœÐÂ… •˜˜¨#F8U>α…útöìYuíÚU………Š‹‹Spp°’’’4tèP§ÊÀÇ9¾jAAvíÚ¥²²2ÅÄÄ8²VÖõ`TûøìBý’TZZª’’UG¹Ë" ØÇ'êÿä“O”žž^alúôé SíÚµÕ§OýðÃv—€KØP'Mš¤œœïû-[¶èÏþ³ž{î9-Y²DÔ„ ì. —°ýDD„>ýôSµoß^’4fÌmß¾]+V¬$}ôÑGJHHÐÁƒí,{Í8Å`Ÿ8ÅŸ››«ÈÈHïûÍ›7«sçÎÞ÷íÚµÓ±cÇì. —°= †……é›o¾‘$•””hëÖ­ºçž{¼Û‹ŠŠàØêVðq¶Ô‡zHÉÉÉ:|ø°þú׿JR…#¨Û·oW‹-ì. —°ýPæäɓեKÝ~ûíòx<š1c†BCC½Û?øàÅÅÅÙ].áÈ:¨EEEÊÊÊRÆ Õ¼yó Û6lØ ;î¸C 6´»ì5á&)ûøôBý¦  ØÇ'îânF! À(TÅÑ€¦Ã‡;Y.c{@ÍÌÌTaaa¥ñºuëêÀv—€ËØP‡ ¢°°0uêÔIÚ¸q£ÎŸ?ow¸”íuÿþý:zô¨ž}öYùûûk„ ŠˆˆPAAæÍ›§M›6éÂ… v—€KؾPÿþýûÕ²eKI?^ƒš••¥€€Ýu×]êÑ£‡¶oß®“'O*??ßβ׌…úìãÄBývï°cÇŽ Vll¬ õÕW_©{÷îò÷÷×믿®;ï¼S_ýµÝeà¶ŸâÏÍÍÕªU«Ô³gOy<=öØcjÚ´©ŠŠŠôßÿþW‡R“&Mì. —°ýÿÅ´uëVåää¨sçÎêСƒ¶oß®°°0;vÌ©²WÄ)~ûøÄ)þKy<Ýwß} Ðüùó¥-[¶8]>ÊÑ€š››[¹`@€:uêädYø0Ç –ãÔ:®…£:®Fqô.~ýÄÚp”Çã±}ŸÕv ª)jê Vnä“ËL®ìõ×+ÿå>f 7–øéâT…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Q¨0 F! À(T…€ £P`*ŒB@€Qjzv:wîœÆŽ«Ó§O«Aƒš}úHrg¯åÞzë-}úé§²,Kýû÷×£>*ɽ=O›6Í»ÔaQQ‘Ξ=«5kÖ¸²ßÏ>ûLo¾ù¦$Éãñhøðáêܹ³$wþ|÷íÛ§ääd•””¨iÓ¦š8q¢BBB$¹³ßjW£·há¦íرÃ:uê”õ‹_ü¢Ò¶iÓ¦YóçÏ·,˲æÏŸo¥¦¦V÷ôluàÀëÌ™3–eYÖ_|aõíÛ×»Ím½–ËÏÏ÷~muïÞÝûÞ­=ùå—ÖØ±c+ýžvc¿Uý¹µ,wöjY–µtéRëå—_¶JKK-˲¬³gÏz·¹µç‹-Z´ÈJNN¶,ËývïÞÝ:xð eY–uøða«GÞmnìwРAÖúõë-˲¬ 6X3gÎônsc¿ÕSü>®mÛ¶Þ‡\êrOÖòU-Z´P½zõ$I?ÿùÏuæÌï6·õZ®üã’TPP [o½ÕûÞ=+55UcÆŒ©´Íý^Ž[{]²d‰ž|òIùùýøOOXX˜w›[{¾Øÿþ÷?onì·I“&Þ‡áœ;wN5ònsc¿GŽÑý÷ß/IêÔ©S…žÜØouã¿‹]îÉZn°lÙ2ï©nÉݽ.Z´H‹-Raa¡æÌ™ãwcϳgÏV¿~ý¼ÿ¹˜ûµ,KTݺu5vìXÝ~ûí’ÜÙ«ôã?èŸ|ò‰Ö®]«ððp½ð jÚ´©$÷ö\îøñã:~ü¸÷‘Ûnì÷•W^Ñ!CäñxdY–æÎëÝæÆ~[´h¡•+WªW¯^Z¹r¥Nœ8áÝæÆ~«GPásöíÛ§ (11±¦§R-~ûÛßjéÒ¥JHHД)Sjz:ŽÙ½{·öîÝ«Gy¤¦§Rm222´páBýêW¿Òĉkz:Ž+--UóæÍµhÑ"õíÛW)))5=¥j³bÅ uëÖÍ{ôئNª„„}ôÑG5j”^{íµšž’£Æ¯%K–è±ÇÓäïï_ÓSr÷þI4h œœIÒéÓ§U¿~ýžÑÍ;yò¤ÆŽ«I“&U¸´Á½^ªgÏžÚ¹s§÷½ÛzÎÊÊRvv¶âã㯢¢"ÅÇÇ«¬¬L’ûú•¤ððpIR=tðàAï¸{•¤Ûn»MÝ»w—$uëÖM_}õ•w›[{.wñé}ÉýnݺUݺu“ôãÏwÛ¶mÞmnì÷Ž;îМ9sôþûïë‘GQ³fͼÛÜØou# º˜Ûž¬•ŸŸ¯ÄÄD5J­[·®°Ím½–;~ü¸÷ëÌÌLï)`É}=8PË—/WFF†222¬ŒŒ ï'·õ›››+ëÿ–¡^¿~½š7oîÝæ¶^ËÅÆÆêóÏ?—ôãªÿƒîÖž%);;[jÛ¶­wÌý6iÒÄûóݼy³7nìÝæÆ~¿ÿþ{I?^ªóöÛo+>>Þ»ÍýV7ê÷q³fÍÒǬœœ5hÐ@½{÷Öˆ#$¹ïÉZ ,М9s¼×¬IÒ{ï½'???×õZnÒ¤IÊÊÊ’eY «p¢[{.§uëÖyß»­ßåË—+--M’¬_|Q-[¶”ä¾^Ëåååiüøñúæ›o¨—_~Ùõ=KÒßÿþwY–¥aÆyÇÜØï®]»ô—¿üEÅÅŪU«–Ƨ˜˜Iîì÷ßÿþ·ÒÓÓåïï¯Î;køðáÞ%ÝØou# À(œâ€Q¨0 F! À(T…€ UX»v­<÷…—¾÷U7Ò‡½»å×@õ  0Ê‘#GÔ¥KEFF* @õë××€ôõ×_{?s¥°ãñx®úº±±±úöÛoqMŸ7)€•Ï%77×–ý]ï¯Ü,*£è÷¿ÿ½V¬X¡#GŽèÃ?Ô±cÇÔ«W¯kúþo¿ýÖûZ¼x±$iß¾}ƯE­ZµtÛm·]s u3~-T7*£4nÜXO=õ”Ú·o¯Æ«S§N7nœvîÜ©¼¼¼«~ÿm·Ýæ}Õ«WO’Ya\’æÏŸ¯öíÛ+((Hááá4hP…#ŽN9s¦Zµj¥Zµj©I“&z饗TZZZ©æŠ+Ô¡CéÞ{ïÕ¾}û¼Ÿ)..Vbb¢4h :uê¨oß¾JOO¯pÄ´K—.’¤ðððË5þòË//[ãR—»ÜáJ󼜬¬,ÅÆÆ*88XÍ›7׬Y³ª¬µjÕª+~€»Pí»ï¾ÓüùóÕ­[7Õ­[×¶ýúùùiÚ´i:pà€–.]ªmÛ¶iäÈ‘¶íÿR&LÐßþö7͘1CÙÙÙzçw´`Á½ôÒK•>›œœ¬7ß|SÛ¶mS@@€ž~úiï¶gžyFï¿ÿ¾æÏŸ¯={ö(>>^‰‰‰¾¿ª#Ç×SãZÝÈ>þô§?iìØ±Ú¿¿Æ¯1cÆèí·ß¾áÏp) Ô³gO+$$Ä’dõïßß:þüuïcÍš5–$ëìÙ³Wýì’%K¬:uêXeee¾7''§Ê÷—«UÕöüü|«víÚÖÆ+Œ/\¸ÐªW¯^¥}¬^½Ú;öþûï[Ö… ¬ï¿ÿÞ ´ÒÓÓ+ì'))©BŸWêûj5®¥·›ÙÇ»ï¾[aü¹çž³¢££¯ûsÜ#¨Œ4oÞ}úÈãñ¨~ýú¶ôw³RRR®víÚiåÊ•JMM­òýkýw" 0ŠŸŸŸRRR´oß>«Y³f8p Æo[FiΜ9zñÅõÆoèÁÔĉõÄOÜô¾Ë—xºØ¹sçôòË/«aÆzýõ×5dÈ*&&FC‡½®ý§¦¦*((Hƒ RQQ‘~øaMš4IO>ù¤÷ò‡fÍšé•W^Ñ /¼ Áƒ«¬¬ìºOß;eÖ¬Yz饗”••¥ÈÈHM™2Eƒ¾áÏp'eÊßZ€òꫯjΜ9:|øpMO妭]»V]ºtQNNŽ1G}T?Ž €Ù¶m›vìØ¡x@þþþZµj•^}õU[0@M# €IMMÕÓO?­óçÏ+**JãÇ׳Ï>[ÓÓÛpŠFùè²þþàIEND®B`‚prinseq-lite-0.20.4/example/example1.gd0000664000076700007670000006402512240000570020067 0ustar rschmiedrschmied#Graph data #[prinseq-lite-0.20.4] [11/10/2013 12:11:59] Command: "perl prinseq-lite.pl -fastq example/example1.fastq -graph_data example/example1.gd -verbose -out_good null -out_bad null" {"numseqs":12,"numbases":1150,"pairedend":0,"maxlength":200,"binval":2,"exactonly":0,"tagmidnum":0,"scale":1,"filename1":"6578616d706c65312e6661737471","format1":"fastq","counts":{"gc":{"50":5,"53":1,"0":1,"49":1,"56":2,"57":2},"length":{"50":3,"200":1,"100":8},"ns":{"10":2},"tail3":{"50":1},"tail5":{"50":1}},"stats":{"gc":{"p25":50,"p75":56,"mode":50,"min":0,"std":"14.83","range":58,"max":57,"modeval":5,"median":50,"mean":"48.17"},"length":{"p25":75,"p75":100,"mode":100,"min":50,"std":"37.96","range":151,"max":200,"modeval":8,"median":100,"mean":"95.83"},"ns":{"p25":10,"p75":10,"mode":10,"min":10,"std":"0.00","range":1,"max":10,"modeval":2,"median":10,"mean":"10.00"},"tail3":{"p25":50,"p75":50,"mode":50,"min":50,"std":"0.00","range":1,"max":50,"modeval":1,"median":50,"mean":"50.00"},"tail5":{"p25":50,"p75":50,"mode":50,"min":50,"std":"0.00","range":1,"max":50,"modeval":1,"median":50,"mean":"50.00"}},"quals":{"0":{"p25":13,"p75":33,"mode":16,"min":0,"std":"12.68","range":38,"max":37,"modeval":4,"median":16,"mean":"19.58"},"1":{"p25":13,"p75":33,"mode":17,"min":0,"std":"13.06","range":40,"max":39,"modeval":4,"median":17,"mean":"20.25"},"10":{"p25":18,"p75":35,"mode":18,"min":7,"std":"9.55","range":31,"max":37,"modeval":4,"median":19,"mean":"23.17"},"11":{"p25":19,"p75":32,"mode":19,"min":7,"std":"8.81","range":31,"max":37,"modeval":4,"median":19,"mean":"23.00"},"12":{"p25":17,"p75":32,"mode":17,"min":7,"std":"9.16","range":31,"max":37,"modeval":4,"median":18,"mean":"22.33"},"13":{"p25":16,"p75":31,"mode":16,"min":7,"std":"9.19","range":31,"max":37,"modeval":4,"median":18,"mean":"21.83"},"14":{"p25":18,"p75":28,"mode":18,"min":7,"std":"8.14","range":31,"max":37,"modeval":4,"median":19,"mean":"21.83"},"15":{"p25":19,"p75":28,"mode":19,"min":7,"std":"7.82","range":31,"max":37,"modeval":4,"median":19,"mean":"22.33"},"16":{"p25":16,"p75":28,"mode":16,"min":9,"std":"8.09","range":29,"max":37,"modeval":4,"median":18,"mean":"21.50"},"17":{"p25":17,"p75":28,"mode":17,"min":9,"std":"7.87","range":29,"max":37,"modeval":4,"median":18,"mean":"21.83"},"18":{"p25":18,"p75":32,"mode":18,"min":9,"std":"8.17","range":28,"max":36,"modeval":4,"median":19,"mean":"22.75"},"19":{"p25":19,"p75":32,"mode":19,"min":9,"std":"7.98","range":28,"max":36,"modeval":4,"median":19,"mean":"23.08"},"2":{"p25":14,"p75":33,"mode":18,"min":0,"std":"12.28","range":40,"max":39,"modeval":4,"median":18,"mean":"21.08"},"20":{"p25":16,"p75":33,"mode":16,"min":9,"std":"8.80","range":28,"max":36,"modeval":4,"median":18,"mean":"22.25"},"21":{"p25":17,"p75":28,"mode":17,"min":9,"std":"7.71","range":28,"max":36,"modeval":4,"median":18,"mean":"21.75"},"22":{"p25":18,"p75":28,"mode":18,"min":10,"std":"7.38","range":27,"max":36,"modeval":4,"median":19,"mean":"22.17"},"23":{"p25":19,"p75":28,"mode":19,"min":10,"std":"7.21","range":27,"max":36,"modeval":4,"median":19,"mean":"22.50"},"24":{"p25":16,"p75":32,"mode":16,"min":8,"std":"9.24","range":29,"max":36,"modeval":4,"median":18,"mean":"22.75"},"25":{"p25":17,"p75":32,"mode":17,"min":8,"std":"8.82","range":29,"max":36,"modeval":4,"median":19,"mean":"23.33"},"26":{"p25":18,"p75":32,"mode":18,"min":8,"std":"8.59","range":29,"max":36,"modeval":5,"median":19,"mean":"23.67"},"27":{"p25":19,"p75":32,"mode":19,"min":8,"std":"8.38","range":29,"max":36,"modeval":4,"median":19,"mean":"24.00"},"28":{"p25":16,"p75":32,"mode":16,"min":4,"std":"9.10","range":33,"max":36,"modeval":4,"median":18,"mean":"21.33"},"29":{"p25":17,"p75":32,"mode":17,"min":4,"std":"8.92","range":33,"max":36,"modeval":4,"median":18,"mean":"21.67"},"3":{"p25":14,"p75":33,"mode":19,"min":0,"std":"11.74","range":38,"max":37,"modeval":4,"median":19,"mean":"21.08"},"30":{"p25":18,"p75":32,"mode":18,"min":4,"std":"8.76","range":33,"max":36,"modeval":6,"median":18,"mean":"22.00"},"31":{"p25":18,"p75":33,"mode":19,"min":4,"std":"9.23","range":33,"max":36,"modeval":4,"median":19,"mean":"22.83"},"32":{"p25":16,"p75":33,"mode":16,"min":4,"std":"9.74","range":33,"max":36,"modeval":4,"median":18,"mean":"21.83"},"33":{"p25":17,"p75":33,"mode":17,"min":4,"std":"9.49","range":33,"max":36,"modeval":4,"median":19,"mean":"22.33"},"34":{"p25":18,"p75":33,"mode":18,"min":10,"std":"8.28","range":27,"max":36,"modeval":4,"median":20,"mean":"23.75"},"35":{"p25":19,"p75":33,"mode":19,"min":10,"std":"8.06","range":27,"max":36,"modeval":4,"median":20,"mean":"24.08"},"36":{"p25":16,"p75":33,"mode":16,"min":10,"std":"9.11","range":27,"max":36,"modeval":4,"median":20,"mean":"23.67"},"37":{"p25":17,"p75":32,"mode":17,"min":10,"std":"8.45","range":26,"max":35,"modeval":4,"median":20,"mean":"23.67"},"38":{"p25":18,"p75":32,"mode":18,"min":8,"std":"8.58","range":28,"max":35,"modeval":4,"median":20,"mean":"23.92"},"39":{"p25":19,"p75":32,"mode":19,"min":8,"std":"7.77","range":26,"max":33,"modeval":4,"median":20,"mean":"23.75"},"4":{"p25":13,"p75":33,"mode":16,"min":0,"std":"12.00","range":38,"max":37,"modeval":4,"median":16,"mean":"20.08"},"40":{"p25":16,"p75":32,"mode":16,"min":7,"std":"8.62","range":27,"max":33,"modeval":4,"median":20,"mean":"22.67"},"41":{"p25":17,"p75":32,"mode":17,"min":7,"std":"8.36","range":27,"max":33,"modeval":4,"median":23,"mean":"23.50"},"42":{"p25":18,"p75":32,"mode":32,"min":4,"std":"8.63","range":29,"max":32,"modeval":5,"median":24,"mean":"23.67"},"43":{"p25":19,"p75":32,"mode":19,"min":4,"std":"8.96","range":32,"max":35,"modeval":4,"median":24,"mean":"24.50"},"44":{"p25":16,"p75":32,"mode":16,"min":4,"std":"9.58","range":32,"max":35,"modeval":4,"median":22,"mean":"23.25"},"45":{"p25":17,"p75":32,"mode":17,"min":4,"std":"9.33","range":32,"max":35,"modeval":4,"median":22,"mean":"23.58"},"46":{"p25":18,"p75":32,"mode":18,"min":4,"std":"9.11","range":32,"max":35,"modeval":4,"median":22,"mean":"23.92"},"47":{"p25":19,"p75":32,"mode":19,"min":4,"std":"8.90","range":32,"max":35,"modeval":4,"median":22,"mean":"24.25"},"48":{"p25":16,"p75":30,"mode":16,"min":4,"std":"8.39","range":29,"max":32,"modeval":4,"median":22,"mean":"22.08"},"49":{"p25":17,"p75":30,"mode":17,"min":4,"std":"8.00","range":29,"max":32,"modeval":4,"median":22,"mean":"22.08"},"5":{"p25":13,"p75":33,"mode":17,"min":0,"std":"11.89","range":38,"max":37,"modeval":4,"median":17,"mean":"20.42"},"50":{"p25":18,"p75":31,"mode":18,"min":8,"std":"7.50","range":25,"max":32,"modeval":4,"median":22,"mean":"23.33"},"51":{"p25":19,"p75":31,"mode":19,"min":8,"std":"7.27","range":25,"max":32,"modeval":4,"median":22,"mean":"23.67"},"52":{"p25":16,"p75":31,"mode":16,"min":13,"std":"8.10","range":26,"max":38,"modeval":4,"median":22,"mean":"23.58"},"53":{"p25":18,"p75":34,"mode":18,"min":13,"std":"8.75","range":26,"max":38,"modeval":4,"median":22,"mean":"25.42"},"54":{"p25":17,"p75":34,"mode":17,"min":16,"std":"8.62","range":22,"max":37,"modeval":4,"median":22,"mean":"25.25"},"55":{"p25":19,"p75":36,"mode":19,"min":16,"std":"8.40","range":22,"max":37,"modeval":4,"median":21,"mean":"26.08"},"56":{"p25":16,"p75":36,"mode":16,"min":9,"std":"10.08","range":29,"max":37,"modeval":4,"median":20,"mean":"24.42"},"57":{"p25":17,"p75":36,"mode":17,"min":9,"std":"9.81","range":29,"max":37,"modeval":4,"median":20,"mean":"24.75"},"58":{"p25":18,"p75":31,"mode":18,"min":9,"std":"8.38","range":29,"max":37,"modeval":4,"median":20,"mean":"23.92"},"59":{"p25":19,"p75":31,"mode":19,"min":9,"std":"8.16","range":29,"max":37,"modeval":4,"median":20,"mean":"24.25"},"6":{"p25":14,"p75":35,"mode":18,"min":0,"std":"11.83","range":38,"max":37,"modeval":4,"median":18,"mean":"21.33"},"60":{"p25":16,"p75":36,"mode":16,"min":9,"std":"10.08","range":29,"max":37,"modeval":4,"median":20,"mean":"24.42"},"61":{"p25":17,"p75":36,"mode":17,"min":9,"std":"9.81","range":29,"max":37,"modeval":4,"median":20,"mean":"24.75"},"62":{"p25":18,"p75":36,"mode":18,"min":12,"std":"8.94","range":26,"max":37,"modeval":4,"median":20,"mean":"24.67"},"63":{"p25":19,"p75":36,"mode":19,"min":12,"std":"8.74","range":26,"max":37,"modeval":4,"median":20,"mean":"24.92"},"64":{"p25":16,"p75":36,"mode":16,"min":10,"std":"10.00","range":30,"max":39,"modeval":4,"median":19,"mean":"23.83"},"65":{"p25":17,"p75":36,"mode":17,"min":10,"std":"9.75","range":30,"max":39,"modeval":4,"median":19,"mean":"24.17"},"66":{"p25":18,"p75":35,"mode":18,"min":9,"std":"9.22","range":31,"max":39,"modeval":4,"median":19,"mean":"24.08"},"67":{"p25":19,"p75":32,"mode":19,"min":9,"std":"8.48","range":31,"max":39,"modeval":5,"median":19,"mean":"23.92"},"68":{"p25":16,"p75":31,"mode":16,"min":6,"std":"9.40","range":34,"max":39,"modeval":4,"median":19,"mean":"22.50"},"69":{"p25":17,"p75":32,"mode":17,"min":6,"std":"9.34","range":34,"max":39,"modeval":4,"median":19,"mean":"23.00"},"7":{"p25":14,"p75":35,"mode":19,"min":0,"std":"11.74","range":38,"max":37,"modeval":4,"median":19,"mean":"21.67"},"70":{"p25":18,"p75":36,"mode":18,"min":6,"std":"10.07","range":34,"max":39,"modeval":4,"median":19,"mean":"24.17"},"71":{"p25":19,"p75":36,"mode":19,"min":6,"std":"9.87","range":34,"max":39,"modeval":5,"median":19,"mean":"24.50"},"72":{"p25":16,"p75":36,"mode":16,"min":8,"std":"10.09","range":30,"max":37,"modeval":4,"median":18,"mean":"23.33"},"73":{"p25":17,"p75":36,"mode":17,"min":8,"std":"9.86","range":30,"max":37,"modeval":5,"median":18,"mean":"23.67"},"74":{"p25":18,"p75":36,"mode":18,"min":8,"std":"9.64","range":30,"max":37,"modeval":4,"median":19,"mean":"24.00"},"75":{"p25":19,"p75":36,"mode":19,"min":8,"std":"9.45","range":30,"max":37,"modeval":4,"median":19,"mean":"24.33"},"76":{"p25":16,"p75":36,"mode":16,"min":9,"std":"9.97","range":29,"max":37,"modeval":4,"median":18,"mean":"23.42"},"77":{"p25":17,"p75":36,"mode":17,"min":9,"std":"9.73","range":29,"max":37,"modeval":5,"median":18,"mean":"23.75"},"78":{"p25":18,"p75":36,"mode":18,"min":9,"std":"9.51","range":29,"max":37,"modeval":4,"median":19,"mean":"24.08"},"79":{"p25":19,"p75":36,"mode":19,"min":9,"std":"9.30","range":29,"max":37,"modeval":4,"median":19,"mean":"24.42"},"8":{"p25":14,"p75":35,"mode":16,"min":0,"std":"12.04","range":38,"max":37,"modeval":4,"median":16,"mean":"20.75"},"80":{"p25":16,"p75":36,"mode":16,"min":16,"std":"9.07","range":22,"max":37,"modeval":4,"median":20,"mean":"24.33"},"81":{"p25":17,"p75":36,"mode":17,"min":17,"std":"8.77","range":21,"max":37,"modeval":5,"median":20,"mean":"24.67"},"82":{"p25":18,"p75":36,"mode":18,"min":16,"std":"8.57","range":22,"max":37,"modeval":4,"median":20,"mean":"24.92"},"83":{"p25":19,"p75":36,"mode":19,"min":16,"std":"8.43","range":22,"max":37,"modeval":4,"median":20,"mean":"24.92"},"84":{"p25":16,"p75":37,"mode":16,"min":16,"std":"9.62","range":22,"max":37,"modeval":5,"median":20,"mean":"25.17"},"85":{"p25":17,"p75":37,"mode":17,"min":16,"std":"9.31","range":22,"max":37,"modeval":4,"median":20,"mean":"25.50"},"86":{"p25":18,"p75":34,"mode":18,"min":8,"std":"9.42","range":30,"max":37,"modeval":4,"median":20,"mean":"24.67"},"87":{"p25":19,"p75":34,"mode":19,"min":8,"std":"9.19","range":30,"max":37,"modeval":4,"median":20,"mean":"25.00"},"88":{"p25":16,"p75":32,"mode":16,"min":8,"std":"9.31","range":30,"max":37,"modeval":4,"median":20,"mean":"23.33"},"89":{"p25":17,"p75":33,"mode":17,"min":8,"std":"9.22","range":30,"max":37,"modeval":4,"median":20,"mean":"23.83"},"9":{"p25":15,"p75":34,"mode":17,"min":0,"std":"11.48","range":38,"max":37,"modeval":4,"median":17,"mean":"20.75"},"90":{"p25":18,"p75":31,"mode":18,"min":0,"std":"10.35","range":38,"max":37,"modeval":4,"median":19,"mean":"21.67"},"91":{"p25":19,"p75":30,"mode":19,"min":0,"std":"9.94","range":38,"max":37,"modeval":4,"median":19,"mean":"21.67"},"92":{"p25":16,"p75":29,"mode":16,"min":0,"std":"10.23","range":38,"max":37,"modeval":4,"median":18,"mean":"20.58"},"93":{"p25":17,"p75":26,"mode":17,"min":0,"std":"8.91","range":38,"max":37,"modeval":4,"median":19,"mean":"20.92"},"94":{"p25":18,"p75":29,"mode":18,"min":0,"std":"9.62","range":38,"max":37,"modeval":4,"median":22,"mean":"22.83"},"95":{"p25":19,"p75":29,"mode":19,"min":0,"std":"9.43","range":38,"max":37,"modeval":4,"median":21,"mean":"22.67"},"96":{"p25":16,"p75":29,"mode":16,"min":0,"std":"9.91","range":38,"max":37,"modeval":4,"median":21,"mean":"21.67"},"97":{"p25":17,"p75":29,"mode":17,"min":0,"std":"9.84","range":38,"max":37,"modeval":4,"median":18,"mean":"21.33"},"98":{"p25":15,"p75":29,"mode":18,"min":0,"std":"10.19","range":38,"max":37,"modeval":4,"median":18,"mean":"20.83"},"99":{"p25":16,"p75":29,"mode":19,"min":0,"std":"10.11","range":38,"max":37,"modeval":4,"median":19,"mean":"21.17"}},"qualsbin":{"0":{"p25":13,"p75":33,"mode":37,"min":0,"std":"12.46","range":40,"max":39,"modeval":5,"median":18,"mean":"20.47"},"1":{"p25":13,"p75":35,"mode":37,"min":0,"std":"12.00","range":38,"max":37,"modeval":6,"median":19,"mean":"21.08"},"10":{"p25":17,"p75":28,"mode":28,"min":4,"std":"8.00","range":33,"max":36,"modeval":5,"median":19,"mean":"20.79"},"11":{"p25":16,"p75":28,"mode":16,"min":4,"std":"8.70","range":33,"max":36,"modeval":4,"median":19,"mean":"21.42"},"12":{"p25":17,"p75":33,"mode":17,"min":8,"std":"9.10","range":31,"max":38,"modeval":4,"median":19,"mean":"23.54"},"13":{"p25":16,"p75":32,"mode":16,"min":9,"std":"9.04","range":29,"max":37,"modeval":5,"median":19,"mean":"23.79"},"14":{"p25":17,"p75":32,"mode":32,"min":9,"std":"9.19","range":29,"max":37,"modeval":6,"median":19,"mean":"23.50"},"15":{"p25":16,"p75":35,"mode":16,"min":10,"std":"9.53","range":30,"max":39,"modeval":4,"median":19,"mean":"24.33"},"16":{"p25":17,"p75":35,"mode":17,"min":6,"std":"10.07","range":34,"max":39,"modeval":4,"median":19,"mean":"24.12"},"17":{"p25":16,"p75":35,"mode":16,"min":6,"std":"10.05","range":34,"max":39,"modeval":4,"median":19,"mean":"24.00"},"18":{"p25":17,"p75":33,"mode":17,"min":8,"std":"9.33","range":30,"max":37,"modeval":4,"median":19,"mean":"23.71"},"19":{"p25":16,"p75":32,"mode":32,"min":9,"std":"8.26","range":29,"max":37,"modeval":8,"median":20,"mean":"23.71"},"2":{"p25":13,"p75":36,"mode":37,"min":0,"std":"12.15","range":38,"max":37,"modeval":6,"median":18,"mean":"21.08"},"20":{"p25":17,"p75":32,"mode":32,"min":15,"std":"7.87","range":23,"max":37,"modeval":8,"median":20,"mean":"24.75"},"21":{"p25":17,"p75":34,"mode":16,"min":15,"std":"8.41","range":23,"max":37,"modeval":4,"median":25,"mean":"25.67"},"22":{"p25":17,"p75":32,"mode":17,"min":15,"std":"7.61","range":21,"max":35,"modeval":4,"median":24,"mean":"24.88"},"23":{"p25":17,"p75":32,"mode":16,"min":15,"std":"7.86","range":23,"max":37,"modeval":4,"median":24,"mean":"25.00"},"24":{"p25":18,"p75":30,"mode":18,"min":15,"std":"7.13","range":23,"max":37,"modeval":5,"median":20,"mean":"24.14"},"25":{"p25":18,"p75":30,"mode":16,"min":16,"std":"6.77","range":17,"max":32,"modeval":4,"median":19,"mean":"23.56"},"26":{"p25":18,"p75":32,"mode":18,"min":17,"std":"8.57","range":21,"max":37,"modeval":6,"median":18,"mean":"25.11"},"27":{"p25":18,"p75":36,"mode":16,"min":16,"std":"9.06","range":22,"max":37,"modeval":4,"median":19,"mean":"25.56"},"28":{"p25":18,"p75":32,"mode":18,"min":17,"std":"8.26","range":21,"max":37,"modeval":6,"median":18,"mean":"24.78"},"29":{"p25":18,"p75":32,"mode":16,"min":16,"std":"8.31","range":22,"max":37,"modeval":4,"median":19,"mean":"24.78"},"3":{"p25":13,"p75":35,"mode":37,"min":0,"std":"11.91","range":38,"max":37,"modeval":6,"median":19,"mean":"21.00"},"30":{"p25":18,"p75":36,"mode":18,"min":17,"std":"8.87","range":21,"max":37,"modeval":6,"median":18,"mean":"25.11"},"31":{"p25":18,"p75":36,"mode":16,"min":16,"std":"8.77","range":22,"max":37,"modeval":4,"median":19,"mean":"24.67"},"32":{"p25":18,"p75":35,"mode":18,"min":17,"std":"8.35","range":21,"max":37,"modeval":5,"median":19,"mean":"24.56"},"33":{"p25":19,"p75":31,"mode":16,"min":16,"std":"7.07","range":21,"max":36,"modeval":4,"median":20,"mean":"23.67"},"34":{"p25":18,"p75":32,"mode":17,"min":17,"std":"7.90","range":21,"max":37,"modeval":4,"median":20,"mean":"24.33"},"35":{"p25":19,"p75":36,"mode":16,"min":16,"std":"8.62","range":22,"max":37,"modeval":4,"median":20,"mean":"24.89"},"36":{"p25":18,"p75":36,"mode":17,"min":17,"std":"8.57","range":21,"max":37,"modeval":4,"median":20,"mean":"24.89"},"37":{"p25":19,"p75":36,"mode":16,"min":16,"std":"8.62","range":22,"max":37,"modeval":4,"median":20,"mean":"24.89"},"38":{"p25":18,"p75":36,"mode":17,"min":17,"std":"8.57","range":21,"max":37,"modeval":4,"median":20,"mean":"24.89"},"39":{"p25":19,"p75":36,"mode":16,"min":16,"std":"8.62","range":22,"max":37,"modeval":4,"median":20,"mean":"24.89"},"4":{"p25":17,"p75":34,"mode":17,"min":0,"std":"10.51","range":38,"max":37,"modeval":4,"median":18,"mean":"21.75"},"40":{"p25":18,"p75":36,"mode":17,"min":17,"std":"8.57","range":21,"max":37,"modeval":4,"median":20,"mean":"24.89"},"41":{"p25":19,"p75":37,"mode":37,"min":16,"std":"8.96","range":22,"max":37,"modeval":5,"median":20,"mean":"25.83"},"42":{"p25":18,"p75":34,"mode":17,"min":17,"std":"8.60","range":21,"max":37,"modeval":4,"median":20,"mean":"25.56"},"43":{"p25":19,"p75":32,"mode":16,"min":16,"std":"8.04","range":22,"max":37,"modeval":4,"median":20,"mean":"25.00"},"44":{"p25":17,"p75":32,"mode":17,"min":0,"std":"9.68","range":38,"max":37,"modeval":4,"median":19,"mean":"23.78"},"45":{"p25":16,"p75":30,"mode":16,"min":0,"std":"10.60","range":38,"max":37,"modeval":4,"median":19,"mean":"22.00"},"46":{"p25":17,"p75":25,"mode":17,"min":0,"std":"9.96","range":38,"max":37,"modeval":4,"median":18,"mean":"20.89"},"47":{"p25":16,"p75":22,"mode":16,"min":0,"std":"9.85","range":38,"max":37,"modeval":4,"median":19,"mean":"20.33"},"48":{"p25":17,"p75":18,"mode":18,"min":0,"std":"9.12","range":38,"max":37,"modeval":6,"median":18,"mean":"18.00"},"49":{"p25":13,"p75":24,"mode":19,"min":0,"std":"8.98","range":38,"max":37,"modeval":4,"median":19,"mean":"18.70"},"5":{"p25":17,"p75":32,"mode":32,"min":8,"std":"8.77","range":30,"max":37,"modeval":5,"median":19,"mean":"22.38"},"50":{"p25":24,"p75":24,"mode":24,"min":24,"std":"0.00","range":1,"max":24,"modeval":2,"median":24,"mean":"24.00"},"51":{"p25":24,"p75":24,"mode":24,"min":24,"std":"0.00","range":1,"max":24,"modeval":2,"median":24,"mean":"24.00"},"52":{"p25":24,"p75":24,"mode":24,"min":24,"std":"0.00","range":1,"max":24,"modeval":2,"median":24,"mean":"24.00"},"53":{"p25":24,"p75":24,"mode":24,"min":24,"std":"0.00","range":1,"max":24,"modeval":2,"median":24,"mean":"24.00"},"54":{"p25":24,"p75":24,"mode":24,"min":24,"std":"0.00","range":1,"max":24,"modeval":2,"median":24,"mean":"24.00"},"55":{"p25":21,"p75":21,"mode":21,"min":21,"std":"0.00","range":1,"max":21,"modeval":2,"median":21,"mean":"21.00"},"56":{"p25":21,"p75":21,"mode":21,"min":21,"std":"0.00","range":1,"max":21,"modeval":2,"median":21,"mean":"21.00"},"57":{"p25":21,"p75":21,"mode":21,"min":21,"std":"0.00","range":1,"max":21,"modeval":2,"median":21,"mean":"21.00"},"58":{"p25":21,"p75":21,"mode":21,"min":21,"std":"0.00","range":1,"max":21,"modeval":2,"median":21,"mean":"21.00"},"59":{"p25":21,"p75":21,"mode":21,"min":21,"std":"0.00","range":1,"max":21,"modeval":2,"median":21,"mean":"21.00"},"6":{"p25":16,"p75":28,"mode":18,"min":4,"std":"8.65","range":34,"max":37,"modeval":5,"median":18,"mean":"20.75"},"60":{"p25":21,"p75":21,"mode":21,"min":21,"std":"0.00","range":1,"max":21,"modeval":2,"median":21,"mean":"21.00"},"61":{"p25":21,"p75":21,"mode":21,"min":21,"std":"0.00","range":1,"max":21,"modeval":2,"median":21,"mean":"21.00"},"62":{"p25":21,"p75":21,"mode":21,"min":21,"std":"0.00","range":1,"max":21,"modeval":2,"median":21,"mean":"21.00"},"63":{"p25":19,"p75":19,"mode":19,"min":19,"std":"0.00","range":1,"max":19,"modeval":2,"median":19,"mean":"19.00"},"64":{"p25":19,"p75":19,"mode":19,"min":19,"std":"0.00","range":1,"max":19,"modeval":2,"median":19,"mean":"19.00"},"65":{"p25":19,"p75":19,"mode":19,"min":19,"std":"0.00","range":1,"max":19,"modeval":2,"median":19,"mean":"19.00"},"66":{"p25":19,"p75":19,"mode":19,"min":19,"std":"0.00","range":1,"max":19,"modeval":2,"median":19,"mean":"19.00"},"67":{"p25":19,"p75":19,"mode":19,"min":19,"std":"0.00","range":1,"max":19,"modeval":2,"median":19,"mean":"19.00"},"68":{"p25":19,"p75":19,"mode":19,"min":19,"std":"0.00","range":1,"max":19,"modeval":2,"median":19,"mean":"19.00"},"69":{"p25":19,"p75":19,"mode":19,"min":19,"std":"0.00","range":1,"max":19,"modeval":2,"median":19,"mean":"19.00"},"7":{"p25":16,"p75":26,"mode":16,"min":4,"std":"8.17","range":34,"max":37,"modeval":4,"median":19,"mean":"20.04"},"70":{"p25":19,"p75":19,"mode":19,"min":19,"std":"0.00","range":1,"max":19,"modeval":2,"median":19,"mean":"19.00"},"71":{"p25":17,"p75":19,"mode":17,"min":17,"std":"1.00","range":3,"max":19,"modeval":1,"median":18,"mean":"18.00"},"72":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"73":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"74":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"75":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"76":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"77":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"78":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"79":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"8":{"p25":17,"p75":28,"mode":17,"min":10,"std":"7.72","range":28,"max":37,"modeval":4,"median":19,"mean":"21.83"},"80":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"81":{"p25":17,"p75":17,"mode":17,"min":17,"std":"0.00","range":1,"max":17,"modeval":2,"median":17,"mean":"17.00"},"82":{"p25":16,"p75":16,"mode":16,"min":16,"std":"0.00","range":1,"max":16,"modeval":2,"median":16,"mean":"16.00"},"83":{"p25":16,"p75":16,"mode":16,"min":16,"std":"0.00","range":1,"max":16,"modeval":2,"median":16,"mean":"16.00"},"84":{"p25":16,"p75":16,"mode":16,"min":16,"std":"0.00","range":1,"max":16,"modeval":2,"median":16,"mean":"16.00"},"85":{"p25":8,"p75":16,"mode":8,"min":8,"std":"4.00","range":9,"max":16,"modeval":1,"median":12,"mean":"12.00"},"86":{"p25":8,"p75":8,"mode":8,"min":8,"std":"0.00","range":1,"max":8,"modeval":2,"median":8,"mean":"8.00"},"87":{"p25":8,"p75":8,"mode":8,"min":8,"std":"0.00","range":1,"max":8,"modeval":2,"median":8,"mean":"8.00"},"88":{"p25":8,"p75":8,"mode":8,"min":8,"std":"0.00","range":1,"max":8,"modeval":2,"median":8,"mean":"8.00"},"89":{"p25":8,"p75":8,"mode":8,"min":8,"std":"0.00","range":1,"max":8,"modeval":2,"median":8,"mean":"8.00"},"9":{"p25":16,"p75":32,"mode":16,"min":7,"std":"8.78","range":30,"max":36,"modeval":4,"median":19,"mean":"22.38"},"90":{"p25":8,"p75":8,"mode":8,"min":8,"std":"0.00","range":1,"max":8,"modeval":2,"median":8,"mean":"8.00"},"91":{"p25":8,"p75":8,"mode":8,"min":8,"std":"0.00","range":1,"max":8,"modeval":2,"median":8,"mean":"8.00"},"92":{"p25":8,"p75":8,"mode":8,"min":8,"std":"0.00","range":1,"max":8,"modeval":2,"median":8,"mean":"8.00"},"93":{"p25":29,"p75":29,"mode":29,"min":29,"std":"0.00","range":1,"max":29,"modeval":2,"median":29,"mean":"29.00"},"94":{"p25":29,"p75":29,"mode":29,"min":29,"std":"0.00","range":1,"max":29,"modeval":2,"median":29,"mean":"29.00"},"95":{"p25":29,"p75":29,"mode":29,"min":29,"std":"0.00","range":1,"max":29,"modeval":2,"median":29,"mean":"29.00"},"96":{"p25":29,"p75":29,"mode":29,"min":29,"std":"0.00","range":1,"max":29,"modeval":2,"median":29,"mean":"29.00"},"97":{"p25":29,"p75":29,"mode":29,"min":29,"std":"0.00","range":1,"max":29,"modeval":2,"median":29,"mean":"29.00"},"98":{"p25":29,"p75":29,"mode":29,"min":29,"std":"0.00","range":1,"max":29,"modeval":2,"median":29,"mean":"29.00"},"99":{"p25":29,"p75":29,"mode":29,"min":29,"std":"0.00","range":1,"max":29,"modeval":1,"median":29,"mean":"29.00"}},"complvals":{"dust":{"maxval":100,"minseq":"NNNNNNNNNNTACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAAGTGAGAGTTGAGAAGAGGCGTGGAGGAGATGACACACCCCGTGTGTTCTC","minval":2,"maxseq":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"entropy":{"maxval":81,"minseq":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","minval":0,"maxseq":"NNNNNNNNNNTACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAAGTGAGAGTTGAGAAGAGGCGTGGAGGAGATGACACACCCCGTGTGTTCTC"}},"dubscounts":{"1":{"0":1},"3":{"0":1}},"dubslength":{"100":{"0":4}},"qualsmean":{"27":1,"11":1,"32":1,"33":2,"18":1,"29":1,"17":4,"20":1},"tagprob":{"3":33,"5":33},"compldust":{"4":2,"3":2,"23":4,"100":1,"2":1,"5":2},"complentropy":{"81":1,"35":4,"77":1,"0":1,"73":3,"76":2},"dinucodds":{"AATT":"0.395437960","AT":"0.362329006","AGCT":"0.485808170","CATG":"1.073571725","GATC":"0.433830048","CCGG":"0.300572486","CG":"1.916620315","TA":"1.833186173","GC":"0.582918467","ACGT":"2.437785575"},"tail":1,"freqs":{"3":{"11":{"A":8,"T":50,"N":8,"C":16,"G":16},"7":{"A":16,"T":33,"N":0,"C":25,"G":25},"17":{"A":16,"T":0,"N":8,"C":50,"G":25},"2":{"A":8,"T":16,"N":0,"C":33,"G":41},"1":{"A":25,"T":8,"N":0,"C":33,"G":33},"18":{"A":8,"T":8,"N":8,"C":16,"G":58},"0":{"A":41,"T":33,"N":0,"C":16,"G":8},"16":{"A":50,"T":33,"C":0,"N":8,"G":8},"13":{"A":16,"T":8,"N":8,"C":33,"G":33},"6":{"A":16,"T":8,"N":0,"C":25,"G":50},"3":{"A":25,"T":41,"N":0,"C":0,"G":33},"9":{"A":16,"T":8,"N":0,"C":58,"G":16},"12":{"A":50,"T":33,"C":0,"N":8,"G":8},"14":{"A":8,"T":16,"N":8,"C":25,"G":41},"15":{"A":33,"T":41,"N":8,"C":8,"G":8},"8":{"A":50,"T":25,"N":0,"C":8,"G":16},"4":{"A":41,"T":16,"N":0,"C":25,"G":16},"19":{"A":16,"T":41,"N":8,"C":8,"G":25},"10":{"A":8,"T":33,"C":0,"N":8,"G":50},"5":{"A":33,"T":8,"N":0,"C":50,"G":8}},"5":{"11":{"A":16,"T":50,"N":0,"C":33,"G":0},"7":{"A":8,"T":33,"N":8,"C":25,"G":25},"17":{"A":8,"T":41,"N":0,"C":33,"G":16},"2":{"A":8,"T":0,"C":16,"N":8,"G":66},"1":{"A":50,"T":0,"N":8,"C":41,"G":0},"18":{"A":16,"T":8,"N":0,"C":0,"G":75},"0":{"A":50,"T":41,"C":0,"N":8,"G":0},"16":{"A":50,"T":8,"N":0,"C":16,"G":25},"13":{"A":16,"T":50,"N":0,"C":33,"G":0},"6":{"A":25,"T":0,"N":8,"C":8,"G":58},"3":{"A":50,"T":41,"C":0,"N":8,"G":0},"9":{"A":8,"T":25,"N":8,"C":33,"G":25},"12":{"A":41,"T":0,"N":0,"C":8,"G":50},"14":{"A":33,"T":0,"N":0,"C":25,"G":41},"15":{"A":8,"T":50,"N":0,"C":33,"G":8},"8":{"A":58,"T":8,"C":0,"N":8,"G":25},"4":{"A":41,"T":25,"C":16,"N":8,"G":8},"19":{"A":16,"T":75,"N":0,"C":0,"G":8},"10":{"A":16,"T":8,"N":0,"C":0,"G":75},"5":{"A":16,"T":25,"N":8,"C":50,"G":0}}}} prinseq-lite-0.20.4/example/example1_ns.png0000664000076700007670000002214212240000123020745 0ustar rschmiedrschmied‰PNG  IHDR¨ú]ôwbKGDÿÿÿ ½§“ IDATxœíÝ{|Ïõÿÿñû{Û{›ÙØÌ!‡eRŒI ¥R|RZŸŸò!}:é(‡!‰OB%R*§¤ôöQV1T|9…)gÂÈb3vz~ÿè·÷ÏlcËûµ½Þ¯n×Ëe—‹÷óux<Ÿ^o—ݽÏ—ËcØ„_ew8¶B@€­P`+TØ ¶B@€­P`+TØ ¶B@€­P`+TØ ¶B@€­P`+TØ ¶B@€­P`+TØ ¶B@€­P`+TØ ¶B@€­P`+TØ ¶B@€­P`+TØ ¶B@€­8* ¾ôÒKºêª«*»8Ž ¨k×®UFF†+»+8ލ999š8q¢\Ù]Ày ¨ìxÃäÉ“uÇw¨F%.oÓ¦çÏ«W¯®¨nàðù€ºyóf¥¥¥©_¿~¥®sz(ÍÌ̬ˆnü)„††z}Ÿ>‰ݺuÚ±c‡âã㯓'O*>>^•Ý5ü.cŒ©ìNxSûöíõõ×_—ºœ3¨ÞÃT8žãΠž gP¼‡3¨p<*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [! ÀV¨°*l…€ [qcLew¢"ýɆ `)—Ëåõ}x}6—••UÙ]pŒÐÐP¯ï“Kü°*l…€ [©Ð€šÍCJ8+Ëê„ ôÙgŸI’òóóuûí·+$$D^x¡Ö¬YcUYø8ËêË/¿¬úõëK’’““µ|ùr}ôÑGêÔ©“úöíkUYø8˦™:xð "##%I)))êÙ³§þö·¿©U«Vеª,|œegPëÕ«§¤¤$mذA)))ºñÆ%IyyyªR¥ŠUeàã, ¨C‡Õ°aÃtÙe—)&&F]»v•$}õÕWjÓ¦Ueàã,}ÕéÎ;uäȵjÕJ¿ßM°jÕ*………©Y³fV•=«ÌÌÌJ© àDV¼IÊÒ€Z(33S!!!òó«üiW ¨ÞãS¯:ÍËËÓðáé°°0íØ±C’4räHMŸ>ݪ²ðq–ÔÄÄDÍž=[“&MRpp°§½I“&š1c†Ueàã, ¨3fÌдiÓÔ£Gùûû{Ú[·n­7ZU>β€šžž®¦M›kw»ÝÊÉɱª,|œe5::Z›7o.Ö¾|ùrÅÄÄXU>β€Ú§O 0@+W®”$8p@IIIJHHГO>iUYø8Ë^uÚ¯_?=zT7Üpƒ²³³Õ¾}{kèСzøá‡­* gù<¨'NœÐ¦M›TPP ØØXKæÊ*æAðŸ¨ßN¨ÞãSõ9Rï½÷^±ö™3gêù矷ª,|œeuòäÉjÞ¼y±öfÍšiòäÉV•€³tÔ:uêk¯[·®|¸ÈPË.ñ»\®³.·xò€Rq‰À{¬¸ÄoÙCR©©©Vífù<¨vÃTïñ©‡¤N—™™©‚‚‚Š(gY@ÍËËÓðáé°°0íØ±C’4räHMŸ>ݪ²ðq–ÔÄÄDÍž=[“&MRpp°§½I“&š1c†Ueàã, ¨3fÌдiÓÔ£Gùûû{Ú[·n­7ZU>β€šžž^â[¤Ün·rrr¬* gY@ŽŽÖæÍ›‹µ/_¾\111V•€³, öéÓG ÐÊ•+%IPRR’ôä“OZU>β‰úûõë§£Gê†nPvv¶Ú·o¯àà` :T?ü°Ueàã,Ÿ¨ÿĉÚ´i“ kÉd®åÁDýÞcE¶³, fddœuyxx¸eω€ à=VTË.ñGDDœuùŸì «(#Ëjjjj‘ÏúñÇ5qâD=÷ÜsV•€³üÔ3ÍŸ?_¯¾úª.\X‘e=8s à=.—Ëûû¬è€ºsçN5oÞ\ÙÙÙYÖƒ{P¼Ç§îA=|øp±¶ôôt9RQQQV•ýÓ7®ø—cð`Â8ð=–ÔZµj•Ú>{öl«ÊÀÇUØCR.—KÕªUS‹-äv»­* gY@mÕªU‰íYYYÅÚ*kNTØO¥Íƒz:ž¬@!Ëê¬Y³4pà@Ýÿýºîºë$ý~ÙæÌ™š0a‚4h`Uiø0ËjRR’F­Þ½{{Ún¾ùf]rÉ%úðÃ5oÞ<«JÀ‡ùYµã¥K—ê/ùK±ö®]»jñâÅV•€³, †„„hãÆÅÚׯ_¯«ÊÀÇYPÿñ衇Òû￯½{÷jÏž=š5k–z÷î­ûî»Ïª²ðq–݃úâ‹/*77W=ôrrr$Izì±Ç4vìX«ÊÀǹŒÅs<;vLiii’¤˜˜U«VÍÊrç”™éÌ×òªSPBC‹góeÙÔBÕªUSóæÍ"??Ëî(€CX–óòò4|øpEFF*,,L;vì$9RÓ§O·ª,|œe511Q³gÏÖ¤I“ìioÒ¤‰f̘aUYø8ËêŒ34mÚ4õèÑCþþþžöÖ­[—8ý YPÓÓÓÕ´iÓbín·ÛóT?p&Ëjtt´6oÞ\¬}ùò劉‰±ª,|œeµOŸ>0`€V®\)I:pà€’’’” 'Ÿ|Òª²ðq–M3Õ¯_?=zT7Üpƒ²³³Õ¾}{kèСzøá‡­* gùDý'NœÐ¦M›TPP ØØXK&s-&ê🜨?$$DmÛ¶U~~¾òòò¬.çõ{P¿øâ Íž=»HÛ„ ®*Uª¨[·n:v옷ËÀ!¼PÇŒ£ôôtÏçÕ«WkРA2dˆæÎ«íÛ·ë¹çžóvY8„×ê¦M›Ô¡CÏç9sæ¨sçÎ1b„þú׿ê•W^ѧŸ~êí²p¯ÔŒŒ Õ®]Ûóù»ï¾+X[¶l©½{÷z»,Âë5<<\ûöí“$åååiíÚµºüòË=ËOž<©€ËŸÍ€òz@½îºë”˜˜¨]»vé•W^‘¤"gP7lØ Æ{»,Âë§2ÇŽ«N:©Q£Fr¹\zõÕWæYþÑG©}ûöÞ. ‡ðz@½ä’K´mÛ6­[·NuëÖUÆ ‹,ïÛ·¯.ºè"o—€CXr3hpp°ÚµkWâ²k®¹ÆŠ’p¯ßƒ œ*l…€ [! ÀV, ¨áááÚµk—•%à0^¨Ë—/Wvvv±öÐÐPmÛ¶ÍÛåà0^¨½{÷Vxx¸Úµk§'NhÅŠ:uê”·ËÀ¡¼Púé'íÙ³GO=õ”üýýõÜsÏ)22R'NœÐôéÓµråJåææz»,Â’€Z§NÝyç ÒÂ… •––¦   ¥¥¥éž{îQxx¸·ËÀ!¼þ&©6mÚ(88XqqqÊÎÎÖÏ?ÿ¬.]ºÈßß_ãÆÓÅ_¬ÿýïÞ. ‡ðúÔŒŒ }õÕWêÚµ«\.—ºwﮨ¨(wêÔ©ÄõZ·nM;í´ÓN;í´ÓN»Û½ÉQõÎ;ï44Æ“žžnîºë®JéGE8êR—ºÔ¥.u©K]§rÔ=¨qqqZ°`$iþüùŠ‹‹«ä ¼\ÆSÙð–cÇŽièС:räˆjÖ¬©±cÇ*,,¬²»€rpT@€ïsÔ%~ø>GM3õg4eÊ¥¤¤(==]ß}÷]‘eN{³ÖêÕ«5~üxåççËÏÏOC‡Õe—]&Éyc-ôá‡*99Y.—K’Ô·o_]sÍ5’œ;fIz饗”œœ\ä;íÄñÆÅÅ)::Z’tÏ=÷¨[·n’œ9ÖBS¦LÑâÅ‹eŒÑ]wÝ¥»ï¾[’sÇ<~üxÏT‡'OžÔÑ£G•ššêÈñ.[¶Lo¼ñ†$Éår©OŸ>êСƒ$gß­[·*11QyyyŠŠŠÒ¨Q£"É™ã­p•úˆÎÛÆÍ¡C‡Ìµ×^[lÙøñãÍ»ï¾kŒ1æÝwß5'N¬èîyÕ¶mÛÌ‘#GŒ1ƬY³ÆÜ~ûížeNk¡¬¬,ÏŸwìØaºtéâùìÔ1ÿðÃæ™gž)övâxKúwkŒ3ÇjŒ1Ÿ|ò‰yöÙgM~~¾1Ƙ£Gz–9u̧›3gŽILL4Æ8s¼]ºt1Û·o7Ƴk×.sã7z–9q¼½zõ2ß|ó1Ƙo¿ýÖ¼öÚkžeNoEã¿kÑ¢…çåg*íÍZ¾ªqãÆªQ£†$éÒK/Õ‘#G<Ëœ6ÖB…ÿ—¤'N¨N:žÏNsNNŽ&Nœ¨Áƒ[æÄñ–Æ©c;w®xàùùýþ«'<<̩ܳc>Ý—_~é£ÇÛ AÏËpŽ?®zõêy–9q¼»wïÖUW]%Ij×®]‘19q¼KüVÚ›µœ`Þ¼yžKÝ’³Ç:gÎÍ™3GÙÙÙš:uª§Ý‰cžÿüóêÝ»·\.—Œ1š6mšg™ÇÛ¸qc-Z´H7Ýt“-Z¤x–9q¼3¨ð9[·nÕ¬Y³”PÙ]©ÿûßõÉ'Ÿ¨_¿~zñÅ+»;–Ù¼y³ÒÒÒtë­·VvW*LJJŠ’’’tÛm·iÔ¨Q•ÝËåçç«aÆš3gŽn¿ýv9²²»Ta.\¨Î;{Î;ÑK/½¤~ýúéóÏ?×€ôòË/Wv—,5bÄÍ;WÝ»w×¶mÛäïï_Ù]rçþKjÕª¥ôôtIÒáÇU³fÍJîÑù;xð žyæ3¦È­ N뙺víªüÑóÙic^·nvìØ¡øøxÅÇÇëäÉ“ŠWAA$çW’"""$I7Þx£¶oßîiwâX%é‚ .P—.]$I;wÖÏ?ÿìYæÔ1:ýò¾äÌñ®]»V;w–ôûñ]¿~½g™Ç{ÑEiêÔ©úàƒtë­·ê /ô,sâx+ÕÁœöf­¬¬,%$$hÀ€jÖ¬Y‘eNk¡ýû÷{þ¼|ùrÏ%`ÉycîÙ³§,X ””¥¤¤(88X)))ž3NNoFF†Ìÿ›†ú›o¾QÆ =Ëœ6ÖBqqqZµj•¤ßgå8ýºSÇ,I;vìЉ'Ô¢E O›ÇÛ AÏñýî»ïT¿~}Ï2'Ž÷·ß~“ôû­:ï¼óŽâãã=Ëœ8ÞŠÆDý>nÒ¤Iš?¾ÒÓÓU«V-Ý|óÍzòÉ'%9ïÍZ³fÍÒÔ©S=÷¬IÒûï¿/???ǵИ1c´nÝ:c^ä>E§Ž¹Pûöíõõ×_{>;m¼ ,ÐŒ3$IÁÁÁúç?ÿ©&MšHrÞX effjĈÚ·oŸÜn·ž}öYÇY’Þzë-côÄOxÚœ8ÞM›6é…^PNNŽ5|øpÅÆÆJræx?þøcÍž=[þþþêСƒúôéã™Љã­hTØ —ø`+TØ ¶B@€­P`+T8ÃÔ©SÕ¨Q#ùûû{¦AÅXºt©\.—222J]gÔ¨QêÕ«WöªrµnÝZüqew¨PTÀf AþÔ¨QC={öô¼•ÄW”%hØÑ¾}ûôøãëé§ŸÖÞ½{õË/¿”¸^áø.¿ür>[ß™ã.üì+ïâ>óûW½zuuíÚU›7o®ì®I’~ýõW7Nÿüç?‹´?òÈ#ºúê«Vîï]Y¶}å•WÔ¨Q#éÒK/Õܹs˽Nrr²7n,·Û­+®¸Â3©½$åææêÒK/Urrr±ý6L#FŒ³BâÏ„€ ØÔ¦M›ôË/¿hþüùÚ°aƒî»ï¾óÞg^^žzælÛ·oWAAºwï®zõêé‚ .8ëúiiiúôÓO+¨wÞu¶ïCá÷/55UºãŽ;*°g¥{ûí·«˜˜˜"íùùùêÞ½»FŒQî}žkÛI“&)11Q/¿ü²~úé'=òÈ#ºûlÙ²2¯sèÐ!õìÙSwß}·¶lÙ¢F©{÷îžíǧ‹.ºHwÞyg±úñññ:xð -ZTî±>˰•ÔÔT#ɤ§§{Ú>üðCãïïorrrÜ4hÐÀ¸ÝnÓ¤I3}úô"뜭ß%§¾}ûšV­Z™‚‚‚"í…ý<óxNž<ÙDEES¯^=3~üøRû[¸í¢E‹ÌÕW_m‚‚‚Ì…^h^ýõbëþÑïCi5Oÿþ-X°ÀH2ÙÙÙåªy®ãœ››k ä9ÎñññfÖ¬YÅŽó鮸â 3vìØsþ•¶ýÙ”´mAAiР=zt‘u{ôèaºuëVæu¾ùæ#ÉìÝ»×cÌüùó$“••e¶mÛfjÕªeöìÙSjßzôèa|ðÁr ðUTÀfJ Ÿ~ú©q¹\æäÉ“Æcž}öYÓ´iS3þ|³wï^³hÑ"m† Vl?­Zµ2K—.5»ví2éééfÈ!&""ÂÌž=ÛìÙ³Ç|ÿý÷fæÌ™žíʳ︸8³råJ³eËÓ®];sÝu×yÖINN6’ÌÖ­[Í/¿üb~ùåϲ÷Þ{Ï,^¼ØìÙ³Ç,]ºÔ´hÑÂôêÕ˳ü±Ç3uëÖ5Ÿþ¹Ù½{·yûí·M:uŠ„‡²ôóLO<ñ„©U«–™7ožÙ½{·™6mš 23fÌ(S¿K:NÛ¶m3fîܹEÚK ¨;wî4.—ËŒ3ÆìÚµË|ÿý÷fÞ¼y¥ö·pÛ‹/¾ø¬}>ŸïCi5 —edd˜{ï½×4kÖ¬Èze©y®ãܯ_?S»vmÏØ¦L™bjÖ¬YjÀ0&77·È:e sçÎ5U«V5æ·ß~3n·ÛÌž=»È:C‡õ쯬ý<]FF†q»Ýæ½÷Þ+Ò>dÈOP(O¿O?N‰‰‰ž³¨gÛþûï¿7’ÌúõëϺï3k”Ô瘘cÌù}ÎV³jÕª¦jÕªF’iÒ¤‰Ù¶m›g?ò÷oLñãXllƒ.õïï‡~0’ÌÏ?ÿ|Îþ{+ ®X±ÂH2û÷ï/²îÂ… $sâĉ2­cŒ1Ÿ}ö™iÕª•©S§Žéر£Ù¸q£™5k–iÓ¦Yµj•‰‹‹3QQQ¦[·nfß¾}Eö•œœl\.W‘«(€“q*`SÑÑÑ UíÚµ•••¥wß}WÒï÷fgg«K—. õü<øàƒúõ×_•™™Yd?­[·öüyË–-:uê”®¿þúk–wß±±±ž?×®][yyyÊÊÊ:çØ¾ýö[uîÜYµk×VXX˜zô衬¬,effjË–-ÊÍÍÕ5×\Sd›öíÛÿá~J¿ß+š››«Ž;iïØ±£¶nݪS§N³ß¥éß¿¿vïÞ­O>ùä¬ëµjÕJmÛ¶U‡tï½÷ê£>R~~þ9÷_RŸÓÒÒtêÔ©óú>œMjjªÖ¬Y£7ß|S;wîÔúõë=ËÊZólÇ9--M999ÅÆÖ©S§RûT¸ßÐÐÐ2át§÷ól_–ÙεN·nÝ´víZ8p@K—.U½zõ4dÈMš4I·ß~»âããµk×.U«VM<ð@‘m«U«&cL‰ßmÀ‰*»J–ššª5j(<<\‘‘‘žö‚‚IÒ‚ J|€'$$¤ÈçÀÀÀ2×,ï¾ýüŠÿלãI㌌ ÝtÓMºãŽ;4jÔ(Õ¬YS+W®Ô}÷ÝW$¬ùËþôÏåí§ÕªW¯®„„9RãÇ/u½€€}ûí·úòË/µ`Á=úè£JJJ*ñ‰ðÓ-øXõ}hÔ¨‘jÖ¬©¦M›jëÖ­JHHP||¼Ünw™jþÑã|6…Áòøñãç|xíLëÖ­+×ú…êÖ­+IÚ¿‘šû÷ïWõêÕU¥J•2­S’§žzJ÷Üs´oß>õêÕK~~~êÙ³§n»í6åææÊívK’Ž;&—Ëõ‡Â5à‹¨€M„3ÅÆÆ*88X{öìѵ×^[®}6kÖLAAAZ²d‰î¿ÿ~¯îûLþþþ’þ€*´yóf?~\£FRTT”$y >&&Fn·[ß~ûm‘§œ¿þúëóêg³fÍäv»µlÙ2Ý{~öeË–)&&FAAAåäiú÷ï¯ &œó,ªÛíÖ-·Ü¢[n¹E;vÔÝwß­ìììRCLaOŸ÷sùòåž>{ó˜•fàÀš4i’>þøcõèÑ£L5Ërœ‹méÒÑ £’ IDAT¥¥öãâ‹/–ËåÒîÝ»uÉ%—”k _|q¹Ö/Ô°aC5hÐ@ .ÔW\ái_¸p¡gìeYçLË–-Sjjª~üñGýøã’~ŸjJ’rrrTPPPäßÎîݻըQ#O`œŽ€ ø˜ÐÐP :T}ûöU~~¾:tè ÜÜ\­Y³F[·nÕ¿þõ¯R· Sÿþý5hÐ U©REqqq:xð 6mÚ¤ûî»ï¼ö}¦† J’æÍ›§nݺÉår©fÍšŠŽŽ–¿¿¿^ýu=ñÄZ·n^{í5ÏvÕ«W×C=¤ªZµjjÑ¢…–,Y¢wÞyG’÷Î{>÷3wyç.ïIrÇà¡~wÁC’ Ï‘dÀs$™ðI&|¸–-[¦¬¬,M:Õu ¯­X±Bݺu ýí8Ž222ô»ßýN;vì$ýþ÷¿WíÚµµtéRMŸ>]RåŸY±Š^÷øãë¿ÿû¿µlÙ2ÝxãzüñÇ+íßîÝ»µ{÷nuìØÑóþÏ×¢E -]ºT¿úÕ¯B¯—*ÿ¼Îœ9£Ö­[kÉ’%êÔ©“üqýèG?Ò /¼ ¿þõ¯jÛ¶mD1*êcEËމëTUÛhe}ž>}º~õ«_iéÒ¥jÑ¢… +|ʶÇH?ûp¸\†kÚ´©êÖ­«7ß|SuêÔÑùçŸvÞ¤¤¤P2wå•Wjß¾}¡iyyyzðÁ#Ž»sçNÍš5KP­Zµôõ×_‡¦ýö·¿Õ­·Þª””M˜0¡\?Ú´i£hß¾}:xð 4hŠ_YÜH½ûî»Ú¹sgèï‚‚×1¼´}ûv-Y²Dóçϵ­\¹R5ÒªU«4eÊ”°—(+ûÌ*³yóf=òÈ#’¤~ýú•;[UÖÚµkÕ»wïЙìXôï†n¨°?U}^×]w]è÷ 6èþûï½w½zõªŒí–dÚ:%U½VÖç²ëÇc=Vá{T¶=Vw\I2À ÐC=¤»îº«ÒùjÔ¨¡ZµÊïÚOœ8¡#GŽ(---â¸÷ß¿²²²Ô¾}{†‘¤Ã‡ëرc:}ú´Nž<©óÎ;¯Üë{÷î­×_]û÷ï%UÅ-Ëq%%%éÌ™3:sæL¨½¨¨H‹-R:u*xسg&Mš¤©S§–ßFI:›xUv¶6Ügæµ5kÖèü£/ý«ìóªY³f©û “’’\LjuýTÙ6êEŸ+Û«;®\. ôêÕKÇWïÞ½£zýÆC—I#{ìØ15mÚT’ôâ‹/ÊqœÐ´‡~Xÿó?ÿ£~ýúé©§žªð=¯¿þz­]»V¯¿þz©ø•Å-©Y³f¡ûÃÖ®][*ÉìܹsèI¡Ë½ñVPP ñãÇkܸq¡Ëº’tèСÐr½ýöÛjÑ¢EhZrr²Nž<éú½Ê¾®C‡¡ûõV¯^­öíÛ‡}í矮cǎ骫®ŠYÿ$…ú³fÍuèÐ!ÔîæóêÒ¥‹þþ÷¿K:ûOFñÙ¹h?óH—Ç”uª¬Ê¶ÑÊú\rýX³fMØí,Òí1$™`ºuëê׿þµêÖ­ÕëËÞIÜ1cÆ„.‹÷Ýw¡³M+V¬PJJŠúöí«_ÿú×úè£ôÞ{ï•{ýÅ_¬‚‚5kÖ,ôpLeq˺뮻4iÒ$Ýzë­úúë¯KÍ7a½ûî»gÎ 4¨Ô“†Åöîݪ1–ššªüüüд’¥7Š¿b fŠk’¹uëVmÛ¶McÇŽuýÚ’‰åÑ£G½ì@B«_¿¾ç1ãz¹|óæÍúüóÏ5pà@ 8P'NœÐÀUTT$IJKK }eQ~~¾RSSãÙ=xÄ×FeË<ñÄJMMÕ­·ÞªÅ‹ëÀ7n\¹×q&À;֟ɬÊÈ‘#CßB°aÃ1Âï. VcçL&€w&Á@’ ÏŽNf¬åäÔWJÊÙ;ºu+¨²`·ûyÓÚD¸$3%Å©pc×°‹Ûý¼ií@¢àr9<ÇÓå Ž§Ë`’Lx.pIæúõõ\µìâv?oZ;(÷t9Ø®drRòéäpí`"’L0P¸$’ä€-w¹þ£„fýúzž± ×Õ‹F$™ Ž:™°Bà’LJI@°™V’ˆãP±À%™`;’A`m £œœúJI9{;iun„‡voÛÄŽiÛ;û“Ê™6ž¦´OŸ^þžÀ®]åå%UØ^Ë”þ¥ÝKÖ&™))Ž'ƒ.íÞ¶ˆÓ¶wö'•3m0I&€˜!©ƒÉx ˆ-’LË™ö41;a úLÛŽØÞ$n×[ÓŽ§6¯I2^­ä¦mŒ6mì^0­ÿ|.`.’L1CR‰ËʧËQºäB^ÞÙß33†m÷‹iýtÛ¿ÚMcÂø3ás)™ —¼Ô«vÄVUŸoÙÏ–í•ãsŒ?’L‹•-¹P|Àª¨½x§éÇÓ¸núnûãW»iL?ÚK®ß±ÜfLK8ƒø VUŸo$óÃ>Ñ|ަU±©z—Ëa7"PI&%p–ðIf‚ái\ úb}¹Ê´íˆí‰Ì´ª#6¯I2a7"PI&˜L܈€Ê„ÛîܶûÅ–~z%¨Ë…è°>T—Ëà9’LH²«$à7Μ0­ô‰Çk_’Ì^xAC† ÑСC5tèP­_¿>4íÈ‘#=z´†ª1cƨ €6Î1q#åù’dþìg?Ó²eË”­©S§*+++4mÁ‚êܹ³²³³Õ©S'-\¸Ð. |yð§nݺ¡ß;¦óÏ??ôwnn®fÍš%Iêß¿¿F¥±cǪcÇŽ’¤Ÿýl£’’Jß|[ü7íîÛëÕ«Wî÷póDÛnZ?MÚíj/^—^}5I}ú”긢v“úO;í´›u<2±ÝK¾=]ž­ììl?~\óæÍ µïÝ»Wiii’¤ÔÔTåççK’6nÜ(Iš’dÂ*$½Ø$ž#É€çH2!É®’Ø&<]žà**¡™yÔ³v¯”ŒŸ—W¿Â÷¤ÄI&Ê•2(~XÆ«vÓú bËå1–ˆ':H2à9’LxŽ$ž#Ɉ±D,aD’ Ï‘dÀs$™1F #À$™ðI&zô¨êÖ­«5ÈUÊš>½~¹¶ÌÌ£>ô$þ\g‡§OŸÖÿøG5iÒD 4ÐçŸ.Iz衇´`ÁÏ;`³®]Д8åŒ\'™YYYúë_ÿª™3gªN:¡öË.»L‹-ò´s°“ë$sÑ¢Eš?¾n¾ùfÕ¬Y3ÔþãÿX|ð§€\'™ûöíS›6mʵ'''«°°Ð“NÀn®“Ì–-[jëÖ­åÚßzë-]~ùåžt vsdÞyç7nœòòò$Iß~û­–.]ªñãÇkôèÑžwöq]ÂhìØ±:xð ®»î:?~\Ý»wW:u4qâDýö·¿E`WIæ©S§´fÍ=Z&LÐG}¤¢¢"]y啪_¿|($&WIf­Zµ4hÐ }òÉ'JMMU§NbÕ/XÌÕ=™IIIj×®vîÜ£î \?ø3eÊ7N/¿ü²vïÞ­üüüR?€ë  I8p`…ÓÇ©^`=×IfNNN,ú€qdöìÙ3Ý@¸N2K:yò¤$©víÚžt*òüóY’¤¯¾’ºv}°Êv€ÿ¢J2ŸyæM›6MÛ·o—$]~ùåš8q¢n»í6O;’4lØÙ2//I’Se;À®“Ì hôèѺ뮻tíµ×J’Þ|óMÝqÇ***Òo~óÏ; »¸N2üqÍš5K#FŒµõïß_—^z©¦M›F’ ÷u2wìØ¡>}ú”k¿þúëµcÇO:»¹N2›6mª-[¶”kß²e‹Î?ÿ|O:»¹N2o»í69RK–,Ñ—_~©/¿üRK–,ÑÈ‘#õë_ÿ:]€m\ß“™••¥C‡iĈ:uê”$)99Y¿ÿýïõÀxÞAØÇu’Y«V-Íš5K<òˆ¶mÛ&IjÛ¶­6lèyç$ê^@pD]Œý{ßûžºtéâe_$8ê^@p¸¾'ó¡‡Òâŋ˵?ûì³zøá‡=éìæ:Éœ3gŽ®¸âŠrímÛ¶Õœ9s<éìæ:ÉÜ·o_…¥Š~ðƒhÏž=žt vsd6oÞ\¹¹¹åÚsssÕ¼ysO:»¹~ðç·¿ý­F¥ãÇë§?ý©$é7ÞÐÝwß­ &xÞAØÇu’ùÿþßÿÓþýûuÇw¨°°P’T»vmÝu×]$™Œ®R¢µ0_·_×If54}út=øàƒúøã%IW\q…êׯïyç áJ!%Z;óyûºNfƒ Ô¹sgIÒñãÇå8Ž’’’<ëìåúÁŸ?ÿùÏzùå—%IgΜÑM7ݤºuëꢋ.Ò¦M›<ï ìã:É|üñÇuÁH’–/_®·ÞzKûÛßÔ«W/3ÆóÀ>®/—ïÙ³GMš4‘$­\¹Rúå/©:èÊ+¯ô¼ƒ°ë3™?üáµtéR½ÿþûZ¹r¥n¸áIÒéÓ§uÞyçyÞAØÇu’9qâDÝ{ï½jß¾½.¿ürõíÛW’ôÚk¯©cÇŽžwöq}¹üÎ;ïTÿþýµÿ~uèÐAµj ѹsg]wÝužw ×ß‚.uq£*aÔªU+µjÕªT[q9#€‚\º ÔÅu}¹¨ I&<õ7þDkãÆzâ‰'tæÌÕ¨QC'NTûöí%IGŽѤI“”ŸŸ¯´´4=ú裪W¯^¼»€jr}&sìØ±zÿý÷£~ÃFiæÌ™Z¶l™þð‡?(+++4mÁ‚êܹ³²³³Õ©S'-\¸0ê÷€\'™›6mRûöíÕ©S'Í;Wß}÷«×·nÝZ7–$µk×Nû÷ïMËÍÍ •Dêß¿¿Þ~ûíдŽ;†J$%%%…~Šÿ¦vÚi§vÚi§=úv¯¹¾\¾~ýzmß¾]‹-RVV–î¾ûnýò—¿Ôˆ#Ô£GW±V¬X¡nݺ…þÞ»w¯ÒÒÒ$I©©©ÊÏÏMÛ¸q£$iòdÉqJ>M•ô'ÑN;íaÚŸ/WòÂÌvÓÆ-¨í¦}î¬'vµ›¶>°¾y×îÉlÓ¦¦M›¦GyD«V­Ò¢E‹tÝuשU«V1b„n¿ýöP²ÎöíÛµdÉÍŸ??ªŽˆœÛR~µ#>LûÜYOìbÚúÀúf®j=]^XX¨Ã‡ëðáÃ***Ò…^¨gžyF-[¶ÔóÏ?öu{öìѤI“4uêÔRÉhZZšöíÛ'IÊÏÏWjjjuºŸD•dnذAwÜq‡š5k¦ &èšk®Ñ'Ÿ|¢7ÞxCÛ¶mÓ´iÓt÷ÝwWøÚ‚‚?^ãÆSÛ¶mKMKOO×êÕ«%I«V­Rzzz4Ý€Ï\'™W]u•ºuë¦]»viñâÅúòË/õÈ#èâ‹/Í3dÈÐɲþñ諯¾Òœ9s”‘‘¡ŒŒ I’FŽ©wÞyGC† ц 4bĈ( ~r}OæàÁƒuûí·ë / ;OZZZ™›JÏ>|¸†^á´† jöìÙn»øN2xàXôâúryRR’¾ýöÛríùùù1«³»xöµ’Žã¨F û¾ ½|],3ãW'//IëÖMÍ“™™©¼¼úįFüpŸW¬ûï¶?^̶LÇ9ݺxÚâ?VñÝl§áÚ+Û~cß-ÛãWĦõ3ÖÇ—ŠÄz|Üö'Z'™‡ ýþÝwß©N:¡¿‹ŠŠôÊ+¯èüóÏ÷¶wqëºX^Å/'3󨤳+F·nÕí&ñÃĉWÿÝö§ºó÷ýúz1é?ñ‰ËøÕ­XÕöëønÙ¿,¿×·b}|)+Öãã¶?Õq’Ù¨Q£ÐïmÚ´©pž?ýéOÕï¬q’™““#IêÕ«—–/_úþqIªY³¦Z¶l©æÍ›{ßCT*–ÿåßÿø±fûøŸøÄ'>ñÍq’Ù³gOIe¿7(/¢$3??_Mš4QRR’òóó+—¯‚@Dƒ§¥¥iÏž=¡ß+ûA|­__øŽk¶ñ‰O|âß\ÉÌÉÉ ÝƒY|o¦ml)UT‘²¥ ªÓŸp¥ˆ^<ú_²F$Ëëþ»AüøÄu?ýzßDŒoûþÓDŒï×þÙmé­xˆ(É,¾³ìï6±¥TQYÑ–2p[jƒø‹WÿK—Â(P·nªð}‹ë¤™R ƒøñ‰.Ž×uó"}_âW/¾íûÏH%j|¿öÏnKoÅCÄ÷dFŠ{2Q’éæ^Kž>/ÛK(ß_¶ñ‰O|âß\ß“ Ù¾2?ºø^½oPÇ'Ñâûuбe|ˆO|â›Åõ=™@U"*aTÇqtäÈ:t¨ÔâËö Ä÷—íãC|âŸøÄ7—ë$óàÁƒ6l˜4h † ªQ£F¥~¶¯ÌÄ.¾WïÔñI´ø~tlâŸøf‰øk%‹Ýyçúè£ôüóÏëæ›oÖܹsµgÏ=õÔSzøá‡cÑGWl®‡éUü²u·ºu+ˆy©“pïK|â?¶¼z_ÛLJøÄ'~éøñ8îWÅu’ùÊ+¯èå—_V÷îÝU³fMuíÚU—^z©.½ôR=ýôÓºõÖ[cÑψÙZÓ«ø±®æ×ûŸø‰?Öïkûøߌø±”ñ±5~u¸¾\~âÄ µlÙR’tÞyçéÀ’¤:è_ÿú—§CÕlêøþ²}|ˆO|âŸøærd¶mÛVŸ|ò‰$éꫯּyóôÕW_iöìÙÜ“CnW¶XÏï6ñ£‹ïÕçÔñ!>ñ‰oN|·ïëUâ{ÇK®/—?^»ví’$eee©_¿~Z´h‘jÕª¥ xÞAØÇõ™ÌÛn»MÇ—$ýä'?ÑW_}¥õë×ë‹/¾Ðm·ÝæyQ9ÛŸz#¾¿lâŸøÄ'¾¹\'™ÕżâŠ+T·n]êdÆÛ•-Öó»Cüèâ{õ9u|ˆVNN}­__¯Üô¤ ÛÝÆ·}|ˆŸøáxµ~†‹cËøØ^ª.®/—Wuße¼¾»Ü†RB~ƯHÙ~Ç!>ñ‰ïMü”§Âû±*j7±ÿÄv|¯ÖÏpqÜ0q|üˆë~sd–ýó¢¢"}øá‡š1c†&OžìU¿ªdz)!¿ã—E©â?¸ñ#} ÀÔþß®øn¹]?ÝÆ‰TPÆ?vÇqïëjºN2+úóŸþô§ºä’Kô—¿üLo¡ÖùIDAT%t¿&âÖ§‰o&ÛLJøþ²}|ˆïoüX³}|l©ß]^VÛ¶m©“C”0JÌø”0"~,â¸oûø?>ñýbËøØ¾ˆ†ë3™ùùùåÚöíÛ§‡zHÍ›7÷¤Sˆ[VfâŸøÄ'¾™ñmgûøÛr—¢8“™––VîçŠ+®Ð믿®§Ÿ~:}D%l/¡@|Ù>>Ä÷—íãC|ãÇšíãcûøKQ$™999¥~Ö­[§ÿûßÚµk—®»îºXô¢„Q¢Æ§„ñcÇm|ÛLJøñ‰ï[ÆÇöýC4\'™={öTÏž=•žž®k®¹F×^{­þë¿þKÉÉɱè¬ßÿþ÷ºúê«%I[¶lÑœ9sôòË/+//O›7oÖ¦M›”™™³N‘×õñ¼B|ãÇšíãC|Ù>>Ä÷7~¬Ù>>¦×DÄIæ”)S”œœ¬>ø@õëŸ+ØÙ¯_?5J½zõÒ/~ñ ½óÎ;š?~L:›È(a”˜ñ)aDüXÄqßöñ!~|âûÅ–ñ±}ÿˆ“Ì¿ýíoš7o^©³XÆ õÈ#¨oß¾š2eŠn¹åO;™HLÿÏÈë8Ä'>ñ‰O|»âÛÎöñ7íäCe"¾'s÷îÝjÛ¶mØémÛ¶U5tß}÷yÒ1DÆ–Œ‰o&ÛLJøþ²}|ˆïoüX³}|lÉE’Ù¨Q#íÚµ+ìô¯¿þZM›6õ¤S(F‰ŸFÄE·ñmâÇ'¾_lÛ÷ш8ÉìÛ·¯}ôQ9ŽSnZQQ‘¦Nª¾}ûzÚ¹DdËF¶ô“øÄ'>ñ‰’lÓN>T&â{2³²²Ô©S']ýõºûî»Õ®];IÒû￯ÿýßÿÕû￯7Ƭ£ÕQüè~¤í±ŽïÕû˜*â$³eË–ÊÍÍÕèÑ£5`À€Ðͤ¤$õéÓG¹¹¹jÑ¢EÌ:­pðwë¦ ÛóòÊ?ØäeüpíÑ2ícâÛÅöñ!¾¿lâû?ÖlÛÇ_r‘dJÒ¥—^ª5kÖhÿþýúôÓOCm7ŽIçp%Œ3¾iOßÌø^ êø?>ñýbËøØ¾ˆ†«$³X“&MÔ¤I¯ûÙóŸ‘-ý$>ñ‰O|â£$ÛÇß´“•qýÝå¶2í?¯Þ×´Œ‰oÛLJøþ²}|ˆïoüX³}|l)’LÛQÂ(1ã›ö!ñ͌Žñãß/¶Œíû‡hdÆ–ÿŒlé'ñ‰O|â%Ù>þ¦|¨LÂ$™¦ý‡ÂN@8……IZ¿¾^¹ýD¸v0QTþø­lÉnÝ ”—W¿Âvã{É´Œ‰oÛÇ'¨ñ{õ:êªÝ/AâÇ'~¬Ù>>¶¿da’9y²tôèÑru&ÃÕ«t+\¯âG‹F‰ß´§‰ïoüX³}|ˆïo|¿Ø2>‰XÂ(É©è{" WQ’YÌöv€x«_ßÝ—ÑDÂÚ{2½:#dZ»[¦Ý`L|»Ø>>Ä÷—íãC|ãÇšíãcûøK'™‰†F‰ß´§‰ïoüX³}|ˆïo|¿Ø2>”0‚ïlùÏÈ–~Ÿø6Æ5ÛLJøþÆ·íãoÚɇÊX›dzuFÈ´vH4”l‚ɺ§ËQší%ˆï/ÛLJøþòªÿ))N…±b]²ÉöÏ×öø±fûøØ>þ’Åg2 %Œ3>%ŒˆO¶ñýï[ƇF– „€w(aT‚i¥‡(aD|Ù>>Ä÷ý'¾ÉlÛÇ_²8ÉL4”0JÌø¦=EH|ãÇší%Vlÿ|mï[ÆÇöí+$™†±å?#[úI|âÛ?Ölâûßv¶¿i'*cm’iZé!Jœcm’‰³l/¡@|Ù>>Ä÷ý'¾ÉlÛÇ_"É´%Œ3>%ŒˆO¶—X±ýóµ=¾_lÛ·¯hPÂȰv€x£„Q ¦•¢„ñmdûøß_ôŸø&³}|lÉâ$3ÑPÂ(1ã›ö!ñýk¶—X±ýóµ=¾_lÛ·¯hø’dÎ;W?ûÙÏÔ¥K—rÓŽ9¢Ñ£GkèС3fŒ ë’²-ÿÙÒOâ߯ø±fûøßßø¶³}üM;ùP_’Ìnݺé™gžQJJJ¹i ,PçΕ­N:iáÂ…Æ0­ô%ŒÎ©åÇ›^uÕUa§åææjÖ¬Y’¤þýûkÔ¨Q;v¬:vìšç½÷ÞSRR’êÕ+Ÿ¨%Zûõ×Kñ “”›{ö¦å>}œRó‡k7©ÿ±nw;>áæ¯,ŽÍëiñcÍ´ñq‹õÓßø¦1m|l‰ïÕöX_’ÌÊìÝ»Wiii’¤ÔÔTåççK’6nÜšçèÑ£rœz^Jj{zºäæÎpó{ßmœXÇïÕëÜï%§§§WÜnZÿݶÇz|RRê)=½ \{eql^L‹k¦[¬ŸþÆ7iãcZüHó ž.O¶wµ¥ŸÄ'¾ñcÍöñ!¾¿ñmgûø›V?¹2Æ%™iiiÚ·oŸ$)??_©©©ÎgZé!J™?Ölï¬Ù¾þØ?Öè?ñMfûøØ>þ’IfzzºV¯^-IZµj•ÒK^ÏK`”0ò6ŽÛø¶—0Š5Û×[âÇšíÛo¬ß×öõÇöõ3[Æ'¨ÛWe|I2gΜ©þýûëĉêß¿¿fΜš6räH½óÎ;2dˆ6lØ #FøÑEߨòŸ‘-ý$¾™lÆßßø±fûøØ>þ±fûøÛTÂÈ—F­Ñ£GW8­aÆš={v•1Ö¯7ëë ½jã.—ÃÓn06-~¬ÙÞÿX³}ý±=~¬Ñâ›Ìöñ±}ü%K¡b^=MæÕü……I¡Síe_립äéú’íÑÄ÷B¬ÔŠõb~í”üŸD‹ï• n¿•qÓÿplYbýùšÆ´ñ7-¾Ÿ’ÇqªžÍ,G5î27—Ë€­¨“Y‚i¥‡(a”˜ŸÊÙ¾~Úþbýñ—íã„Ï×Ú$3ÑØRÂÈv¦•°°ås´½Ä‡-ñá/Ö3Ù2þ”0‚ïøÏ(>lgÛ?GÛÇÇöñGåX‚ÍöÏצFÖ&™^2­ ¬M2q%üÅøTÎöõÓöøðë¿lÿ |¾”0²„i%ŒlçW‰ –0’«DŒÛø’Ý%bp%†ÌË[AØÿø…F†µÄ[,JY›dâ¬X'«$Ã0ë?LÆúlAÛÿP'3QÂ(‚ZÂÈ+”Éx31±ÿ‰I¦aL+}€èð9VÎöñ±}üQ9>_T‡iûJEÁ´ÒC”08ÇÚ$gQB‰Œõ&cý 6ö?U#É´%Œ‚!È%Œ¼äF°_¬×˜‰ýOô¨“i˜p+I¸z_nÛKN«n„ǸU‹eÝ?ÆÕÁç‹ê0mÿãç?G”0`­ •A°°þ[Ðö?”0,G £èPB&àAÎÄÄþ'z$™†1q%{¦•°H4Œ?ªƒÏÕaÚþ‡FQ0­ô%ŒÎ±6ÉÓn°Jbý 6ö?U#ÉâˆFÑ¡„L@ £ÄÄþ'z”02Œ‰+ Üã?\1þ¨./J½Q.1™¶ÿ¡„‘K”0 ¯„‚…õ'Ø‚¶ÿ¡„`9JE‡"° f0°ÿ‰I¦aL\Iàži%, ãÀ/¦í(aÓJQÂàk“L0í{‰ƒýOÕH28¢„Qt(!À/ì¢G’iW¸Ç¸þbüøÅ´ý%Œ\¢„)x%DØ#hûJ–£„Qt(!À/ì¢G’iW¸gZ ‹DÃøð‹iûJEÁ´ÒC”08ÇÚ$L»Á@â`ÿS5’L Ž(aJˆð ûŸè‘dÆÄ•îñ®¿~1mÿC #—(aÓ•¼ç¶ä†ìW»íÂ-WNN}¥¤8åÚ½7¯âJU­–çTºcðâ’y4ñmWÑr¥¤8žO¬ã°“WÉ^¸8±Žï'.—†§Îƒ{2£ëñaüx…FçX›dšVzˆFçX›døÅ´|LD’ %Œ¢G’iWÓÎpRÂÈ%J?Q¨jœÉëucý °‰“dÆÄ•D†FçX›dšVzˆFçX›døÅ´|LD’ %Œ¢G’iWÓÎpRÂÈ%J?Q¨jœÉƒFÑ#É4Œ‰+ ˆ %ŒÎ±6É4­ô%ŒÎ±6Éð‹iø˜ˆ$ JE$Ó0&®$ 2¦á¤„‘K”0~¢„QÕ8“ %Œ¢G’iWJcm’iZé!Jœcm’ àÓð1I&@”0ŠI¦aL\I@dL;ÃI £Ž9¢I“&)??_iiizôÑGU¯^éû)aüD £ªw&sÁ‚êܹ³²³³Õ©S'-\¸Ðï.€E £èÕò»eåææjÖ¬Y’¤þýûkÔ¨Q;v¬:vìšgݺu¥³d¦o{{NN}¥¤8åÚ@ü&…ŽÙ%ËáÚÃÇÝÆñ*~¸ùã‘o—dîÝ»Wiii’¤ÔÔTåççK’6nÜš§ør¹Ûû lhOIqH.0D¸ãrPÛ½dÜ=™×^{­Ö­[§¤¤$IÒOúS½ñÆ>÷*~:vìX*¡:–7ØXÞ`cyƒåEuwOfZZšöíÛ'IÊÏÏWjjªÏ=€[Æ%™éééZ½zµ$iÕªUJOO÷¹Gp˸Ëåß}÷&Nœ¨ýû÷+55U>ú¨4hàw·à‚qI&ìgÜårØÏ¸F‰fîܹZ¹r¥öíÛ§ 6”šÉ·ÙfãÆzâ‰'tæÌÕ¨QC'NTûöí%sy%é…^ÐòåËCÆŒ£nݺI î2KÒc=¦åË——Z¯ƒ¸¼éééjÙ²¥$é–[nÑ€$sY‹Í;W¯¿þºÇѯ~õ+ èœ9sÆqÇ9xð`hZP—¹¤ììl'++Ëqœ`.oŸ>}œÏ>ûÌqÇÙ¹s§sà 7„¦qy‡ æ¼ýöÛŽã8Îúõë'Ÿ|24-ˆËo\.÷ÙUW]*>_Vnn®úöí+éì·½ýöÛñìZL´nÝZ7–$µk×Nû÷ïM âòJ ýW,IÇŽÓùçŸú;ˆË\XX¨3f(33³Ü´ .o8A]Ö_|Q¿ùÍoT£ÆÙÃÇ÷¿ÿýд .sIkÖ¬ -c—÷ / }áÉ‘#GôÃþ04-ˆËûÅ_¨K—.’¤k®¹¦Ô2qyãËå ÷íGA±bÅŠÐec)ØË›­ììl?~\óæÍ µq™çÌ™£Aƒ…þ™()ˆËë8Ž222T¿~}Mš4I­Zµ’Ìe•ΔÿùÏjݺujÔ¨‘î½÷^5oÞ\Rp—¹ØîÝ»µ{÷îÐ×qy~øa9RIIIrGóçÏM âò¶nÝZ¯¾úªúõë§W_}Uß~ûmhZ—7Þ8“ _lß¾]K–,ÑøñãýîJ\ :T/½ô’ÆŽ«iÓ¦ùݘٺu«¶mÛ¦o¼Ñï®ÄÍÊ•+µtéRýüç?×”)SüîNÌ9sF-Z´Pvv¶nºé&=ôÐC~w)nÖ®]«Þ½{‡ÎâÑc=¦±cÇê•W^ѸqãôøãûÝ¥˜ºÿþûõâ‹/jÈ!úôÓOU³fM¿»(ÁÝR ¨ß~´gÏMš4IS§N-u«@P—·¤¾}ûêÃ? ý´eÞ¼y³>ÿüs 8PÔ‰'4pà@I ÞòJR£F$I7Üpƒ>ûì³P{—U’š5k¦>}úH’z÷î­O>ù$4-¨Ë\¬ä¥r)˜ËûŸÿüG½{÷–töóݲeKhZ—÷â‹/Ö¼yó´lÙ2Ýxãºè¢‹BÓ‚¸¼ñF’i° ~ûQAAƯqãÆ©mÛ¶¥¦qy¥³—ØŠ½õÖ[¡Ë©Rð–9##C«W¯ÖÊ•+µråJÕ©SG+W® ù Úò:tHÎÿ•~ûí·Õ¢E‹Ð´ -k±ôôt½ûî»’ÎV‹(yPê2KÒ矮cǎ骫® µqy/¼ðÂÐç»aÃ]pÁ¡iA\ÞÇK:{ÛË3Ï<£†¦qyãbì>›9s¦V­Z¥}ûö)--Mýû÷×èÑ£%óÛ–,Y¢yóæ…îá’¤çŸ^5jÔäòJÒÔ©Sµyóf9Ž£ïÿû¥îÛ ê2ëÞ½»þõ¯…þÚò®^½Z‹-’$Õ©SG÷ÝwŸ.»ì2IÁ[ÖbGÕý÷߯]»v)99Y>ø`à—Y’ž~úi9Ž£Q£F…Ú‚¸¼}ô‘þô§?©°°P)))úãÿ¨+¯¼RR0—÷ïÿ»þú׿ªfÍšêÑ£‡î¼óÎP¹¹ .o¼‘dÀs\.€çH2à9’LxŽ$ž#É€çH2Öºuë”””¤C‡ÑH¾–ÎͼñêDƒ$@Ì'2Å?ßûÞ÷Ô·o_mݺÕï®ÅUzzº¾ùæ5iÒDRåÉoÙyãÕ§h,_¾\­[·Vrr²~ô£…ŠxKÒ©S§Ô®];-_¾Ü‹î°I&€˜ûè£ôÍ7ß(''GEEE4hß]Š«””5kÖ,TäÙ«yãÕ§ŠìÝ»WþøcµjÕJC† MŸ>}º.¾øbýâ¿ðªË,C’ æš6mªfÍšéG?ú‘î¹çmß¾]'Nœ(5Ï“O>©6mÚ(%%E^x¡xà9s&4ý¹çžS‡T»vm5jÔHÆ +u&ðôéÓÊÌÌTZZšêÕ«§o¼Q_ýu¥ý*>£øÚk¯)==]uêÔQ‹-4sæÌRó>}Z÷ÝwŸš7o®””µiÓF .,5ÏܹsuÑE©V­Zºà‚ ôç?ÿ¹Üû_šîÕ«—¤³ß{^|–7ܼ‘¼wñkÖ®]«ÿøÇª]»¶:uê¤íÛ·W¹ìÅïã6Æ'Ÿ|¢ÂÂBÝyçºä’K4räHíܹSÇŽÓgŸ}¦?ÿùÏåÆ@‚q FrrrIξ}ûÇqœC‡9ÇwÚ¶m[j¾|ÐiÓ¦³jÕ*端¾r^}õU§e˖ν÷ÞšgñâÅÎ믿î|ùå—κu뜫®ºÊ6lXhúرc¦M›:+V¬p¾øâ gîܹNjjª#É9xð`¥ý»ä’KB¯›?¾S»vmgÑ¢E¡ùF夥¥…gÇŽNRR’3uêTgçÎÎ{ï½ç¬X±"ì8,_¾Ü‘älß¾Ýùæ›oœo¾ù&ì¼U½wÉפ§§;yyyÎÇì\sÍ5NÏž=#þlÜÆÈÏÏwêÔ©ãÌ;×9sæŒ3f̧M›6Žã8NïÞ½¿üå/aß@b É3ʼnK½zõœzõê9’œË.»ÌùôÓOCó8çwž“››[êµK—.u7n6ö‹/¾èÔ«WÏ)**r>줤¤8‹/.5OfffDIfÙ×M˜0Á¹üòËÇ9›'''W8OqRõÞ{ï9’œ-[¶Tú>eºŠúUrÞHÞ»äkÞxãPÛ²eËœZµj9§NrÕ'71^~ùe§C‡ÎùçŸï\{íµÎ|à,Y²Ä騱£óî»ï:éééNóæÍ8»víª0€àâr9€˜ËÉÉѦM›4{ölíØ±C[¶l Mûè£tüøqõéÓGõë×ýÜ~ûí:pà€Ž=*IZ¿~½z÷î­¦M›ªAƒºùæ›UPP £GjÛ¶m*,,Ôµ×^[ê}‹/KW¥ì뮽öZmÛ¶M'OžÔ¶mÛtêÔ© çÙ¾}»Nž<©:¨S§NêÑ£‡†®¿ýío¥.õG+’÷.éÊ+¯ ýÞ´iS>}Z®ÞÓMŒè?ÿù¾ýö[­[·N?üá5aÂÍœ9S7Ýt“¨;wªaÆúÍo~ãªìWËï¾V­Z)55UmÚ´ÑöíÛ5~üx 8PÉÉÉ***’$­^½ZÍš5+÷ÚºuëêСCêׯŸ ¤)S¦(55Uyyyºí¶ÛJ%sÑ>ÄR݇ljÕª¥õë×kÍš5Z½zµî¸ã-]ºT/¾øbµâºU£FùóŽãÄ-ÆþðÝrË-ªU«–víÚ¥aÆ©FÊÈÈÐÏþs:uJÉÉÉ®úÀ^œÉWwß}·víÚ¥¿ÿýï’Ξ9«S§Ž¾üòK]rÉ%å~jÔ¨¡­[·êÈ‘#š2eŠºvíªK/½T{÷î żüòË•’’¢7ß|³Ô{­[·.¢>•}Ý[o½¥Ë/¿\µk×VÛ¶m•œœ\nž7ß|34$%''ëg?û™fΜ©¹sç꥗^ÒñãÇ+|¿š5kJR(Á'Ò÷6Á›o¾©œœeee…ÿS§NI’ UTTTåòÎdˆ«‹.ºHÔ“O>©›o¾Yõë××ĉ5fÌ9sF=zôЩS§´iÓ&mß¾]<ð€Z¶l©š5kê©§žÒ¨Q£´yóf=ùä“¡˜ 6Ôï~÷;effªQ£Fj×®^}õU=ûì³õ顇R£FtõÕWëÕW_ÕŒ3BOF—ݾ}{­]»V3fÌÐÓO?-Iz÷Ýwõî»ïªwïÞªU«–V®\© .¸@uêÔ©ðýZ´h!IZ±b…  ¤¤$¥¦¦–›/’÷6ÁÉ“'uÇwhÖ¬Yª[·®®¾új5iÒDÓ§O×=÷Ü£Ù³gë'?ù‰QI1€8ðû¦PÁUöá’b¯¿þº#Éyï½÷BmsçÎu®¾új'%%Å©W¯žÓ¹sggþüù¡é .t~ðƒ8uêÔq®»î:çÙgŸ-õðLaa¡3~üx§I“&Îyççôë×ÏY²dIDþ¬Y³ÆéÒ¥‹S»vm§yóæÎŒ3JÍwêÔ)çÞ{ïu.¸à'99Ù¹ì²ËJõmëÖ­N¯^½œ 8ÉÉÉN—.]œ 6T:?ü°óƒüÀ©Q£†SrW\vÞªÞ;\üÊ.ªè5ÑÄ(öàƒ:C† )ÕöÆo8mÚ´q’““ôôôR{H IŽãò†ˆuëÖ©W¯^Ú·o_…gÑãžLxŽ$žãr9<Ç™LxŽ$ž#É€çH2à9’Lxîÿ¿mçº1j1IEND®B`‚prinseq-lite-0.20.4/example/example1.html0000664000076700007670000206354312240000654020452 0ustar rschmiedrschmied PRINSEQ-graphs Report

PRINSEQ-graphs v0.6 HTML Report   

[Generated: 11/10/2013 12:12:36]

Input Information
Input file(s):example1.fastq
Input format(s):FASTQ
# Sequences:12
Total bases:1,150

Length Distribution
Mean sequence length: 95.83 ± 37.96 bp
Minimum length: 50 bp
Maximum length:200 bp
Length range:151 bp
Mode length: 100 bp with 8 sequences


GC Content Distribution
Mean GC content: 48.17 ± 14.83 %
Minimum GC content: 0 %
Maximum GC content: 57 %
GC content range: 58 %
Mode GC content: 50 % with 5 sequences


Base Quality Distribution





Occurence of N
Sequences with N: 2  (16.67 %)
Max percentage of Ns per sequence: 10 %


Poly-A/T Tails
5'-end 3'-end
Sequences with tail:1  (8.33 %) 1  (8.33 %)
Maximum tail length: 50 50




Tag Sequence Check
5'-end3'-end
Probability of tag sequence:33 %33 %
GSMIDs or RLMIDs:none 










































































 ... 




















































































        10     15     20  20     15     10        
 Position from Sequence Ends

Sequence Duplication
# Sequences Max duplicates
Exact duplicates:4  (33.33 %)3
Exact duplicates with reverse complements:0 0
5' duplicates0 0
3' duplicates0 0
5'/3' duplicates with reverse complements0 0
Total:4  (33.33 %)-






Sequence Complexity
ValueSequence
Minimum DUST score:2NNNNNNNNNNTACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAAGTGAGAGTTG
AGAAGAGGCGTGGAGGAGATGACACACCCCGTGTGTTCTC
Maximum DUST score:100AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Minimum Entropy value:0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Maximum Entropy value:81NNNNNNNNNNTACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAAGTGAGAGTTG
AGAAGAGGCGTGGAGGAGATGACACACCCCGTGTGTTCTC




Dinucleotide Odds Ratios
 AA/TTAC/GTAG/CTATCA/TGCC/GGCGGA/TCGCTA
Odds ratio0.39542.43780.48580.36231.07360.30061.91660.43380.58291.8332





prinseq-lite-0.20.4/example/example1.fastq0000644000076700007670000000541512240000123020601 0ustar rschmiedrschmied@seq1 length=100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT +seq1 length=100 1234123412342134123412341234123412341234123412341234132412341234123412341234123412341234123412341234 @seq1_dupl1 length=100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT +seq1_dupl1 length=100 1234123412342134123412341234123412341234123412341234132412341234123412341234123412341234123412341234 @seq1_dupl2 length=100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT +seq1_dupl2 length=100 1234123412342134123412341234123412341234123412341234132412341234123412341234123412341234123412341234 @seq1_dupl3 length=100 ACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGTACGT +seq1_dupl3 length=100 1234123412342134123412341234123412341234123412341234132412341234123412341234123412341234123412341234 @seq2 length=200 ACGTGACGTGACGTGGTGTACACAGAGATATATGAGACACACAGATAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTGCGTGTACGTGACGTGACGTGGTGTACACAGAGATATATGAGACACACAGATAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTGCGTGTAACCACGT +seq2 length=200 ++++++++++++++++..............00000000000000000000333333333333333355555555555555555AAAAAAAAAAAAAA999999999999996666666666666666444444444444444442222222222222222222221111111)))))))))))))))>>>>>>>>>>>>> @seq3 length=100 TAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTGCGTGTACGTGACGTGACGTGGTGTATAGATTGCGTGCGTACGTGTGTGCATGCG +seq3 length=100 FHHFFFFFFDDAA@====AAB===BBBBAAADDDDDDDDAAAADDDDD?????FFFFF??FFFFFFDA@AFFFFFFFFFFFFFFFFCCABA?>9:773.. @seq3_dupl1 length=100 TAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTGCGTGTACGTGACGTGACGTGGTGTATAGATTGCGTGCGTACGTGTGTGCATGCG +seq3_dupl1 length=100 FHHFFFFFFDDAA@====AAB===BBBBAAADDDDDDDDAAAADDDDD?????FFFFF??FFFFFFDA@AFFFFFFFFFFFFFFFFCCABA?>9:773.. @seq4 length=50 TAGATTGCGTGCGTACGTGTGTGCATGCGTTGTGCCGCGCTCTGTAGAGA +seq4 length=50 ???CCDDBBBBBAA333:ABB=:::AGFFFFFHHHHFFFFFFFF??@FFF @seq5 length=100 Ns_begin=10 NNNNNNNNNNTACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAAGTGAGAGTTGAGAAGAGGCGTGGAGGAGATGACACACCCCGTGTGTTCTC +seq5 length=100 Ns_begin=10 !!!!!!!!!!99999999999999AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFF @seq6 length=100 Ns_end=10 TACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAAGTGAGAGTTGTACACCAGAGGTGTCTCTGTGTGGGGCCTGTGTGCCAAAANNNNNNNNNN +seq6 length=100 Ns_end=10 FFFFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAA9999999999999999999995555555!!!!!!!!!! @seq7 length=50 TACACCAGAGGTGTCTCTGTGTGGGTACACCAGAGGTGTCTCTGTGTGGG +seq7 length=50 !''*((((***+))%%%++)(%%%%).1***-+*''))**55CCF>>>>> @seq8 length=50 As=50 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +seq8 length=50 As=50 55555555555555555555555555555555555555555555555555prinseq-lite-0.20.4/example/example1_dm.png0000664000076700007670000002321612240000123020730 0ustar rschmiedrschmied‰PNG  IHDR¨ú]ôwbKGDÿÿÿ ½§“ IDATxœíÝ{\UUþÿñ÷¹ˆÈ€BšIZfŠšñ(§æë7¯)y +g¼D™]tÔ‘Ò)Í4»xùYÞ*oxë‹hc9¡3j¼e£c“ä%m&-k4PDaÿþðËùB@’çl_ÏǃÇ㜵öÙŸµ6go>ì½öÚ˲,n«¶”E‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·B‚ ·R§¶ûˆ›V­å6ÿ¿Á†[b?Óõ@µ–{V6Ü÷ðÎ}=ªµÜ€Mn‰{˜·foµ–‹i¸%°³#FTk¹= n ®œA…ÛèØ±£bbbœ?‹-ryŒ”””j/Ûµk×_¯S§N¿x®PvÛnذÁY^ÝöÙi[HÒš5k4hÐ }ºš4ibvøHƒ *-·û¶p¾>wîœ5jä|­n“R:tÐñãÇïOŸ>­)S¦(++KuêÔÑ /¼ ˆˆÍ;W5rþá\¸p¡êÖ­«!C†T¹îÊöË:è?ÿù&Nœ¨‚‚jêÔ©ºþúë%]Þ~O<ñ„¶nݪ¼¼<;V_}õ•vìØ¡Ó§Oëü£óÌÎ/ÝÖUõ•ãë]Ëß³ª”=ö=zT7Þx£¼¼¼®Ùã—øá6Š‹‹Ë]âß°aƒÚ´i£Î;ë7ÞÐìÙ³Õ·o_µhÑBÒåjÅŠJKKÓ”)S4mÚ4çºf̘¡;î¸Ck֬ѪU«¡‘#GÊÏÏO©©©þ(HÒÌ™35`À¥¦¦ªY³f***ªv»›5k¦ÔÔT 0 Òu×6˲£ßÿþ÷:zô¨³üÏ®|̪·E©´´4=øàƒzæ™g4uêTgùµ¼M$éã?ÖM7Ýä|?sæL 2D«W¯Vbb¢^yåIRTT”>üðÿÆø~øá‡ŠŠŠúÉuW¶_––?ðÀZ½zµúõë§3f8?S\\¬ë®»NË—/×´iÓôüóÏ+<<\Ë–-ÓôéÓ5gΜrËþ’m]U_9¹Þµü=«ÎñxçÎêØ±£óýµx¼"A…Û(½ìQúÓ·o_IÒðáõk×.}ùå—:t¨sùo¾ùF#GŽÔÀõâ‹/–ÛÑwíÚ¥ßýîw’$‡Ã¡zõê]1þÞ½{uß}÷I’z÷î-‡ÃQí¶—ý\fffµ?WSÒÓÓ•ššª|PÉÉÉW\ÞÎÛ¢ÔàÁƒµnÝ:ÅÅÅ•K*ªbçmRúÏaß¾}5iÒ$ýñtÖíÞ½[¯½öšbbb4yòd9sF’ÔªU+>}ZÙÙÙúꫯT¿~ýrgv*SÕ~ùãm[v9g]ëÖ­URR¢ž={:ßggg—‹ñK¶uU}•8¹߳˪s<þôÓOõ_ÿõ_Î÷×âñŠKüp{gΜѹsçtéÒ%]¸pAuëÖ•$Mš4I‰‰‰ºýöÛUTT¤nݺ9?ósvÆê²,K‡CÅÅÅ*..vùúM ‘tùÀSƒÛ•xò¶ø±^½z]óÛ¤ôŸÃ’’Í;W‹/Ö¬Y³$I%%%JII‘¿¿…ÏõèÑC}ô‘N:åü£öS®f¿ôòò’󽯯¯¼¼Ìœ[ù©¾rúåøž]v¥ãqaa¡~øá………U¨»–ŽWœA…Û›:uªF¥Þ½{kîܹÎòsçÎéºë®“$½÷Þ{²,ËYw÷ÝwëOú“¤Ë;bAA$ÉÇÇG.\¨4Ndd¤sàù¦M›Ê­¯qãÆ:xð $ióæÍv貟‹Œt¯©|òòòœ}Ù±c‡š5kvÅÏØu[”*;ömÛ¶må.5VÅîÛDºüGzÔ¨QúꫯtàÀIÒ]wÝ¥wß}×¹LÙ3„QQQÚ¼y³>úè#õèqå©¿ªÚ/ËnÛ7êöÛo¿ê>ü’mýS}å8ä:×ò÷¬:Çã={ö¨C‡Î÷×êñŠnãÇcPgÍš¥÷ß_¾¾¾êÕ«—üq8p@ÿûß%IO?ý´†®Ç{LgÏž•¯¯¯s]¥7# 8P111:tè$©ÿþ}ºÖ®]«]»vÕvSp•l3õóÏ?W^^^¹±ð<¶HP‹ŠŠ4{öì«ð ÷a‹1¨o½õ–ú÷ï_å#¿ÊN×°gÏžšj®‚Ç'¨Ô¡C‡Wå2e“ÒüüüšhÀ5!00ÐåëôøKü{÷îÕ‘#G­èèh*::Z%%%µÝ4\[ÝÅ/]y/Π¸gP`{¶;ƒz%œApΠÀöHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVHPàVj4A=þ¼,˪Éð0ÆÔ×^{Mëׯ—$롇R@@€n¼ñF}öÙg¦ÂÀÃKPg̘¡n¸A’´víZmÛ¶Mï¼óŽºu릧Ÿ~ÚTXx¸:¦Vœ••¥† J’ÒÓÓ£ßýîwŠŒŒTÛ¶mM…€‡3vµI“&JMMÕ_|¡ôôtÝwß}’¤K—.©nݺ¦ÂÀÃKPǯçŸ^·ß~»Z·n­^½zI’>üðCuèÐÁTXx8‡eð¶ú£GêÔ©SŠŒŒT:—GìÞ½[õë×WDD„©°?)??¿VâØQ`` Ë×i4A-•ŸŸ¯€€yyÕþ´«$¨®c"A5–1^ºtI'NTÆ U¿~}9rD’”””¤Å‹› g,AMLLÔªU«4oÞ<ùûû;Ëo½õV¥¤¤˜ g,AMIIÑ¢E‹ôðÃËÛÛÛY~çwjß¾}¦ÂÀÃKP³³³ÕªU« å>>>***2ÎX‚Ú¼ysýôSIÒ‰'”ššª„„ÅÆÆš gìQ§qqqÊÍÍÕ½÷Þ«óçÏ«S§Nò÷÷×øñã5|øpSaàáŒÏƒzîÜ98p@%%%jÛ¶­‘¹²~æAp¨ß ¸ŽGMÔïp8tâĉ å999r8¦ÂÀÃÕø³G-Ër‹GžÀ=¹ü&©¼¼<çë³gÏ–{ŠTII‰6lØ F¹:,lÂå jHHˆóueõKÒK/½äê°° —'¨’¤nݺiíÚµjР³ÎÛÛ[Í›7Wxx¸«ÃÀ&¸‹WÍÄ]üÆ&ê/eY–òóóU\\\®<88Øthx c·ÓçææêÑGUýúõ¤r?@eŒA=z´8 ·ß~[?ü°,X ¬¬,Í;WS§N5öŠêÕ«Wk±peÆÆ þêW¿ÒúõëÕ©S'êóÏ?WË–-µnÝ:½ùæ›Ú´i“‰°WÄT×ñ¨1¨………jÞ¼¹$©nݺ:}ú´$)22RÛ·o7öŠú¿¸¾BÙ»‰÷×BKPccP#""ôÏþS’Ô¾}{-\¸Pß}÷Þxã Æ  JÆÎ &$$èßÿþ·$)11Q½{÷VJJŠêÔ©£Å‹› g,A:t¨óõ=÷Ü£ï¾ûNTóæÍÕ¤ISaàáŒÏƒZ*88X;v¬©pðPÆÆ &%%iÅŠÊ—-[V«ÓLÀ½KPßzë-µiÓ¦ByDD„Þzë-SaàáŒ%¨ÙÙÙjÔ¨Q…ò믿^YYY¦ÂÀÃKPÃÃõsçÎ å;wîTxx¸©°ðpÆn’>|¸þð‡?èüùóêÞ½»$éã?Ö3Ï<£gŸ}ÖTXx8c êsÏ=§S§NiĈ***’$ùùùi̘1$¨¨’ò,Ëd€~øA_~ù¥$©M›6Fž×úsDM«PÆ£N®Ž‰ÜÎ¥gPsrrÔ°aC9åää8Ëo¾ùfIRaa¡ %I¡¡¡® ›pi‚¦ÿüç?jܸ±ÂÂÂ~rYÃ'nà¡\š fdd¨AƒÎ×ÀÏåÒµk×®•¾ªËåcP«‹1¨¨ŒËÇ VcPP—A~ ccP€«áUA.\¸  .ÔD(x8£ ê’%K!ùûû+""BK—.5ÎX‚:gÎÅÆÆêІ ´aÃõë×O£FÒ¼yóL…€‡séÔ²fΜ©ùóçëÉ'Ÿt–õéÓG-[¶Trr²bccM…€3võäÉ“êÑ£G…ò¨¨(eee™ g,AŒŒÔ¾}û*”gffêŽ;î0ÎØ%þ¤¤$ÅÆÆ*77W]ºt‘eYÚºu«’’’ôæ›o–{êO•@)‡eè‘N‡£ÚËÖäS¥¢Æ¦U({7ñþ‹`'._§±3¨ŒŒ¬t™‚‚Ĩ €Ê¹4A½Òܧe1**ãÒµìeýï¿ÿ^Ï<óŒüqç”SZ¶l™^{í5W†€¸4A-;÷iŸ>}ôòË/kذaåÊZ¶l©5kÖèÑGuehØ„±yP·lÙ¢¨¨¨ å½zõÒG}d*,<œ±5 @ûöí«Pž™™©€€SaàáŒ%¨=ö˜žzê)½ýöÛúî»ïtìØ1­\¹RÆ ÓСCM…€‡36ê´iÓtñâE=õÔS***’$ùúújäÈ‘zõÕWM…€‡sX†ç{:{ö¬:$Ijݺµ‚‚‚L†»¢¨±iÊÞM¼¿Zàù]¾NcgPKé®»î26a}ú¨eË–JNNæN~TÊØÔ“'OªGÊ£¢¢”••e*,<œ±522²ÒGšfffêŽ;î0Î¥—øsrrœ¯“’’«ÜÜ\uéÒE–eiëÖ­JJJÒ›o¾éʰ°—&¨aaaʆ R¡¬gÏž2<ý*<”KÔŒŒ W®× —&¨]»vuåêp 2þ$©ââbåççW¸¤l:4<±»ø¿úê+Ý{ï½ò÷÷Wpp°BBBÊý•1v5&&FuëÖÕªU«j* lÆX‚ºoß>íÛ·O·Þz«©.S¯^½Únþ—±µ]»vÊËË3µz—*((¨í&x¤ÀÀ@—¯ÓX‚:þ|=÷ÜsJJJRÛ¶mååU~¸«»Ý$ÕÿÅõÊÞM¼¿Zpm3– †††ê‡~PçÎ+­g¢~TÆøMRï¼ó7I ÚŒ%¨_|ñ…¾øâ ¸I îÃØ<¨mÚ´Qnn®©ÕÀ¦Œ%¨/¿ü²”‘‘¡“'O*''§ÜPc—ø{÷î-IêÞ½{¥õÜ$€ÊKP322L­6f,AíÚµ«©UÀÆŒ%¨WzŠ”»MÔ÷`,A ùÉzÆ  256µ¤¤Dû÷ï×ìÙ³5eÊSaàájt j÷îÝuË-·èõ×_×!CL…€36jU"""´}ûöš aì je“ñggg+))Iááá¦ÂÀÃKPê,_µj•©°ðp5v“”ÃáPPPÚµk'Saàá\ž –ÎYi}AA$æA@å\ž ^iþÓR̃ €Ê¸}´cÇIR‡œ?po¶ºÄòäI………I’BCC•““#IÚ³gs™¨±iµÒ6T“e#;w¶JJJœï»uëVérwÞy'å”SN9å”SN9å.,w%[%¨¿ýío­¬¬,˲,+;;Û0`@­´£&~qÄ%.q‰K\â—¸ve«1¨;vÔÆ%IùË_Ô±cÇZn~.‡eYVm7ÂUΞ=«ñãÇëÔ©S Õ«¯¾ªúõë×v³ð3Ø*A€ç³Õ%~x>[M3u-Z°`ÒÓÓ•­]»v•«³Û“µöìÙ£Y³f©¸¸X^^^?~¼n¿ývIöëk©5kÖhíÚµr8’¤§Ÿ~Zÿýßÿ-ɾ}–¤éÓ§kíÚµå¾ÓvìoÇŽÕ¼ysIÒ#<¢¾}ûJ²g_K-X°@}ô‘,ËÒ€4pà@Iöíó¬Y³œS*77W¶ìïÖ­[5þ|I’ÃáÐèÑ£Õ¹sgIöüý>|X‰‰‰ºté’ÂÃÕœœ¬€€Iöìo«Õ[´ð‹íÛ·Ï:yò¤uÏ=÷T¨›5k–µ|ùr˲,kùòåÖìÙ³kºy.õ¯ýË:uê”eY–õÙgŸY=ô³În}-UPPà|}äÈ«gÏžÎ÷víó?þñk„ ¾Óvìoeû­eÙ³¯–eYëÖ­³^|ñE«¸¸Ø²,ËÊÍÍuÖÙµÏe¥¥¥Y‰‰‰–eÙ³¿={ö´¾þúk˲,ë›o¾±î»ï>gûûè£Z;vì°,˲>ùäkΜ9Î:;ö·¦q‰ßõk×Îùp‚«êÉZžªE‹jР$é¶ÛnÓ©S§œuvëk©ÒÿÆ%éܹsjÔ¨‘ó½û\TT¤Ù³gkܸqêìØßªØµ¯ï½÷žžxâ yy]þÓ쬳kŸËÚ´i“³vìoÓ¦M•ŸŸ/éòÄ&Mš8ëìØßo¿ýVwß}·$é7¿ùM¹>Ù±¿5Kü6VÕ“µìàý÷ßw^ê–ìÝ×´´4¥¥¥éüùóZ¸p¡³ÜŽ}~ë­·Ô¿ç?"eÙ±¿–e)&&Fš0a‚nºé&Iöì«tùú_ÿúWmÙ²E!!!zþùç.ɾ}.uüøq?~ÜùÈm;öwêÔ©6l˜‡,ËÒ¢E‹œuvìo‹-ôÁ¨wïÞúàƒtâÄ gû[Ó8ƒ søða­\¹R µÝ”1xð`­[·Nqqqš6mZm7ǘƒêСCêׯ_m7¥Æ¤§§+55U>ø ’““k»9Æ«Y³fJKKÓC=¤¤¤¤ÚnRÙ¼y³zôèá<{lGÓ§OW\\œ6lØ øøx͘1£¶›dÔ¤I“ôÞ{ïiРAú׿þ%ooïÚn’­ØwO”-IÊÉÉQhhh-·è—ËÊÊÒ„ ôÊ+¯”Ú`ǾþX¯^½´ÿ~ç{»õyïÞ½:r䈢££­ÂÂBEGG«¤¤D’ýú+I!!!’¤ûî»O_ýµ³ÜŽ}•¤Æ«gÏž’¤=zèŸÿü§³Î®}.Uöò¾dÏþ~þùçêÑ£‡¤Ë¿ßÌÌLgû{óÍ7káÂ…Z½zµúõë§o¼ÑYgÇþÖ4TK‡97IDAT³Û“µ ” øøxEDD”«³[_K?~ÜùzÛ¶mÎKÀ’ýú£7*==]éééò÷÷WzzºóŒ“Ýú›——'ë§¡Þ±c‡š5k欳[_KuìØQ»wï–tyV޲ÐíÚgI:räˆÎ;§víÚ9ËìØß¦M›:¿»víÒ 7ÜଳcÏœ9#éòP¥K—*::ÚYgÇþÖ4&ê÷póæÍÓ_þòegg+,,L}úôQll¬$û=YkåÊ•Z¸p¡sÌš$½ýöÛòòò²]_K½òÊ+Ú»w¯,ËRppp¹qŠvís©N:iûöíÎ÷vëïÆ•’’"Iò÷÷× /¼ [o½U’ýúZ*??_“&MÒ¿ÿýoùøøèÅ_´}Ÿ%éÍ7ß”eYúÃþà,³c8 —^zIEEEòõõÕĉÕ¶m[IöìïŸþô'­ZµJÞÞÞêܹ³FíœÐŽý­i$¨p+\â€[!A€[!A€[!A€[!A€[!A€[!A€ùúë¯5pà@………©N: U—.]œo̪SÛ wRXX¨®]»ê¶ÛnÓúõëÕ´iSeggkÛ¶mÊÍÍ­íæÀ53¨PÆÞ½{õý÷ßë7ÞÐÝwß­n¸A‘‘‘Š‹‹ÓÃ?\nÙ9sæ¨U«VòõõUÓ¦M5yòd;ë/]º¤qãÆ),,LõêÕS¿~ýôöÛoËáp(//O[¶l‘ÃáPNNŽó3¥eyyyÕŽSú™Í›7ëÎ;ŸŸ~ýë_ëðáÃÎeJJJ4}útÝrË-òõõU“&M”””ô³ú5…ʸþúëåp8´zõj]ºt©Êå¦L™¢7ÞxC¯¿þºŽ9¢eË–iåÊ•š" and quotes automatically from sequence ids before renaming. Fixed problem with saving "0" values instead of default values into parameters file. Fixed header line keep/remove mismatch. Fixed "division by 0" bug when calculating 1/length for sequence fractions. Automatically remove space and dash from sequences when parsing the input data. Add function to convert base U to T. Fixed length range filter bug. Fixed issue parsing FASTQ files with no information in '+' header line. prinseq-web-0.2: Fixed .qual file linebreak bug. prinseq-web-0.1: First release of prinseq web version. prinseq-lite-0.20.4/prinseq-lite.pl0000644000076700007670000056571012240000153017357 0ustar rschmiedrschmied#!/usr/bin/perl #=============================================================================== # Author: Robert SCHMIEDER, Computational Science Research Center @ SDSU, CA # # File: prinseq-lite # Date: 2013-11-10 # Version: 0.20.4 lite # # Usage: # prinseq-lite [options] # # Try 'prinseq-lite -h' for more information. # # Purpose: PRINSEQ will help you to preprocess your genomic or metagenomic # sequence data in FASTA or FASTQ format. The lite version does not # require any non-core perl modules for processing. # # Bugs: Please use http://sourceforge.net/p/prinseq/bugs/ or # https://groups.google.com/d/forum/edwardslabtools # #=============================================================================== use strict; use warnings; #use Data::Dumper; ### use Getopt::Long; use Pod::Usage; use File::Temp qw(tempfile); #for output files use Fcntl qw(:flock SEEK_END); #for log file use Digest::MD5 qw(md5_hex); #for dereplication use Cwd; use List::Util qw(sum min max); $| = 1; # Do not buffer output my $WINDOWSIZE = 64; my $WINDOWSTEP = 32; my $WORDSIZE = 3; my @WINDOWSIZEARRAY = (0..61); my $LOG62 = log(62); my $ONEOVERLOG62 = 1/log(62); my $POINTFIVE = 1/2; my $LINE_WIDTH = 60; my $GRAPH_DATA_SEQ_MAX_LENGTH = 1000; my $TRIM_QUAL_WINDOW = 1; my $TRIM_QUAL_STEP = 1; my $TRIM_QUAL_TYPE = 'min'; my $TRIM_QUAL_RULE = 'lt'; my $TAG_LENGTH = 20; my %MIDS = (ACGAGTGCGT => 0, ACGCTCGACA => 0, AGACGCACTC => 0, AGCACTGTAG => 0, ATCAGACACG => 0, ATATCGCGAG => 0, CGTGTCTCTA => 0, CTCGCGTGTC => 0, TAGTATCAGC => 0, TCTCTATGCG => 0, TGATACGTCT => 0, TACTGAGCTA => 0, CATAGTAGTG => 0, CGAGAGATAC => 0, ACACGACGACT => 0, ACACGTAGTAT => 0, ACACTACTCGT => 0, ACGACACGTAT => 0, ACGAGTAGACT => 0, ACGCGTCTAGT => 0, ACGTACACACT => 0, ACGTACTGTGT => 0, ACGTAGATCGT => 0, ACTACGTCTCT => 0, ACTATACGAGT => 0, ACTCGCGTCGT => 0); my $MIDCHECKLENGTH = 15; #maximum MID length plus possible key length (by default 4 bp for 454) my %DN_DI = ('AA' => 0, 'AC' => 0, 'AG' => 0, 'AT' => 0, 'CA' => 0, 'CC' => 0, 'CG' => 0, 'CT' => 0, 'GA' => 0, 'GC' => 0, 'GG' => 0, 'GT' => 0, 'TA' => 0, 'TC' => 0, 'TG' => 0, 'TT' => 0); my %GRAPH_OPTIONS = map {$_ => 1} qw(ld gc qd ns pt ts aq de da sc dn); my $VERSION = '0.20.4'; my $WHAT = 'lite'; my $man = 0; my $help = 0; my %params = ('help' => \$help, 'h' => \$help, 'man' => \$man); GetOptions( \%params, 'help|h', 'man', 'verbose', 'version' => sub { print "PRINSEQ-$WHAT $VERSION\n"; exit; }, 'fastq=s', 'fasta=s', 'fastq2=s', 'fasta2=s', 'qual=s', 'min_len=i', 'max_len=i', 'range_len=s', 'min_gc=i', 'max_gc=i', 'range_gc=s', 'min_qual_score=i', 'max_qual_score=i', 'min_qual_mean=i', 'max_qual_mean=i', 'ns_max_p=i', 'ns_max_n=i', 'noniupac', 'seq_num=i', 'derep=i', 'derep_min=i', 'lc_method=s', 'lc_threshold=i', 'trim_to_len=i', 'trim_left=i', 'trim_right=i', 'trim_left_p=i', 'trim_right_p=i', 'trim_tail_left=i', 'trim_tail_right=i', 'trim_ns_left=i', 'trim_ns_right=i', 'trim_qual_left=i', 'trim_qual_right=i', 'trim_qual_type=s', 'trim_qual_rule=s', 'trim_qual_window=i', 'trim_qual_step=i', 'seq_case=s', 'dna_rna=s', 'line_width=i', 'rm_header', 'seq_id=s', 'seq_id_mappings:s', 'out_format=i', 'out_good=s', 'out_bad=s', 'stats_len', 'stats_dinuc', 'stats_info', 'stats_tag', 'stats_dupl', 'stats_ns', 'stats_assembly', 'stats_all', 'aa', 'log:s', 'graph_data:s', 'graph_stats=s', 'phred64', 'qual_noscale', 'no_qual_header', 'exact_only', 'web:s', 'filename1=s', 'filename2=s', 'custom_params=s', 'params=s' ) or pod2usage(2); pod2usage(1) if $help; pod2usage(-exitstatus => 0, -verbose => 2) if $man; =head1 NAME PRINSEQ - PReprocessing and INformation of SEQuence data =head1 VERSION PRINSEQ-lite 0.20.4 =head1 SYNOPSIS perl prinseq-lite.pl [-h] [-help] [-version] [-man] [-verbose] [-fastq input_fastq_file] [-fasta input_fasta_file] [-fastq2 input_fastq_file_2] [-fasta2 input_fasta_file_2] [-qual input_quality_file] [-min_len int_value] [-max_len int_value] [-range_len ranges] [-min_gc int_value] [-max_gc int_value] [-range_gc ranges] [-min_qual_score int_value] [-max_qual_score int_value] [-min_qual_mean int_value] [-max_qual_mean int_value] [-ns_max_p int_value] [-ns_max_n int_value] [-noniupac] [-seq_num int_value] [-derep int_value] [-derep_min int_value] [-lc_method method_name] [-lc_threshold int_value] [-trim_to_len int_value] [-trim_left int_value] [-trim_right int_value] [-trim_left_p int_value] [-trim_right_p int_value] [-trim_ns_left int_value] [-trim_ns_right int_value] [-trim_tail_left int_value] [-trim_tail_right int_value] [-trim_qual_left int_value] [-trim_qual_right int_value] [-trim_qual_type type] [-trim_qual_rule rule] [-trim_qual_window int_value] [-trim_qual_step int_value] [-seq_case case] [-dna_rna type] [-line_width int_value] [-rm_header] [-seq_id id_string] [-out_format int_value] [-out_good filename_prefix] [-out_bad filename_prefix] [-phred64] [-stats_info] [-stats_len] [-stats_dinuc] [-stats_tag] [-stats_dupl] [-stats_ns] [-stats_assembly] [-stats_all] [-aa] [-graph_data file] [-graph_stats string] [-qual_noscale] [-no_qual_header] [-exact_only] [-log file] [-custom_params string] [-params file] [-seq_id_mappings file] =head1 DESCRIPTION PRINSEQ will help you to preprocess your genomic or metagenomic sequence data in FASTA (and QUAL) or FASTQ format. The lite version does not require any non-core perl modules for processing. =head1 OPTIONS =over 8 =item B<-help> | B<-h> Print the help message; ignore other arguments. =item B<-man> Print the full documentation; ignore other arguments. =item B<-version> Print program version; ignore other arguments. =item B<-verbose> Prints status and info messages during processing. =item B<***** INPUT OPTIONS *****> =item B<-fastq> Input file in FASTQ format that contains the sequence and quality data. Use stdin instead of a file name to read from STDIN (-fasta stdin). This can be useful to process compressed files using Unix pipes. =item B<-fasta> Input file in FASTA format that contains the sequence data. Use stdin instead of a file name to read from STDIN (-fastq stdin). This can be useful to process compressed files using Unix pipes. =item B<-qual> Input file in QUAL format that contains the quality data. =item B<-fastq2> For paired-end data only. Input file in FASTQ format that contains the sequence and quality data. The sequence identifiers for two matching paired-end sequences in separate files can be marked by /1 and /2, or _L and _R, or _left and _right, or must have the exact same identifier in both input files. The input sequences must be sorted by their sequence identifiers. Singletons are allowed in the input files. =item B<-fasta2> For paired-end data only. Input file in FASTA format that contains the sequence data. The sequence identifiers for two matching paired-end sequences in separate files can be marked by /1 and /2, or _L and _R, or _left and _right, or must have the exact same identifier in both input files. The input sequences must be sorted by their sequence identifiers. Singletons are allowed in the input files. =item B<-params> Input file in text format that contains PRINSEQ parameters. Each parameter should be specified on a new line and arguments should be separated by spaces or tabs. Comments can be specified on lines starting with the # sign. Can be combined with command line parameters. Parameters specified on the command line will overwrite the arguments in the file (if any). =item B<-si13> This option was replaced by option -phred64. =item B<-phred64> Quality data in FASTQ file is in Phred+64 format (http://en.wikipedia.org/wiki/FASTQ_format#Encoding). Not required for Illumina 1.8+, Sanger, Roche/454, Ion Torrent, PacBio data. =item B<-aa> Input is amino acid (protein) sequences instead of nucleic acid (DNA or RNA) sequences. Allowed amino acid characters: ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*- and allowed nucleic acid characters: ACGTURYKMSWBDHVNXacgturykmswbdhvnx- The following options are ignored for -aa: stats_dinuc,stats_tag,stats_ns,dna_rna =item B<***** OUTPUT OPTIONS *****> =item B<-out_format> To change the output format, use one of the following options. If not defined, the output format will be the same as the input format. 1 (FASTA only), 2 (FASTA and QUAL), 3 (FASTQ), 4 (FASTQ and FASTA), or 5 (FASTQ, FASTA and QUAL) =item B<-out_good> By default, the output files are created in the same directory as the input file containing the sequence data with an additional "_prinseq_good_XXXX" in their name (where XXXX is replaced by random characters to prevent overwriting previous files). To change the output filename and location, specify the filename using this option. The file extension will be added automatically (either .fasta, .qual, or .fastq). For paired-end data, filenames contain additionally "_1", "_1_singletons", "_2", and "_2_singletons" before the file extension. Use "-out_good null" to prevent the program from generating the output file(s) for data passing all filters. Use "-out_good stdout" to write data passing all filters to STDOUT (only for FASTA or FASTQ output files). Example: use "file_passed" to generate the output file file_passed.fasta in the current directory =item B<-out_bad> By default, the output files are created in the same directory as the input file containing the sequence data with an additional "_prinseq_bad_XXXX" in their name (where XXXX is replaced by random characters to prevent overwriting previous files). To change the output filename and location, specify the filename using this option. The file extension will be added automatically (either .fasta, .qual, or .fastq). For paired-end data, filenames contain additionally "_1" and "_2" before the file extension. Use "-out_bad null" to prevent the program from generating the output file(s) for data not passing any filter. Use "-out_bad stdout" to write data not passing any filter to STDOUT (only for FASTA or FASTQ output files). Example: use "file_filtered" to generate the output file file_filtered.fasta in the current directory Example: "-out_good stdout -out_bad null" will write data passing filters to STDOUT and data not passing any filter will be ignored =item B<-log> Log file to keep track of parameters, errors, etc. The log file name is optional. If no file name is given, the log file name will be "inputname.log". If the log file already exists, new content will be added to the file. =item B<-graph_data> File that contains the necessary information to generate the graphs similar to the ones in the web version. The file name is optional. If no file name is given, the file name will be "inputname.gd". If the file already exists, new content will overwrite the file. Use "-out_good null -out_bad null" to prevent generating any additional outputs. (See below for more options related to the graph data.) The graph data can be used as input for the prinseq-graphs.pl file to generate the PNG graph files or an HTML report file. If you have trouble installing the required prinseq-graphs.pl modules or want to see an output example report, upload the graph data file at: http://edwards.sdsu.edu/prinseq/ -> Choose "Get Report" =item B<-graph_stats> Use this option to select what statistics should be calculated and included in the graph_data file. This is useful if you e.g. do not need sequence complexity information, which requires a lot of computation. Requires to have graph_data specified. Default is all selected. Allowed option are (separate multiple by comma with no spaces): ld (Length distribution), gc (GC content distribution), qd (Base quality distribution), ns (Occurence of N), pt (Poly-A/T tails), ts (Tag sequence check), aq (Assembly quality measure), de (Sequence duplication - exact only), da (Sequence duplication - exact + 5'/3'), sc (Sequence complexity), dn (Dinucleotide odds ratios, includes the PCA plots) Example use: -graph_stats ld,gc,qd,de =item B<-qual_noscale> Use this option if all your sequences are shorter than 100bp as they do not require to scale quality data to 100 data points in the graph. By default, quality scores of sequences shorter than 100bp or longer than 100bp are fit to 100 data points. (To retrieve this information and calculate the graph data would otherwise require to parse the data two times or store all the quality data in memory.) =item B<-no_qual_header> In order to reduce the file size, this option will generate an empty header line for the quality data in FASTQ files. Instead of +header, only the + sign will be output. The header of the sequence data will be left unchanged. This option applies to FASTQ output files only. =item B<-exact_only> Use this option to check for exact (forward and reverse) duplicates only when generating the graph data. This allows to keep the memory requirements low for large input files and is faster. This option will automatically be applied when using -derep options 1 and/or 4 only. Specify option -derep 1 or -derep 4 if you do not want to apply both at the same time. =item B<-seq_id_mappings> Text file containing the old and new (specified with -seq_id) identifiers for later reference. This option is useful if e.g. a renamed sequence has to be identified based on the new sequence identifier. The file name is optional. If no file name is given, the file name will be "inputname_prinseq_good.ids" (only good sequences are renamed). If a file with the same name already exists, new content will overwrite the old file. The text file contains one sequence identifier pair per line, separated by tabs (old-tab-new). Requires option -seq_id. =item B<***** FILTER OPTIONS *****> =item B<-min_len> Filter sequence shorter than min_len. =item B<-max_len> Filter sequence longer than max_len. =item B<-range_len> Filter sequence by length range. Multiple range values should be separated by comma without spaces. Example: -range_len 50-100,250-300 =item B<-min_gc> Filter sequence with GC content below min_gc. =item B<-max_gc> Filter sequence with GC content above max_gc. =item B<-range_gc> Filter sequence by GC content range. Multiple range values should be separated by comma without spaces. Example: -range_gc 50-60,75-90 =item B<-min_qual_score> Filter sequence with at least one quality score below min_qual_score. =item B<-max_qual_score> Filter sequence with at least one quality score above max_qual_score. =item B<-min_qual_mean> Filter sequence with quality score mean below min_qual_mean. =item B<-max_qual_mean> Filter sequence with quality score mean above max_qual_mean. =item B<-ns_max_p> Filter sequence with more than ns_max_p percentage of Ns. =item B<-ns_max_n> Filter sequence with more than ns_max_n Ns. =item B<-noniupac> Filter sequence with characters other than A, C, G, T or N. =item B<-seq_num> Only keep the first seq_num number of sequences (that pass all other filters). =item B<-derep> Type of duplicates to filter. Allowed values are 1, 2, 3, 4 and 5. Use integers for multiple selections (e.g. 124 to use type 1, 2 and 4). The order does not matter. Option 2 and 3 will set 1 and option 5 will set 4 as these are subsets of the other option. 1 (exact duplicate), 2 (5' duplicate), 3 (3' duplicate), 4 (reverse complement exact duplicate), 5 (reverse complement 5'/3' duplicate) =item B<-derep_min> This option specifies the number of allowed duplicates. If you want to remove sequence duplicates that occur more than x times, then you would specify x+1 as the -derep_min values. For examples, to remove sequences that occur more than 5 times, you would specify -derep_min 6. This option can only be used in combination with -derep 1 and/or 4 (forward and/or reverse exact duplicates). [default : 2] =item B<-lc_method> Method to filter low complexity sequences. The current options are "dust" and "entropy". Use "-lc_method dust" to calculate the complexity using the dust method. =item B<-lc_threshold> The threshold value (between 0 and 100) used to filter sequences by sequence complexity. The dust method uses this as maximum allowed score and the entropy method as minimum allowed value. =item B<-custom_params> Can be used to specify additional filters. The current set of possible rules is limited and has to follow the specifications below. The custom parameters have to be specified within quotes (either ' or "). Please separate parameter values with a space and separate new parameter sets with semicolon (;). Parameters are defined by two values: (1) the pattern (any combination of the letters "ACGTN"), (2) the number of repeats or percentage of occurence Percentage values are defined by a number followed by the %-sign (without space). If no %-sign is given, it is assumed that the given number specifies the number of repeats of the pattern. Examples: "AAT 10" (filters out sequences containing AATAATAATAATAATAATAATAATAATAAT anywhere in the sequence), "T 70%" (filters out sequences with more than 70% Ts in the sequence), "A 15" (filters out sequences containing AAAAAAAAAAAAAAA anywhere in the sequence), "AAT 10;T 70%;A 15" (apply all three filters) =item B<***** TRIM OPTIONS *****> =item B<-trim_to_len> Trim all sequence from the 3'-end to result in sequence with this length. =item B<-trim_left> Trim sequence at the 5'-end by trim_left positions. =item B<-trim_right> Trim sequence at the 3'-end by trim_right positions. =item B<-trim_left_p> Trim sequence at the 5'-end by trim_left_p percentage of read length. The trim length is rounded towards the lower integer (e.g. 143.6 is rounded to 143 positions). Use an integer between 1 and 100 for the percentage value. =item B<-trim_right_p> Trim sequence at the 3'-end by trim_right_p percentage of read length. The trim length is rounded towards the lower integer (e.g. 143.6 is rounded to 143 positions). Use an integer between 1 and 100 for the percentage value. =item B<-trim_tail_left> Trim poly-A/T tail with a minimum length of trim_tail_left at the 5'-end. =item B<-trim_tail_right> Trim poly-A/T tail with a minimum length of trim_tail_right at the 3'-end. =item B<-trim_ns_left> Trim poly-N tail with a minimum length of trim_ns_left at the 5'-end. =item B<-trim_ns_right> Trim poly-N tail with a minimum length of trim_ns_right at the 3'-end. =item B<-trim_qual_left> Trim sequence by quality score from the 5'-end with this threshold score. =item B<-trim_qual_right> Trim sequence by quality score from the 3'-end with this threshold score. =item B<-trim_qual_type> Type of quality score calculation to use. Allowed options are min, mean, max and sum. [default: min] =item B<-trim_qual_rule> Rule to use to compare quality score to calculated value. Allowed options are lt (less than), gt (greater than) and et (equal to). [default: lt] =item B<-trim_qual_window> The sliding window size used to calculate quality score by type. To stop at the first base that fails the rule defined, use a window size of 1. [default: 1] =item B<-trim_qual_step> Step size used to move the sliding window. To move the window over all quality scores without missing any, the step size should be less or equal to the window size. [default: 1] =item B<***** REFORMAT OPTIONS *****> =item B<-seq_case> Changes sequence character case to upper or lower case. Allowed options are "upper" and "lower". Use this option to remove soft-masking from your sequences. =item B<-dna_rna> Convert sequence between DNA and RNA. Allowed options are "dna" (convert from RNA to DNA) and "rna" (convert from DNA to RNA). =item B<-line_width> Sequence characters per line. Use 0 if you want each sequence in a single line. Use 80 for line breaks every 80 characters. Note that this option only applies to FASTA output files, since FASTQ files store sequences without additional line breaks. [default: 60] =item B<-rm_header> Remove the sequence header. This includes everything after the sequence identifier (which is kept unchanged). =item B<-seq_id> Rename the sequence identifier. A counter is added to each identifier to assure its uniqueness. Use option -seq_id_mappings to generate a file containing the old and new identifiers for later reference. Example: "mySeq_10" will generate the IDs (in FASTA format) >mySeq_101, >mySeq_102, >mySeq_103, ... =item B<***** SUMMARY STATISTIC OPTIONS *****> The summary statistic values are written to STDOUT in the form: "parameter_name statistic_name value" (without the quotes). For example, "stats_info reads 10000" or "stats_len max 500". Only one statistic is written per line and values are separated by tabs. If you specify any statistic option, no other ouput will be generated. To preprocess data, do not specify a statistics option. =item B<-stats_info> Outputs basic information such as number of reads (reads) and total bases (bases). =item B<-stats_len> Outputs minimum (min), maximum (max), range (range), mean (mean), standard deviation (stddev), mode (mode) and mode value (modeval), and median (median) for read length. =item B<-stats_dinuc> Outputs the dinucleotide odds ratio for AA/TT (aatt), AC/GT (acgt), AG/CT (agct), AT (at), CA/TG (catg), CC/GG (ccgg), CG (cg), GA/TC (gatc), GC (gc) and TA (ta). =item B<-stats_tag> Outputs the probability of a tag sequence at the 5'-end (prob5) and 3'-end (prob3) in percentage (0..100). Provides the number of predefined MIDs (midnum) and the MID sequences (midseq, separated by comma, only provided if midnum > 0) that occur in more than 34/100 (approx. 3%) of the reads. =item B<-stats_dupl> Outputs the number of exact duplicates (exact), 5' duplicates (5), 3' duplicates (3), exact duplicates with reverse complements (exactrevcom) and 5'/3' duplicates with reverse complements (revcomp), and total number of duplicates (total). The maximum number of duplicates is given under the value name with an additional "maxd" (e.g. exactmaxd or 5maxd). =item B<-stats_ns> Outputs the number of reads with ambiguous base N (seqswithn), the maximum number of Ns per read (maxn) and the maximum percentage of Ns per read (maxp). The maxn and maxp value are not necessary from the same sequence. =item B<-stats_assembly> Outputs the N50, N90, etc contig sizes. The Nxx contig size is a weighted median that is defined as the length of the smallest contig C in the sorted list of all contigs where the cumulative length from the largest contig to contig C is at least xx% of the total length (sum of contig lengths). =item B<-stats_all> Outputs all available summary statistics. =item B<***** ORDER OF PROCESSING *****> The available options are processed in the following order: seq_num, trim_left, trim_right, trim_left_p, trim_right_p, trim_qual_left, trim_qual_right, trim_tail_left, trim_tail_right, trim_ns_left, trim_ns_right, trim_to_len, min_len, max_len, range_len, min_qual_score, max_qual_score, min_qual_mean, max_qual_mean, min_gc, max_gc, range_gc, ns_max_p, ns_max_n, noniupac, lc_method, derep, seq_id, seq_case, dna_rna, out_format =back =head1 AUTHOR Robert SCHMIEDER, C<< >> =head1 BUGS If you find a bug please email me at C<< >> or use http://sourceforge.net/tracker/?group_id=315449 so that I can make PRINSEQ better. =head1 COPYRIGHT Copyright (C) 2010-2012 Robert SCHMIEDER =head1 LICENSE 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 . =cut # ################################################################################ ## DATA AND PARAMETER CHECKING ################################################################################ # my ($file1,$file2,$command,@dataread,$aa,%filtercount,$slashnum,$trimnum1,$trimnum2); #check if params file if(exists $params{params}) { my $ps = &readParamsFile($params{params}); foreach my $p (keys %$ps) { next if(exists $params{$p}); $params{$p} = $ps->{$p}; } } #check if amino acid or nucleic acid input if(exists $params{aa}) { $aa = 1; $command .= ' -aa'; } else { $aa = 0; } #Check if input file exists and check if file format is correct if(exists $params{fasta} && exists $params{fastq}) { &printError('fasta and fastq cannot be used together'); } elsif(exists $params{fasta}) { $command .= ' -fasta '.$params{fasta}; $file1 = $params{fasta}; if($params{fasta} eq 'stdin') { if(exists $params{qual} && $params{qual} eq 'stdin') { &printError('input from STDIN is only allowed for either of the input files'); } else { my $format = &checkInputFormat(); unless($format eq 'fasta') { &printError('input data for -fasta is in '.uc($format).' format not in FASTA format'); } } } elsif(-e $params{fasta}) { #check for file format my $format = &checkFileFormat($file1); unless($format eq 'fasta') { &printError('input file for -fasta is in '.uc($format).' format not in FASTA format'); } } else { &printError("could not find input file \"".$params{fasta}."\""); } } elsif(exists $params{fastq}) { $command .= ' -fastq '.$params{fastq}; $file1 = $params{fastq}; if($params{fastq} eq 'stdin') { my $format = &checkInputFormat(); unless($format eq 'fastq') { &printError('input data for -fastq is in '.uc($format).' format not in FASTQ format'); } } elsif(-e $params{fastq}) { #check for file format my $format = &checkFileFormat($file1); unless($format eq 'fastq') { &printError('input file for -fastq is in '.uc($format).' format not in FASTQ format'); } } else { &printError("could not find input file \"".$params{fastq}."\""); } } else { &printError("you did not specify an input file containing the query sequences"); } if(exists $params{fastq} && exists $params{qual}) { &printError('fastq and qual cannot be used together'); } elsif(exists $params{qual}) { $command .= ' -qual '.$params{qual}; if($params{qual} eq 'stdin') { &printError('QUAL data cannot be read from STDIN'); } elsif(-e $params{qual}) { #check for file format my $format = &checkFileFormat($params{qual}); unless($format eq 'qual') { &printError('input file for -qual is in '.uc($format).' format not in QUAL format'); } } else { &printError("could not find input file \"".$params{qual}."\""); } } if(exists $params{fasta2} && exists $params{fastq2}) { &printError('fasta2 and fastq2 cannot be used together'); } elsif(exists $params{fasta2}) { if(!exists $params{fasta}) { &printError('option fasta2 requires option fasta'); } elsif($params{fasta} eq $params{fasta2}) { &printError('option fasta and fasta2 cannot be the same input file'); } else { $command .= ' -fasta2 '.$params{fasta2}; $file2 = $params{fasta2}; if($params{fasta} eq 'stdin' || $params{fasta2} eq 'stdin') { &printError('paired-end data cannot be processed from STDIN'); } elsif(-e $params{fasta2}) { #check for file format my $format = &checkFileFormat($file2); unless($format eq 'fasta') { &printError('input file for -fasta2 is in '.uc($format).' format not in FASTA format'); } } else { &printError("could not find input file \"".$params{fasta2}."\""); } } ($slashnum,$trimnum1,$trimnum2) = &checkSlashnum($file2); } elsif(exists $params{fastq2}) { if(!exists $params{fastq}) { &printError('option fastq2 requires option fastq'); } elsif($params{fastq} eq $params{fastq2}) { &printError('option fastq and fastq2 cannot be the same input file'); } else { $command .= ' -fastq2 '.$params{fastq2}; $file2 = $params{fastq2}; if($params{fastq} eq 'stdin' || $params{fastq2} eq 'stdin') { &printError('paired-end data cannot be processed from STDIN'); } elsif(-e $params{fastq2}) { #check for file format my $format = &checkFileFormat($file2); unless($format eq 'fastq') { &printError('input file for -fastq2 is in '.uc($format).' format not in FASTQ format'); } } else { &printError("could not find input file \"".$params{fastq2}."\""); } } ($slashnum,$trimnum1,$trimnum2) = &checkSlashnum($file2); } #check if stats_all if(exists $params{stats_all}) { $params{stats_info} = 1; $params{stats_len} = 1; $params{stats_dupl} = 1 unless($file2); $params{stats_dinuc} = 1; $params{stats_tag} = 1; $params{stats_ns} = 1; $params{stats_assembly} = 1; delete($params{stats_all}); } if($aa) { delete($params{stats_dinuc}); delete($params{stats_tag}); delete($params{stats_ns}); } if($file2) { delete($params{stats_dupl}); delete($params{stats_assembly}); } #check if anything todo unless( exists $params{min_len} || exists $params{max_len} || exists $params{range_len} || exists $params{min_gc} || exists $params{max_gc} || exists $params{range_gc} || exists $params{min_qual_score} || exists $params{max_qual_score} || exists $params{min_qual_mean} || exists $params{max_qual_mean} || exists $params{ns_max_p} || exists $params{ns_max_n} || exists $params{noniupac} || exists $params{seq_num} || exists $params{derep} || exists $params{lc_method} || exists $params{lc_threshold} || exists $params{trim_to_len} || exists $params{trim_left} || exists $params{trim_right} || exists $params{trim_left_p} || exists $params{trim_right_p} || exists $params{trim_tail_left} || exists $params{trim_tail_right} || exists $params{trim_ns_left} || exists $params{trim_ns_right} || exists $params{trim_qual_left} || exists $params{trim_qual_right} || exists $params{trim_qual_type} || exists $params{trim_qual_rule} || exists $params{trim_qual_window} || exists $params{trim_qual_step} || exists $params{seq_case} || exists $params{dna_rna} || exists $params{exact_only} || exists $params{line_width} || exists $params{rm_header} || exists $params{seq_id} || exists $params{out_format} || exists $params{stats_info} || exists $params{stats_len} || exists $params{stats_dinuc} || exists $params{stats_tag} || exists $params{stats_dupl} || exists $params{stats_ns} || exists $params{stats_assembly} || exists $params{phred64} || exists $params{no_qual_header} || exists $params{graph_data} || exists $params{custom_params} ) { &printError('nothing to do with input data'); } #prevent out of files for stats if(exists $params{stats_info} || exists $params{stats_len} || exists $params{stats_dinuc} || exists $params{stats_tag} || exists $params{stats_dupl} || exists $params{stats_ns} || exists $params{stats_assembly}) { $params{out_good} = 'null'; $params{out_bad} = 'null'; $params{stats} = 1; } elsif(exists $params{out_good} && $params{out_good} eq 'null' && exists $params{out_bad} && $params{out_bad} eq 'null' && !exists $params{graph_data}) { &printError('no output selected (both set to null)'); } #check if FASTQ file is given for option phred64 if(exists $params{phred64}) { $command .= ' -phred64'; unless(exists $params{fastq}) { &printError('option -phred64 can only be used for FASTQ input files'); } } #check if output format is possible if(exists $params{out_format}) { $command .= ' -out_format '.$params{out_format}; if($params{out_format} =~ /\D/) { &printError('output format option has to be an integer value'); } elsif($params{out_format} == 2 || $params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5) { unless(exists $params{fastq} || exists $params{qual}) { &printError('cannot use this output format option without providing quality data as input'); } if(exists $params{fastq2} && ($params{out_format} == 2 || $params{out_format} == 4 || $params{out_format} == 5)) { &printError('cannot use this output format option for paired-end input data. Only values 1 and 3 are allowed'); } } elsif($params{out_format} != 1) { &printError('output format option not available'); } } else { if(exists $params{fastq}) { $params{out_format} = 3; } elsif(exists $params{fasta} && exists $params{qual}) { $params{out_format} = 2; } else { $params{out_format} = 1; } } if(exists $params{no_qual_header} && $params{out_format} != 3) { &printError('the option -no_qual_header can only be used for FASTQ outputs'); } #check if output names are different if(exists $params{out_good} && exists $params{out_bad} && $params{out_good} eq $params{out_bad} && $params{out_good} ne 'null' && $params{out_good} ne 'stdout') { &printError('the output names for -out_good and -out_bad have to be different'); } #check if output can be written to standard output if(($params{out_format} == 2 || $params{out_format} == 4 || $params{out_format} == 5) && ((exists $params{out_good} && $params{out_good} eq 'stdout') || (exists $params{out_bad} && $params{out_bad} eq 'stdout'))) { &printError('the output cannot be written to STDOUT for multiple output files. This option can only be used for FASTA only (-out_format 1) or FASTQ output (-out_format 3)'); } #check dereplication option #1 - exact dub, 2 - prefix, 3 - suffix, 4 - revcomp exact, 5 - revcomp prefix/suffix my $derep = 0; my %dereptypes; my $derepmin = 2; if(exists $params{derep}) { $command .= ' -derep '.$params{derep}; if($params{derep} < 0 || $params{derep} > 54321) { &printError('invalid option for dereplication'); } else { my @tmp = split('',$params{derep}); foreach(@tmp) { if($_ < 1 || $_ > 5) { &printError('invalid option '.$_.'for dereplication'); } else { $derep = 1; $dereptypes{($_-1)} = 0; } } } } if(!exists $dereptypes{0} && (exists $dereptypes{1} || exists $dereptypes{2})) { $dereptypes{0} = 0; } if(!exists $dereptypes{3} && exists $dereptypes{4}) { $dereptypes{3} = 0; } my $exactonly = 0; if(exists $params{exact_only}) { $command .= ' -exact_only'; if(exists $dereptypes{1} || exists $dereptypes{2} || exists $dereptypes{4}) { &printError('option -exact_only can only be used with -derep options 1 and/or 4'); } if(!exists $params{graph_data}) { &printError('option -exact_only requires option -graph_data'); } if(!exists $params{derep}) { $dereptypes{0} = 1; $dereptypes{3} = 1; } $exactonly = 1; } elsif((exists $dereptypes{0} || exists $dereptypes{3}) && !exists $dereptypes{1} && !exists $dereptypes{2} && !exists $dereptypes{4}) { $command .= ' -exact_only'; $exactonly = 1; $params{exact_only} = 1; } if(exists $params{derep_min}) { $command .= ' -derep_min '.$params{derep_min}; if($params{derep_min} < 2) { &printError('invalid option '.$params{derep_min}.'for derep_min. The values has to be greater than 1'); } elsif(exists $dereptypes{1} || exists $dereptypes{2} || exists $dereptypes{4}) { &printError('option -derep_min can only be used with -derep options 1 and/or 4'); } else { $derepmin = $params{derep_min}; } } #check for low complexity method my $complval; if(exists $params{lc_method}) { $command .= ' -lc_method '.$params{lc_method}; unless($params{lc_method} eq 'dust' || $params{lc_method} eq 'entropy') { &printError('invalid low complexity method'); } unless(exists $params{lc_threshold}) { &printError('the low complexity method requires a threshold value specified by -lc_threshold'); } $command .= ' -lc_threshold '.$params{lc_threshold}; $complval = $params{lc_threshold}; } if(exists $params{lc_threshold} && !exists $params{lc_method}) { &printError('the low complexity threshold requires a method specified by -lc_method'); } #check for quality trimming my $trimscore; if(exists $params{trim_qual_left} || exists $params{trim_qual_right}) { $command .= ' -trim_qual_right '.$params{trim_qual_right} if(exists $params{trim_qual_right}); $command .= ' -trim_qual_left '.$params{trim_qual_left} if(exists $params{trim_qual_left}); if(exists $params{trim_qual_type}) { unless($params{trim_qual_type} eq 'min' || $params{trim_qual_type} eq 'mean' || $params{trim_qual_type} eq 'max' || $params{trim_qual_type} eq 'sum') { &printError('invalid value for trim_qual_type'); } } else { $params{trim_qual_type} = $TRIM_QUAL_TYPE; } $command .= ' -trim_qual_type '.$params{trim_qual_type}; if(exists $params{trim_qual_rule}) { unless($params{trim_qual_rule} eq 'lt' || $params{trim_qual_rule} eq 'gt' || $params{trim_qual_rule} eq 'et') { &printError('invalid value for trim_qual_rule'); } } else { $params{trim_qual_rule} = $TRIM_QUAL_RULE; } $command .= ' -trim_qual_rule '.$params{trim_qual_rule}; unless(exists $params{trim_qual_window}) { $params{trim_qual_window} = $TRIM_QUAL_WINDOW; } $command .= ' -trim_qual_window '.$params{trim_qual_window}; unless(exists $params{trim_qual_step}) { $params{trim_qual_step} = $TRIM_QUAL_STEP; } $command .= ' -trim_qual_step '.$params{trim_qual_step}; $trimscore = 1; } #check sequence case if(exists $params{seq_case}) { $command .= ' -seq_case '.$params{seq_case}; unless($params{seq_case} eq 'upper' || $params{seq_case} eq 'lower') { &printError('invalid sequence case option'); } } #check for dna/rna if(exists $params{dna_rna}) { $command .= ' -dna_rna '.$params{dna_rna}; unless($params{dna_rna} eq 'dna' || $params{dna_rna} eq 'rna') { &printError('invalid option for -dna_rna'); } if($aa) { &printError('option -dna_rna cannot be used with option -aa'); } } #set remaining parameters my $linelen; if($params{out_format} == 3) { $linelen = 0; } elsif(exists $params{line_width}) { $linelen = $params{line_width}; $command .= ' -line_width '.$params{line_width}; } else { $linelen = $LINE_WIDTH; } if(exists $params{seq_id}) { $command .= ' -seq_id '.$params{seq_id}; #remove spaces, ">" and quotes from sequence ids $params{seq_id} =~ s/[\s\>\"\'\`]//g; } elsif(exists $params{seq_id_mappings}) { &printError('option -seq_id_mappings requires option -seq_id'); } if(exists $params{seq_id_mappings}) { $command .= ' -seq_id_mappings'.($params{seq_id_mappings} ? ' '.$params{seq_id_mappings} : ''); } my ($repAleft,$repTleft,$repAright,$repTright,$repNleft,$repNright); if(exists $params{trim_tail_left}) { $command .= ' -trim_tail_left '.$params{trim_tail_left}; $repAleft = 'A'x$params{trim_tail_left}; $repAleft = qr/^$repAleft/; $repTleft = 'T'x$params{trim_tail_left}; $repTleft = qr/^$repTleft/; } if(exists $params{trim_tail_right}) { $command .= ' -trim_tail_right '.$params{trim_tail_right}; $repAright = 'A'x$params{trim_tail_right}; $repAright = qr/$repAright$/; $repTright = 'T'x$params{trim_tail_right}; $repTright = qr/$repTright$/; } if(exists $params{trim_ns_left}) { $command .= ' -trim_ns_left '.$params{trim_ns_left}; $repNleft = 'N'x$params{trim_ns_left}; $repNleft = qr/^$repNleft/; } if(exists $params{trim_ns_right}) { $command .= ' -trim_ns_right '.$params{trim_ns_right}; $repNright = 'N'x$params{trim_ns_right}; $repNright = qr/$repNright$/; } #graph data file if(exists $params{graph_data}) { if(exists $params{stats}) { &printError("The graph data cannot be generated at the same time as the statistics"); } $command .= ' -graph_data'.($params{graph_data} ? ' '.$params{graph_data} : ''); unless($params{graph_data}) { $params{graph_data} = join("__",$file1||'nonamegiven').'.gd'; } $params{graph_data} = cwd().'/'.$params{graph_data} unless($params{graph_data} =~ /^\//); } my $scale = 1; if(exists $params{qual_noscale}) { $command .= ' -qual_noscale'; $scale = 0; } #graph data selection if(exists $params{graph_stats} && !exists $params{graph_data}) { &printError('option -graph_stats requires option -graph_data'); } my %webstats = %GRAPH_OPTIONS; my %graphstats = %GRAPH_OPTIONS; if(exists $params{graph_stats}) { $command .= ' -graph_stats'.($params{graph_stats} ? ' '.$params{graph_stats} : ''); if($params{graph_stats}) { #set all zeroto reset default selection foreach my $s (keys %graphstats) { $graphstats{$s} = 0; $webstats{$s} = 0; } my @tmp = split(',',$params{graph_stats}); foreach my $s (@tmp) { if(exists $graphstats{$s}) { $graphstats{$s} = 1; } else { &printError('unknown option "'.$s.'" for -graph_stats'); } } } else { &printError('please specify at least one option for -graph_stats'); } } if(exists $params{graph_stats} && exists $params{web}) { &printError('option -graph_stats cannot be used in combination with -web'); } #web output my $webnoprocess = 0; if(exists $params{web}) { $command .= ' -web'.($params{web} ? ' '.$params{web} : ''); if($params{web}) { unless($params{web} eq 'process') { $webnoprocess = 1; foreach my $s (keys %webstats) { $webstats{$s} = 0; $graphstats{$s} = 0; } my @tmp = split(',',$params{web}); foreach my $s (@tmp) { $webstats{$s} = 1; } } } } if(exists $params{graph_stats} && $graphstats{da}) { if($exactonly) { &printError('"-exact_only" and "-graph_stats da" cannot be specified at the same time'); } else { $graphstats{de} = 0; } } #do not calculate all duplicates for paired-end data (at least for now) if($file2) { if(exists $webstats{da}) { $webstats{da} = 0; } if(exists $graphstats{da}) { $graphstats{da} = 0; } } if($webstats{da}) { $webstats{de} = 0; } if($graphstats{da}) { $graphstats{de} = 0; } if((exists $params{graph_data} && $graphstats{de}) || (exists $params{web} && $webstats{de})) { $exactonly = 1; } #custom params my @cps = (); if(exists $params{custom_params}) { $command .= ' -custom_params "'.$params{custom_params}.'"'; my ($repeats,@tmp,$bases); foreach my $rule (split(/\s*\;\s*/,$params{custom_params})) { $repeats = 1; @tmp = split(/\s+/,$rule); next unless(scalar(@tmp) == 2); $bases = ($tmp[0] =~ tr/ACGTN//); next if($bases < length($tmp[0])); if(index($tmp[1],'%') != -1) { $tmp[1] =~ s/\%//g; $repeats = 0; } next unless($tmp[1] =~ m/^\d+$/o); push(@cps,[$repeats,$tmp[0],$tmp[1]]); } } #add remaining to log command if(exists $params{log} || exists $params{graph_data}) { if(exists $params{log}) { $command .= ' -log'.($params{log} ? ' '.$params{log} : ''); } if(exists $params{min_len}) { $command .= ' -min_len '.$params{min_len}; } if(exists $params{max_len}) { $command .= ' -max_len '.$params{max_len}; } if(exists $params{range_len}) { $command .= ' -range_len '.$params{range_len}; } if(exists $params{min_gc}) { $command .= ' -min_gc '.$params{min_gc}; } if(exists $params{max_gc}) { $command .= ' -max_gc '.$params{max_gc}; } if(exists $params{range_gc}) { $command .= ' -range_gc '.$params{range_gc}; } if(exists $params{min_qual_score}) { $command .= ' -min_qual_score '.$params{min_qual_score}; } if(exists $params{max_qual_score}) { $command .= ' -max_qual_score '.$params{max_qual_score}; } if(exists $params{min_qual_mean}) { $command .= ' -min_qual_mean '.$params{min_qual_mean}; } if(exists $params{max_qual_mean}) { $command .= ' -max_qual_mean '.$params{max_qual_mean}; } if(exists $params{ns_max_p}) { $command .= ' -ns_max_p '.$params{ns_max_p}; } if(exists $params{ns_max_n}) { $command .= ' -ns_max_n '.$params{ns_max_n}; } if(exists $params{noniupac}) { $command .= ' -noniupac'; } if(exists $params{seq_num}) { $command .= ' -seq_num '.$params{seq_num}; } if(exists $params{trim_to_len}) { $command .= ' -trim_to_len '.$params{trim_to_len}; } if(exists $params{trim_left}) { $command .= ' -trim_left '.$params{trim_left}; } if(exists $params{trim_right}) { $command .= ' -trim_right '.$params{trim_right}; } if(exists $params{trim_left_p}) { $command .= ' -trim_left_p '.$params{trim_left_p}; } if(exists $params{trim_right_p}) { $command .= ' -trim_right_p '.$params{trim_right_p}; } if(exists $params{rm_header}) { $command .= ' -rm_header'; } if(exists $params{stats_len}) { $command .= ' -stats_len'; } if(exists $params{stats_dinuc}) { $command .= ' -stats_dinuc'; } if(exists $params{stats_info}) { $command .= ' -stats_info'; } if(exists $params{stats_tag}) { $command .= ' -stats_tag'; } if(exists $params{stats_dupl}) { $command .= ' -stats_dupl'; } if(exists $params{stats_ns}) { $command .= ' -stats_ns'; } if(exists $params{stats_assembly}) { $command .= ' -stats_assembly'; } if(exists $params{verbose}) { $command .= ' -verbose'; } if(exists $params{out_good}) { $command .= ' -out_good '.$params{out_good}; } if(exists $params{out_bad}) { $command .= ' -out_bad '.$params{out_bad}; } if(exists $params{no_qual_header}) { $command .= ' -no_qual_header'; } if(exists $params{log}) { unless($params{log}) { $params{log} = join("__",$file1||'nonamegiven').'.log'; } $params{log} = cwd().'/'.$params{log} unless($params{log} =~ /^\//); if(exists $params{web}) { &printLog("Executing PRINSEQ using params file"); } else { &printLog("Executing PRINSEQ with command: \"perl prinseq-".$WHAT.".pl".$command."\""); } } } # ################################################################################ ## DATA PROCESSING ################################################################################ # #order of processing: #seq_num, trim_left, trim_right, trim_left_p, trim_right_p, trim_qual_left, trim_qual_right, trim_tail_left, trim_tail_right, trim_ns_left, trim_ns_right, trim_to_len, min_len, max_len, range_len, min_qual_score, max_qual_score, min_qual_mean, max_qual_mean, min_gc, max_gc, range_gc, ns_max_p, ns_max_n, noniupac, lc_method, derep, seq_id, seq_case, dna_rna, out_format my $filename = $file1; while($filename =~ /[\w\d]+\.[\w\d]+$/) { $filename =~ s/\.[\w\d]+$//; last if($filename =~ /\/[^\.]+$/); } my $filename2; if($file2) { $filename2 = $file2; while($filename2 =~ /[\w\d]+\.[\w\d]+$/) { $filename2 =~ s/\.[\w\d]+$//; last if($filename2 =~ /\/[^\.]+$/); } } #create filehandles for the output data my ($fhgood,$fhgood2,$fhgood3,$fh2good,$fh2good2,$fhbad,$fhbad2,$fhbad3,$fh2bad,$fhmappings); my ($filenamegood,$filenamegood2,$filenamegood3,$filename2good,$filename2good2,$filenamebad,$filenamebad2,$filenamebad3,$filename2bad,$filenamemappings); my ($nogood,$nobad,$stdoutgood,$stdoutbad,$mappings); $nogood = $nobad = $stdoutgood = $stdoutbad = $mappings = 0; if(exists $params{out_good}) { if($params{out_good} eq 'null') { $nogood = 1; } elsif($params{out_good} eq 'stdout') { $stdoutgood = 1; } else { if($filename2) { #first input file outputs open($fhgood,">".$params{out_good}.'_1.fast'.($params{out_format} == 3 ? 'q' : 'a')) or &printError('cannot open output file'); $filenamegood = $params{out_good}.'_1.fast'.($params{out_format} == 3 ? 'q' : 'a'); open($fhgood2,">".$params{out_good}.'_1_singletons.fast'.($params{out_format} == 3 ? 'q' : 'a')) or &printError('cannot open output file'); $filenamegood2 = $params{out_good}.'_1_singletons.fast'.($params{out_format} == 3 ? 'q' : 'a'); #second input file outputs open($fh2good,">".$params{out_good}.'_2.fast'.($params{out_format} == 3 ? 'q' : 'a')) or &printError('cannot open output file'); $filename2good = $params{out_good}.'_2.fast'.($params{out_format} == 3 ? 'q' : 'a'); open($fh2good2,">".$params{out_good}.'_2_singletons.fast'.($params{out_format} == 3 ? 'q' : 'a')) or &printError('cannot open output file'); $filename2good2 = $params{out_good}.'_2_singletons.fast'.($params{out_format} == 3 ? 'q' : 'a'); } else { open($fhgood,">".$params{out_good}.'.fast'.(($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5 ) ? 'q' : 'a')) or &printError('cannot open output file'); $filenamegood = $params{out_good}.'.fast'.(($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5 ) ? 'q' : 'a'); } } } else { if($filename2) { $fhgood = File::Temp->new( TEMPLATE => $filename.'_prinseq_good_XXXX', SUFFIX => '.fast'.(($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5 ) ? 'q' : 'a'), UNLINK => 0); $filenamegood = $fhgood->filename; $fhgood2 = File::Temp->new( TEMPLATE => $filename.'_prinseq_good_singletons_XXXX', SUFFIX => '.fast'.($params{out_format} == 3 ? 'q' : 'a'), UNLINK => 0); $filenamegood2 = $fhgood2->filename; $fh2good = File::Temp->new( TEMPLATE => $filename2.'_prinseq_good_XXXX', SUFFIX => '.fast'.(($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5 ) ? 'q' : 'a'), UNLINK => 0); $filename2good = $fh2good->filename; $fh2good2 = File::Temp->new( TEMPLATE => $filename2.'_prinseq_good_singletons_XXXX', SUFFIX => '.fast'.($params{out_format} == 3 ? 'q' : 'a'), UNLINK => 0); $filename2good2 = $fh2good2->filename; } else { $fhgood = File::Temp->new( TEMPLATE => $filename.'_prinseq_good_XXXX', SUFFIX => '.fast'.(($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5 ) ? 'q' : 'a'), UNLINK => 0); $filenamegood = $fhgood->filename; } } if(exists $params{out_bad}) { if($params{out_bad} eq 'null') { $nobad = 1; } elsif($params{out_bad} eq 'stdout') { $stdoutbad = 1; } else { if($filename2) { open($fhbad,">".$params{out_bad}.'_1.fast'.($params{out_format} == 3 ? 'q' : 'a')) or &printError('cannot open output file'); $filenamebad = $params{out_bad}.'_1.fast'.($params{out_format} == 3 ? 'q' : 'a'); open($fh2bad,">".$params{out_bad}.'_2.fast'.($params{out_format} == 3 ? 'q' : 'a')) or &printError('cannot open output file'); $filename2bad = $params{out_bad}.'_2.fast'.($params{out_format} == 3 ? 'q' : 'a'); } else { open($fhbad,">".$params{out_bad}.'.fast'.(($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5 ) ? 'q' : 'a')) or &printError('cannot open output file'); $filenamebad = $params{out_bad}.'.fast'.(($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5 ) ? 'q' : 'a'); } } } else { $fhbad = File::Temp->new( TEMPLATE => $filename.'_prinseq_bad_XXXX', SUFFIX => '.fast'.(($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5 ) ? 'q' : 'a'), UNLINK => 0); $filenamebad = $fhbad->filename; if($filename2) { $fh2bad = File::Temp->new( TEMPLATE => $filename2.'_prinseq_bad_XXXX', SUFFIX => '.fast'.($params{out_format} ? 'q' : 'a'), UNLINK => 0); $filename2bad = $fh2bad->filename; } } if($params{out_format} == 2 || $params{out_format} == 5) { if(exists $params{out_good}) { unless($nogood) { open($fhgood2,">".$params{out_good}.'.qual') or &printError('cannot open output file'); $filenamegood2 = $params{out_good}.'.qual'; } } else { $fhgood2 = File::Temp->new( TEMPLATE => $filename.'_prinseq_good_XXXX', SUFFIX => '.qual', UNLINK => 0); $filenamegood2 = $fhgood2->filename; } if(exists $params{out_bad}) { unless($nobad) { open($fhbad2,">".$params{out_bad}.'.qual') or &printError('cannot open output file'); $filenamebad2 = $params{out_bad}.'.qual'; } } else { $fhbad2 = File::Temp->new( TEMPLATE => $filename.'_prinseq_bad_XXXX', SUFFIX => '.qual', UNLINK => 0); $filenamebad2 = $fhbad2->filename; } } if($params{out_format} == 4 || $params{out_format} == 5) { if(exists $params{out_good}) { unless($nogood) { open($fhgood3,">".$params{out_good}.'.fasta') or &printError('cannot open output file'); $filenamegood3 = $params{out_good}.'.fasta'; } } else { $fhgood3 = File::Temp->new( TEMPLATE => $filename.'_prinseq_good_XXXX', SUFFIX => '.fasta', UNLINK => 0); $filenamegood3 = $fhgood3->filename; } if(exists $params{out_bad}) { unless($nobad) { open($fhbad3,">".$params{out_bad}.'.fasta') or &printError('cannot open output file'); $filenamebad3 = $params{out_bad}.'.fasta'; } } else { $fhbad3 = File::Temp->new( TEMPLATE => $filename.'_prinseq_bad_XXXX', SUFFIX => '.fasta', UNLINK => 0); $filenamebad3 = $fhbad3->filename; } } if(exists $params{seq_id_mappings}) { $mappings = 1; if($params{seq_id_mappings}) { open($fhmappings,">".$params{seq_id_mappings}) or &printError('cannot open output file'); $filenamemappings = $params{seq_id_mappings}; } else { open($fhmappings,">".$filename.'_prinseq_good.ids') or &printError('cannot open output file'); $filenamemappings = $filename.'_prinseq_good.ids'; } } my $numlines = 0; $webnoprocess = 1 if(!$webnoprocess && exists $params{graph_data} && !exists $params{web} && $nogood && $nobad); my ($progress,$counter,$part); $progress = 0; $counter = $part = 1; if(exists $params{verbose}) { print STDERR "Estimate size of input data for status report (this might take a while for large files)\n"; $numlines = ($file1 eq 'stdin' ? 1 : &getLineNumber($file1)); $numlines += &getLineNumber($file2) if($file2); print STDERR "\tdone\n"; } if(exists $params{web}) { &printWeb("STATUS: Estimate size of input data for status report (this might take a while for large files)"); $numlines = &getLineNumber($file1) unless($numlines); $numlines += &getLineNumber($file2) if($file2) } #for progress bar if($numlines) { $part = int($numlines/100); } #parse input data print STDERR "Parse and process input data\n" if(exists $params{verbose}); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); if(exists $params{web}) { &printWeb("STATUS: Parsing and processing input data"); &printWeb("STATUS: process-status $progress"); &printLog("Parsing and processing input data"); } else { &printLog("Parsing and processing input data: \"".$file1."\"".(exists $params{qual} ? " and \"".$params{qual}."\"" : "").($file2 ? " and \"".$file2."\"" : "")); } my $numseqs = 0; my $numseqs2 = 0; my $pairs = 0; my $goodcount = 0; my $badcount = 0; my $badcount2 = 0; my ($tsvfile,$seqid,$header,$seq,$qual,$count,$numbases,$numbases2,$length,$seqgd); $count = 0; $qual = ''; $seq = ''; #stats data my (%stats,%kmers,%odds,%counts,%graphdata,%kmers2,%counts2,%graphdata2,$md5,$md5r,%md5s,%md5sg,$ucseq,$maxlength); $maxlength = 0; #parse data my $seqcount = 0; my $seqcount1 = 0; #singleton file 1 my $seqcount2 = 0; #singleton file 2 my $seqbases = 0; my $seqbases1 = 0; #singleton file 1 my $seqbases2 = 0; #singleton file 2 my $badbases = 0; my $badbases2 = 0; my (@seqs,@seqsP,@printtmp,$line); #seqs for stats and graph data, seqsP for preprocessing sequences - all used for duplicate checking/removal if($file2) { open(FILE,"perl -pe 's/\r\n|\r/\n/g' < $file1 |") or &printError("Could not open file $file1: $!"); open(FILE2,"perl -pe 's/\r\n|\r/\n/g' < $file2 |") or &printError("Could not open file $file2: $!"); } else { if($file1 eq 'stdin') { *FILE = *STDIN; } else { open(FILE,"perl -pe 's/\r\n|\r/\n/g' < $file1 |") or &printError("Could not open file $file1: $!"); } if(exists $params{qual}) { if($params{qual} eq 'stdin') { &printError('QUAL data cannot be read from STDIN'); } else { open(FILE2,"perl -pe 's/\r\n|\r/\n/g' < ".$params{qual}." |") or &printError("Could not open file ".$params{qual}.": $!"); } } } my $exists_stats = (exists $params{stats} ? 1 : 0); my $exists_graphdata = (exists $params{graph_data} ? 1 : 0); if($file2) { my ($seqid2,$seq2,$header2,$qual2,$length2,%tmpids,@tmpdata1,@tmpdata2,$tmpindex,$tmpentry,$skip1,$skip2,$tmpid,$tmpid2); $skip1 = $skip2 = 0; if(exists $params{fastq}) { while(1) { ($seq,$seqid,$qual,$header,$tmpid) = &readEntryFastq(*FILE,$skip1--,$trimnum1); ($seq2,$seqid2,$qual2,$header2,$tmpid2) = &readEntryFastq(*FILE2,$skip2--,$trimnum2); last unless($seq || $seq2); #check if both have same id; if not, store in tmpdata if(defined $tmpid && defined $tmpid2 && $tmpid eq $tmpid2) { #same ids &processEntryPairedEnd(length($seq),$seq,$seqid,$header,$qual,length($seq2),$seq2,$seqid2,$header2,$qual2); if(keys %tmpids) { #empty tmpdata %tmpids = (); while(@tmpdata1) { &processEntryPairedEnd(@{(shift(@tmpdata1))}[0..4]); } while(@tmpdata2) { &processEntryPairedEnd(undef,undef,undef,undef,undef,@{(shift(@tmpdata2))}[0..4]); } } $skip1 = $skip2 = 0; } elsif(defined $tmpid && exists $tmpids{$tmpid}) { while(@tmpdata1) { $tmpentry = shift(@tmpdata1); &processEntryPairedEnd(@$tmpentry[0..4]); delete($tmpids{$tmpentry->[5]}); } $tmpindex = $tmpids{$tmpid}; while($tmpindex-- > 0) { $tmpentry = shift(@tmpdata2); &processEntryPairedEnd(undef,undef,undef,undef,undef,@$tmpentry[0..4]); delete($tmpids{$tmpentry->[5]}); } #correct indices $tmpindex = $tmpids{$tmpid}+1; foreach my $k (keys %tmpids) { $tmpids{$k} -= $tmpindex; } &processEntryPairedEnd(length($seq),$seq,$seqid,$header,$qual,@{(shift(@tmpdata2))}[0..4]); delete($tmpids{$tmpid}); if(defined $seqid2) { $tmpids{$tmpid2} = scalar(@tmpdata2); push(@tmpdata2,[length($seq2),$seq2,$seqid2,$header2,$qual2,$tmpid2]); } #equal out tmpdata1 and tmpdata2 unless(scalar(@tmpdata1) == scalar(@tmpdata2)) { $skip1 = 0; $skip2 = scalar(@tmpdata2); } } elsif(defined $seqid2 && exists $tmpids{$tmpid2}) { while(@tmpdata2) { $tmpentry = shift(@tmpdata2); &processEntryPairedEnd(undef,undef,undef,undef,undef,@$tmpentry[0..4]); delete($tmpids{$tmpentry->[5]}); } $tmpindex = $tmpids{$tmpid2}; while($tmpindex-- > 0) { $tmpentry = shift(@tmpdata1); &processEntryPairedEnd(@$tmpentry[0..4]); delete($tmpids{$tmpentry->[5]}); } #correct indices $tmpindex = $tmpids{$tmpid2}+1; foreach my $k (keys %tmpids) { $tmpids{$k} -= $tmpindex; } &processEntryPairedEnd(@{(shift(@tmpdata1))}[0..4],length($seq2),$seq2,$seqid2,$header2,$qual2); delete($tmpids{$tmpid2}); if(defined $seqid) { $tmpids{$tmpid} = scalar(@tmpdata1); push(@tmpdata1,[length($seq),$seq,$seqid,$header,$qual,$tmpid]); } #equal out tmpdata1 and tmpdata2 unless(scalar(@tmpdata1) == scalar(@tmpdata2)) { $skip1 = scalar(@tmpdata1); $skip2 = 0; } } else { #store in tmpdata if(defined $seqid) { $tmpids{$tmpid} = scalar(@tmpdata1); push(@tmpdata1,[length($seq),$seq,$seqid,$header,$qual,$tmpid]); } if(defined $seqid2) { $tmpids{$tmpid2} = scalar(@tmpdata2); push(@tmpdata2,[length($seq2),$seq2,$seqid2,$header2,$qual2,$tmpid2]); } } #progress bar stuff if($counter > $part) { $counter = 1; $progress++; $progress = 99 if($progress > 99); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); &printWeb("STATUS: process-status $progress"); } } #process remaining in tmpdata while(@tmpdata1) { $tmpentry = shift(@tmpdata1); &processEntryPairedEnd(@$tmpentry[0..4]); delete($tmpids{$tmpentry->[5]}); } while(@tmpdata2) { $tmpentry = shift(@tmpdata2); &processEntryPairedEnd(undef,undef,undef,undef,undef,@$tmpentry[0..4]); delete($tmpids{$tmpentry->[5]}); } } else { #format is FASTA my ($nextid,$nextheader,$nextid2,$nextheader2); while(1) { ($seq,$seqid,$header,$tmpid,$nextid,$nextheader) = &readEntryFasta(*FILE,$skip1--,$trimnum1,$nextid,$nextheader); ($seq2,$seqid2,$header2,$tmpid2,$nextid2,$nextheader2) = &readEntryFasta(*FILE2,$skip2--,$trimnum2,$nextid2,$nextheader2); last unless($seq || $seq2); #check if both have same id; if not, store in tmpdata if(defined $tmpid && defined $tmpid2 && $tmpid eq $tmpid2) { #same ids &processEntryPairedEnd(length($seq),$seq,$seqid,$header,undef,length($seq2),$seq2,$seqid2,$header2,undef); if(keys %tmpids) { #empty tmpdata %tmpids = (); while(@tmpdata1) { &processEntryPairedEnd(@{(shift(@tmpdata1))}[0..3]); } while(@tmpdata2) { &processEntryPairedEnd(undef,undef,undef,undef,undef,@{(shift(@tmpdata2))}[0..3]); } } $skip1 = $skip2 = 0; } elsif(defined $tmpid && exists $tmpids{$tmpid}) { while(@tmpdata1) { $tmpentry = shift(@tmpdata1); &processEntryPairedEnd(@$tmpentry[0..3]); delete($tmpids{$tmpentry->[4]}); } $tmpindex = $tmpids{$tmpid}; while($tmpindex-- > 0) { $tmpentry = shift(@tmpdata2); &processEntryPairedEnd(undef,undef,undef,undef,undef,@$tmpentry[0..3]); delete($tmpids{$tmpentry->[4]}); } #correct indices $tmpindex = $tmpids{$tmpid}+1; foreach my $k (keys %tmpids) { $tmpids{$k} -= $tmpindex; } &processEntryPairedEnd(length($seq),$seq,$seqid,$header,undef,@{(shift(@tmpdata2))}[0..3]); delete($tmpids{$tmpid}); if(defined $seqid2) { $tmpids{$tmpid2} = scalar(@tmpdata2); push(@tmpdata2,[length($seq2),$seq2,$seqid2,$header2,$tmpid2]); } #equal out tmpdata1 and tmpdata2 unless(scalar(@tmpdata1) == scalar(@tmpdata2)) { $skip1 = 0; $skip2 = scalar(@tmpdata2); } } elsif(defined $seqid2 && exists $tmpids{$tmpid2}) { while(@tmpdata2) { $tmpentry = shift(@tmpdata2); &processEntryPairedEnd(undef,undef,undef,undef,undef,@$tmpentry[0..3]); delete($tmpids{$tmpentry->[4]}); } $tmpindex = $tmpids{$tmpid2}; while($tmpindex-- > 0) { $tmpentry = shift(@tmpdata1); &processEntryPairedEnd(@$tmpentry[0..3]); delete($tmpids{$tmpentry->[4]}); } #correct indices $tmpindex = $tmpids{$tmpid2}+1; foreach my $k (keys %tmpids) { $tmpids{$k} -= $tmpindex; } &processEntryPairedEnd(@{(shift(@tmpdata1))}[0..3],undef,length($seq2),$seq2,$seqid2,$header2); delete($tmpids{$tmpid2}); if(defined $seqid) { $tmpids{$tmpid} = scalar(@tmpdata1); push(@tmpdata1,[$length,$seq,$seqid,$header,$tmpid]); } #equal out tmpdata1 and tmpdata2 unless(scalar(@tmpdata1) == scalar(@tmpdata2)) { $skip1 = scalar(@tmpdata1); $skip2 = 0; } } else { #store in tmpdata if(defined $seqid) { $tmpids{$tmpid} = scalar(@tmpdata1); push(@tmpdata1,[$length,$seq,$seqid,$header,$tmpid]); } if(defined $seqid2) { $tmpids{$tmpid2} = scalar(@tmpdata2); push(@tmpdata2,[length($seq2),$seq2,$seqid2,$header2,$tmpid2]); } } #progress bar stuff if($counter > $part) { $counter = 1; $progress++; $progress = 99 if($progress > 99); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); &printWeb("STATUS: process-status $progress"); } } #process remaining in tmpdata while(@tmpdata1) { $tmpentry = shift(@tmpdata1); &processEntryPairedEnd(@$tmpentry[0..3]); delete($tmpids{$tmpentry->[4]}); } while(@tmpdata2) { $tmpentry = shift(@tmpdata2); &processEntryPairedEnd(undef,undef,undef,undef,undef,@$tmpentry[0..3]); delete($tmpids{$tmpentry->[4]}); } } } else { if(exists $params{fastq}) { foreach(@dataread) { #only used for stdin inputs chomp(); if($count == 0 && /^\@(\S+)\s*(.*)$/o) { $length = length($seq); if($length) { &processEntry($length,$seq,$seqid,$qual,$header); } $seqid = $1; $header = $2 || ''; $seq = ''; $qual = ''; } elsif($count == 1) { $seq = $_; } elsif($count == 3) { $qual = $_; $count = -1; } $count++; } while() { chomp(); if($count == 0 && /^\@(\S+)\s*(.*)$/o) { $length = length($seq); if($length) { &processEntry($length,$seq,$seqid,$qual,$header); } $seqid = $1; $header = $2 || ''; $seq = ''; $qual = ''; } elsif($count == 1) { $seq = $_; } elsif($count == 3) { $qual = $_; $count = -1; } $count++; #progress bar stuff $counter++; if($counter > $part) { $counter = 1; $progress++; $progress = 99 if($progress > 99); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); &printWeb("STATUS: process-status $progress"); } } #add last one $length = length($seq); if($length) { &processEntry($length,$seq,$seqid,$qual,$header); } } elsif(exists $params{fasta}) { foreach(@dataread) { #only used for stdin inputs chomp(); if(/^>(\S+)\s*(.*)$/o) { $length = length($seq); if($length) { #get qual data if provided if(exists $params{qual}) { while() { chomp(); last if(/^>/ && $qual); next if(/^>/); $qual .= $_.' '; } $qual = &convertQualNumsToAsciiString($qual); } &processEntry($length,$seq,$seqid,$qual,$header); $qual = ''; } $seqid = $1; $header = $2 || ''; $seq = ''; } else { $seq .= $_; } } while() { chomp(); if(/^>(\S+)\s*(.*)$/o) { $length = length($seq); if($length) { #get qual data if provided if(exists $params{qual}) { while() { chomp(); last if(/^>/ && $qual); next if(/^>/); $qual .= $_.' '; } $qual = &convertQualNumsToAsciiString($qual); } &processEntry($length,$seq,$seqid,$qual,$header); $qual = ''; } $seqid = $1; $header = $2 || ''; $seq = ''; } else { $seq .= $_; } #progress bar stuff $counter++; if($counter > $part) { $counter = 1; $progress++; $progress = 99 if($progress > 99); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); &printWeb("STATUS: process-status $progress"); } } #add last one $length = length($seq); if($length) { #get qual data if provided if(exists $params{qual}) { while() { chomp(); last if(/^>/ && $qual); next if(/^>/); $qual .= $_.' '; } $qual = &convertQualNumsToAsciiString($qual); } &processEntry($length,$seq,$seqid,$qual,$header); $qual = ''; } } } print STDERR "\r\tdone \n" if(exists $params{verbose}); &printWeb("STATUS: process-status 100"); &printWeb("Done parsing and processing input data"); &printLog("Done parsing and processing input data"); if($derep && !exists $params{stats} && !$exactonly && !$webnoprocess) { &printLog("Remove duplicates"); &derepSeqs(); &printLog("Done removing duplicates"); } close(FILE); close(FILE2) if(exists $params{qual} || $file2); print STDERR "Clean up empty files\n" if(exists $params{verbose} && !exists $params{stats}); #close filehandles unless($nogood || $stdoutgood) { close($fhgood); if($file2) { close($fhgood2); close($fh2good); close($fh2good2); } } unless($nobad || $stdoutbad) { close($fhbad); if($file2) { close($fh2bad); } } if($params{out_format} == 2 || $params{out_format} == 5) { close($fhgood2) unless($nogood || $stdoutgood); close($fhbad2) unless($nobad || $stdoutbad); } if($params{out_format} == 4 || $params{out_format} == 5) { close($fhgood3) unless($nogood || $stdoutgood); close($fhbad3) unless($nobad || $stdoutbad); } if(exists $params{seq_id_mappings}) { close($fhmappings); } #remove empty files if($seqcount == 0 && !$nogood && !$stdoutgood) { unlink($filenamegood); if($params{out_format} == 2 || $params{out_format} == 5) { unlink($filenamegood2); } if($params{out_format} == 4 || $params{out_format} == 5) { unlink($filenamegood3); } unlink($fhmappings); } if($badcount == 0 && !$nobad && !$stdoutbad) { unlink($filenamebad); if($params{out_format} == 2 || $params{out_format} == 5) { unlink($filenamebad2); } if($params{out_format} == 4 || $params{out_format} == 5) { unlink($filenamebad3); } } if($file2) { foreach my $f ($filenamegood2,$filename2good,$filename2good2,$filename2bad) { if(defined $f && -e $f && &getLineNumber($f) == 0) { unlink($f); } } } print STDERR "\tdone\n" if(exists $params{verbose} && !exists $params{stats}); #print processing stats if((exists $params{verbose} || !$webnoprocess) && !exists $params{stats}) { print STDERR "Input and filter stats:\n"; if($file2) { print STDERR "\tInput sequences (file 1): ".&addCommas($numseqs)."\n"; print STDERR "\tInput bases (file 1): ".&addCommas($numbases)."\n"; print STDERR "\tInput mean length (file 1): ".sprintf("%.2f",$numbases/$numseqs)."\n" if($numseqs); print STDERR "\tInput sequences (file 2): ".&addCommas($numseqs2)."\n"; print STDERR "\tInput bases (file 2): ".&addCommas($numbases2)."\n"; print STDERR "\tInput mean length (file 2): ".sprintf("%.2f",$numbases2/$numseqs2)."\n" if($numseqs2); print STDERR "\tGood sequences (pairs): ".&addCommas($seqcount)."\n" if($numseqs); print STDERR "\tGood bases (pairs): ".&addCommas($seqbases)."\n" if($seqcount); print STDERR "\tGood mean length (pairs): ".sprintf("%.2f",$seqbases/$seqcount)."\n" if($seqcount); print STDERR "\tGood sequences (singletons file 1): ".&addCommas($seqcount1)." (".sprintf("%.2f",(100*$seqcount1/$numseqs))."%)\n" if($numseqs); print STDERR "\tGood bases (singletons file 1): ".&addCommas($seqbases1)."\n" if($seqcount1); print STDERR "\tGood mean length (singletons file 1): ".sprintf("%.2f",$seqbases1/$seqcount1)."\n" if($seqcount1); print STDERR "\tGood sequences (singletons file 2): ".&addCommas($seqcount2)." (".sprintf("%.2f",(100*$seqcount2/$numseqs2))."%)\n" if($numseqs2); print STDERR "\tGood bases (singletons file 2): ".&addCommas($seqbases2)."\n" if($seqcount2); print STDERR "\tGood mean length (singletons file 2): ".sprintf("%.2f",$seqbases2/$seqcount2)."\n" if($seqcount2); print STDERR "\tBad sequences (file 1): ".&addCommas($badcount)." (".sprintf("%.2f",(100*$badcount/$numseqs))."%)\n" if($numseqs); print STDERR "\tBad bases (file 1): ".&addCommas($badbases)."\n" if($badcount); print STDERR "\tBad mean length (file 1): ".sprintf("%.2f",$badbases/$badcount)."\n" if($badcount); print STDERR "\tBad sequences (file 2): ".&addCommas($badcount2)." (".sprintf("%.2f",(100*$badcount2/$numseqs2))."%)\n" if($numseqs2); print STDERR "\tBad bases (file 2): ".&addCommas($badbases2)."\n" if($badcount2); print STDERR "\tBad mean length (file 2): ".sprintf("%.2f",$badbases2/$badcount2)."\n" if($badcount2); } else { print STDERR "\tInput sequences: ".&addCommas($numseqs)."\n"; print STDERR "\tInput bases: ".&addCommas($numbases)."\n"; print STDERR "\tInput mean length: ".sprintf("%.2f",$numbases/$numseqs)."\n" if($numseqs); print STDERR "\tGood sequences: ".&addCommas($seqcount)." (".sprintf("%.2f",(100*$seqcount/$numseqs))."%)\n" if($numseqs); print STDERR "\tGood bases: ".&addCommas($seqbases)."\n" if($seqcount); print STDERR "\tGood mean length: ".sprintf("%.2f",$seqbases/$seqcount)."\n" if($seqcount); print STDERR "\tBad sequences: ".&addCommas($badcount)." (".sprintf("%.2f",(100*$badcount/$numseqs))."%)\n" if($numseqs); print STDERR "\tBad bases: ".&addCommas($badbases)."\n" if($badcount); print STDERR "\tBad mean length: ".sprintf("%.2f",$badbases/$badcount)."\n" if($badcount); } my $tmp = &getFiltercounts(); if($tmp) { print STDERR "\tSequences filtered by specified parameters:\n"; if(scalar(@$tmp)) { print STDERR "\t$_\n" foreach(@$tmp); } else { print STDERR "\tnone\n"; } } if(exists $params{log}) { if($file2) { &printLog("Input sequences (file 1): ".&addCommas($numseqs)); &printLog("Input bases (file 1): ".&addCommas($numbases)); &printLog("Input mean length (file 1): ".sprintf("%.2f",$numbases/$numseqs)) if($numseqs); &printLog("Input sequences (file 2): ".&addCommas($numseqs2)); &printLog("Input bases (file 2): ".&addCommas($numbases2)); &printLog("Input mean length (file 2): ".sprintf("%.2f",$numbases2/$numseqs2)) if($numseqs2); &printLog("Good sequences (pairs): ".&addCommas($seqcount)) if($numseqs); &printLog("Good bases (pairs): ".&addCommas($seqbases)) if($seqcount); &printLog("Good mean length (pairs): ".sprintf("%.2f",$seqbases/$seqcount)) if($seqcount); &printLog("Good sequences (singletons file 1): ".&addCommas($seqcount1)." (".sprintf("%.2f",(100*$seqcount1/$numseqs))."%)") if($numseqs); &printLog("Good bases (singletons file 1): ".&addCommas($seqbases1)) if($seqcount1); &printLog("Good mean length (singletons file 1): ".sprintf("%.2f",$seqbases1/$seqcount1)) if($seqcount1); &printLog("Good sequences (singletons file 2): ".&addCommas($seqcount2)." (".sprintf("%.2f",(100*$seqcount2/$numseqs2))."%)") if($numseqs2); &printLog("Good bases (singletons file 2): ".&addCommas($seqbases2)) if($seqcount2); &printLog("Good mean length (singletons file 2): ".sprintf("%.2f",$seqbases2/$seqcount2)) if($seqcount2); &printLog("Bad sequences (file 1): ".&addCommas($badcount)." (".sprintf("%.2f",(100*$badcount/$numseqs))."%)") if($numseqs); &printLog("Bad bases (file 1): ".&addCommas($badbases)) if($badcount); &printLog("Bad mean length (file 1): ".sprintf("%.2f",$badbases/$badcount)) if($badcount); &printLog("Bad sequences (file 2): ".&addCommas($badcount2)." (".sprintf("%.2f",(100*$badcount2/$numseqs2))."%)") if($numseqs2); &printLog("Bad bases (file 2): ".&addCommas($badbases2)) if($badcount2); &printLog("Bad mean length (file 2): ".sprintf("%.2f",$badbases2/$badcount2)) if($badcount2); } else { &printLog("Input sequences: ".&addCommas($numseqs)); &printLog("Input bases: ".&addCommas($numbases)); &printLog("Input mean length: ".sprintf("%.2f",$numbases/$numseqs)) if($numseqs); &printLog("Good sequences: ".&addCommas($seqcount)." (".sprintf("%.2f",(100*$seqcount/$numseqs))."%)") if($numseqs); &printLog("Good bases: ".&addCommas($seqbases)) if($seqcount); &printLog("Good mean length: ".sprintf("%.2f",$seqbases/$seqcount)) if($seqcount); &printLog("Bad sequences: ".&addCommas($badcount)." (".sprintf("%.2f",(100*$badcount/$numseqs))."%)") if($numseqs); &printLog("Bad bases: ".&addCommas($badbases)) if($badcount); &printLog("Bad mean length: ".sprintf("%.2f",$badbases/$badcount)) if($badcount); } if($tmp) { &printLog("Sequences filtered by specified parameters:"); if(scalar(@$tmp)) { &printLog($_) foreach(@$tmp); } else { &printLog("none"); } } } } #print summary stats if(exists $params{stats}) { if(exists $params{stats_info}) { $stats{stats_info}->{reads} = $numseqs; $stats{stats_info}->{bases} = $numbases; if($file2) { $stats{stats_info2}->{reads} = $numseqs2; $stats{stats_info2}->{bases} = $numbases2; } } if(exists $params{stats_len}) { $stats{stats_len} = &generateStats($counts{length}); $stats{stats_len2} = &generateStats($counts2{length}) if($file2); } if(exists $params{stats_dinuc}) { foreach my $i (keys %odds) { $stats{stats_dinuc}->{lc($i)} = sprintf("%.9f",$odds{$i}/($numseqs+$numseqs2)); } } if(exists $params{stats_tag}) { #calculate frequency of 5-mers my $kmersum = &getTagFrequency(\%kmers); #check for frequency of MID tags my $midsum = 0; my $midcount = 0; my @midseqs; foreach my $mid (keys %MIDS) { $midsum += $MIDS{$mid}; if($MIDS{$mid} > $numseqs/34) { #in more than 34/100 (approx. 3%) as this is estimated average error for MIDs $midcount++; push(@midseqs,$mid); } } $stats{stats_tag}->{midnum} = $midcount; if($midcount) { $stats{stats_tag}->{midseq} = join(",",@midseqs); } if($midsum > $kmersum->{5}) { $kmersum->{5} = $midsum; } foreach my $kmer (keys %$kmersum) { $stats{stats_tag}->{'prob'.$kmer} = sprintf("%d",(100/$numseqs*$kmersum->{$kmer})); } if($file2) { my $kmersum2 = &getTagFrequency(\%kmers2); foreach my $kmer (keys %$kmersum2) { $stats{stats_tag2}->{'prob'.$kmer} = sprintf("%d",(100/$numseqs2*$kmersum2->{$kmer})); } } } if(exists $params{stats_assembly}) { #calculate N50, N90, etc #sort in decreasing order my @sortvals = sort {$b <=> $a} keys %{$counts{length}}; #calculate nx values my $n50 = $numbases*0.5; my $n75 = $numbases*0.75; my $n90 = $numbases*0.9; my $n95 = $numbases*0.95; my $curlen = 0; foreach my $len (@sortvals) { foreach my $i (1..$counts{length}->{$len}) { $curlen += $len; if($curlen >= $n50 && !exists $stats{stats_assembly}->{N50}) { $stats{stats_assembly}->{N50} = $len; } elsif($curlen >= $n75 && !exists $stats{stats_assembly}->{N75}) { $stats{stats_assembly}->{N75} = $len; } elsif($curlen >= $n90 && !exists $stats{stats_assembly}->{N90}) { $stats{stats_assembly}->{N90} = $len; } elsif($curlen >= $n95 && !exists $stats{stats_assembly}->{N95}) { $stats{stats_assembly}->{N95} = $len; } } } foreach my $i (50,75,90,95) { unless(exists $stats{stats_assembly}->{'N'.$i}) { $stats{stats_assembly}->{'N'.$i} = '-'; } } } if(exists $params{stats_dupl}) { #empty vars before n-plicate check %counts = %kmers = %odds = (); #0 - exact dub, 1 - prefix, 2 - suffix, 3 - revcomp exact, 4 - revcomp prefix/suffix my %types = (0 => 'exact', 1 => '5', 2 => '3', 3 => 'exactrevcomp', 4 => 'revcomp'); my ($dupls,undef,undef) = &checkForDupl(\@seqs,\%types,$numseqs); #set zero counts foreach my $s (keys %types) { $stats{stats_dupl}->{$types{$s}} = 0; $stats{stats_dupl}->{$types{$s}.'maxd'} = 0; } foreach my $n (keys %$dupls) { foreach my $s (keys %{$dupls->{$n}}) { $stats{stats_dupl}->{$types{$s}} += $dupls->{$n}->{$s} * $n; $stats{stats_dupl}->{$types{$s}.'maxd'} = $n unless($stats{stats_dupl}->{$types{$s}.'maxd'} > $n); $stats{stats_dupl}->{total} += $dupls->{$n}->{$s} * $n; } } } foreach my $type (sort keys %stats) { foreach my $value (sort keys %{$stats{$type}}) { print STDOUT join("\t",$type,$value,(defined $stats{$type}->{$value} ? $stats{$type}->{$value} : '-'))."\n"; } } } if(exists $params{graph_data}) { &printLog("Generate graph data"); print STDERR "Generate graph data\n" if(exists $params{verbose}); &printWeb("Start generating statistics from data"); #get qual stats my $binval = &getBinVal($maxlength); if($graphdata{quals} || $graphdata{quala}) { &printWeb("Generating statistics from quality data"); if($graphdata{quals}) { $graphdata{quals} = &generateStatsType($graphdata{quals}); } if($graphdata{quala}) { #calculate bin values my $tmppos; foreach my $pos (keys %{$graphdata{quala}}) { $tmppos = int(($pos-1)/$binval); foreach my $val (keys %{$graphdata{quala}->{$pos}}) { $graphdata{qualsbin}->{$tmppos}->{$val} += $graphdata{quala}->{$pos}->{$val}; } } $graphdata{qualsbin} = &generateStatsType($graphdata{qualsbin}); } } if($file2 && ($graphdata2{quals} || $graphdata2{quala})) { $graphdata{qualsmean2} = $graphdata2{qualsmean}; if($graphdata2{quals}) { $graphdata{quals2} = &generateStatsType($graphdata2{quals}); } if($graphdata2{quala}) { #calculate bin values my $tmppos; foreach my $pos (keys %{$graphdata2{quala}}) { $tmppos = int(($pos-1)/$binval); foreach my $val (keys %{$graphdata2{quala}->{$pos}}) { $graphdata{qualsbin2}->{$tmppos}->{$val} += $graphdata2{quala}->{$pos}->{$val}; } } $graphdata{qualsbin2} = &generateStatsType($graphdata{qualsbin2}); } } #get length stats if($graphdata{counts}) { &printWeb("Generating statistics from basic counts"); $graphdata{stats} = &generateStatsType($graphdata{counts}); } if($file2 && $graphdata2{counts}) { $graphdata{counts2} = $graphdata2{counts}; $graphdata{stats2} = &generateStatsType($graphdata2{counts}); } #check for ns if(($webstats{ns} || $graphstats{ns}) && scalar(keys %{$graphdata{counts}->{ns}}) == 0) { $graphdata{counts}->{ns}->{0} = 0; } if($file2 && ($webstats{ns} || $graphstats{ns}) && scalar(keys %{$graphdata{counts2}->{ns}}) == 0) { $graphdata{counts2}->{ns}->{0} = 0; } #add base frequencies foreach my $site (keys %{$graphdata{freqs}}) { foreach my $i (0..$TAG_LENGTH-1) { foreach my $base ('A','C','G','T','N') { if(exists $graphdata{freqs}->{$site}->{$i}->{$base}) { $graphdata{freqs}->{$site}->{$i}->{$base} = int($graphdata{freqs}->{$site}->{$i}->{$base}*100/$numseqs); } else { $graphdata{freqs}->{$site}->{$i}->{$base} = 0; } } } } if($file2) { foreach my $site (keys %{$graphdata2{freqs}}) { foreach my $i (0..$TAG_LENGTH-1) { foreach my $base ('A','C','G','T','N') { if(exists $graphdata2{freqs}->{$site}->{$i}->{$base}) { $graphdata{freqs2}->{$site}->{$i}->{$base} = int($graphdata2{freqs}->{$site}->{$i}->{$base}*100/$numseqs2); } else { $graphdata{freqs2}->{$site}->{$i}->{$base} = 0; } } } } } #calculate possibility for tag sequences if(scalar(keys %{$graphdata{kmers}})) { &printWeb("Generating statistics for tag sequences"); my %prob; #calculate frequency of 5-mers my $kmersum = &getTagFrequency($graphdata{kmers},$numseqs); #check for frequency of MID tags my $midsum = 0; my $midcount = 0; my @midseqs; foreach my $mid (keys %{$graphdata{mids}}) { $midsum += $graphdata{mids}->{$mid}; if($graphdata{mids}->{$mid} > $numseqs/34) { #in more than 34/100 (approx. 3%) as this is estimated average error for MIDs $midcount++; push(@midseqs,$mid); } } if($midcount) { $graphdata{tagmidseq} = join(",",@midseqs); } $graphdata{tagmidnum} = $midcount; if($midsum > $kmersum->{5}) { $kmersum->{5} = $midsum; } foreach my $kmer (keys %$kmersum) { $prob{$kmer} = sprintf("%d",(100/$numseqs*$kmersum->{$kmer})); } $graphdata{tagprob} = \%prob; delete($graphdata{kmers}); } if($file2 && scalar(keys %{$graphdata2{kmers}})) { my %prob; #calculate frequency of 5-mers my $kmersum = &getTagFrequency($graphdata2{kmers},$numseqs2); foreach my $kmer (keys %$kmersum) { $prob{$kmer} = sprintf("%d",(100/$numseqs2*$kmersum->{$kmer})); } $graphdata{tagprob2} = \%prob; delete($graphdata2{kmers}); } #add dinucleotide odd ratios if(($webstats{dn} || $graphstats{dn}) && scalar(keys %{$graphdata{dinucodds}})) { &printWeb("Generating statistics from dinucleotide counts"); foreach my $i (keys %{$graphdata{dinucodds}}) { $graphdata{dinucodds}->{$i} = sprintf("%.9f",$graphdata{dinucodds}->{$i}/($numseqs+$numseqs2)); } } #check for n-plicates (for paired-end data, not separated by input file) if($webstats{de} || $webstats{da} || $graphstats{de} || $graphstats{da}) { &printWeb("Generating statistics from duplicate counts"); if($webstats{de} || $graphstats{de}) { foreach my $m (keys %md5sg) { if(exists $md5sg{$m}->{0} && $md5sg{$m}->{0} > 0) { $graphdata{dubscounts}->{$md5sg{$m}->{0}}->{0}++; } if(exists $md5sg{$m}->{3} && $md5sg{$m}->{3} > 0) { $graphdata{dubscounts}->{$md5sg{$m}->{3}}->{3}++; } } } else { my %types = (0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0); ($graphdata{dubscounts},$graphdata{dubslength},undef) = &checkForDupl(\@seqs,\%types,$numseqs); #0 - exact dub, 1 - prefix, 2 - suffix, 3 - revcomp exact, 4 - revcomp prefix/suffix } } #generate JSON string without the need of the JSON module my $str = ''; $str .= '{"numseqs":'.$numseqs.',"numbases":'.$numbases.',"pairedend":'.($file2 ? 1 : 0).($file2 ? ',"numseqs2":'.$numseqs2.',"numbases2":'.$numbases2.',"pairs":'.$pairs : '').',"maxlength":'.$maxlength.',"binval":'.$binval.',"exactonly":'.$exactonly.',"tagmidnum":'.($graphdata{tagmidnum}||0).',"scale":'.$scale.',"filename1":"'.(exists $params{filename1} ? $params{filename1} : &convertStringToInt(&getFileName($file1))).'","format1":"'.(exists $params{fasta} ? 'fasta' : 'fastq').'"'.(exists $params{qual} ? ',"filename2":"'.(exists $params{filename2} ? $params{filename2} : &convertStringToInt(&getFileName($params{qual}))).'","format2":"qual"' : '').($file2 ? ',"filename2":"'.(exists $params{filename2} ? $params{filename2} : &convertStringToInt(&getFileName($file2))).'"' : ''); foreach my $s (qw(counts counts2 stats stats2 quals quals2 qualsbin qualsbin2 complvals dubscounts dubslength)) { next unless exists($graphdata{$s}); $str .= ',"'.$s.'":{'; foreach my $t (sort keys %{$graphdata{$s}}) { $str .= '"'.$t.'":{'; while (my ($k,$v) = each(%{$graphdata{$s}->{$t}})) { if($v =~ /^\d+$/) { $str .= '"'.$k.'":'.$v.','; } else { $str .= '"'.$k.'":"'.$v.'",'; } } $str =~ s/\,$//; $str .= '},'; } $str =~ s/\,$//; $str .= '}'; } foreach my $s (qw(qualsmean qualsmean2 tagprob tagprob2 compldust complentropy dinucodds)) { next unless exists($graphdata{$s}); $str .= ',"'.$s.'":{'; while (my ($k,$v) = each(%{$graphdata{$s}})) { if($v =~ /^\d+$/) { $str .= '"'.$k.'":'.$v.','; } else { $str .= '"'.$k.'":"'.$v.'",'; } } $str =~ s/\,$//; $str .= '}'; } $str .= ',"tail":'.(exists $graphdata{counts}->{tail5} || exists $graphdata{counts}->{tail3} ? 1 : 0); $str .= ',"tail2":'.(exists $graphdata2{counts}->{tail5} || exists $graphdata2{counts}->{tail3} ? 1 : 0) if($file2); if($webstats{ts} || $graphstats{ts}) { $str .= ',"freqs":{'; foreach my $i (keys %{$graphdata{freqs}}) { # 5, 3 $str .= '"'.$i.'":{'; foreach my $pos (keys %{$graphdata{freqs}->{$i}}) { $str .= '"'.$pos.'":{'; while (my ($base,$v) = each(%{$graphdata{freqs}->{$i}->{$pos}})) { $str .= '"'.$base.'":'.$v.','; } $str =~ s/\,$//; $str .= '},'; } $str =~ s/\,$//; $str .= '},'; } $str =~ s/\,$//; $str .= '}'; if($file2) { $str .= ',"freqs2":{'; foreach my $i (keys %{$graphdata{freqs2}}) { # 5, 3 $str .= '"'.$i.'":{'; foreach my $pos (keys %{$graphdata{freqs2}->{$i}}) { $str .= '"'.$pos.'":{'; while (my ($base,$v) = each(%{$graphdata{freqs2}->{$i}->{$pos}})) { $str .= '"'.$base.'":'.$v.','; } $str =~ s/\,$//; $str .= '},'; } $str =~ s/\,$//; $str .= '},'; } $str =~ s/\,$//; $str .= '}'; } } foreach my $s (qw(tagmidseq)) { next unless exists($graphdata{$s}); $str .= ',"'.$s.'":"'.$graphdata{$s}.'"'; } $str =~ s/\,$//; $str .= '}'; #write data to file my $time = sprintf("%02d/%02d/%04d %02d:%02d:%02d",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); open(FH, ">", $params{graph_data}) or &printError("Cannot open file ".$params{graph_data}.": $!"); flock(FH, LOCK_EX) or &printError("Cannot lock file ".$params{graph_data}.": $!"); print FH "#Graph data\n"; print FH "#[prinseq-".$WHAT."-$VERSION] [$time] Command: \"perl prinseq-".$WHAT.".pl".$command."\"\n" unless(exists $params{web}); print FH $str; flock(FH, LOCK_UN) or &printError("Cannot unlock ".$params{graph_data}.": $!"); close(FH); &printLog("Done with graph data"); print STDERR "\tdone\n" if(exists $params{verbose}); } &printWeb("STATUS: done"); ## ################################################################################# ### MISC FUNCTIONS ################################################################################# ## sub printError { my $msg = shift; print STDERR "\nERROR: ".$msg.".\n\nTry \'perl prinseq-".$WHAT.".pl -h\' for more information.\nExit program.\n"; &printLog("ERROR: ".$msg.". Exit program.\n"); exit(0); } sub printWarning { my $msg = shift; print STDERR "WARNING: ".$msg.".\n"; &printLog("WARNING: ".$msg.".\n"); } sub printWeb { my $msg = shift; if(exists $params{web}) { print STDERR &getTime()."$msg\n"; } } sub getTime { return sprintf("[%02d/%02d/%04d %02d:%02d:%02d] ",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); } sub printLog { my $msg = shift; if(exists $params{log}) { my $time = sprintf("%02d/%02d/%04d %02d:%02d:%02d",sub {($_[4]+1,$_[3],$_[5]+1900,$_[2],$_[1],$_[0])}->(localtime)); open(FH, ">>", $params{log}) or &printError("Cannot open file ".$params{log}.": $!"); flock(FH, LOCK_EX) or &printError("Cannot lock file ".$params{log}.": $!"); print FH "[prinseq-".$WHAT."-$VERSION] [$time] $msg\n"; flock(FH, LOCK_UN) or &printError("Cannot unlock ".$params{log}.": $!"); close(FH); } } sub addCommas { my $num = shift; return unless(defined $num); return $num if($num < 1000); $num = scalar reverse $num; $num =~ s/(\d{3})/$1\,/g; $num =~ s/\,$//; $num = scalar reverse $num; return $num; } sub getLineNumber { my $file = shift; my $lines = 0; open(FILE,"perl -pe 's/\r\n|\r/\n/g' < $file |") or &printError("Could not open file $file: $!"); $lines += tr/\n/\n/ while sysread(FILE, $_, 2 ** 16); close(FILE); return $lines; } sub readParamsFile { my $file = shift; my @args; my %parameters = (); open(FILE,"perl -pe 's/\r\n|\r/\n/g' < $file |") or &printError("Could not open file $file: $!"); while() { next if(/^\#/); chomp(); @args = split(/\s+/); if(@args) { $args[0] =~ s/^\-//; $parameters{$args[0]} = (defined $args[1] ? join(" ",@args[1..scalar(@args)-1]) : ''); } } close(FILE); return \%parameters; } sub checkFileFormat { my $file = shift; my ($format,$count,$id,$fasta,$fastq,$qual); $count = 3; $fasta = $fastq = $qual = 0; $format = 'unknown'; open(FILE,"perl -pe 's/\r\n|\r/\n/g' < $file |") or &printError("Could not open file $file: $!"); while () { # chomp(); # next unless(length($_)); if($count-- == 0) { last; } elsif(!$fasta && /^\>\S+\s*/o) { $fasta = 1; $qual = 1; } elsif($fasta == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/o) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/o))) { $fasta = 2; } elsif($qual == 1 && /^\s*\d+/o) { $qual = 2; } elsif(!$fastq && /^\@(\S+)\s*/o) { $id = $1; $fastq = 1; } elsif($fastq == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/o) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/o))) { $fastq = 2; } elsif($fastq == 2 && /^\+(\S*)\s*/o) { $fastq = 3 if($id eq $1 || /^\+\s*$/o); } } close(FILE); if($fasta == 2) { $format = 'fasta'; } elsif($qual == 2) { $format = 'qual'; } elsif($fastq == 3) { $format = 'fastq'; } return $format; } sub checkSlashnum { my $file = shift; open(FILE,"perl -pe 's/\r\n|\r/\n/g' < $file |") or &printError("Could not open file $file: $!"); while() { chomp(); next unless(length($_)); if(/^\S+\/[12]\s*/ || /^\S+\_[LR]\s*/) { close(FILE); return (1,2,2); } elsif(/^\S+\_left\s*/) { close(FILE); return (1,6,5); } elsif(/^\S+\_right\s*/) { close(FILE); return (1,5,6); } else { close(FILE); return 0; } } return 0; } sub checkInputFormat { my ($format,$count,$id,$fasta,$fastq,$qual); $count = 3; $fasta = $fastq = $qual = 0; $format = 'unknown'; while () { push(@dataread,$_); # chomp(); # next unless(length($_)); if($count-- == 0) { last; } elsif(!$fasta && /^\>\S+\s*/o) { $fasta = 1; $qual = 1; } elsif($fasta == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/o) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/o))) { $fasta = 2; } elsif($qual == 1 && /^\s*\d+/) { $qual = 2; } elsif(!$fastq && /^\@(\S+)\s*/) { $id = $1; $fastq = 1; } elsif($fastq == 1 && (($aa && /^[ABCDEFGHIKLMNOPQRSTUVWYZXabcdefghiklmmopqrstuvwyzx*-]+/o) || (!$aa && /^[ACGTURYKMSWBDHVNXacgturykmswbdhvnx-]+/o))) { $fastq = 2; } elsif($fastq == 2 && /^\+(\S*)\s*/o) { $fastq = 3 if($id eq $1 || /^\+\s*$/o); } } if($fasta == 2) { $format = 'fasta'; } elsif($qual == 2) { $format = 'qual'; } elsif($fastq == 3) { $format = 'fastq'; } return $format; } sub getArrayMean { return @_ ? sum(@_) / @_ : 0; } sub convertQualNumsToAscii { my $qual = shift; my @ascii; $qual =~ s/^\s+//; $qual =~ s/\s+$//; my @nums = split(/\s+/,$qual); foreach(@nums) { push(@ascii,chr(($_ <= 93 ? $_ : 93) + 33)); } return \@ascii; } sub convertQualNumsToAsciiString { my $qual = shift; my $ascii; $qual =~ s/^\s+//; $qual =~ s/\s+$//; my @nums = split(/\s+/,$qual); foreach(@nums) { $ascii .= chr(($_ <= 93 ? $_ : 93) + 33); } return $ascii; } sub convertQualAsciiToNums { my $qual = shift; my @nums; my @ascii = split(//,$qual); foreach(@ascii) { push(@nums,(ord($_) - 33)); } return \@nums; } sub convertQualAsciiToNumsPhred64 { my $qual = shift; my @nums; my $tmp; my $err = 0; my @ascii = split('',$qual); foreach(@ascii) { $tmp = (ord($_) - 64); if($tmp < 0) { $err = 1; last; } push(@nums,$tmp); } return (\@nums,$err); } sub convertQualArrayToString { my ($nums,$linelen) = @_; $linelen = 80 unless($linelen); my $str; my $count = 1; foreach my $n (@$nums) { $str .= ($n < 10 ? ' '.$n : $n).' '; if(++$count > $linelen) { $count = 1; $str =~ s/\s$//; $str .= "\n"; } } $str =~ s/[\s\n]$//; return $str; } sub checkRange { my ($range,$val) = @_; my @ranges = split(/\,/,$range); foreach my $r (@ranges) { my @tmp = split(/\-/,$r); return 0 if($val < $tmp[0] || $val > $tmp[1]); } return 1; } sub getFiltercounts { my @order = qw(seq_num trim_left trim_right trim_left_p trim_right_p trim_qual_left trim_qual_right trim_tail_left trim_tail_right trim_ns_left trim_ns_right zero_length min_len max_len range_len min_qual_score max_qual_score min_qual_mean max_qual_mean min_gc max_gc range_gc ns_max_p ns_max_n noniupac custom_params lc_method derep); my @counts; foreach my $p (@order) { if(exists $filtercount{$p}) { push(@counts,$p.': '.$filtercount{$p}); } } return \@counts; } sub readEntryFastq { my ($fh,$skip,$trimnum) = @_; if($skip > 0) { return 1; } my ($seq,$seqid,$qual,$header,$line,$tmpid); if(defined($line = <$fh>)) { $line =~ /^\@(\S+)\s*(.*)$/o; $seqid = $1; $header = $2 || ''; $seq = readline($fh); chomp($seq); readline($fh); $qual = readline($fh); chomp($qual); #progress bar stuff $counter += 4; } if($slashnum && $seqid) { $tmpid = substr($seqid, 0, -$trimnum) } else { $tmpid = $seqid; } return ($seq,$seqid,$qual,$header,$tmpid); } sub readEntryFasta { my ($fh,$skip,$trimnum,$nextid,$nextheader) = @_; if($skip > 0) { return (1,undef,undef,undef,$nextid,$nextheader); } my ($seq,$seqid,$header,$line,$tmpid); $seq = ''; if($nextid) { $seqid = $nextid; $header = $nextheader; } while(<$fh>) { chomp(); if(/^>(\S+)\s*(.*)$/o) { if($seq) { $nextid = $1; $nextheader = $2 || ''; last; } $seqid = $1; $header = $2 || ''; } else { $seq .= $_; } } if($slashnum) { $tmpid = substr($seqid, 0, -$trimnum) } else { $tmpid = $seqid; } return ($seq,$seqid,$header,$tmpid,$nextid,$nextheader); } sub processEntry { my ($length,$seq,$seqid,$qual,$header) = @_; #check that sequence and quality are same length if(defined $qual && length($qual) && $length != length($qual)) { &printError("The number of bases and quality scores are not the same for sequence \"$seqid\""); } #remove anything non-alphabetic from sequences $seq =~ tr/a-zA-Z//cd; $numseqs++; $numbases += $length; #process entry if($exists_stats) { #calc summary stats $seq = uc($seq); &calcSeqStats($seq,$length,\%stats,\%kmers,\%odds,\%counts); if(exists $params{stats_dupl}) { push(@seqs,[$seq,$numseqs,$length]); } } else { #process data &processData($seqid,$seq,$qual,$header) unless($webnoprocess); #get graph data if($exists_graphdata) { $ucseq = uc($seq); &getSeqStats(\%graphdata,$ucseq,$length); if($qual) { &getQualStats(\%graphdata,$qual,$length); } if($webstats{de} || $graphstats{de}) { $md5 = md5_hex($ucseq); if(exists $md5sg{$md5}) { #forward duplicate $graphdata{dubslength}->{$length}->{0}++; $md5sg{$md5}->{0}++; } else { $md5r = md5_hex(&revcompuc($ucseq)); if(exists $md5sg{$md5r}) { #reverse duplicate $graphdata{dubslength}->{$length}->{3}++; $md5sg{$md5}->{3}++; } unless(exists $md5sg{$md5}) { $md5sg{$md5} = {0 => 0, 3 => 0}; } } } elsif($webstats{da} || $graphstats{da}) { push(@seqs,[$ucseq,$numseqs,$length]); } } } } sub processEntryPairedEnd { my ($length,$seq,$seqid,$header,$qual,$length2,$seq2,$seqid2,$header2,$qual2) = @_; my ($tmpseq1,$tmpseq2,$tmpgood1,$tmpgood2,$tmpbegin1,$tmpend1,$tmpbegin2,$tmpend2); $tmpgood1 = $tmpgood2 = 0; if($length) { #check that sequence and quality are same length if(defined $qual && $length != length($qual)) { &printError("The number of bases and quality scores are not the same for sequence \"$seqid\""); } #remove anything non-alphabetic from sequences $seq =~ tr/a-zA-Z//cd; $numseqs++; $numbases += $length; #process entry if($exists_stats) { #calc summary stats $seq = uc($seq); &calcSeqStats($seq,$length,\%stats,\%kmers,\%odds,\%counts); } else { #process data ($tmpseq1,$tmpgood1,$tmpbegin1,$tmpend1) = &processData($seqid,$seq,$qual,$header) unless($webnoprocess); #get graph data if($exists_graphdata) { $ucseq = uc($seq); &getSeqStats(\%graphdata,$ucseq,$length); if($qual) { &getQualStats(\%graphdata,$qual,$length); } if($length2) { $pairs++; } if($webstats{de} || $graphstats{de}) { if($length2) { #both $md5 = md5_hex($ucseq.'0'.uc($seq2)); if(exists $md5sg{$md5}) { #forward duplicate $md5sg{$md5}->{0}++; $graphdata{dubslength}->{($length+$length2)}->{0}++; } else { $md5sg{$md5}->{0} = 0; } $md5 = md5_hex($ucseq); unless(exists $md5sg{$md5}) { $md5sg{$md5}->{0} = 0; } } else { #only seq, no seq2 $md5 = md5_hex($ucseq); if(exists $md5sg{$md5}) { #forward duplicate $md5sg{$md5}->{0}++; $graphdata{dubslength}->{$length}->{0}++; } else { $md5sg{$md5}->{0} = 0; } } } } } } if($length2) { if(defined $qual2 && $length2 != length($qual2)) { &printError("The number of bases and quality scores are not the same for sequence \"$seqid2\""); } #remove anything non-alphabetic from sequences $seq2 =~ tr/a-zA-Z//cd; $numseqs2++; $numbases2 += $length2; #process entry if($exists_stats) { #calc summary stats $seq2 = uc($seq2); &calcSeqStats($seq2,$length2,\%stats,\%kmers2,\%odds,\%counts2,1); #last one used to calculate stats for second input file } else { #process data ($tmpseq2,$tmpgood2,$tmpbegin2,$tmpend2) = &processData($seqid2,$seq2,$qual2,$header2) unless($webnoprocess); #get graph data if($exists_graphdata) { $ucseq = uc($seq2); &getSeqStats(\%graphdata2,$ucseq,$length2); if($qual2) { &getQualStats(\%graphdata2,$qual2,$length2); } if($webstats{de} || $graphstats{de}) { #only seq2, no seq $md5 = md5_hex($ucseq); unless($length) { if(exists $md5sg{$md5}) { #forward duplicate $md5sg{$md5}->{0}++; $graphdata{dubslength}->{$length2}->{0}++; } else { $md5sg{$md5}->{0} = 0; } } } } } } return if($exists_stats || $webnoprocess); #check for duplicates if($derep) { if($tmpgood1 && $tmpgood2) { $md5 = md5_hex($tmpseq1.'0'.$tmpseq2); if(exists $md5s{$md5}) { #forward duplicate $md5s{$md5}++; if($derepmin <= $md5s{$md5}+1) { $tmpgood1 = $tmpgood2 = 0; $filtercount{derep}++; } } else { $md5s{$md5} = 0; } $md5 = md5_hex($tmpseq1); unless(exists $md5s{$md5}) { $md5s{$md5} = 0; } $md5 = md5_hex($tmpseq2); unless(exists $md5s{$md5}) { $md5s{$md5} = 0; } } elsif($tmpgood1) { $md5 = md5_hex($tmpseq1); if(exists $md5s{$md5}) { #forward duplicate $md5s{$md5}++; if($derepmin <= $md5s{$md5}+1) { $tmpgood1 = 0; $filtercount{derep}++; } } else { $md5s{$md5} = 0; } } elsif($tmpgood2) { $md5 = md5_hex($tmpseq2); if(exists $md5s{$md5}) { #forward duplicate $md5s{$md5}++; if($derepmin <= $md5s{$md5}+1) { $tmpgood2 = 0; $filtercount{derep}++; } } else { $md5s{$md5} = 0; } } } #write to outputs files if($tmpgood1) { if(exists $params{seq_id}) { if($mappings) { print $fhmappings join("\t",$seqid,$params{seq_id}.$seqcount)."\n"; } $seqid = $params{seq_id}.$seqcount; } if(exists $params{rm_header}) { $header = undef; } #trim if necessary if($tmpbegin1) { $seq = substr($seq,$tmpbegin1); $qual = substr($qual,$tmpbegin1) if(defined $qual && length($qual)); } if($tmpend1) { $length = length($seq); $seq = substr($seq,0,$length-$tmpend1); $qual = substr($qual,0,$length-$tmpend1) if(defined $qual && length($qual)); } #change case if(exists $params{seq_case}) { if($params{seq_case} eq 'lower') { #lower case $seq = lc($seq); } elsif($params{seq_case} eq 'upper') { #upper case $seq = uc($seq); } } #convert between DNA and RNA if(exists $params{dna_rna}) { if($params{dna_rna} eq 'dna') { #RNA to DNA $seq =~ tr/Uu/Tt/; } elsif($params{dna_rna} eq 'rna') { #DNA to RNA $seq =~ tr/Tt/Uu/; } } } if($tmpgood2) { if(exists $params{seq_id}) { if($mappings) { print $fhmappings join("\t",$seqid2,$params{seq_id}.$seqcount)."\n"; } $seqid2 = $params{seq_id}.$seqcount; } if(exists $params{rm_header}) { $header2 = undef; } #trim if necessary if($tmpbegin2) { $seq2 = substr($seq2,$tmpbegin2); $qual2 = substr($qual2,$tmpbegin2) if(defined $qual2 && length($qual2)); } if($tmpend2) { $length2 = length($seq2); $seq2 = substr($seq2,0,$length2-$tmpend2); $qual2 = substr($qual2,0,$length2-$tmpend2) if(defined $qual2 && length($qual2)); } #change case if(exists $params{seq_case}) { if($params{seq_case} eq 'lower') { #lower case $seq2 = lc($seq2); } elsif($params{seq_case} eq 'upper') { #upper case $seq2 = uc($seq2); } } #convert between DNA and RNA if(exists $params{dna_rna}) { if($params{dna_rna} eq 'dna') { #RNA to DNA $seq2 =~ tr/Uu/Tt/; } elsif($params{dna_rna} eq 'rna') { #DNA to RNA $seq2 =~ tr/Tt/Uu/; } } } if($tmpgood1 && $tmpgood2) { #pair $seqcount++; $seqbases += $length+$length2; return if($nogood); if($params{out_format} == 3) { # FASTQ &printError("missing quality data for sequence \"$seqid\" or greater number of sequences than available quality scores") unless(defined $qual); &printError("missing quality data for sequence \"$seqid2\" or greater number of sequences than available quality scores") unless(defined $qual2); if($stdoutgood) { print STDOUT '@'.$seqid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $seqid.($header ? ' '.$header : ''))."\n"; print STDOUT $qual."\n"; print STDOUT '@'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print STDOUT $seq2."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $seqid2.($header2 ? ' '.$header2 : ''))."\n"; print STDOUT $qual2."\n"; } else { print $fhgood '@'.$seqid.($header ? ' '.$header : '')."\n"; print $fhgood $seq."\n"; print $fhgood '+'.(exists $params{no_qual_header} ? '' : $seqid.($header ? ' '.$header : ''))."\n"; print $fhgood $qual."\n"; print $fh2good '@'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print $fh2good $seq2."\n"; print $fh2good '+'.(exists $params{no_qual_header} ? '' : $seqid2.($header2 ? ' '.$header2 : ''))."\n"; print $fh2good $qual2."\n"; } } else { #FASTA #set line length if($linelen) { $seq =~ s/(.{$linelen})/$1\n/g; $seq =~ s/\n$//; $seq2 =~ s/(.{$linelen})/$1\n/g; $seq2 =~ s/\n$//; } if($stdoutgood) { print STDOUT '>'.$seqid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '>'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print STDOUT $seq2."\n"; } else { print $fhgood '>'.$seqid.($header ? ' '.$header : '')."\n"; print $fhgood $seq."\n"; print $fh2good '>'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print $fh2good $seq2."\n"; } } } elsif($tmpgood1) { #singleton $seqcount1++; $seqbases1 += $length; return if($nogood); if($params{out_format} == 3) { # FASTQ &printError("missing quality data for sequence \"$seqid\" or greater number of sequences than available quality scores") unless(defined $qual); if($stdoutgood) { print STDOUT '@'.$seqid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $seqid.($header ? ' '.$header : ''))."\n"; print STDOUT $qual."\n"; } else { print $fhgood2 '@'.$seqid.($header ? ' '.$header : '')."\n"; print $fhgood2 $seq."\n"; print $fhgood2 '+'.(exists $params{no_qual_header} ? '' : $seqid.($header ? ' '.$header : ''))."\n"; print $fhgood2 $qual."\n"; } } else { #FASTA #set line length if($linelen) { $seq =~ s/(.{$linelen})/$1\n/g; $seq =~ s/\n$//; } if($stdoutgood) { print STDOUT '>'.$seqid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; } else { print $fhgood2 '>'.$seqid.($header ? ' '.$header : '')."\n"; print $fhgood2 $seq."\n"; } } if($length2) { $badcount2++; $badbases2 += length($seq2); return if($nobad); #write data if($params{out_format} == 3) { # FASTQ &printError("missing quality data for sequence \"$seqid2\" or greater number of sequences than available quality scores") unless(defined $qual2); if($stdoutbad) { print STDOUT '@'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print STDOUT $seq2."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $seqid2.($header2 ? ' '.$header2 : ''))."\n"; print STDOUT $qual2."\n"; } else { print $fh2bad '@'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print $fh2bad $seq2."\n"; print $fh2bad '+'.(exists $params{no_qual_header} ? '' : $seqid2.($header2 ? ' '.$header2 : ''))."\n"; print $fh2bad $qual2."\n"; } } else { #FASTA #set line length if($linelen) { $seq2 =~ s/(.{$linelen})/$1\n/g; $seq2 =~ s/\n$//; } if($stdoutbad) { print STDOUT '>'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print STDOUT $seq2."\n"; } else { print $fh2bad '>'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print $fh2bad $seq2."\n"; } } } } elsif($tmpgood2) { #singleton $seqcount2++; $seqbases2 += $length2; return if($nogood); if($params{out_format} == 3) { # FASTQ &printError("missing quality data for sequence \"$seqid2\" or greater number of sequences than available quality scores") unless(defined $qual2); if($stdoutgood) { print STDOUT '@'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print STDOUT $seq2."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $seqid2.($header2 ? ' '.$header2 : ''))."\n"; print STDOUT $qual2."\n"; } else { print $fh2good2 '@'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print $fh2good2 $seq2."\n"; print $fh2good2 '+'.(exists $params{no_qual_header} ? '' : $seqid2.($header2 ? ' '.$header2 : ''))."\n"; print $fh2good2 $qual2."\n"; } } else { #FASTA #set line length if($linelen) { $seq2 =~ s/(.{$linelen})/$1\n/g; $seq2 =~ s/\n$//; } if($stdoutgood) { print STDOUT '>'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print STDOUT $seq2."\n"; } else { print $fh2good2 '>'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print $fh2good2 $seq2."\n"; } } if($length) { $badcount++; $badbases += length($seq); return if($nobad); #write data if($params{out_format} == 3) { # FASTQ &printError("missing quality data for sequence \"$seqid\" or greater number of sequences than available quality scores") unless(defined $qual); if($stdoutbad) { print STDOUT '@'.$seqid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $seqid.($header ? ' '.$header : ''))."\n"; print STDOUT $qual."\n"; } else { print $fhbad '@'.$seqid.($header ? ' '.$header : '')."\n"; print $fhbad $seq."\n"; print $fhbad '+'.(exists $params{no_qual_header} ? '' : $seqid.($header ? ' '.$header : ''))."\n"; print $fhbad $qual."\n"; } } else { #FASTA #set line length if($linelen) { $seq =~ s/(.{$linelen})/$1\n/g; $seq =~ s/\n$//; } if($stdoutbad) { print STDOUT '>'.$seqid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; } else { print $fhbad '>'.$seqid.($header ? ' '.$header : '')."\n"; print $fhbad $seq."\n"; } } } } else { if($length) { $badcount++; $badbases += length($seq); return if($nobad); #write data if($params{out_format} == 3) { # FASTQ &printError("missing quality data for sequence \"$seqid\" or greater number of sequences than available quality scores") unless(defined $qual); if($stdoutbad) { print STDOUT '@'.$seqid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $seqid.($header ? ' '.$header : ''))."\n"; print STDOUT $qual."\n"; } else { print $fhbad '@'.$seqid.($header ? ' '.$header : '')."\n"; print $fhbad $seq."\n"; print $fhbad '+'.(exists $params{no_qual_header} ? '' : $seqid.($header ? ' '.$header : ''))."\n"; print $fhbad $qual."\n"; } } else { #FASTA #set line length if($linelen) { $seq =~ s/(.{$linelen})/$1\n/g; $seq =~ s/\n$//; } if($stdoutbad) { print STDOUT '>'.$seqid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; } else { print $fhbad '>'.$seqid.($header ? ' '.$header : '')."\n"; print $fhbad $seq."\n"; } } } if($length2) { $badcount2++; $badbases2 += length($seq2); return if($nobad); #write data if($params{out_format} == 3) { # FASTQ &printError("missing quality data for sequence \"$seqid2\" or greater number of sequences than available quality scores") unless(defined $qual2); if($stdoutbad) { print STDOUT '@'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print STDOUT $seq2."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $seqid2.($header2 ? ' '.$header2 : ''))."\n"; print STDOUT $qual2."\n"; } else { print $fh2bad '@'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print $fh2bad $seq2."\n"; print $fh2bad '+'.(exists $params{no_qual_header} ? '' : $seqid2.($header2 ? ' '.$header2 : ''))."\n"; print $fh2bad $qual2."\n"; } } else { #FASTA #set line length if($linelen) { $seq2 =~ s/(.{$linelen})/$1\n/g; $seq2 =~ s/\n$//; } if($stdoutbad) { print STDOUT '>'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print STDOUT $seq2."\n"; } else { print $fh2bad '>'.$seqid2.($header2 ? ' '.$header2 : '')."\n"; print $fh2bad $seq2."\n"; } } } } } #process sequence (and qual) data sub processData { my ($sid,$seq,$qual,$header) = @_; #assume sequence is good ;-) my $good = 1; my $seqn = uc($seq); my $qualn = $qual; my $begin = 0; my $end = 0; my ($length,$bylength,$qualsnums); #check for maximum number sequences requested if(exists $params{seq_num} && $params{seq_num} <= $seqcount) { $good = 0; $filtercount{seq_num}++; } #trim sequence ends if($good && exists $params{trim_left}) { $begin += $params{trim_left}; if($begin >= length($seqn)) { $good = 0; $filtercount{trim_left}++; } else { $seqn = substr($seqn,$begin); $qualn = substr($qualn,$begin) if(defined $qualn && length($qualn)); } } if($good && exists $params{trim_right}) { $end += $params{trim_right}; $length = length($seqn); if($end >= $length) { $good = 0; $filtercount{trim_right}++; } else { $seqn = substr($seqn,0,$length-$end); $qualn = substr($qualn,0,$length-$end) if(defined $qualn && length($qualn)); } } if($good && exists $params{trim_left_p}) { $length = length($seqn); my $begintmp = int($params{trim_left_p}/100*$length); if($begintmp >= $length) { $good = 0; $filtercount{trim_left_p}++; } else { $seqn = substr($seqn,$begintmp); $qualn = substr($qualn,$begintmp) if(defined $qualn && length($qualn)); $begin += $begintmp; } } if($good && exists $params{trim_right_p}) { $length = length($seqn); my $endtmp = int($params{trim_right_p}/100*$length); if($endtmp >= $length) { $good = 0; $filtercount{trim_right_p}++; } else { $seqn = substr($seqn,0,$length-$endtmp); $qualn = substr($qualn,0,$length-$endtmp) if(defined $qualn && length($qualn)); $end += $endtmp; } } #check for quality scores if($good && defined $qualn && $trimscore) { my ($err); if(exists $params{phred64}) { #scale data to Phred scale if necessary ($qualsnums,$err) = &convertQualAsciiToNumsPhred64($qualn); if($err) { &printError("The sequence quality scores are not in Phred+64 format"); } } else { $qualsnums = &convertQualAsciiToNums($qualn); } $length = length($qualn); my $i = 0; my $begintmp = 0; my $endtmp = 0; my ($window,$val); #left if(exists $params{trim_qual_left}) { while($i < $length) { #calculate maximum window $window = ($i+$params{trim_qual_window} <= $length ? $params{trim_qual_window} : ($length-$i)); #calculate value used to compare with given value if($window == 1) { $val = $qualsnums->[$i]; } elsif($params{trim_qual_type} eq 'min') { $val = min(@$qualsnums[$i..($i+$window-1)]); } elsif($params{trim_qual_type} eq 'max') { $val = max(@$qualsnums[$i..($i+$window-1)]); } elsif($params{trim_qual_type} eq 'mean') { $val = &getArrayMean(@$qualsnums[$i..($i+$window-1)]); } elsif($params{trim_qual_type} eq 'sum') { last if($window < $params{trim_qual_window}); $val = sum(@$qualsnums[$i..($i+$window-1)]); } else { last; } #compare values if(($params{trim_qual_rule} eq 'lt' && $val < $params{trim_qual_left}) || ($params{trim_qual_rule} eq 'gt' && $val > $params{trim_qual_left}) || ($params{trim_qual_rule} eq 'et' && $val == $params{trim_qual_left})) { $begintmp += $params{trim_qual_step}; $i += $params{trim_qual_step}; } else { last; } } if($begintmp >= $length) { $good = 0; $filtercount{trim_qual_left}++; } elsif($begintmp > 0) { $seqn = substr($seqn,$begintmp); $qualn = substr($qualn,$begintmp); $begin += $begintmp; } } #right if($good && exists $params{trim_qual_right}) { $length -= $begintmp; my @quals = reverse(@$qualsnums); $i = 0; while($i < $length) { #calculate maximum window $window = ($i+$params{trim_qual_window} <= $length ? $params{trim_qual_window} : ($length-$i)); #calculate value used to compare with given value if($window == 1) { $val = $quals[$i]; } elsif($params{trim_qual_type} eq 'min') { $val = min(@quals[$i..($i+$window-1)]); } elsif($params{trim_qual_type} eq 'max') { $val = max(@quals[$i..($i+$window-1)]); } elsif($params{trim_qual_type} eq 'mean') { $val = &getArrayMean(@quals[$i..($i+$window-1)]); } elsif($params{trim_qual_type} eq 'sum') { last if($window < $params{trim_qual_window}); $val = sum(@quals[$i..($i+$window-1)]); } else { last; } #compare values if(($params{trim_qual_rule} eq 'lt' && $val < $params{trim_qual_right}) || ($params{trim_qual_rule} eq 'gt' && $val > $params{trim_qual_right}) || ($params{trim_qual_rule} eq 'et' && $val == $params{trim_qual_right})) { $endtmp += $params{trim_qual_step}; $i += $params{trim_qual_step}; } else { last; } } if($endtmp >= $length) { $good = 0; $filtercount{trim_qual_right}++; } elsif($endtmp > 0) { $seqn = substr($seqn,0,$length-$endtmp); $qualn = substr($qualn,0,$length-$endtmp); $end += $endtmp; } } } #check for tails with min trimtails char repeats if($good && exists $params{trim_tail_left}) { $length = length($seqn); my $begintmp = 0; if($seqn =~ $repAleft || $seqn =~ $repTleft) { my @tmp = split('',$seqn); my $tmpchar = $tmp[0]; #A or T $begintmp += $params{trim_tail_left}; foreach ($params{trim_tail_left}..$length-1) { last unless($tmp[$_] eq $tmpchar || $tmp[$_] eq 'N'); $begintmp++; } if($begintmp >= $length) { $good = 0; $filtercount{trim_tail_left}++; } else { $seqn = substr($seqn,$begintmp); $qualn = substr($qualn,$begintmp) if(defined $qualn && length($qualn)); $length = length($seqn); $begin += $begintmp; } } } if($good && exists $params{trim_tail_right}) { $length = length($seqn); my $endtmp = 0; if($seqn =~ $repAright || $seqn =~ $repTright) { my @tmp = split('',$seqn); my $tmpchar = $tmp[$length-1]; #A or T $endtmp += $params{trim_tail_right}; foreach (reverse 0..$length-$params{trim_tail_right}-1) { last unless($tmp[$_] eq $tmpchar || $tmp[$_] eq 'N'); $endtmp++; } if($endtmp >= $length) { $good = 0; $filtercount{trim_tail_right}++; } else { $seqn = substr($seqn,0,$length-$endtmp); $qualn = substr($qualn,0,$length-$endtmp) if(defined $qualn && length($qualn)); $end += $endtmp; } } } if($good && exists $params{trim_ns_left}) { $length = length($seqn); my $begintmp = 0; if($seqn =~ $repNleft) { my @tmp = split('',$seqn); $begintmp += $params{trim_ns_left}; foreach ($params{trim_ns_left}..$length-1) { last unless($tmp[$_] eq 'N'); $begintmp++; } if($begintmp >= $length) { $good = 0; $filtercount{trim_ns_left}++; } else { $seqn = substr($seqn,$begintmp); $qualn = substr($qualn,$begintmp) if(defined $qualn && length($qualn)); $length = length($seqn); $begin += $begintmp; } } } if($good && exists $params{trim_ns_right}) { $length = length($seqn); my $endtmp = 0; if($seqn =~ $repNright) { my @tmp = split('',$seqn); $endtmp += $params{trim_ns_right}; foreach (reverse 0..$length-$params{trim_ns_right}-1) { last unless($tmp[$_] eq 'N'); $endtmp++; } if($endtmp >= $length) { $good = 0; $filtercount{trim_ns_right}++; } else { $seqn = substr($seqn,0,$length-$endtmp); $qualn = substr($qualn,0,$length-$endtmp) if(defined $qualn && length($qualn)); $end += $endtmp; } } } #check if trim to certain length $length = length($seqn); if($good && exists $params{trim_to_len} && $length > $params{trim_to_len}) { $seqn = substr($seqn,0,$params{trim_to_len}); $qualn = substr($qualn,0,$params{trim_to_len}) if(defined $qualn && length($qualn)); $end += ($length-$params{trim_to_len}); } #check for sequence length $length = length($seqn); $bylength = ($length ? 100/$length : 0); if($bylength == 0) { $good = 0; $filtercount{zero_length}++; } if($good && exists $params{min_len} && $length < $params{min_len}) { $good = 0; $filtercount{min_len}++; } if($good && exists $params{max_len} && $length > $params{max_len}) { $good = 0; $filtercount{max_len}++; } if($good && exists $params{range_len} && !&checkRange($params{range_len},$length)) { $good = 0; $filtercount{range_len}++; } #check for quality scores if($good && defined $qualn && (exists $params{min_qual_score} || exists $params{max_qual_score} || exists $params{min_qual_mean} || exists $params{max_qual_mean})) { my ($err); if($qualsnums) { if($begin > 0) { shift(@$qualsnums) foreach(1..$begin); } if($end > 0) { pop(@$qualsnums) foreach(1..$end); } } else { if(exists $params{phred64}) { #scale data to Phred scale if necessary ($qualsnums,$err) = &convertQualAsciiToNumsPhred64($qualn); if($err) { &printError("The sequence quality scores are not in Phred+64 format"); } } else { $qualsnums = &convertQualAsciiToNums($qualn); } } if($good && exists $params{min_qual_score} && min(@$qualsnums) < $params{min_qual_score}) { $good = 0; $filtercount{min_qual_score}++; } if($good && exists $params{max_qual_score} && max(@$qualsnums) < $params{max_qual_score}) { $good = 0; $filtercount{max_qual_score}++; } if($good && exists $params{min_qual_mean} && &getArrayMean(@$qualsnums) < $params{min_qual_mean}) { $good = 0; $filtercount{min_qual_mean}++; } if($good && exists $params{max_qual_mean} && &getArrayMean(@$qualsnums) < $params{max_qual_mean}) { $good = 0; $filtercount{max_qual_mean}++; } } #check for GC content if($good && (exists $params{min_gc} || exists $params{max_gc} || exists $params{range_gc})) { my $gc = ($seqn =~ tr/GC//); $gc = sprintf("%d",$gc*$bylength); if(exists $params{min_gc} && $gc < $params{min_gc}) { $good = 0; $filtercount{min_gc}++; } if($good && exists $params{max_gc} && $gc > $params{max_gc}) { $good = 0; $filtercount{max_gc}++; } if($good && exists $params{range_gc} && !&checkRange($params{range_gc},$gc)) { $good = 0; $filtercount{range_gc}++; } } #check for N's in sequence if($good && (exists $params{ns_max_p} || exists $params{ns_max_n})) { my $ns = ($seqn =~ tr/N//); if(exists $params{ns_max_p} && ($ns*$bylength) > $params{ns_max_p}) { $good = 0; $filtercount{ns_max_p}++; } if($good && exists $params{ns_max_n} && $ns > $params{ns_max_n}) { $good = 0; $filtercount{ns_max_n}++; } } #check for non IUPAC chars in sequence if($good && exists $params{noniupac} && $seqn =~ /[^ACGTN]/o) { $good = 0; $filtercount{noniupac}++; } #check for additional filter parameters if($good && @cps) { foreach my $p (@cps) { if($p->[0]) { #repeats if(index($seqn,$p->[1]x$p->[2]) != -1) { $good = 0; $filtercount{custom_params}++; last; } } else { #percentage my $ns = 0; my $v = $p->[1]; $ns++ while($seqn =~ /$v/g); if((100*$ns/$length) > $p->[2]) { $good = 0; $filtercount{custom_params}++; last; } } } } #check for sequence complexity if($good && defined $complval) { my ($rest,$steps,@vals,$str,$num,$bynum); if($length <= $WINDOWSIZE) { $rest = $length; $steps = 0; } else { $steps = int(($length - $WINDOWSIZE) / $WINDOWSTEP) + 1; $rest = $length - $steps * $WINDOWSTEP; unless($rest > $WINDOWSTEP) { $rest += $WINDOWSTEP; $steps--; } } $num = $WINDOWSIZE-2; $bynum = 1/$num; $num--; my $mean = 0; if($params{lc_method} eq 'dust') { my $dustscore; foreach my $i (0..$steps-1) { $str = substr($seqn,($i * $WINDOWSTEP),$WINDOWSIZE); %counts = (); foreach my $i (@WINDOWSIZEARRAY) { $counts{substr($str,$i,3)}++; } $dustscore = 0; foreach(values %counts) { $dustscore += ($_ * ($_ - 1) * $POINTFIVE); } push(@vals,($dustscore * $bynum)); } #last step if($rest > 5) { $str = substr($seqn,($steps * $WINDOWSTEP),$rest); %counts = (); $num = $rest-2; foreach my $i (0..($num - 1)) { $counts{substr($str,$i,3)}++; } $dustscore = 0; foreach(values %counts) { $dustscore += ($_ * ($_ - 1) * $POINTFIVE); } push(@vals,(($dustscore / ($num-1)) * (($WINDOWSIZE - 2) / $num))); } else { push(@vals,31); #to assign a maximum score based on the scaling factor 100/31 } $mean = &getArrayMean(@vals); if(int($mean * 100 / 31) > $complval) { $good = 0; $filtercount{lc_method}++; } } elsif($params{lc_method} eq 'entropy') { my $entropyval; foreach my $i (0..$steps-1) { $str = substr($seqn,($i * $WINDOWSTEP),$WINDOWSIZE); %counts = (); foreach my $i (@WINDOWSIZEARRAY) { $counts{substr($str,$i,3)}++; } $entropyval = 0; foreach(values %counts) { $entropyval -= ($_ * $bynum) * log($_ * $bynum); } push(@vals,($entropyval * $ONEOVERLOG62)); } #last step if($rest > 5) { $str = substr($seqn,($steps * $WINDOWSTEP),$rest); %counts = (); $num = $rest-2; foreach my $i (0..($num - 1)) { $counts{substr($str,$i,3)}++; } $entropyval = 0; $bynum = 1/$num; foreach(values %counts) { $entropyval -= ($_ * $bynum) * log($_ * $bynum); } push(@vals,($entropyval / log($num))); } else { push(@vals,0); } $mean = &getArrayMean(@vals); if(int($mean * 100) < $complval) { $good = 0; $filtercount{lc_method}++; } } } #stop here for paired-end reads if($file2) { return ($seqn,$good,$begin,$end); } #check for read duplicates if($good && $derep) { if($exactonly) { $md5 = md5_hex($seqn); if(exists $dereptypes{0}) { if(exists $md5s{$md5}) { #forward duplicate $md5s{$md5}->{0}++; if($derepmin <= $md5s{$md5}->{0}+1) { $good = 0; $filtercount{derep}++; } } } if($good && exists $dereptypes{3}) { $md5r = md5_hex(&revcompuc($seqn)); if(exists $md5s{$md5r}) { #reverse duplicate $md5s{$md5}->{3}++; if($derepmin <= $md5s{$md5}->{3}+1) { $good = 0; $filtercount{derep}++; } } } unless(exists $md5s{$md5}) { $md5s{$md5} = {0 => 0, 3 => 0}; } } else { push(@seqsP,[$seqn,$goodcount++,$length]); #keep write data for possible duplicates if($params{out_format} == 1) { #FASTA push(@printtmp,[$sid,$header,$seq,$begin,$end,'']); } else { # FASTQ or FASTA+QUAL or FASTQ+FASTA or FASTQ+FASTA+QUAL push(@printtmp,[$sid,$header,$seq,$begin,$end,$qual]); } } } if($good && (($derep && $exactonly) || !$derep)) { #passed filters $seqcount++; $seqbases += $length; return if($nogood); #check if change of sequence ID if(exists $params{seq_id}) { if($mappings) { print $fhmappings join("\t",$sid,$params{seq_id}.$seqcount)."\n"; } $sid = $params{seq_id}.$seqcount; } if(exists $params{rm_header}) { $header = undef; } #trim if necessary if($begin) { $seq = substr($seq,$begin); $qual = substr($qual,$begin) if(defined $qual && length($qual)); } if($end) { $length = length($seq); $seq = substr($seq,0,$length-$end); $qual = substr($qual,0,$length-$end) if(defined $qual && length($qual)); } #change case if(exists $params{seq_case}) { if($params{seq_case} eq 'lower') { #lower case $seq = lc($seq); } elsif($params{seq_case} eq 'upper') { #upper case $seq = uc($seq); } } #convert between DNA and RNA if(exists $params{dna_rna}) { if($params{dna_rna} eq 'dna') { #RNA to DNA $seq =~ tr/Uu/Tt/; } elsif($params{dna_rna} eq 'rna') { #DNA to RNA $seq =~ tr/Tt/Uu/; } } #write data if($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5) { # FASTQ &printError("missing quality data for sequence \"$sid\" or greater number of sequences than available quality scores") unless(defined $qual); if($stdoutgood) { print STDOUT '@'.$sid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $sid.($header ? ' '.$header : ''))."\n"; print STDOUT $qual."\n"; } else { print $fhgood '@'.$sid.($header ? ' '.$header : '')."\n"; print $fhgood $seq."\n"; print $fhgood '+'.(exists $params{no_qual_header} ? '' : $sid.($header ? ' '.$header : ''))."\n"; print $fhgood $qual."\n"; } } if($params{out_format} == 1 || $params{out_format} == 2 || $params{out_format} == 4 || $params{out_format} == 5) { #FASTA #set line length if($linelen) { $seq =~ s/(.{$linelen})/$1\n/g; $seq =~ s/\n$//; } if($stdoutgood) { print STDOUT '>'.$sid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; } elsif($params{out_format} == 1 || $params{out_format} == 2) { print $fhgood '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhgood $seq."\n"; } else { print $fhgood3 '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhgood3 $seq."\n"; } } if($params{out_format} == 2 || $params{out_format} == 5) { #QUAL &printError("missing quality data for sequence \"$sid\" or greater number of sequences than available quality scores") unless(defined $qual); print $fhgood2 '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhgood2 &convertQualArrayToString(&convertQualAsciiToNums($qual),$linelen)."\n"; } } elsif($good && $derep && !$exactonly) { #do nothing as sequences will be used for duplicate check } else { #filtered out $badcount++; $badbases += length($seq); return if($nobad); #write data if($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5) { # FASTQ &printError("missing quality data for sequence \"$sid\" or greater number of sequences than available quality scores") unless(defined $qual); if($stdoutbad) { print STDOUT '@'.$sid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $sid.($header ? ' '.$header : ''))."\n"; print STDOUT $qual."\n"; } else { print $fhbad '@'.$sid.($header ? ' '.$header : '')."\n"; print $fhbad $seq."\n"; print $fhbad '+'.(exists $params{no_qual_header} ? '' : $sid.($header ? ' '.$header : ''))."\n"; print $fhbad $qual."\n"; } } if($params{out_format} == 1 || $params{out_format} == 2 || $params{out_format} == 4 || $params{out_format} == 5) { #FASTA #set line length if($linelen) { $seq =~ s/(.{$linelen})/$1\n/g; $seq =~ s/\n$//; } if($stdoutbad) { print STDOUT '>'.$sid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; } elsif($params{out_format} == 1 || $params{out_format} == 2) { print $fhbad '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhbad $seq."\n"; } else { print $fhbad3 '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhbad3 $seq."\n"; } } if($params{out_format} == 2 || $params{out_format} == 5) { #QUAL &printError("missing quality data for sequence \"$sid\" or greater number of sequences than available quality scores") unless(defined $qual); print $fhbad2 '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhbad2 &convertQualArrayToString(&convertQualAsciiToNums($qual),$linelen)."\n"; } } } #dereplicate sequences sub derepSeqs { my $numseqs = scalar(@seqsP); if($derep && $numseqs) { my ($sid,$seq,$qual,$header,$begin,$end); my ($dcounts,undef,$dupls) = &checkForDupl(\@seqsP,\%dereptypes,$numseqs); print STDERR "Write results to output file(s)\n" if(exists $params{verbose}); #for progress bar my $progress = 0; my $counter = 1; my $part = int($numseqs/100); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); foreach my $i (0..$numseqs-1) { #progress bar stuff $counter++; if($counter > $part) { $counter = 1; $progress++; $progress = 99 if($progress > 99); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); } #get data $sid = $printtmp[$i]->[0]; $seq = $printtmp[$i]->[2]; $qual = $printtmp[$i]->[5]; $header = $printtmp[$i]->[1]; $begin = $printtmp[$i]->[3]; $end = $printtmp[$i]->[4]; #write data if(exists $dupls->{$i} || (exists $params{seq_num} && $params{seq_num} <= $seqcount)) { #bad $filtercount{derep}++; $badcount++; $badbases += length($seq); next if($nobad); #write data if($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5) { # FASTQ &printError("missing quality data for sequence \"$sid\" or greater number of sequences than available quality scores") unless(defined $qual); if($stdoutbad) { print STDOUT '@'.$sid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $sid.($header ? ' '.$header : ''))."\n"; print STDOUT $qual."\n"; } else { print $fhbad '@'.$sid.($header ? ' '.$header : '')."\n"; print $fhbad $seq."\n"; print $fhbad '+'.(exists $params{no_qual_header} ? '' : $sid.($header ? ' '.$header : ''))."\n"; print $fhbad $qual."\n"; } } if($params{out_format} == 1 || $params{out_format} == 2 || $params{out_format} == 4 || $params{out_format} == 5) { #FASTA #set line length if($linelen) { $seq =~ s/(.{$linelen})/$1\n/g; $seq =~ s/\n$//; } if($stdoutbad) { print STDOUT '>'.$sid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; } elsif($params{out_format} == 1 || $params{out_format} == 2) { print $fhbad '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhbad $seq."\n"; } else { print $fhbad3 '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhbad3 $seq."\n"; } } if($params{out_format} == 2 || $params{out_format} == 5) { #QUAL &printError("missing quality data for sequence \"$sid\" or greater number of sequences than available quality scores") unless(defined $qual); print $fhbad2 '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhbad2 &convertQualArrayToString(&convertQualAsciiToNums($qual),$linelen)."\n"; } } else { #good $seqcount++; $seqbases += (length($seq)-$begin-$end); next if($nogood); #check if change of sequence ID if(exists $params{seq_id}) { if($mappings) { print $fhmappings join("\t",$sid,$params{seq_id}.$seqcount)."\n"; } $sid = $params{seq_id}.$seqcount; } if(exists $params{rm_header}) { $header = undef; } #trim if necessary if($begin) { $seq = substr($seq,$begin); $qual = substr($qual,$begin) if(defined $qual && length($qual)); } if($end) { $length = length($seq); $seq = substr($seq,0,$length-$end); $qual = substr($qual,0,$length-$end) if(defined $qual && length($qual)); } #change case if(exists $params{seq_case}) { if($params{seq_case} eq 'lower') { #lower case $seq = lc($seq); } elsif($params{seq_case} eq 'upper') { #upper case $seq = uc($seq); } } #convert between DNA and RNA if(exists $params{dna_rna}) { if($params{dna_rna} eq 'dna') { #RNA to DNA $seq =~ tr/Uu/Tt/; } elsif($params{dna_rna} eq 'rna') { #DNA to RNA $seq =~ tr/Tt/Uu/; } } #write data if($params{out_format} == 3 || $params{out_format} == 4 || $params{out_format} == 5) { # FASTQ &printError("missing quality data for sequence \"$sid\" or greater number of sequences than available quality scores") unless(defined $qual); if($stdoutgood) { print STDOUT '@'.$sid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; print STDOUT '+'.(exists $params{no_qual_header} ? '' : $sid.($header ? ' '.$header : ''))."\n"; print STDOUT $qual."\n"; } else { print $fhgood '@'.$sid.($header ? ' '.$header : '')."\n"; print $fhgood $seq."\n"; print $fhgood '+'.(exists $params{no_qual_header} ? '' : $sid.($header ? ' '.$header : ''))."\n"; print $fhgood $qual."\n"; } } if($params{out_format} == 1 || $params{out_format} == 2 || $params{out_format} == 4 || $params{out_format} == 5) { #FASTA #set line length if($linelen) { $seq =~ s/(.{$linelen})/$1\n/g; $seq =~ s/\n$//; } if($stdoutgood) { print STDOUT '>'.$sid.($header ? ' '.$header : '')."\n"; print STDOUT $seq."\n"; } elsif($params{out_format} == 1 || $params{out_format} == 2) { print $fhgood '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhgood $seq."\n"; } else { print $fhgood3 '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhgood3 $seq."\n"; } } if($params{out_format} == 2 || $params{out_format} == 5) { #QUAL &printError("missing quality data for sequence \"$sid\" or greater number of sequences than available quality scores") unless(defined $qual); print $fhgood2 '>'.$sid.($header ? ' '.$header : '')."\n"; print $fhgood2 &convertQualArrayToString(&convertQualAsciiToNums($qual),$linelen)."\n"; } } } print STDERR "\r\tdone \n" if(exists $params{verbose}); } } #calculate summary statistics from sequences sub calcSeqStats { my ($seq,$length,$stats,$kmers,$odds,$counts,$pair) = @_; #length related: min, max, range, mean, stddev, mode if(exists $params{stats_len} || exists $params{stats_assembly}) { $counts->{length}->{$length}++; } #dinucleotide odds ratio related: aatt, acgt, agct, at, catg, ccgg, cg, gatc, gc, ta if(exists $params{stats_dinuc}) { &dinucOdds($seq,$length,$odds); } #tag related: probability of 5' and 3' tag sequence based on kmer counts if(exists $params{stats_tag}) { #get kmers if($length >= 5) { #get 5' and 3' ends my $str5 = substr($seq,0,5); my $str3 = substr($seq,$length-5); unless($str5 eq 'AAAAA' || $str5 eq 'TTTTT' || $str5 eq 'CCCCC' || $str5 eq 'GGGGG' || $str5 eq 'NNNNN') { $kmers->{5}->{$str5}++; } unless($str3 eq 'AAAAA' || $str3 eq 'TTTTT' || $str3 eq 'CCCCC' || $str3 eq 'GGGGG' || $str3 eq 'NNNNN') { $kmers->{3}->{$str3}++; } } #check for MID tags if($length >= $MIDCHECKLENGTH) { my $str5 = substr($seq,0,$MIDCHECKLENGTH); foreach my $mid (keys %MIDS) { if(index($str5,$mid) != -1) { $MIDS{$mid}++; last; } } } } #ambiguous base N related: seqswithn, maxp if(exists $params{stats_ns}) { my $bylength = 100/$length; my $ns = ($seq =~ tr/N//); if($pair) { $stats->{stats_ns2}->{seqswithn}++ if($ns > 0); $stats->{stats_ns2}->{maxn} = $ns if($ns > ($stats->{stats_ns2}->{maxn}||0)); $ns = ($ns > 0 && $ns*$bylength < 1 ? 1 : sprintf("%d",$ns*$bylength)); $stats->{stats_ns2}->{maxp} = $ns if($ns > ($stats->{stats_ns2}->{maxp}||0)); } else { $stats->{stats_ns}->{seqswithn}++ if($ns > 0); $stats->{stats_ns}->{maxn} = $ns if($ns > ($stats->{stats_ns}->{maxn}||0)); $ns = ($ns > 0 && $ns*$bylength < 1 ? 1 : sprintf("%d",$ns*$bylength)); $stats->{stats_ns}->{maxp} = $ns if($ns > ($stats->{stats_ns}->{maxp}||0)); } } } #dinucleotide odds ratio calculation sub dinucOdds { my ($seq,$length,$odds) = @_; my ($mononum,$dinum,$i,$x,$y); my %di = %DN_DI; my (%mono,$lengthtmp); my @tmp = split(/N+/,$seq); foreach(@tmp) { $lengthtmp = length($_)-1; next unless($lengthtmp > 0); $mono{AT} += ($_ =~ tr/AT//); $mono{GC} += ($_ =~ tr/GC//); $i = 0; while($i < $lengthtmp) { $di{substr($_,$i++,2)}++; } } $dinum = sum(values %di); if($dinum) { $mononum = sum(values %mono); my $factor = 2 * $mononum * $mononum / $dinum; my $AT = $mono{AT}; my $GC = $mono{GC}; if($AT) { my $AT2 = $factor / ($AT * $AT); $odds->{'AATT'} += ($di{'AA'} + $di{'TT'}) * $AT2; $odds->{'AT'} += 2 * $di{'AT'} * $AT2; $odds->{'TA'} += 2 * $di{'TA'} * $AT2; if($GC) { my $ATGC = $factor / ($AT * $GC); $odds->{'ACGT'} += ($di{'AC'} + $di{'GT'}) * $ATGC; $odds->{'AGCT'} += ($di{'AG'} + $di{'CT'}) * $ATGC; $odds->{'CATG'} += ($di{'CA'} + $di{'TG'}) * $ATGC; $odds->{'GATC'} += ($di{'GA'} + $di{'TC'}) * $ATGC; my $GC2 = $factor / ($GC * $GC); $odds->{'CCGG'} += ($di{'CC'} + $di{'GG'}) * $GC2; $odds->{'CG'} += 2 * $di{'CG'} * $GC2; $odds->{'GC'} += 2 * $di{'GC'} * $GC2; } } elsif($GC) { my $GC2 = $factor / ($GC * $GC); $odds->{'CCGG'} += ($di{'CC'} + $di{'GG'}) * $GC2; $odds->{'CG'} += 2 * $di{'CG'} * $GC2; $odds->{'GC'} += 2 * $di{'GC'} * $GC2; } } } #calculate basic stats from an hash of number->count values sub generateStats { my $counts = shift; my ($min,$max,$modeval,$mode,$mean,$count,$std,$x,$c,@vals,$num,$median,%stats); #min, max, mode and modeval $min = -1; $max = $modeval = $mean = $count = $std = $num = 0; while (($x, $c) = each(%$counts)) { if($min == -1) { $min = $x; } elsif($min > $x) { $min = $x; } if($max < $x) { $max = $x; } if($modeval < $c) { $modeval = $c; $mode = $x; } $mean += $x*$c; $count += $c; foreach(1..$c) { push(@vals,$x); $num++; } } #mean and stddev $mean /= $count; while (($x, $c) = each(%$counts)) { $std += $c*(($x-$mean)**2); } #median if($num == 1) { $median = $vals[0]; } elsif($num == 2) { $median = ($vals[0]+$vals[1])/2; } else { @vals = sort {$a <=> $b} @vals; if($num % 2) { $median = $vals[($num-1)/2]; } else { $median = ($vals[$num/2]+$vals[$num/2-1])/2; } } #save stats $stats{min} = $min; $stats{max} = $max; $stats{range} = $max-$min+1; $stats{modeval} = $modeval; $stats{mode} = $mode; $stats{mean} = sprintf("%.2f",$mean); $stats{stddev} = sprintf("%.2f",($std/$count)**(1/2)); $stats{median} = $median; return \%stats; } sub generateStatsType { my $counts = shift; my (%stats,$min,$max,$modeval,$mode,$mean,$std,$x,$c,@vals,$num,$median,$p25,$p75,$numq,$i,$j,$median1,$median2,$p251,$p252,$p751,$p752); foreach my $kind (keys %$counts) { @vals = (); $min = -1; $max = $modeval = $mean = $std = $num = 0; foreach my $x1 (sort {$a <=> $b} keys %{$counts->{$kind}}) { $c = $counts->{$kind}->{$x1}; if($min == -1) { $min = $x1; } if($max < $x1) { $max = $x1; } if($modeval < $c) { $modeval = $c; $mode = $x1; } $mean += $x1*$c; $num += $c; push(@vals,[$c,$x1]); #count, values } $mean /= $num; while (($x, $c) = each(%{$counts->{$kind}})) { $std += $c*(($x-$mean)**2); } if($num == 1) { $median = $p25 = $p75 = $vals[0]->[1]; } elsif($num == 2) { if($vals[0]->[0] == 1) { #two different numbers $p25 = $vals[0]->[1]; $p75 = $vals[1]->[1]; $median = ($vals[0]->[1]+$vals[1]->[1])/2; } else { $p25 = $p75 = $median = $vals[0]->[1]; #both same } } elsif($num > 2) { if($num % 2) { $i = 0; $j = 0; while($i <= ($num-1)/2) { $median = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } $numq = ($num+1)/2; } else { $i = 0; $j = 0; while($i <= ($num/2-1)) { $median1 = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } $median2 = $median1; while($i <= ($num/2)) { $median2 = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } $median = ($median1 + $median2)/2; $numq = $num/2; } if($numq % 2) { $i = 0; $j = 0; while($i <= (($numq-1)/2)) { $p25 = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } $p75 = $p25; while($i <= ($num-($numq-1)/2-1)) { $p75 = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } } else { $i = 0; $j = 0; while($i <= ($numq/2-1)) { $p251 = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } $p252 = $p251; while($i <= ($numq/2)) { $p252 = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } $p751 = $p252; while($i <= ($num-$numq/2-1)) { $p751 = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } $p752 = $p751; while($i <= ($num-$numq/2)) { $p752 = $vals[$j]->[1]; $i += $vals[$j]->[0]; $j++; } $p25 = ($p251 + $p252) / 2; $p75 = ($p751 + $p752) / 2; } } else { $median = $p25 = $p75 = 0; } $stats{$kind}->{min} = $min; $stats{$kind}->{max} = $max; $stats{$kind}->{range} = $max-$min+1; $stats{$kind}->{modeval} = $modeval; $stats{$kind}->{mode} = $mode; $stats{$kind}->{mean} = sprintf("%.2f",$mean); $stats{$kind}->{std} = sprintf("%.2f",($std/$num)**(1/2)); $stats{$kind}->{median} = int($median); $stats{$kind}->{p25} = int($p25); $stats{$kind}->{p75} = int($p75); } return \%stats; } #requires seqs array with [upper-case seq, array index, length] for each entry sub checkForDupl { #requires seqs array with [upper-case seq, array index, length] for each entry my ($seqs,$types,$numseqs) = @_; my (@sort,$num,%dupls,$pretype,$precount,%counts,%lens); #precount = number duplicates for the same sequence print STDERR "Check for duplicates\n" if(exists $params{verbose}); #for progress bar my $progress = 1; my $counter = 1; my $part = int($numseqs*4/100); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); &printWeb("STATUS: duplicate-status $progress"); #exact duplicates and prefix duplicates if(exists $types->{0} || exists $types->{1} || exists $types->{2}) { $precount = 0; $pretype = -1; @sort = sort {$a->[0] cmp $b->[0]} @$seqs; foreach my $i (0..$numseqs-2) { if(exists $types->{0} && $sort[$i]->[2] == $sort[$i+1]->[2] && $sort[$i]->[0] eq $sort[$i+1]->[0]) { $dupls{$sort[$i]->[1]} = 0; $lens{$sort[$i]->[2]}->{0}++; if($pretype == 0) { $precount++; } else { if($pretype == 1 && $precount) { $counts{$precount}->{$pretype}++; } $pretype = 0; $precount = 1; } } elsif(exists $types->{1} && $sort[$i]->[2] < $sort[$i+1]->[2] && $sort[$i]->[0] eq substr($sort[$i+1]->[0],0,$sort[$i]->[2])) { $dupls{$sort[$i]->[1]} = 1; $lens{$sort[$i]->[2]}->{1}++; if($pretype == 1) { $precount++; } else { if($pretype == 0 && $precount) { $counts{$precount}->{$pretype}++; } $pretype = 1; $precount = 1; } } else { if($precount) { $counts{$precount}->{$pretype}++; $precount = 0; } $pretype = -1; } $sort[$i] = undef; #progress bar stuff $counter++; if($counter > $part) { $counter = 1; $progress++; $progress = 99 if($progress > 99); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); &printWeb("STATUS: duplicate-status $progress"); } } if($precount) { $counts{$precount}->{$pretype}++; } } #suffix duplicates if(exists $types->{2}) { $num = 0; @sort = (); foreach(@$seqs) { next if(exists $dupls{$_->[1]}); push(@sort,[(scalar reverse $_->[0]),$_->[1],$_->[2]]); $num++; } if($num > 1) { $precount = 0; $pretype = -1; @sort = sort {$a->[0] cmp $b->[0]} @sort; foreach my $i (0..$num-2) { if($sort[$i]->[2] < $sort[$i+1]->[2] && $sort[$i]->[0] eq substr($sort[$i+1]->[0],0,$sort[$i]->[2])) { $dupls{$sort[$i]->[1]} = 2; $lens{$sort[$i]->[2]}->{2}++; if($pretype == 2) { $precount++; } else { $pretype = 2; $precount = 1; } } else { if($precount) { $counts{$precount}->{$pretype}++; $precount = 0; } $pretype = -1; } $sort[$i] = undef; #progress bar stuff $counter++; if($counter > $part) { $counter = 1; $progress++; $progress = 99 if($progress > 99); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); &printWeb("STATUS: duplicate-status $progress"); } } if($precount) { $counts{$precount}->{$pretype}++; } } } #reverse complement exact and prefix/suffix duplicates if(exists $types->{3} || exists $types->{4}) { $num = 0; @sort = (); foreach(@$seqs) { if(exists $dupls{$_->[1]}) { $counter++; next; } push(@sort,[$_->[0],$_->[1],$_->[2],0]); push(@sort,[&revcompuc($_->[0]),$_->[1],$_->[2],1]); $num += 2; } if($num > 1) { $precount = 0; $pretype = -1; @sort = sort {$a->[0] cmp $b->[0]} @sort; foreach my $i (0..$num-2) { unless($sort[$i]->[3] == $sort[$i+1]->[3] || $sort[$i]->[1] eq $sort[$i+1]->[1] || exists $dupls{$sort[$i]->[1]}) { #don't check if both same (original or revcomp) or already counted as dubs if(exists $types->{3} && $sort[$i]->[2] == $sort[$i+1]->[2] && $sort[$i]->[0] eq $sort[$i+1]->[0]) { $dupls{$sort[$i]->[1]} = 3; $lens{$sort[$i]->[2]}->{3}++; if($pretype == 3) { $precount++; } else { if($pretype == 4 && $precount) { $counts{$precount}->{$pretype}++; } $pretype = 3; $precount = 1; } } elsif(exists $types->{4} && $sort[$i]->[2] < $sort[$i+1]->[2] && $sort[$i]->[0] eq substr($sort[$i+1]->[0],0,$sort[$i]->[2])) { $dupls{$sort[$i]->[1]} = 4; $lens{$sort[$i]->[2]}->{4}++; if($pretype == 4) { $precount++; } else { if($pretype == 3 && $precount) { $counts{$precount}->{$pretype}++; } $pretype = 4; $precount = 1; } } else { if($precount) { $counts{$precount}->{$pretype}++; $precount = 0; } $pretype = -1; } } $sort[$i] = undef; #progress bar stuff $counter++; if($counter > $part) { $counter = 1; $progress++; $progress = 99 if($progress > 99); print STDERR "\r\tstatus: ".int($progress)." \%" if(exists $params{verbose}); &printWeb("STATUS: duplicate-status $progress"); } } if($precount) { $counts{$precount}->{$pretype}++; } } } print STDERR "\r\tdone \n" if(exists $params{verbose}); &printWeb("STATUS: duplicate-status 100"); return (\%counts,\%lens,\%dupls); } #get the frequency of possible tags by shifting kmers by max 2 positions when aligned sub getTagFrequency { my ($kmers) = @_; #find most abundant kmer counts my $percentone = $numseqs/100; my $percentten = $numseqs/10; my %most; foreach my $sp (keys %$kmers) { $most{$sp}->{max} = 0; foreach(keys %{$kmers->{$sp}}) { # next if($_ eq 'A'x5 || $_ eq 'T'x5 || $_ eq 'C'x5 || $_ eq 'G'x5 || $_ eq 'N'x5); if($kmers->{$sp}->{$_} >= $percentten) { $most{$sp}->{ten}++; } elsif($kmers->{$sp}->{$_} >= $percentone) { $most{$sp}->{one}++; } #get max count $most{$sp}->{max} = $kmers->{$sp}->{$_} if($most{$sp}->{max} < $kmers->{$sp}->{$_}); } } #filter kmers by frequency - threshold of >10% occurrence -> max of 9 different kmers or more if there is non with >10% occurrence my $numseqssub = $numseqs/10; my $onecount = 2; foreach my $sp (keys %$kmers) { foreach(keys %{$kmers->{$sp}}) { if(exists $most{$sp}->{ten} && $most{$sp}->{ten} > 0) { delete $kmers->{$sp}->{$_} if($kmers->{$sp}->{$_} < $percentten); } elsif(exists $most{$sp}->{one} && $most{$sp}->{one} > 0) { delete $kmers->{$sp}->{$_} if($kmers->{$sp}->{$_} < $percentone); } else { delete $kmers->{$sp}->{$_} if($kmers->{$sp}->{$_} != $most{$sp}->{max}); } } } my (%kmersum,%kmershift); foreach my $sp (sort {$b <=> $a} keys %$kmers) { #5' before 3' #if more than one kmer in array, test if shifted by max 2 positions my $numkmer = scalar(keys %{$kmers->{$sp}}); if($numkmer > 1) { my @matrix; my @kmersort = sort {$kmers->{$sp}->{$b} <=> $kmers->{$sp}->{$a}} keys %{$kmers->{$sp}}; foreach my $i (0..($numkmer-2)) { foreach my $j (($i+1)..($numkmer-1)) { $matrix[$i]->[$j-($i+1)] = &align2seqs($kmersort[$j],$kmersort[$i]); } } my $countgood = 0; foreach my $i (0..($numkmer-2)) { unless(@{$matrix[0]->[$i]}) { #not matching my $count = 0; foreach my $j (1..($numkmer-2)) { $count++; last if(defined $matrix[$j]->[$i-$j]); #found shift using other kmers } if($count < ($numkmer-1) && $i > 0) { my $sum = 0; my $sign; foreach my $j (0..$count) { next unless(defined $matrix[$j] && defined $matrix[$j]->[$i-1]); #fix: 08/2010 if(defined $sign) { if(($sign < 0 && (defined $matrix[$j]->[$i-1]->[0] && $matrix[$j]->[$i-1]->[0] < 0)) || ($sign > 0 && (defined $matrix[$j]->[$i-1]->[0] && $matrix[$j]->[$i-1]->[0] > 0))) { $sum += $matrix[$j]->[$i-1]->[0]; } elsif(($sign < 0 && (defined $matrix[$j]->[$i-1]->[1] && $matrix[$j]->[$i-1]->[1] < 0)) || $sign > 0 && (defined $matrix[$j]->[$i-1]->[1] && $matrix[$j]->[$i-1]->[1] > 0)) { $sum += $matrix[$j]->[$i-1]->[1]; } } elsif(defined $matrix[$j]->[$i-1]->[0]) { $sum += $matrix[$j]->[$i-1]->[0]; } $sign = ((defined $matrix[$j]->[$i-1]->[0] && $matrix[$j]->[$i-1]->[0] < 0) ? -1 : 1); } $matrix[0]->[$i] = [$sum] if(defined $sign); #fix: 08/2010 } } unless(@{$matrix[0]->[$i]}) { last; } else { $countgood++; } } if($countgood) { my $min; if($sp == 3) { #3' prime end, 5 for 5' end #find maximum shift to right (pos value) $min = -100; foreach my $i (0..($countgood-1)) { $min = ((defined $matrix[0]->[$i]->[0] && $min > $matrix[0]->[$i]->[0]) ? $min : $matrix[0]->[$i]->[0]); } if($min > 0) { $min = -$min; } else { $min = 0; } } else { #find maximum shift to left (neg value) $min = 100; foreach my $i (0..($countgood-1)) { $min = ((defined $matrix[0]->[$i]->[0] && $min < $matrix[0]->[$i]->[0]) ? $min : $matrix[0]->[$i]->[0]); } if($min < 0) { $min = abs($min); } else { $min = 0; } } # $kmershift{$sp}->{$kmersort[0]} = $min; $kmersum{$sp} += $kmers->{$sp}->{$kmersort[0]}; foreach my $i (0..($countgood-1)) { # $kmershift{$sp}->{$kmersort[$i+1]} = $matrix[0]->[$i]->[0]+$min; $kmersum{$sp} += $kmers->{$sp}->{$kmersort[$i+1]}; } } else { my $tmp = (sort {$kmers->{$sp}->{$b} <=> $kmers->{$sp}->{$a}} keys %{$kmers->{$sp}})[0]; # $kmershift{$sp}->{$tmp} = 0; $kmersum{$sp} += $kmers->{$sp}->{$tmp}; } } elsif($numkmer == 1) { my $tmp = (keys %{$kmers->{$sp}})[0]; # $kmershift{$sp}->{$tmp} = 0; $kmersum{$sp} += $kmers->{$sp}->{$tmp}; } } return \%kmersum; } sub align2seqs { my ($seq1,$seq2) = @_; my @shift; #get number of shifted positions if(substr($seq1,0,4) eq substr($seq2,1,4)) { #shift right by 1 push(@shift,1); } elsif(substr($seq1,0,3) eq substr($seq2,2,3)) { #shift right by 2 push(@shift,2); } if(substr($seq1,1,4) eq substr($seq2,0,4)) { #shift left by 1 push(@shift,-1); } elsif(substr($seq1,2,3) eq substr($seq2,0,3)) { #shift left by 2 push(@shift,-2); } return \@shift; } sub revcompuc { my $seq = shift; $seq = scalar reverse $seq; $seq =~ tr/GATC/CTAG/; return $seq; } sub compuc { my $seq = shift; $seq =~ tr/GATC/CTAG/; return $seq; } #get data for graphs sub getSeqStats { my ($graphdata,$seqgd,$length) = @_; if($length > $maxlength) { $maxlength = $length; } my ($gc,$ns,$begin,$end,$str5,$str3,$bylength,$tmp); $begin = $end = $gc = $ns = 0; #get length $bylength = 100/$length; #get 5' and 3' ends if($webstats{pt} || $webstats{ts} || $graphstats{pt} || $graphstats{ts}) { $str5 = substr($seqgd,0,5); $str3 = substr($seqgd,$length-5); } #GC content if($webstats{gc} || $graphstats{gc}) { $gc = ($seqgd =~ tr/GC//); $gc = sprintf("%d",$gc*$bylength); } #N's if($webstats{ns} || $graphstats{ns}) { $ns = ($seqgd =~ tr/N//); $ns = ($ns > 0 && $ns*$bylength < 1 ? 1 : sprintf("%d",$ns*$bylength)); } #tail stuff with min 5 char repeats if($webstats{pt} || $graphstats{pt}) { #at sequence 5'-end if($str5 eq 'AAAAA' || $str5 eq 'TTTTT') { my $tmpchar = substr($str5,0,1); #A or T $begin = 5; foreach(5..$length-1) { $tmp = substr($seqgd,$_,1); last unless($tmp eq $tmpchar || $tmp eq 'N'); $begin++; } } #at sequence 3'-end if($str3 eq 'AAAAA' || $str3 eq 'TTTTT') { my $tmpchar = substr($str3,0,1); #A or T $end = 5; foreach (reverse 0..$length-6) { $tmp = substr($seqgd,$_,1); last unless($tmp eq $tmpchar || $tmp eq 'N'); $end++; } } } #get base frequencies if($webstats{ts} || $graphstats{ts}) { if($length >= $TAG_LENGTH) { foreach my $i (0..$TAG_LENGTH-1) { $graphdata->{freqs}->{5}->{$i}->{substr($seqgd,$i,1)}++; $graphdata->{freqs}->{3}->{$i}->{substr($seqgd,$length-$TAG_LENGTH+$i,1)}++; } } #get kmers if($length >= 5) { unless($begin > 0 || $str5 eq 'CCCCC' || $str5 eq 'GGGGG' || $str5 eq 'NNNNN') { $graphdata->{kmers}->{5}->{$str5}++; } unless($end > 0 || $str3 eq 'CCCCC' || $str3 eq 'GGGGG' || $str3 eq 'NNNNN') { $graphdata->{kmers}->{3}->{$str3}++; } } #check for MID tags if($length >= $MIDCHECKLENGTH) { $str5 = substr($seqgd,0,$MIDCHECKLENGTH); foreach my $mid (keys %MIDS) { if(index($str5,$mid) != -1) { $graphdata->{mids}->{$mid}++; last; } } } } #calculate sequence complexity if($webstats{sc} || $graphstats{sc}) { my ($rest,$steps,@dust,@entropy,$mean,$str,%counts,$num,$dustscore,$entropyval,$bynum); if($length <= $WINDOWSIZE) { $rest = $length; $steps = 0; } else { $steps = int(($length - $WINDOWSIZE) / $WINDOWSTEP) + 1; $rest = $length - $steps * $WINDOWSTEP; unless($rest > $WINDOWSTEP) { $rest += $WINDOWSTEP; $steps--; } } #dust and entropy $num = $WINDOWSIZE-2; $bynum = 1/$num; $num--; foreach my $i (0..$steps-1) { $str = substr($seqgd,($i * $WINDOWSTEP),$WINDOWSIZE); %counts = (); foreach my $i (@WINDOWSIZEARRAY) { $counts{substr($str,$i,3)}++; } #dust and entropy $dustscore = $entropyval = 0; foreach(values %counts) { $dustscore += ($_ * ($_ - 1) * $POINTFIVE); $entropyval -= ($_ * $bynum) * log($_ * $bynum); } push(@dust,($dustscore * $bynum)); push(@entropy,($entropyval * $ONEOVERLOG62)); } #last step if($rest > 5) { $str = substr($seqgd,($steps * $WINDOWSTEP),$rest); %counts = (); $num = $rest-2; foreach my $i (0..($num - 1)) { $counts{substr($str,$i,3)}++; } $dustscore = $entropyval = 0; $bynum = 1/$num; foreach(values %counts) { $dustscore += ($_ * ($_ - 1) * $POINTFIVE); $entropyval -= ($_ * $bynum) * log($_ * $bynum); } push(@dust,(($dustscore / ($num-1)) * (($WINDOWSIZE - 2) / $num))); push(@entropy,($entropyval / log($num))); } else { push(@dust,31); #to assign a maximum score based on the scaling factor 100/31 push(@entropy,0); } $mean = &getArrayMean(@dust); $mean = int($mean * 100 / 31); #scale to 100 $graphdata{compldust}->{$mean}++; if(!exists $graphdata{complvals}->{dust}->{minval} || $graphdata{complvals}->{dust}->{minval} > $mean) { $graphdata{complvals}->{dust}->{minval} = $mean; $graphdata{complvals}->{dust}->{minseq} = &getGraphDataSequence($seqgd); } if(!exists $graphdata{complvals}->{dust}->{maxval} || $graphdata{complvals}->{dust}->{maxval} < $mean) { $graphdata{complvals}->{dust}->{maxval} = $mean; $graphdata{complvals}->{dust}->{maxseq} = &getGraphDataSequence($seqgd); } $mean = &getArrayMean(@entropy); $mean = int($mean * 100); #scale to 100 $graphdata{complentropy}->{$mean}++; if(!exists $graphdata{complvals}->{entropy}->{minval} || $graphdata{complvals}->{entropy}->{minval} > $mean) { $graphdata{complvals}->{entropy}->{minval} = $mean; $graphdata{complvals}->{entropy}->{minseq} = &getGraphDataSequence($seqgd); } if(!exists $graphdata{complvals}->{entropy}->{maxval} || $graphdata{complvals}->{entropy}->{maxval} < $mean) { $graphdata{complvals}->{entropy}->{maxval} = $mean; $graphdata{complvals}->{entropy}->{maxseq} = &getGraphDataSequence($seqgd); } } #calculate dinucleotide odd ratios if($webstats{dn} || $graphstats{dn}) { &dinucOdds($seqgd,$length,\%{$graphdata{dinucodds}}); } #store counts if($webstats{ld} || $webstats{ld} || $graphstats{ld} || $graphstats{ld}) { $graphdata->{counts}->{length}->{$length}++; } if($begin) { $graphdata->{counts}->{tail5}->{$begin}++; } if($end) { $graphdata->{counts}->{tail3}->{$end}++; } if($webstats{gc} || $graphstats{gc}) { $graphdata->{counts}->{gc}->{$gc}++; } if($ns) { $graphdata->{counts}->{ns}->{$ns}++; } return 1; } sub getGraphDataSequence { my $seq = shift; if(length($seq) > $GRAPH_DATA_SEQ_MAX_LENGTH) { return substr($seq,0,$GRAPH_DATA_SEQ_MAX_LENGTH)."..."; } else { return $seq; } } sub getQualStats { my ($graphdata,$qual,$length) = @_; #check if quality values are available return 0 unless($qual && ($webstats{qd} || $graphstats{qd})); #calculate decimal values of quals my ($vals,$err); if(exists $params{phred64}) { #scale data to Phred scale if necessary ($vals,$err) = &convertQualAsciiToNumsPhred64($qual); if($err) { &printError("The sequence quality scores are not in Phred+64 format"); } } else { $vals = &convertQualAsciiToNums($qual); } #mean quality score $graphdata->{qualsmean}->{int(&getArrayMean(@$vals))}++; my ($factor,$tmp,$count,$xmax,$bin,$tmpbin,$step); if($scale == 1) { #relative #qual if($length == 100) { foreach my $i (0..99) { $graphdata->{quals}->{$i}->{$vals->[$i]}++; } } elsif($length < 100) { #stretch $factor = 100/$length; foreach my $i (0..$length-1) { $tmp = $vals->[$i]; foreach my $j (int($i*$factor)..int(($i+1)*$factor)-1) { $graphdata->{quals}->{$j}->{$tmp}++; } } } elsif($length > 100) { #shrink $factor = $length/100; foreach my $i (0..99) { $tmp = $count = 0; foreach my $j (int($i*$factor)..int(($i+1)*$factor)-1) { $tmp += $vals->[$j]; $count++; } $graphdata->{quals}->{$i}->{int($tmp/$count)}++; } #my $piece = int($length/100); #my $bypiece = 1/($piece+1); #my $start = 0; #my $end = 0; #my $rest = ($length % 100) - 1; #foreach my $i (0..$rest) { # $end += $piece; # $tmp = 0; # foreach my $j ($start..$end) { # $tmp += $vals->[$j]; # } # $graphdata{quals}->{$i}->{int($tmp * $bypiece)}++; # $start = ++$end; #} #$rest++; #$piece--; #$bypiece = 1/($piece+1); #foreach my $i ($rest..99) { # $end += $piece; # $tmp = 0; # foreach my $j ($start..$end) { # $tmp += $vals->[$j]; # } # $graphdata{quals}->{$i}->{int($tmp * $bypiece)}++; # $start = ++$end; #} } } #absolute foreach my $i (0..$length-1) { $graphdata->{quala}->{$i}->{$vals->[$i]}++; } } sub getBinVal { my $val = shift; my $step; if(!$val || $val <= 100) { return 1; } elsif($val < 10000) { return int($val/100)+($val % 100 ? 1 : 0); } elsif($val < 100000) { return 1000; } else { $step = 1000000; my $xmax = ($val % $step ? sprintf("%d",($val/$step+1))*$step : $val); return ($xmax/100); } } sub convertStringToInt { my $string = shift; $string =~ s/(.)/sprintf("%x",ord($1))/eg; return $string; } sub getFileName { my $str = shift; $str =~ s/^.*\/([^\/]+)$/$1/; return $str; }